Merge pull request #5970 from ofalvai/feature/ofa/read-receipts-design

Make read receipt avatar list more compact
This commit is contained in:
Benoit Marty 2022-05-31 18:26:57 +02:00 committed by GitHub
commit e6beb73e3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 89 deletions

1
changelog.d/5970.feature Normal file
View file

@ -0,0 +1 @@
Make read receipt avatar list more compact

View file

@ -28,8 +28,7 @@ import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
import im.vector.app.features.home.room.detail.timeline.item.toMatrixItem import im.vector.app.features.home.room.detail.timeline.item.toMatrixItem
private const val MAX_RECEIPT_DISPLAYED = 5 private const val MAX_RECEIPT_DISPLAYED = 3
private const val MAX_RECEIPT_DESCRIBED = 3
class ReadReceiptsView @JvmOverloads constructor( class ReadReceiptsView @JvmOverloads constructor(
context: Context, context: Context,
@ -45,13 +44,7 @@ class ReadReceiptsView @JvmOverloads constructor(
} }
private val receiptAvatars: List<ImageView> by lazy { private val receiptAvatars: List<ImageView> by lazy {
listOf( listOf(views.receiptAvatar1, views.receiptAvatar2, views.receiptAvatar3)
views.receiptAvatar1,
views.receiptAvatar2,
views.receiptAvatar3,
views.receiptAvatar4,
views.receiptAvatar5
)
} }
private fun setupView() { private fun setupView() {
@ -60,66 +53,58 @@ class ReadReceiptsView @JvmOverloads constructor(
} }
fun render(readReceipts: List<ReadReceiptData>, avatarRenderer: AvatarRenderer) { fun render(readReceipts: List<ReadReceiptData>, avatarRenderer: AvatarRenderer) {
if (readReceipts.isNotEmpty()) { receiptAvatars.forEach { it.isVisible = false }
isVisible = true
for (index in 0 until MAX_RECEIPT_DISPLAYED) {
val receiptData = readReceipts.getOrNull(index)
if (receiptData == null) {
receiptAvatars[index].visibility = View.INVISIBLE
} else {
receiptAvatars[index].visibility = View.VISIBLE
avatarRenderer.render(receiptData.toMatrixItem(), receiptAvatars[index])
}
}
val displayNames = readReceipts readReceipts.take(MAX_RECEIPT_DISPLAYED).forEachIndexed { index, receiptData ->
.mapNotNull { it.displayName } receiptAvatars[index].isVisible = true
.filter { it.isNotBlank() } avatarRenderer.render(receiptData.toMatrixItem(), receiptAvatars[index])
.take(MAX_RECEIPT_DESCRIBED) }
if (readReceipts.size > MAX_RECEIPT_DISPLAYED) { val displayNames = readReceipts
views.receiptMore.visibility = View.VISIBLE .mapNotNull { it.displayName }
views.receiptMore.text = context.getString( .filter { it.isNotBlank() }
R.string.x_plus, readReceipts.size - MAX_RECEIPT_DISPLAYED .take(MAX_RECEIPT_DISPLAYED)
)
} else { if (readReceipts.size > MAX_RECEIPT_DISPLAYED) {
views.receiptMore.visibility = View.GONE views.receiptMore.visibility = View.VISIBLE
} views.receiptMore.text = context.getString(
contentDescription = when (readReceipts.size) { R.string.x_plus, readReceipts.size - MAX_RECEIPT_DISPLAYED
1 -> )
if (displayNames.size == 1) {
context.getString(R.string.one_user_read, displayNames[0])
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
2 ->
if (displayNames.size == 2) {
context.getString(R.string.two_users_read, displayNames[0], displayNames[1])
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
3 ->
if (displayNames.size == 3) {
context.getString(R.string.three_users_read, displayNames[0], displayNames[1], displayNames[2])
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
else ->
if (displayNames.size >= 2) {
val qty = readReceipts.size - 2
context.resources.getQuantityString(
R.plurals.two_and_some_others_read,
qty,
displayNames[0],
displayNames[1],
qty
)
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
}
} else { } else {
isVisible = false views.receiptMore.visibility = View.GONE
}
contentDescription = when (readReceipts.size) {
1 ->
if (displayNames.size == 1) {
context.getString(R.string.one_user_read, displayNames[0])
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
2 ->
if (displayNames.size == 2) {
context.getString(R.string.two_users_read, displayNames[0], displayNames[1])
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
3 ->
if (displayNames.size == 3) {
context.getString(R.string.three_users_read, displayNames[0], displayNames[1], displayNames[2])
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
else ->
if (displayNames.size >= 2) {
val qty = readReceipts.size - 2
context.resources.getQuantityString(
R.plurals.two_and_some_others_read,
qty,
displayNames[0],
displayNames[1],
qty
)
} else {
context.resources.getQuantityString(R.plurals.fallback_users_read, readReceipts.size)
}
} }
} }

View file

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="end"
tools:parentTag="android.widget.LinearLayout"> tools:parentTag="android.widget.LinearLayout">
<TextView <TextView
@ -18,53 +19,40 @@
android:textColor="?vctr_content_primary" android:textColor="?vctr_content_primary"
tools:text="999+" /> tools:text="999+" />
<ImageView
android:id="@+id/receiptAvatar5"
android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp"
android:adjustViewBounds="true"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
tools:src="@sample/user_round_avatars" />
<ImageView
android:id="@+id/receiptAvatar4"
android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp"
android:adjustViewBounds="true"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
tools:src="@sample/user_round_avatars" />
<ImageView <ImageView
android:id="@+id/receiptAvatar3" android:id="@+id/receiptAvatar3"
android:layout_width="@dimen/item_event_message_state_size" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="@dimen/item_event_message_state_size" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:layout_marginEnd="-6dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:padding="1dp"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:ignore="NegativeMargin"
tools:src="@sample/user_round_avatars" /> tools:src="@sample/user_round_avatars" />
<ImageView <ImageView
android:id="@+id/receiptAvatar2" android:id="@+id/receiptAvatar2"
android:layout_width="@dimen/item_event_message_state_size" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="@dimen/item_event_message_state_size" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp" android:layout_marginEnd="-6dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:background="@drawable/pill_receipt"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:padding="1dp"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:ignore="NegativeMargin"
tools:src="@sample/user_round_avatars" /> tools:src="@sample/user_round_avatars" />
<ImageView <ImageView
android:id="@+id/receiptAvatar1" android:id="@+id/receiptAvatar1"
android:layout_width="@dimen/item_event_message_state_size" android:layout_width="@dimen/item_event_message_state_size"
android:layout_height="@dimen/item_event_message_state_size" android:layout_height="@dimen/item_event_message_state_size"
android:layout_marginStart="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:background="@drawable/pill_receipt"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:padding="1dp"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@sample/user_round_avatars" /> tools:src="@sample/user_round_avatars" />

View file

@ -1424,7 +1424,7 @@
<string name="merged_events_collapse">collapse</string> <string name="merged_events_collapse">collapse</string>
<string name="generic_label_and_value">%1$s: %2$s</string> <string name="generic_label_and_value">%1$s: %2$s</string>
<string name="x_plus">%d+</string> <string name="x_plus">+%d</string>
<string name="no_valid_google_play_services_apk">No valid Google Play Services APK found. Notifications may not work properly.</string> <string name="no_valid_google_play_services_apk">No valid Google Play Services APK found. Notifications may not work properly.</string>
<!-- Passphrase --> <!-- Passphrase -->