Only show green indicator for "All Messages"

- Only show green indicator for "All Messages" as mentions doesn't work and we should never see it for muted rooms.
- Remove code that tried to reflect the notificationsEnabled setting I mis-undertood the requirements by reading the iOS code.
This commit is contained in:
David Langley 2023-09-14 16:39:11 +01:00
parent 2a7a46841e
commit 43fab70d30
3 changed files with 18 additions and 36 deletions

View file

@ -49,7 +49,6 @@ dependencies {
implementation(projects.libraries.dateformatter.api) implementation(projects.libraries.dateformatter.api)
implementation(projects.libraries.eventformatter.api) implementation(projects.libraries.eventformatter.api)
implementation(projects.libraries.deeplink) implementation(projects.libraries.deeplink)
implementation(projects.libraries.pushstore.api)
implementation(projects.features.invitelist.api) implementation(projects.features.invitelist.api)
implementation(projects.features.networkmonitor.api) implementation(projects.features.networkmonitor.api)
implementation(projects.features.leaveroom.api) implementation(projects.features.leaveroom.api)

View file

@ -24,12 +24,10 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -154,7 +152,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) {
Text( Text(
text = room.timestamp ?: "", text = room.timestamp ?: "",
style = ElementTheme.typography.fontBodySmRegular, style = ElementTheme.typography.fontBodySmRegular,
color = if (room.hasUnread) { color = if (room.shouldDisplayNotificationAlertDecoration) {
ElementTheme.colors.unreadIndicator ElementTheme.colors.unreadIndicator
} else { } else {
MaterialTheme.roomListRoomMessageDate() MaterialTheme.roomListRoomMessageDate()
@ -184,7 +182,7 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) {
horizontalArrangement = Arrangement.spacedBy(8.dp) horizontalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
NotificationIcon(room) NotificationIcon(room)
if (room.hasUnread) { if (room.shouldDisplayNotificationAlertDecoration) {
UnreadIndicatorAtom( UnreadIndicatorAtom(
modifier = Modifier.padding(top = 3.dp), modifier = Modifier.padding(top = 3.dp),
) )
@ -192,23 +190,28 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) {
} }
} }
// We should never show a green dot/icon for mute. Also mentions is not yet supported by the mobile app.
// In some cases a green @ was incorrectly shown when we switch from ALL_MESSAGES to MENTIONS_AND_KEYWORDS_ONLY
// and we don't know whether the room has mentions, just that it has unread.
private val RoomListRoomSummary.shouldDisplayNotificationAlertDecoration get() = hasUnread
&& notificationMode != RoomNotificationMode.MUTE
&& notificationMode != RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
@Composable @Composable
private fun NotificationIcon(room: RoomListRoomSummary) { private fun NotificationIcon(room: RoomListRoomSummary) {
val tint = if(room.hasUnread) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary
when(room.notificationMode) { when(room.notificationMode) {
null, RoomNotificationMode.ALL_MESSAGES -> return null, RoomNotificationMode.ALL_MESSAGES -> return
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY ->
Icon( Icon(
contentDescription = stringResource(CommonStrings.screen_notification_settings_mode_mentions), contentDescription = stringResource(CommonStrings.screen_notification_settings_mode_mentions),
imageVector = ImageVector.vectorResource(VectorIcons.Mention), imageVector = ImageVector.vectorResource(VectorIcons.Mention),
tint = tint, tint = ElementTheme.colors.iconQuaternary,
) )
RoomNotificationMode.MUTE -> RoomNotificationMode.MUTE ->
Icon( Icon(
contentDescription = stringResource(CommonStrings.common_mute), contentDescription = stringResource(CommonStrings.common_mute),
imageVector = ImageVector.vectorResource(VectorIcons.Mute), imageVector = ImageVector.vectorResource(VectorIcons.Mute),
tint = tint, tint = ElementTheme.colors.iconQuaternary,
) )
} }
} }

View file

@ -26,24 +26,19 @@ import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormat
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -59,8 +54,6 @@ class RoomListDataSource @Inject constructor(
private val coroutineDispatchers: CoroutineDispatchers, private val coroutineDispatchers: CoroutineDispatchers,
notificationSettingsService: NotificationSettingsService, notificationSettingsService: NotificationSettingsService,
appScope: CoroutineScope, appScope: CoroutineScope,
userPushStoreFactory: UserPushStoreFactory,
matrixClient: MatrixClient,
) { ) {
init { init {
notificationSettingsService.notificationSettingsChangeFlow notificationSettingsService.notificationSettingsChangeFlow
@ -69,13 +62,6 @@ class RoomListDataSource @Inject constructor(
roomListService.rebuildRoomSummaries() roomListService.rebuildRoomSummaries()
} }
.launchIn(appScope) .launchIn(appScope)
val userPushStore = userPushStoreFactory.create(matrixClient.sessionId)
userPushStore.getNotificationEnabledForDevice().distinctUntilChanged()
.onEach {
roomListService.rebuildRoomSummaries()
}
.launchIn(appScope)
} }
private val _filter = MutableStateFlow("") private val _filter = MutableStateFlow("")
private val _allRooms = MutableStateFlow<ImmutableList<RoomListRoomSummary>>(persistentListOf()) private val _allRooms = MutableStateFlow<ImmutableList<RoomListRoomSummary>>(persistentListOf())
@ -86,15 +72,13 @@ class RoomListDataSource @Inject constructor(
private val diffCacheUpdater = DiffCacheUpdater<RoomSummary, RoomListRoomSummary>(diffCache = diffCache, detectMoves = true) { old, new -> private val diffCacheUpdater = DiffCacheUpdater<RoomSummary, RoomListRoomSummary>(diffCache = diffCache, detectMoves = true) { old, new ->
old?.identifier() == new?.identifier() old?.identifier() == new?.identifier()
} }
private val userPushStore = userPushStoreFactory.create(matrixClient.sessionId)
fun launchIn(coroutineScope: CoroutineScope) { fun launchIn(coroutineScope: CoroutineScope) {
roomListService roomListService
.allRooms() .allRooms()
.summaries .summaries
.onEach { roomSummaries -> .onEach { roomSummaries ->
replaceWith(roomSummaries, userPushStore.getNotificationEnabledForDevice().first()) replaceWith(roomSummaries)
} }
.launchIn(coroutineScope) .launchIn(coroutineScope)
@ -121,14 +105,14 @@ class RoomListDataSource @Inject constructor(
val allRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _allRooms val allRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _allRooms
val filteredRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _filteredRooms val filteredRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _filteredRooms
private suspend fun replaceWith(roomSummaries: List<RoomSummary>, notificationsEnabled: Boolean) = withContext(coroutineDispatchers.computation) { private suspend fun replaceWith(roomSummaries: List<RoomSummary>) = withContext(coroutineDispatchers.computation) {
lock.withLock { lock.withLock {
diffCacheUpdater.updateWith(roomSummaries) diffCacheUpdater.updateWith(roomSummaries)
buildAndEmitAllRooms(roomSummaries, notificationsEnabled) buildAndEmitAllRooms(roomSummaries)
} }
} }
private suspend fun buildAndEmitAllRooms(roomSummaries: List<RoomSummary>, notificationsEnabled: Boolean) { private suspend fun buildAndEmitAllRooms(roomSummaries: List<RoomSummary>) {
if (diffCache.isEmpty()) { if (diffCache.isEmpty()) {
_allRooms.emit( _allRooms.emit(
RoomListRoomSummaryPlaceholders.createFakeList(16).toImmutableList() RoomListRoomSummaryPlaceholders.createFakeList(16).toImmutableList()
@ -138,7 +122,7 @@ class RoomListDataSource @Inject constructor(
for (index in diffCache.indices()) { for (index in diffCache.indices()) {
val cacheItem = diffCache.get(index) val cacheItem = diffCache.get(index)
if (cacheItem == null) { if (cacheItem == null) {
buildAndCacheItem(roomSummaries, index, notificationsEnabled)?.also { timelineItemState -> buildAndCacheItem(roomSummaries, index)?.also { timelineItemState ->
roomListRoomSummaries.add(timelineItemState) roomListRoomSummaries.add(timelineItemState)
} }
} else { } else {
@ -149,16 +133,12 @@ class RoomListDataSource @Inject constructor(
} }
} }
private fun buildAndCacheItem( private fun buildAndCacheItem(roomSummaries: List<RoomSummary>, index: Int, ): RoomListRoomSummary? {
roomSummaries: List<RoomSummary>,
index: Int,
notificationsEnabled: Boolean,
): RoomListRoomSummary? {
val roomListRoomSummary = when (val roomSummary = roomSummaries.getOrNull(index)) { val roomListRoomSummary = when (val roomSummary = roomSummaries.getOrNull(index)) {
is RoomSummary.Empty -> RoomListRoomSummaryPlaceholders.create(roomSummary.identifier) is RoomSummary.Empty -> RoomListRoomSummaryPlaceholders.create(roomSummary.identifier)
is RoomSummary.Filled -> { is RoomSummary.Filled -> {
// Only show a decoration if notifications are enabled and the mode is not ALL_MESSAGES // Only show a decoration if the mode is not ALL_MESSAGES
val notificationMode = if (roomSummary.details.notificationMode == RoomNotificationMode.ALL_MESSAGES || !notificationsEnabled) { val notificationMode = if (roomSummary.details.notificationMode == RoomNotificationMode.ALL_MESSAGES) {
null null
} else { } else {
roomSummary.details.notificationMode roomSummary.details.notificationMode