diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt index e33179a739..3268f6308e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/RoomSummary.kt @@ -52,6 +52,8 @@ data class RoomSummary( val hasUnreadOriginalContentMessages: Boolean = false, val unreadCount: Int? = 0, val markedUnread: Boolean = false, + val aggregatedUnreadCount: Int = 0, + val aggregatedNotificationCount: Int = 0, val tags: List = emptyList(), val membership: Membership = Membership.NONE, val versioningState: VersioningState = VersioningState.NONE, @@ -156,6 +158,7 @@ data class RoomSummary( // SC addition interface RoomSummaryPreferenceProvider { fun getUnreadKind(isDirect: Boolean): Int + fun aggregateUnreadRoomCounts(): Boolean fun getUnreadRoomSummaryField(isDirect: Boolean): String { return when(getUnreadKind(isDirect)) { UNREAD_KIND_ORIGINAL_CONTENT -> RoomSummaryEntityFields.HAS_UNREAD_ORIGINAL_CONTENT_MESSAGES diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index e5ed04c2e0..13f8efab94 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -49,7 +49,7 @@ internal object RealmSessionStoreMigration : RealmMigration { // SC-specific DB changes on top of Element // 1: added markedUnread field - const val SESSION_STORE_SCHEMA_SC_VERSION = 2L + const val SESSION_STORE_SCHEMA_SC_VERSION = 3L const val SESSION_STORE_SCHEMA_SC_VERSION_OFFSET = (1L shl 12) const val SESSION_STORE_SCHEMA_VERSION = 17L + @@ -82,6 +82,7 @@ internal object RealmSessionStoreMigration : RealmMigration { if (oldScVersion <= 0) migrateToSc1(realm) if (oldScVersion <= 1) migrateToSc2(realm) + if (oldScVersion <= 2) migrateToSc3(realm) } // SC Version 1L added markedUnread @@ -98,6 +99,14 @@ internal object RealmSessionStoreMigration : RealmMigration { ?.addField(RoomSummaryEntityFields.UNREAD_COUNT, Int::class.java) } + // SC Version 3L added aggregated counts + private fun migrateToSc3(realm: DynamicRealm) { + Timber.d("Step SC 2 -> 3") + realm.schema.get("RoomSummaryEntity") + ?.addField(RoomSummaryEntityFields.AGGREGATED_UNREAD_COUNT, Int::class.java) + ?.addField(RoomSummaryEntityFields.AGGREGATED_NOTIFICATION_COUNT, Int::class.java) + } + private fun migrateTo1(realm: DynamicRealm) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt index 7d0c72d666..2fa24beab7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/RoomSummaryMapper.kt @@ -63,6 +63,8 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa highlightCount = roomSummaryEntity.highlightCount, notificationCount = roomSummaryEntity.notificationCount, unreadCount = roomSummaryEntity.unreadCount, + aggregatedUnreadCount = roomSummaryEntity.aggregatedUnreadCount, + aggregatedNotificationCount = roomSummaryEntity.aggregatedNotificationCount, hasUnreadMessages = roomSummaryEntity.hasUnreadMessages, hasUnreadContentMessages = roomSummaryEntity.hasUnreadContentMessages, hasUnreadOriginalContentMessages = roomSummaryEntity.hasUnreadOriginalContentMessages, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt index b68be14496..b3536ee426 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/RoomSummaryEntity.kt @@ -119,6 +119,16 @@ internal open class RoomSummaryEntity( return field } + var aggregatedUnreadCount: Int = 0 + set(value) { + if (value != field) field = value + } + + var aggregatedNotificationCount: Int = 0 + set(value) { + if (value != field) field = value + } + var readMarkerId: String? = null set(value) { if (value != field) field = value diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt index 9609fd47dd..36cb94c7af 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt @@ -229,21 +229,40 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat var notificationCount: RoomAggregateNotificationCount? = null monarchy.doWithRealm { realm -> val roomSummariesQuery = roomSummariesQuery(realm, queryParams) - val notifCount = roomSummariesQuery.sum(RoomSummaryEntityFields.NOTIFICATION_COUNT).toInt() - val highlightCount = roomSummariesQuery.sum(RoomSummaryEntityFields.HIGHLIGHT_COUNT).toInt() - val unreadCount = max( - // Preferred since MSC 2654 - roomSummariesQuery.sum(RoomSummaryEntityFields.UNREAD_COUNT).toInt(), - // TODO-SC-merge: properly use dm/non-dm flag? (note that this will be likely overwritten either way by above field from MSC 2654) - roomSummariesQuery(realm, queryParams).equalTo(preferenceProvider.getUnreadRoomSummaryField(false), true).count().toInt() - ) val markedUnreadCount = roomSummariesQuery(realm, queryParams).equalTo(RoomSummaryEntityFields.MARKED_UNREAD, true).count().toInt() - notificationCount = RoomAggregateNotificationCount( - notifCount, - highlightCount, - unreadCount, - markedUnreadCount - ) + notificationCount = if (preferenceProvider.aggregateUnreadRoomCounts()) { + // Count chats + val notifCount = roomSummariesQuery.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0).count().toInt() + val highlightCount = roomSummariesQuery.greaterThan(RoomSummaryEntityFields.HIGHLIGHT_COUNT, 0).count().toInt() + val unreadCount = max( + // Preferred since MSC 2654 + roomSummariesQuery.greaterThan(RoomSummaryEntityFields.UNREAD_COUNT, 0).count().toInt(), + // TODO-SC-merge: properly use dm/non-dm flag? (note that this will be likely overwritten either way by above field from MSC 2654) + roomSummariesQuery(realm, queryParams).equalTo(preferenceProvider.getUnreadRoomSummaryField(false), true).count().toInt() + ) + RoomAggregateNotificationCount( + notifCount, + highlightCount, + unreadCount, + markedUnreadCount + ) + } else { + // Sum unread counts + val notifCount = roomSummariesQuery.sum(RoomSummaryEntityFields.NOTIFICATION_COUNT).toInt() + val highlightCount = roomSummariesQuery.sum(RoomSummaryEntityFields.HIGHLIGHT_COUNT).toInt() + val unreadCount = max( + // Preferred since MSC 2654 + roomSummariesQuery.sum(RoomSummaryEntityFields.UNREAD_COUNT).toInt(), + // TODO-SC-merge: properly use dm/non-dm flag? (note that this will be likely overwritten either way by above field from MSC 2654) + roomSummariesQuery(realm, queryParams).equalTo(preferenceProvider.getUnreadRoomSummaryField(false), true).count().toInt() + ) + RoomAggregateNotificationCount( + notifCount, + highlightCount, + unreadCount, + markedUnreadCount + ) + } } return notificationCount!! } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 37787f1b2b..b9bfe41d20 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -65,6 +65,7 @@ import org.matrix.android.sdk.internal.session.sync.model.RoomSyncSummary import org.matrix.android.sdk.internal.session.sync.model.RoomSyncUnreadNotifications import timber.log.Timber import javax.inject.Inject +import kotlin.math.min import kotlin.system.measureTimeMillis internal class RoomSummaryUpdater @Inject constructor( @@ -99,6 +100,8 @@ internal class RoomSummaryUpdater @Inject constructor( roomSummaryEntity.highlightCount = unreadNotifications?.highlightCount ?: 0 roomSummaryEntity.notificationCount = unreadNotifications?.notificationCount ?: 0 roomSummaryEntity.unreadCount = unreadCount ?: 0 + roomSummaryEntity.aggregatedNotificationCount = roomSummaryEntity.notificationCount + roomSummaryEntity.aggregatedUnreadCount = roomSummaryEntity.unreadCount if (membership != null) { roomSummaryEntity.membership = membership @@ -385,6 +388,8 @@ internal class RoomSummaryUpdater @Inject constructor( var notificationCount = 0 var unreadCount = 0 var markedUnreadCount = 0 + var aggregateUnreadCount = 0 + var aggregateNotificationCount = 0 realm.where(RoomSummaryEntity::class.java) .process(RoomSummaryEntityFields.MEMBERSHIP_STR, listOf(Membership.JOIN)) .notEqualTo(RoomSummaryEntityFields.ROOM_TYPE, RoomType.SPACE) @@ -395,12 +400,16 @@ internal class RoomSummaryUpdater @Inject constructor( highlightCount += it.highlightCount notificationCount += it.notificationCount unreadCount += it.unreadCount + aggregateNotificationCount += min(it.highlightCount, 1) + aggregateUnreadCount += min(it.unreadCount, 1) markedUnreadCount += if (it.markedUnread) 1 else 0 } space.highlightCount = highlightCount space.notificationCount = notificationCount + markedUnreadCount space.unreadCount = unreadCount + space.aggregatedUnreadCount = aggregateUnreadCount + space.aggregatedNotificationCount = aggregateNotificationCount } // xxx invites?? diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index b526befebf..c5eeb262c4 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -86,6 +86,7 @@ class HomeDetailFragment @Inject constructor( // When this changes, restart the activity for changes to apply private val shouldShowUnimportantCounterBadge = vectorPreferences.shouldShowUnimportantCounterBadge() + private val useAggregateCounts = vectorPreferences.useAggregateCounts() private var hasUnreadRooms = false set(value) { @@ -206,7 +207,8 @@ class HomeDetailFragment @Inject constructor( override fun onResume() { super.onResume() - if (vectorPreferences.shouldShowUnimportantCounterBadge() != shouldShowUnimportantCounterBadge) { + if (vectorPreferences.shouldShowUnimportantCounterBadge() != shouldShowUnimportantCounterBadge || + vectorPreferences.useAggregateCounts() != useAggregateCounts) { activity?.restart() return } diff --git a/vector/src/main/java/im/vector/app/features/home/room/ScSdkPreferences.kt b/vector/src/main/java/im/vector/app/features/home/room/ScSdkPreferences.kt index 21341b8e37..8aa36b83ad 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/ScSdkPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/ScSdkPreferences.kt @@ -12,4 +12,8 @@ class ScSdkPreferences @Inject constructor(private val vectorPreferences: Vector override fun getUnreadKind(isDirect: Boolean): Int { return vectorPreferences?.roomUnreadKind(isDirect) ?: RoomSummary.UNREAD_KIND_FULL } + + override fun aggregateUnreadRoomCounts(): Boolean { + return vectorPreferences?.useAggregateCounts() ?: true + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index adf8d10159..4fc85ffc0c 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -197,6 +197,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_ROOM_UNREAD_KIND_DM = "SETTINGS_ROOM_UNREAD_KIND_DM" private const val SETTINGS_ROOM_UNREAD_KIND_GROUP = "SETTINGS_ROOM_UNREAD_KIND_GROUP" const val SETTINGS_UNIMPORTANT_COUNTER_BADGE = "SETTINGS_UNIMPORTANT_COUNTER_BADGE" + const val SETTINGS_AGGREGATE_UNREAD_COUNTS = "SETTINGS_AGGREGATE_UNREAD_COUNTS" private const val SETTINGS_SIMPLIFIED_MODE = "SETTINGS_SIMPLIFIED_MODE" private const val SETTINGS_LABS_ALLOW_MARK_UNREAD = "SETTINGS_LABS_ALLOW_MARK_UNREAD" const val SETTINGS_ALLOW_URL_PREVIEW_IN_ENCRYPTED_ROOM_KEY = "SETTINGS_ALLOW_URL_PREVIEW_IN_ENCRYPTED_ROOM_KEY" @@ -969,6 +970,11 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_UNIMPORTANT_COUNTER_BADGE, true) } + // SC additions - for spaces/categories: whether to count unread chats, or messages + fun useAggregateCounts(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_AGGREGATE_UNREAD_COUNTS, true) + } + // SC addition fun simplifiedMode(): Boolean { return defaultPrefs.getBoolean(SETTINGS_SIMPLIFIED_MODE, false) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt index 30ce70e466..b6ceed8f81 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceSummaryController.kt @@ -28,6 +28,7 @@ import im.vector.app.features.grouplist.homeSpaceSummaryItem import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.ScSdkPreferences import im.vector.app.features.home.room.list.UnreadCounterBadgeView +import im.vector.app.features.settings.VectorPreferences import im.vector.app.group import im.vector.app.space import org.matrix.android.sdk.api.session.group.model.GroupSummary @@ -40,7 +41,7 @@ import java.util.Locale import javax.inject.Inject class SpaceSummaryController @Inject constructor( - private val scSdkPreferences: ScSdkPreferences, + private val vectorPreferences: VectorPreferences, private val avatarRenderer: AvatarRenderer, private val colorProvider: ColorProvider, private val stringProvider: StringProvider) : EpoxyController() { @@ -142,6 +143,8 @@ class SpaceSummaryController @Inject constructor( listener { host.callback?.onSpaceSelected(null) } } + val useAggregateCounts = vectorPreferences.useAggregateCounts() + rootSpaces ?.forEach { groupSummary -> val isSelected = selected is RoomGroupingMethod.BySpace && groupSummary.roomId == selected.space()?.roomId @@ -168,9 +171,9 @@ class SpaceSummaryController @Inject constructor( toggleExpand { host.callback?.onToggleExpand(groupSummary) } countState( UnreadCounterBadgeView.State( - groupSummary.notificationCount, + if (useAggregateCounts) groupSummary.aggregatedNotificationCount else groupSummary.notificationCount, groupSummary.highlightCount > 0, - groupSummary.safeUnreadCount, + if (useAggregateCounts) groupSummary.aggregatedUnreadCount else groupSummary.safeUnreadCount, groupSummary.markedUnread ) ) @@ -204,6 +207,8 @@ class SpaceSummaryController @Inject constructor( val expanded = expandedStates[childSummary.roomId] == true val isSelected = selected is RoomGroupingMethod.BySpace && childSummary.roomId == selected.space()?.roomId + val useAggregateCounts = vectorPreferences.useAggregateCounts() + subSpaceSummaryItem { avatarRenderer(host.avatarRenderer) id(childSummary.roomId) @@ -217,9 +222,9 @@ class SpaceSummaryController @Inject constructor( indent(currentDepth) countState( UnreadCounterBadgeView.State( - childSummary.notificationCount, + if (useAggregateCounts) childSummary.aggregatedNotificationCount else childSummary.notificationCount, childSummary.highlightCount > 0, - childSummary.safeUnreadCount, + if (useAggregateCounts) childSummary.aggregatedUnreadCount else childSummary.safeUnreadCount, childSummary.markedUnread ) ) diff --git a/vector/src/main/res/values/strings_sc.xml b/vector/src/main/res/values/strings_sc.xml index 87a355f8f4..a5544318e0 100644 --- a/vector/src/main/res/values/strings_sc.xml +++ b/vector/src/main/res/values/strings_sc.xml @@ -44,8 +44,11 @@ Top Bottom + Unread counter Count muted messages Show counts for muted messages in the chat overview + Count chats instead of messages + Whether to count unread chats instead of individual messages in spaces and room categories Mark chats as unread Allow marking chats as unread. Other Matrix clients might not support this yet. diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 498aeb9ac8..69bf1a6f32 100644 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -96,11 +96,23 @@ android:summary="%s" android:title="@string/settings_room_unread_kind_group" /> + + + + + android:title="@string/settings_unimportant_counter_badge_v2" + android:summary="@string/settings_unimportant_counter_badge_summary_v2" /> + +