From 6a626ea3be4f7224f9add44e0d5a7cfa56e66b04 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Wed, 12 Oct 2022 17:54:34 +0200 Subject: [PATCH] Old layout: Sort order setting to show unreads on top Setting is in options menu. Different setting for home than for spaces, to allow e.g. having unreads on top only for home. Change-Id: Ib390a5601ab78ba8372a4c3161311a52d1016b48 --- .../src/main/res/values/strings_sc.xml | 3 + .../migration/MigrateScSessionTo007.kt | 26 ++++++ .../sdk/api/session/room/RoomSortOrder.kt | 5 ++ .../database/RealmSessionStoreMigration.kt | 4 +- .../database/model/RoomSummaryEntity.kt | 40 ++++++++- .../internal/query/QueryRoomOrderProcessor.kt | 5 ++ .../app/features/home/HomeDetailFragment.kt | 84 ++++++++++++++++++- .../features/home/NewHomeDetailFragment.kt | 1 + .../home/room/list/RoomListFragment.kt | 5 +- .../home/room/list/RoomListSectionBuilder.kt | 48 ++++++++--- .../home/room/list/RoomListViewModel.kt | 5 +- .../home/room/list/RoomListViewState.kt | 6 +- .../features/settings/VectorPreferences.kt | 2 + vector/src/main/res/menu/room_list.xml | 17 ++++ 14 files changed, 226 insertions(+), 25 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/de/spiritcroc/android/sdk/internal/database/migration/MigrateScSessionTo007.kt diff --git a/library/ui-strings/src/main/res/values/strings_sc.xml b/library/ui-strings/src/main/res/values/strings_sc.xml index 3d16118bab..066f4911c2 100644 --- a/library/ui-strings/src/main/res/values/strings_sc.xml +++ b/library/ui-strings/src/main/res/values/strings_sc.xml @@ -200,4 +200,7 @@ When changing the system language, also change the app\'s language Element\'s new simplified layout with optional tabs + + Unread + diff --git a/matrix-sdk-android/src/main/java/de/spiritcroc/android/sdk/internal/database/migration/MigrateScSessionTo007.kt b/matrix-sdk-android/src/main/java/de/spiritcroc/android/sdk/internal/database/migration/MigrateScSessionTo007.kt new file mode 100644 index 0000000000..6e68dd0b84 --- /dev/null +++ b/matrix-sdk-android/src/main/java/de/spiritcroc/android/sdk/internal/database/migration/MigrateScSessionTo007.kt @@ -0,0 +1,26 @@ +package de.spiritcroc.android.sdk.internal.database.migration + +import de.spiritcroc.android.sdk.internal.util.database.ScRealmMigrator +import io.realm.DynamicRealm +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields + +internal class MigrateScSessionTo007(realm: DynamicRealm) : ScRealmMigrator(realm, 7) { + + override fun doMigrate(realm: DynamicRealm) { + realm.schema.get("RoomSummaryEntity") + ?.addField(RoomSummaryEntityFields.TREAT_AS_UNREAD_LEVEL, Int::class.java) + ?.transform { obj -> + val unreadCount = tryOrNull { obj.getInt(RoomSummaryEntityFields.UNREAD_COUNT) } + val treatAsUnreadLevel = RoomSummaryEntity.calculateUnreadLevel( + obj.getInt(RoomSummaryEntityFields.HIGHLIGHT_COUNT), + obj.getInt(RoomSummaryEntityFields.NOTIFICATION_COUNT), + obj.getBoolean(RoomSummaryEntityFields.MARKED_UNREAD), + unreadCount + ) + obj.setInt(RoomSummaryEntityFields.TREAT_AS_UNREAD_LEVEL, treatAsUnreadLevel) + } + ?.addIndex(RoomSummaryEntityFields.TREAT_AS_UNREAD_LEVEL) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt index 9368ad6bf4..25f1bf20de 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSortOrder.kt @@ -30,6 +30,11 @@ enum class RoomSortOrder { */ ACTIVITY, + /** + * Show unread above read + */ + UNREAD_AND_ACTIVITY, + /** * Sort room list by room priority and last activity: favorite room first, low priority room last, * then descending last activity. 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 4ebdbadafd..f406909627 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 @@ -22,6 +22,7 @@ import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo0 import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo004 import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo005 import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo006 +import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo007 import io.realm.DynamicRealm import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo001 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo002 @@ -80,7 +81,7 @@ internal class RealmSessionStoreMigration @Inject constructor( companion object { // SC-specific DB changes on top of Element - private val scSchemaVersion = 6L + private val scSchemaVersion = 7L private val scSchemaVersionOffset = (1L shl 12) val schemaVersion = 37L + @@ -144,5 +145,6 @@ internal class RealmSessionStoreMigration @Inject constructor( if (oldScVersion <= 3) MigrateScSessionTo004(realm).perform() if (oldScVersion <= 4) MigrateScSessionTo005(realm).perform() if (oldScVersion <= 5) MigrateScSessionTo006(realm).perform() + if (oldScVersion <= 6) MigrateScSessionTo007(realm).perform() } } 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 6c1fd61a5f..c7e2d4303c 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 @@ -21,6 +21,7 @@ import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.Index import io.realm.annotations.PrimaryKey +import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.room.model.Membership @@ -122,16 +123,19 @@ internal open class RoomSummaryEntity( var notificationCount: Int = 0 set(value) { if (value != field) field = value + updateTreatAsUnread() } var highlightCount: Int = 0 set(value) { if (value != field) field = value + updateTreatAsUnread() } var unreadCount: Int? = null set(value) { if (value != field) field = value + updateTreatAsUnread() } /* -> safeUnreadCount get() { @@ -193,9 +197,25 @@ internal open class RoomSummaryEntity( var markedUnread: Boolean = false set(value) { - if (value != field) field = value + if (value != field) { + field = value + updateTreatAsUnread() + } } + /** + * SchildiChat: Helper var so we can sort depending on how "unread" a chat is: mentions > {notifications, marked unread} > unreads > all read + * Make sure to call `updateTreatAsUnread()` when necessary. + */ + @Index + private var treatAsUnreadLevel: Int = calculateUnreadLevel() + private fun updateTreatAsUnread() { + treatAsUnreadLevel = calculateUnreadLevel() + } + private fun calculateUnreadLevel(): Int { + return calculateUnreadLevel(highlightCount, notificationCount, markedUnread, unreadCount) + } + private var tags: RealmList = RealmList() fun tags(): List = tags @@ -377,7 +397,23 @@ internal open class RoomSummaryEntity( } } - companion object + companion object { + private const val UNREAD_LEVEL_HIGHLIGHT = 4 + private const val UNREAD_LEVEL_NOTIFIED = 3 + private const val UNREAD_LEVEL_MARKED_UNREAD = UNREAD_LEVEL_NOTIFIED + private const val UNREAD_LEVEL_SILENT_UNREAD = 1 + private const val UNREAD_LEVEL_NONE = 0 + + fun calculateUnreadLevel(highlightCount: Int, notificationCount: Int, markedUnread: Boolean, unreadCount: Int?): Int { + return when { + highlightCount > 0 -> UNREAD_LEVEL_HIGHLIGHT + notificationCount > 0 -> UNREAD_LEVEL_NOTIFIED + markedUnread -> UNREAD_LEVEL_MARKED_UNREAD + unreadCount?.let { it > 0 }.orFalse() -> UNREAD_LEVEL_SILENT_UNREAD + else -> UNREAD_LEVEL_NONE + } + } + } // Keep sync with RoomSummary.scHasUnreadMessages! diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt index 8df0482993..04dba256d7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/query/QueryRoomOrderProcessor.kt @@ -30,6 +30,11 @@ internal fun RealmQuery.process(sortOrder: RoomSortOrder): Re RoomSortOrder.ACTIVITY -> { sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING) } + RoomSortOrder.UNREAD_AND_ACTIVITY -> { + sort( + arrayOf(RoomSummaryEntityFields.TREAT_AS_UNREAD_LEVEL, RoomSummaryEntityFields.LAST_ACTIVITY_TIME), + arrayOf(Sort.DESCENDING, Sort.DESCENDING)) + } RoomSortOrder.PRIORITY_AND_ACTIVITY -> { sort( arrayOf( 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 cde3f58f30..606ed240bf 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 @@ -23,8 +23,10 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver +import androidx.core.content.edit import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 @@ -74,6 +76,7 @@ import im.vector.app.features.workers.signout.ServerBackupStatusAction import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo +import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.model.RoomSummary import timber.log.Timber import javax.inject.Inject @@ -124,6 +127,7 @@ class HomeDetailFragment : private var pagerTab: HomeTab? = null private var pagerPagingEnabled: Boolean = false private var previousSelectedSpacePair: Pair? = null + private var roomSortOrderSettings: RoomSortOrderSettings? = null override fun getMenuRes() = R.menu.room_list @@ -133,14 +137,64 @@ class HomeDetailFragment : viewModel.handle(HomeDetailAction.MarkAllRoomsRead) true } + R.id.menu_room_sort_order_activity -> { + storeRoomSortOrder(RoomSortOrder.ACTIVITY) + updateViewPager() + true + } + R.id.menu_room_sort_order_unread -> { + storeRoomSortOrder(RoomSortOrder.UNREAD_AND_ACTIVITY) + updateViewPager() + true + } else -> false } } + private fun currentEffectiveSpace(): String? { + return if (pagerPagingEnabled) { + getSpaceIdForPageIndex(views.roomListContainerPager.currentItem) + } else { + SPACE_ID_FOLLOW_APP + } + } + + private fun storeRoomSortOrder(roomSortOrder: RoomSortOrder) { + val sharedPreferences = context?.let { PreferenceManager.getDefaultSharedPreferences(it) } ?: return + val space = currentEffectiveSpace() + val pref = if (space == null) VectorPreferences.SETTINGS_ROOM_SORT_ORDER_NULL else VectorPreferences.SETTINGS_ROOM_SORT_ORDER_NON_NULL + sharedPreferences.edit { + putString(pref, roomSortOrder.toString()) + } + } + + private fun updateViewPager() { + withState(viewModel) { + val selectedSpace = it.selectedSpaceIgnoreSwipe ?: return@withState + spaceStateHandler.persistSelectedSpace() + setupViewPager(selectedSpace, it.rootSpacesOrdered, it.currentTab) + } + } + override fun handlePrepareMenu(menu: Menu) { withState(viewModel) { state -> val isRoomList = state.currentTab is HomeTab.RoomList menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms + menu.findItem(R.id.menu_room_sort_order).isVisible = true + + // Room sort order + val space = currentEffectiveSpace() + val roomSortOrder = + if (space == null) { + roomSortOrderSettings?.nullSpace + } else { + roomSortOrderSettings?.space + } + when (roomSortOrder) { + RoomSortOrder.ACTIVITY -> menu.findItem(R.id.menu_room_sort_order_activity).isChecked = true + RoomSortOrder.UNREAD_AND_ACTIVITY -> menu.findItem(R.id.menu_room_sort_order_unread).isChecked = true + else -> Unit + } } } @@ -605,10 +659,11 @@ class HomeDetailFragment : views.spaceBarRecyclerView.isVisible = false } val safeSpaces = if (pagingEnabled) unsafeSpaces else listOf() + val newRoomSortOrderSettings = loadRoomSortOrderSettings() // Check if we need to recreate the adapter for a new tab if (oldAdapter != null) { - val changed = pagerTab != tab || pagerSpaces != safeSpaces || pagerPagingEnabled != pagingEnabled - viewPagerDimber.i{ "has changed: $changed (${pagerTab != tab} ${pagerSpaces != safeSpaces} ${pagerPagingEnabled != pagingEnabled} $selectedIndex ${selectedSpacePair.second} ${views.roomListContainerPager.currentItem}) | $safeSpaces" } + val changed = pagerTab != tab || pagerSpaces != safeSpaces || pagerPagingEnabled != pagingEnabled || roomSortOrderSettings != newRoomSortOrderSettings + viewPagerDimber.i{ "has changed: $changed (${pagerTab != tab} ${pagerSpaces != safeSpaces} ${pagerPagingEnabled != pagingEnabled} ${roomSortOrderSettings != newRoomSortOrderSettings} $selectedIndex ${selectedSpacePair.second} ${views.roomListContainerPager.currentItem}) | $safeSpaces" } if (!changed) { // No need to re-setup pager, just check for selected page if (pagingEnabled) { @@ -653,6 +708,7 @@ class HomeDetailFragment : spaceStateHandler.persistSelectedSpace() pagerSpaces = safeSpaces pagerTab = tab + roomSortOrderSettings = newRoomSortOrderSettings if (pagerPagingEnabled != pagingEnabled) { pagerPagingEnabled = pagingEnabled // Update counts which depend on pagerPagingEnabled @@ -691,10 +747,10 @@ class HomeDetailFragment : val params = if (pagingEnabled) { val spaceId = getSpaceIdForPageIndex(position) viewPagerDimber.i{"Home pager: position $position -> space $spaceId"} - RoomListParams(tab.displayMode, spaceId).toMvRxBundle() + RoomListParams(tab.displayMode, spaceId, getRoomSortOrder(spaceId)).toMvRxBundle() } else { viewPagerDimber.i{"Home pager: paging disabled; position $position -> follow"} - RoomListParams(tab.displayMode, SPACE_ID_FOLLOW_APP).toMvRxBundle() + RoomListParams(tab.displayMode, SPACE_ID_FOLLOW_APP, getRoomSortOrder(SPACE_ID_FOLLOW_APP)).toMvRxBundle() } childFragmentManager.fragmentFactory.instantiate(activity!!.classLoader, RoomListFragment::class.java.name).apply { arguments = params @@ -753,6 +809,26 @@ class HomeDetailFragment : return if (position == 0) null else spaces[position-1] } + data class RoomSortOrderSettings(val nullSpace: RoomSortOrder, val space: RoomSortOrder) + + private fun loadRoomSortOrderSettings(): RoomSortOrderSettings? { + val sharedPreferences = context?.let { PreferenceManager.getDefaultSharedPreferences(it) } ?: return null + val default = RoomSortOrder.ACTIVITY + return RoomSortOrderSettings( + tryOrNull { sharedPreferences.getString(VectorPreferences.SETTINGS_ROOM_SORT_ORDER_NULL, null)?.let { RoomSortOrder.valueOf(it) } } ?: default, + tryOrNull { sharedPreferences.getString(VectorPreferences.SETTINGS_ROOM_SORT_ORDER_NON_NULL, null)?.let { RoomSortOrder.valueOf(it) } } ?: default, + ) + } + + private fun getRoomSortOrder(space: String?): RoomSortOrder { + return ( + if (space == null) + roomSortOrderSettings?.nullSpace + else + roomSortOrderSettings?.space + ) ?: RoomSortOrder.ACTIVITY + } + private fun createDialPadFragment(): Fragment { val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name) return (fragment as DialPadFragment).apply { diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index fe3e3c2af8..caee2102d8 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -123,6 +123,7 @@ class NewHomeDetailFragment : val isRoomList = state.currentTab is HomeTab.RoomList menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms menu.findItem(R.id.menu_home_dialpad).isVisible = state.showDialPadTab + menu.findItem(R.id.menu_room_sort_order).isVisible = false } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index 805e6c79de..6d82da7577 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -68,6 +68,8 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.extensions.orTrue +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import org.matrix.android.sdk.api.session.room.model.tag.RoomTag @@ -77,7 +79,8 @@ import javax.inject.Inject @Parcelize data class RoomListParams( val displayMode: RoomListDisplayMode, - val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP + val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP, + val roomSortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY ) : Parcelable @AndroidEntryPoint diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt index 3f15eeb8c0..7ff7012361 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt @@ -51,6 +51,7 @@ import org.matrix.android.sdk.api.query.toActiveSpaceOrNoFilter import org.matrix.android.sdk.api.query.toActiveSpaceOrOrphanRooms import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.model.Membership @@ -82,28 +83,28 @@ class RoomListSectionBuilder( private val dimber = Dimber("ViewPager", DbgUtil.DBG_VIEW_PAGER) - fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List { + fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?, sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): List { dimber.i { "Build sections for $mode, $explicitSpaceId" } val sections = mutableListOf() val activeSpaceAwareQueries = mutableListOf() when (mode) { RoomListDisplayMode.PEOPLE -> { // 4 sections Invites / Fav / Dms / Low Priority - buildDmSections(sections, activeSpaceAwareQueries, explicitSpaceId) + buildDmSections(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder) } RoomListDisplayMode.ROOMS -> { // 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms - buildRoomsSections(sections, activeSpaceAwareQueries, explicitSpaceId) + buildRoomsSections(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder) } RoomListDisplayMode.ALL -> { - buildUnifiedSections(sections, activeSpaceAwareQueries, explicitSpaceId) + buildUnifiedSections(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder) } RoomListDisplayMode.FILTERED -> { // Used when searching for rooms buildFilteredSection(sections) } RoomListDisplayMode.NOTIFICATIONS -> { - buildNotificationsSection(sections, activeSpaceAwareQueries, explicitSpaceId) + buildNotificationsSection(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder) } } @@ -125,13 +126,14 @@ class RoomListSectionBuilder( return sections } - private fun buildUnifiedSections(sections: MutableList, activeSpaceAwareQueries: MutableList, explicitSpaceId: String?) { + private fun buildUnifiedSections(sections: MutableList, activeSpaceAwareQueries: MutableList, explicitSpaceId: String?, sortOrder: RoomSortOrder) { addSection( sections = sections, activeSpaceUpdaters = activeSpaceAwareQueries, nameRes = R.string.invitations_header, notifyOfLocalEcho = true, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, countRoomAsNotif = true ) { @@ -149,6 +151,7 @@ class RoomListSectionBuilder( RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL }, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder ) { it.memberships = listOf(Membership.JOIN) it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null) @@ -160,6 +163,7 @@ class RoomListSectionBuilder( nameRes = R.string.normal_priority_header, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -176,6 +180,7 @@ class RoomListSectionBuilder( nameRes = R.string.low_priority_header, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -192,6 +197,7 @@ class RoomListSectionBuilder( nameRes = R.string.system_alerts_header, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -208,7 +214,8 @@ class RoomListSectionBuilder( private fun buildRoomsSections( sections: MutableList, activeSpaceAwareQueries: MutableList, - explicitSpaceId: String? + explicitSpaceId: String?, + sortOrder: RoomSortOrder ) { if (autoAcceptInvites.showInvites()) { addSection( @@ -217,6 +224,7 @@ class RoomListSectionBuilder( nameRes = R.string.invitations_header, notifyOfLocalEcho = true, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, countRoomAsNotif = true ) { @@ -236,6 +244,7 @@ class RoomListSectionBuilder( RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL }, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS @@ -248,6 +257,7 @@ class RoomListSectionBuilder( nameRes = R.string.bottom_action_rooms, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -265,6 +275,7 @@ class RoomListSectionBuilder( nameRes = R.string.low_priority_header, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -282,6 +293,7 @@ class RoomListSectionBuilder( nameRes = R.string.system_alerts_header, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -366,7 +378,8 @@ class RoomListSectionBuilder( private fun buildDmSections( sections: MutableList, activeSpaceAwareQueries: MutableList, - explicitSpaceId: String? + explicitSpaceId: String?, + sortOrder: RoomSortOrder ) { if (autoAcceptInvites.showInvites()) { addSection( @@ -375,6 +388,7 @@ class RoomListSectionBuilder( nameRes = R.string.invitations_header, notifyOfLocalEcho = true, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -397,7 +411,8 @@ class RoomListSectionBuilder( } else { RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL }, - explicitSpaceId = explicitSpaceId + explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM @@ -414,7 +429,8 @@ class RoomListSectionBuilder( } else { RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL }, - explicitSpaceId = explicitSpaceId + explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM @@ -431,7 +447,8 @@ class RoomListSectionBuilder( } else { RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL }, - explicitSpaceId = explicitSpaceId + explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM @@ -451,7 +468,8 @@ class RoomListSectionBuilder( private fun buildNotificationsSection( sections: MutableList, activeSpaceAwareQueries: MutableList, - explicitSpaceId: String? + explicitSpaceId: String?, + sortOrder: RoomSortOrder ) { if (autoAcceptInvites.showInvites()) { addSection( @@ -460,6 +478,7 @@ class RoomListSectionBuilder( nameRes = R.string.invitations_header, notifyOfLocalEcho = true, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -477,6 +496,7 @@ class RoomListSectionBuilder( nameRes = R.string.bottom_action_rooms, notifyOfLocalEcho = false, explicitSpaceId = explicitSpaceId, + sortOrder = sortOrder, spaceFilterStrategy = if (onlyOrphansInHome) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL } else { @@ -522,6 +542,7 @@ class RoomListSectionBuilder( spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE, countRoomAsNotif: Boolean = false, explicitSpaceId: String?, + sortOrder: RoomSortOrder, query: (RoomSummaryQueryParams.Builder) -> Unit ) { withQueryParams(query) { roomQueryParams -> @@ -537,7 +558,8 @@ class RoomListSectionBuilder( val name = stringProvider.getString(nameRes) val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive( roomQueryParams.process(spaceFilterStrategy, spaceStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId)), - pagedListConfig + pagedListConfig, + sortOrder ) when (spaceFilterStrategy) { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 0d5837bfb4..97e4b57ca3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoomSummary +import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho @@ -152,8 +153,8 @@ class RoomListViewModel @AssistedInject constructor( ) val sections: List by lazy { - viewPagerDimber.i { "Build sections for ${initialState.displayMode}, ${initialState.explicitSpaceId}" } - roomListSectionBuilder.buildSections(initialState.displayMode, initialState.explicitSpaceId) + viewPagerDimber.i { "Build sections for ${initialState.displayMode}, ${initialState.explicitSpaceId} ${initialState.roomSortOrder}" } + roomListSectionBuilder.buildSections(initialState.displayMode, initialState.explicitSpaceId, initialState.roomSortOrder) } override fun handle(action: RoomListAction) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt index f9e8887b2b..615d729fd9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt @@ -20,6 +20,7 @@ import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.home.RoomListDisplayMode +import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo @@ -32,8 +33,9 @@ data class RoomListViewState( val currentUserName: String? = null, val asyncSelectedSpace: Async = Uninitialized, // In comparison to currentRoomGrouping, the explicit space id fixes a filter method that should not change afterwards - val explicitSpaceId: String? = null + val explicitSpaceId: String? = null, + val roomSortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY, ) : MavericksState { - constructor(args: RoomListParams) : this(displayMode = args.displayMode, explicitSpaceId = args.explicitSpaceId) + constructor(args: RoomListParams) : this(displayMode = args.displayMode, explicitSpaceId = args.explicitSpaceId, roomSortOrder = args.roomSortOrder) } 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 d7586e19e0..196dbeda0d 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 @@ -248,6 +248,8 @@ class VectorPreferences @Inject constructor( private const val SETTINGS_SPACE_BACK_NAVIGATION = "SETTINGS_SPACE_BACK_NAVIGATION" const val SETTINGS_FOLLOW_SYSTEM_LOCALE = "SETTINGS_FOLLOW_SYSTEM_LOCALE" const val SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC = "SETTINGS_FORCE_ALLOW_BACKGROUND_SYNC" + const val SETTINGS_ROOM_SORT_ORDER_NULL = "SETTINGS_ROOM_SORT_ORDER_NULL" + const val SETTINGS_ROOM_SORT_ORDER_NON_NULL = "SETTINGS_ROOM_SORT_ORDER_NON_NULL" private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH" diff --git a/vector/src/main/res/menu/room_list.xml b/vector/src/main/res/menu/room_list.xml index ad375d241b..e3868e5dec 100644 --- a/vector/src/main/res/menu/room_list.xml +++ b/vector/src/main/res/menu/room_list.xml @@ -14,4 +14,21 @@ android:visible="false" app:showAsAction="never" tools:visible="true" /> + + + + + + + + +