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
This commit is contained in:
SpiritCroc 2022-10-12 17:54:34 +02:00
parent 2d710923a1
commit 6a626ea3be
14 changed files with 226 additions and 25 deletions

View File

@ -200,4 +200,7 @@
<string name="settings_follow_system_locale_summary">When changing the system language, also change the app\'s language</string> <string name="settings_follow_system_locale_summary">When changing the system language, also change the app\'s language</string>
<string name="labs_enable_new_app_layout_summary_sc">Element\'s new simplified layout with optional tabs</string> <string name="labs_enable_new_app_layout_summary_sc">Element\'s new simplified layout with optional tabs</string>
<string name="home_layout_preferences_sort_unread">Unread</string>
</resources> </resources>

View File

@ -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)
}
}

View File

@ -30,6 +30,11 @@ enum class RoomSortOrder {
*/ */
ACTIVITY, ACTIVITY,
/**
* Show unread above read
*/
UNREAD_AND_ACTIVITY,
/** /**
* Sort room list by room priority and last activity: favorite room first, low priority room last, * Sort room list by room priority and last activity: favorite room first, low priority room last,
* then descending last activity. * then descending last activity.

View File

@ -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.MigrateScSessionTo004
import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo005 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.MigrateScSessionTo006
import de.spiritcroc.android.sdk.internal.database.migration.MigrateScSessionTo007
import io.realm.DynamicRealm import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo001 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo001
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo002 import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo002
@ -80,7 +81,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
companion object { companion object {
// SC-specific DB changes on top of Element // SC-specific DB changes on top of Element
private val scSchemaVersion = 6L private val scSchemaVersion = 7L
private val scSchemaVersionOffset = (1L shl 12) private val scSchemaVersionOffset = (1L shl 12)
val schemaVersion = 37L + val schemaVersion = 37L +
@ -144,5 +145,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldScVersion <= 3) MigrateScSessionTo004(realm).perform() if (oldScVersion <= 3) MigrateScSessionTo004(realm).perform()
if (oldScVersion <= 4) MigrateScSessionTo005(realm).perform() if (oldScVersion <= 4) MigrateScSessionTo005(realm).perform()
if (oldScVersion <= 5) MigrateScSessionTo006(realm).perform() if (oldScVersion <= 5) MigrateScSessionTo006(realm).perform()
if (oldScVersion <= 6) MigrateScSessionTo007(realm).perform()
} }
} }

View File

@ -21,6 +21,7 @@ import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Index import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey 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.extensions.tryOrNull
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
@ -122,16 +123,19 @@ internal open class RoomSummaryEntity(
var notificationCount: Int = 0 var notificationCount: Int = 0
set(value) { set(value) {
if (value != field) field = value if (value != field) field = value
updateTreatAsUnread()
} }
var highlightCount: Int = 0 var highlightCount: Int = 0
set(value) { set(value) {
if (value != field) field = value if (value != field) field = value
updateTreatAsUnread()
} }
var unreadCount: Int? = null var unreadCount: Int? = null
set(value) { set(value) {
if (value != field) field = value if (value != field) field = value
updateTreatAsUnread()
} }
/* -> safeUnreadCount /* -> safeUnreadCount
get() { get() {
@ -193,9 +197,25 @@ internal open class RoomSummaryEntity(
var markedUnread: Boolean = false var markedUnread: Boolean = false
set(value) { 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<RoomTagEntity> = RealmList() private var tags: RealmList<RoomTagEntity> = RealmList()
fun tags(): List<RoomTagEntity> = tags fun tags(): List<RoomTagEntity> = 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! // Keep sync with RoomSummary.scHasUnreadMessages!

View File

@ -30,6 +30,11 @@ internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): Re
RoomSortOrder.ACTIVITY -> { RoomSortOrder.ACTIVITY -> {
sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING) 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 -> { RoomSortOrder.PRIORITY_AND_ACTIVITY -> {
sort( sort(
arrayOf( arrayOf(

View File

@ -23,8 +23,10 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import androidx.core.content.edit
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2 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 im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import org.matrix.android.sdk.api.extensions.tryOrNull 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.crypto.model.DeviceInfo
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.RoomSummary
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -124,6 +127,7 @@ class HomeDetailFragment :
private var pagerTab: HomeTab? = null private var pagerTab: HomeTab? = null
private var pagerPagingEnabled: Boolean = false private var pagerPagingEnabled: Boolean = false
private var previousSelectedSpacePair: Pair<RoomSummary?, SelectSpaceFrom>? = null private var previousSelectedSpacePair: Pair<RoomSummary?, SelectSpaceFrom>? = null
private var roomSortOrderSettings: RoomSortOrderSettings? = null
override fun getMenuRes() = R.menu.room_list override fun getMenuRes() = R.menu.room_list
@ -133,14 +137,64 @@ class HomeDetailFragment :
viewModel.handle(HomeDetailAction.MarkAllRoomsRead) viewModel.handle(HomeDetailAction.MarkAllRoomsRead)
true 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 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) { override fun handlePrepareMenu(menu: Menu) {
withState(viewModel) { state -> withState(viewModel) { state ->
val isRoomList = state.currentTab is HomeTab.RoomList 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_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 views.spaceBarRecyclerView.isVisible = false
} }
val safeSpaces = if (pagingEnabled) unsafeSpaces else listOf() val safeSpaces = if (pagingEnabled) unsafeSpaces else listOf()
val newRoomSortOrderSettings = loadRoomSortOrderSettings()
// Check if we need to recreate the adapter for a new tab // Check if we need to recreate the adapter for a new tab
if (oldAdapter != null) { if (oldAdapter != null) {
val changed = pagerTab != tab || pagerSpaces != safeSpaces || pagerPagingEnabled != pagingEnabled val changed = pagerTab != tab || pagerSpaces != safeSpaces || pagerPagingEnabled != pagingEnabled || roomSortOrderSettings != newRoomSortOrderSettings
viewPagerDimber.i{ "has changed: $changed (${pagerTab != tab} ${pagerSpaces != safeSpaces} ${pagerPagingEnabled != pagingEnabled} $selectedIndex ${selectedSpacePair.second} ${views.roomListContainerPager.currentItem}) | $safeSpaces" } viewPagerDimber.i{ "has changed: $changed (${pagerTab != tab} ${pagerSpaces != safeSpaces} ${pagerPagingEnabled != pagingEnabled} ${roomSortOrderSettings != newRoomSortOrderSettings} $selectedIndex ${selectedSpacePair.second} ${views.roomListContainerPager.currentItem}) | $safeSpaces" }
if (!changed) { if (!changed) {
// No need to re-setup pager, just check for selected page // No need to re-setup pager, just check for selected page
if (pagingEnabled) { if (pagingEnabled) {
@ -653,6 +708,7 @@ class HomeDetailFragment :
spaceStateHandler.persistSelectedSpace() spaceStateHandler.persistSelectedSpace()
pagerSpaces = safeSpaces pagerSpaces = safeSpaces
pagerTab = tab pagerTab = tab
roomSortOrderSettings = newRoomSortOrderSettings
if (pagerPagingEnabled != pagingEnabled) { if (pagerPagingEnabled != pagingEnabled) {
pagerPagingEnabled = pagingEnabled pagerPagingEnabled = pagingEnabled
// Update counts which depend on pagerPagingEnabled // Update counts which depend on pagerPagingEnabled
@ -691,10 +747,10 @@ class HomeDetailFragment :
val params = if (pagingEnabled) { val params = if (pagingEnabled) {
val spaceId = getSpaceIdForPageIndex(position) val spaceId = getSpaceIdForPageIndex(position)
viewPagerDimber.i{"Home pager: position $position -> space $spaceId"} viewPagerDimber.i{"Home pager: position $position -> space $spaceId"}
RoomListParams(tab.displayMode, spaceId).toMvRxBundle() RoomListParams(tab.displayMode, spaceId, getRoomSortOrder(spaceId)).toMvRxBundle()
} else { } else {
viewPagerDimber.i{"Home pager: paging disabled; position $position -> follow"} 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 { childFragmentManager.fragmentFactory.instantiate(activity!!.classLoader, RoomListFragment::class.java.name).apply {
arguments = params arguments = params
@ -753,6 +809,26 @@ class HomeDetailFragment :
return if (position == 0) null else spaces[position-1] 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 { private fun createDialPadFragment(): Fragment {
val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name) val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name)
return (fragment as DialPadFragment).apply { return (fragment as DialPadFragment).apply {

View File

@ -123,6 +123,7 @@ class NewHomeDetailFragment :
val isRoomList = state.currentTab is HomeTab.RoomList 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_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms
menu.findItem(R.id.menu_home_dialpad).isVisible = state.showDialPadTab menu.findItem(R.id.menu_home_dialpad).isVisible = state.showDialPadTab
menu.findItem(R.id.menu_room_sort_order).isVisible = false
} }
} }

View File

@ -68,6 +68,8 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.extensions.orTrue 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.RoomSummary
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
@ -77,7 +79,8 @@ import javax.inject.Inject
@Parcelize @Parcelize
data class RoomListParams( data class RoomListParams(
val displayMode: RoomListDisplayMode, val displayMode: RoomListDisplayMode,
val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP val explicitSpaceId: String? = SPACE_ID_FOLLOW_APP,
val roomSortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY
) : Parcelable ) : Parcelable
@AndroidEntryPoint @AndroidEntryPoint

View File

@ -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.query.toActiveSpaceOrOrphanRooms
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoomSummary 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.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.model.Membership 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) private val dimber = Dimber("ViewPager", DbgUtil.DBG_VIEW_PAGER)
fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?): List<RoomsSection> { fun buildSections(mode: RoomListDisplayMode, explicitSpaceId: String?, sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): List<RoomsSection> {
dimber.i { "Build sections for $mode, $explicitSpaceId" } dimber.i { "Build sections for $mode, $explicitSpaceId" }
val sections = mutableListOf<RoomsSection>() val sections = mutableListOf<RoomsSection>()
val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>() val activeSpaceAwareQueries = mutableListOf<RoomListViewModel.ActiveSpaceQueryUpdater>()
when (mode) { when (mode) {
RoomListDisplayMode.PEOPLE -> { RoomListDisplayMode.PEOPLE -> {
// 4 sections Invites / Fav / Dms / Low Priority // 4 sections Invites / Fav / Dms / Low Priority
buildDmSections(sections, activeSpaceAwareQueries, explicitSpaceId) buildDmSections(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder)
} }
RoomListDisplayMode.ROOMS -> { RoomListDisplayMode.ROOMS -> {
// 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms // 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms
buildRoomsSections(sections, activeSpaceAwareQueries, explicitSpaceId) buildRoomsSections(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder)
} }
RoomListDisplayMode.ALL -> { RoomListDisplayMode.ALL -> {
buildUnifiedSections(sections, activeSpaceAwareQueries, explicitSpaceId) buildUnifiedSections(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder)
} }
RoomListDisplayMode.FILTERED -> { RoomListDisplayMode.FILTERED -> {
// Used when searching for rooms // Used when searching for rooms
buildFilteredSection(sections) buildFilteredSection(sections)
} }
RoomListDisplayMode.NOTIFICATIONS -> { RoomListDisplayMode.NOTIFICATIONS -> {
buildNotificationsSection(sections, activeSpaceAwareQueries, explicitSpaceId) buildNotificationsSection(sections, activeSpaceAwareQueries, explicitSpaceId, sortOrder)
} }
} }
@ -125,13 +126,14 @@ class RoomListSectionBuilder(
return sections return sections
} }
private fun buildUnifiedSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, explicitSpaceId: String?) { private fun buildUnifiedSections(sections: MutableList<RoomsSection>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, explicitSpaceId: String?, sortOrder: RoomSortOrder) {
addSection( addSection(
sections = sections, sections = sections,
activeSpaceUpdaters = activeSpaceAwareQueries, activeSpaceUpdaters = activeSpaceAwareQueries,
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
countRoomAsNotif = true countRoomAsNotif = true
) { ) {
@ -149,6 +151,7 @@ class RoomListSectionBuilder(
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
}, },
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null) it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null)
@ -160,6 +163,7 @@ class RoomListSectionBuilder(
nameRes = R.string.normal_priority_header, nameRes = R.string.normal_priority_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -176,6 +180,7 @@ class RoomListSectionBuilder(
nameRes = R.string.low_priority_header, nameRes = R.string.low_priority_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -192,6 +197,7 @@ class RoomListSectionBuilder(
nameRes = R.string.system_alerts_header, nameRes = R.string.system_alerts_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -208,7 +214,8 @@ class RoomListSectionBuilder(
private fun buildRoomsSections( private fun buildRoomsSections(
sections: MutableList<RoomsSection>, sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
explicitSpaceId: String? explicitSpaceId: String?,
sortOrder: RoomSortOrder
) { ) {
if (autoAcceptInvites.showInvites()) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
@ -217,6 +224,7 @@ class RoomListSectionBuilder(
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL, spaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL,
countRoomAsNotif = true countRoomAsNotif = true
) { ) {
@ -236,6 +244,7 @@ class RoomListSectionBuilder(
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
}, },
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
@ -248,6 +257,7 @@ class RoomListSectionBuilder(
nameRes = R.string.bottom_action_rooms, nameRes = R.string.bottom_action_rooms,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -265,6 +275,7 @@ class RoomListSectionBuilder(
nameRes = R.string.low_priority_header, nameRes = R.string.low_priority_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -282,6 +293,7 @@ class RoomListSectionBuilder(
nameRes = R.string.system_alerts_header, nameRes = R.string.system_alerts_header,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -366,7 +378,8 @@ class RoomListSectionBuilder(
private fun buildDmSections( private fun buildDmSections(
sections: MutableList<RoomsSection>, sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
explicitSpaceId: String? explicitSpaceId: String?,
sortOrder: RoomSortOrder
) { ) {
if (autoAcceptInvites.showInvites()) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
@ -375,6 +388,7 @@ class RoomListSectionBuilder(
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -397,7 +411,8 @@ class RoomListSectionBuilder(
} else { } else {
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
}, },
explicitSpaceId = explicitSpaceId explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
@ -414,7 +429,8 @@ class RoomListSectionBuilder(
} else { } else {
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
}, },
explicitSpaceId = explicitSpaceId explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
@ -431,7 +447,8 @@ class RoomListSectionBuilder(
} else { } else {
RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL
}, },
explicitSpaceId = explicitSpaceId explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder
) { ) {
it.memberships = listOf(Membership.JOIN) it.memberships = listOf(Membership.JOIN)
it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM
@ -451,7 +468,8 @@ class RoomListSectionBuilder(
private fun buildNotificationsSection( private fun buildNotificationsSection(
sections: MutableList<RoomsSection>, sections: MutableList<RoomsSection>,
activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>, activeSpaceAwareQueries: MutableList<RoomListViewModel.ActiveSpaceQueryUpdater>,
explicitSpaceId: String? explicitSpaceId: String?,
sortOrder: RoomSortOrder
) { ) {
if (autoAcceptInvites.showInvites()) { if (autoAcceptInvites.showInvites()) {
addSection( addSection(
@ -460,6 +478,7 @@ class RoomListSectionBuilder(
nameRes = R.string.invitations_header, nameRes = R.string.invitations_header,
notifyOfLocalEcho = true, notifyOfLocalEcho = true,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -477,6 +496,7 @@ class RoomListSectionBuilder(
nameRes = R.string.bottom_action_rooms, nameRes = R.string.bottom_action_rooms,
notifyOfLocalEcho = false, notifyOfLocalEcho = false,
explicitSpaceId = explicitSpaceId, explicitSpaceId = explicitSpaceId,
sortOrder = sortOrder,
spaceFilterStrategy = if (onlyOrphansInHome) { spaceFilterStrategy = if (onlyOrphansInHome) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL
} else { } else {
@ -522,6 +542,7 @@ class RoomListSectionBuilder(
spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE, spaceFilterStrategy: RoomListViewModel.SpaceFilterStrategy = RoomListViewModel.SpaceFilterStrategy.NONE,
countRoomAsNotif: Boolean = false, countRoomAsNotif: Boolean = false,
explicitSpaceId: String?, explicitSpaceId: String?,
sortOrder: RoomSortOrder,
query: (RoomSummaryQueryParams.Builder) -> Unit query: (RoomSummaryQueryParams.Builder) -> Unit
) { ) {
withQueryParams(query) { roomQueryParams -> withQueryParams(query) { roomQueryParams ->
@ -537,7 +558,8 @@ class RoomListSectionBuilder(
val name = stringProvider.getString(nameRes) val name = stringProvider.getString(nameRes)
val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive( val filteredPagedRoomSummariesLive = session.roomService().getFilteredPagedRoomSummariesLive(
roomQueryParams.process(spaceFilterStrategy, spaceStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId)), roomQueryParams.process(spaceFilterStrategy, spaceStateHandler.explicitOrSafeActiveSpaceId(explicitSpaceId)),
pagedListConfig pagedListConfig,
sortOrder
) )
when (spaceFilterStrategy) { when (spaceFilterStrategy) {
RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> { RoomListViewModel.SpaceFilterStrategy.ORPHANS_IF_SPACE_NULL -> {

View File

@ -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.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary 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.UpdatableLivePageResult
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
@ -152,8 +153,8 @@ class RoomListViewModel @AssistedInject constructor(
) )
val sections: List<RoomsSection> by lazy { val sections: List<RoomsSection> by lazy {
viewPagerDimber.i { "Build sections for ${initialState.displayMode}, ${initialState.explicitSpaceId}" } viewPagerDimber.i { "Build sections for ${initialState.displayMode}, ${initialState.explicitSpaceId} ${initialState.roomSortOrder}" }
roomListSectionBuilder.buildSections(initialState.displayMode, initialState.explicitSpaceId) roomListSectionBuilder.buildSections(initialState.displayMode, initialState.explicitSpaceId, initialState.roomSortOrder)
} }
override fun handle(action: RoomListAction) { override fun handle(action: RoomListAction) {

View File

@ -20,6 +20,7 @@ import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import im.vector.app.features.home.RoomListDisplayMode 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.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary 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.SpaceChildInfo
@ -32,8 +33,9 @@ data class RoomListViewState(
val currentUserName: String? = null, val currentUserName: String? = null,
val asyncSelectedSpace: Async<RoomSummary?> = Uninitialized, val asyncSelectedSpace: Async<RoomSummary?> = Uninitialized,
// In comparison to currentRoomGrouping, the explicit space id fixes a filter method that should not change afterwards // 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 { ) : MavericksState {
constructor(args: RoomListParams) : this(displayMode = args.displayMode, explicitSpaceId = args.explicitSpaceId) constructor(args: RoomListParams) : this(displayMode = args.displayMode, explicitSpaceId = args.explicitSpaceId, roomSortOrder = args.roomSortOrder)
} }

View File

@ -248,6 +248,8 @@ class VectorPreferences @Inject constructor(
private const val SETTINGS_SPACE_BACK_NAVIGATION = "SETTINGS_SPACE_BACK_NAVIGATION" private const val SETTINGS_SPACE_BACK_NAVIGATION = "SETTINGS_SPACE_BACK_NAVIGATION"
const val SETTINGS_FOLLOW_SYSTEM_LOCALE = "SETTINGS_FOLLOW_SYSTEM_LOCALE" 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_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" private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH"

View File

@ -14,4 +14,21 @@
android:visible="false" android:visible="false"
app:showAsAction="never" app:showAsAction="never"
tools:visible="true" /> tools:visible="true" />
<item
android:id="@+id/menu_room_sort_order"
android:title="@string/home_layout_preferences_sort_by"
app:showAsAction="never">
<menu>
<group
android:checkableBehavior="single">
<item
android:id="@+id/menu_room_sort_order_activity"
android:title="@string/home_layout_preferences_sort_activity" />
<item
android:id="@+id/menu_room_sort_order_unread"
android:title="@string/home_layout_preferences_sort_unread" />
</group>
</menu>
</item>
</menu> </menu>