-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement all room sorting in the SDK, no need to sort twice
Change-Id: Ieb1a2336b60e5b4cc59e2276ad680ae7dfb0290b
- Loading branch information
1 parent
1fc850d
commit 5c310cd
Showing
15 changed files
with
129 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 45 additions & 73 deletions
118
...res/roomlist/impl/src/main/kotlin/chat/schildi/features/roomlist/ScRoomSortOrderSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,62 @@ | ||
package chat.schildi.features.roomlist | ||
|
||
import androidx.lifecycle.AtomicReference | ||
import chat.schildi.lib.preferences.ScPreferencesStore | ||
import chat.schildi.lib.preferences.ScPrefs | ||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary | ||
import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType | ||
import io.element.android.libraries.core.coroutine.childScope | ||
import io.element.android.libraries.matrix.api.roomlist.RoomList | ||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter | ||
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.ScRoomSortOrder | ||
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.SharedFlow | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.cancel | ||
import kotlinx.coroutines.currentCoroutineContext | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.combine | ||
import kotlinx.coroutines.flow.launchIn | ||
import kotlinx.coroutines.flow.onEach | ||
import kotlinx.coroutines.flow.flatMapLatest | ||
import timber.log.Timber | ||
import javax.inject.Inject | ||
|
||
class ScRoomSortOrderSource @Inject constructor( | ||
private val scPreferencesStore: ScPreferencesStore | ||
private val scPreferencesStore: ScPreferencesStore, | ||
private val roomListService: RoomListService, | ||
) { | ||
private val lastCoroutineScope = AtomicReference<CoroutineScope?>(null) | ||
|
||
private val _sortOrder = MutableSharedFlow<ScRoomSortOrder>(replay = 1) | ||
val sortOrder: SharedFlow<ScRoomSortOrder> = _sortOrder | ||
|
||
fun launchIn(coroutineScope: CoroutineScope) { | ||
// From life space list and current space selection, build the RoomId filter | ||
combine( | ||
@OptIn(ExperimentalCoroutinesApi::class) | ||
fun filteredSummaries(coroutineScope: CoroutineScope): Flow<List<RoomSummary>> { | ||
// Listen to preferences relevant to sort order, then apply these to the dynamic room list | ||
return combine( | ||
scPreferencesStore.settingFlow(ScPrefs.SORT_BY_UNREAD), | ||
scPreferencesStore.settingFlow(ScPrefs.PIN_FAVORITES), | ||
scPreferencesStore.settingFlow(ScPrefs.BURY_LOW_PRIORITY), | ||
scPreferencesStore.settingFlow(ScPrefs.CLIENT_SIDE_SORT), | ||
scPreferencesStore.settingFlow(ScPrefs.SORT_BY_ACTIVITY), | ||
scPreferencesStore.settingFlow(ScPrefs.CLIENT_GENERATED_UNREAD_COUNTS), | ||
) { pinFavorites, buryLowPriority, clientSideSort, activitySort, clientSideUnreadCounts -> | ||
ScRoomSortOrder(pinFavorites, buryLowPriority, clientSideSort, activitySort, clientSideUnreadCounts) | ||
}.onEach { result -> | ||
_sortOrder.emit(result) | ||
}.launchIn(coroutineScope) | ||
} | ||
|
||
fun sortRooms(rooms: List<RoomListRoomSummary>, order: ScRoomSortOrder): List<RoomListRoomSummary> { | ||
// TODO: move to SDK? | ||
return if (order.needsAction()) { | ||
// Do activity-based sorting as separate step, since we do not know for sure the range of timestamps, | ||
// but we want to prioritize favorite state above activity | ||
if (order.activitySort) { | ||
rooms.sortedByDescending { it.lastMessageTimestamp ?: 0L } | ||
} else { | ||
rooms | ||
}.sortedBy { room -> | ||
val inviteAdd = if (room.displayType == RoomSummaryDisplayType.INVITE) -10_000 else 0 | ||
val favoriteAdd = if (order.pinFavorites && !room.isFavorite) 1000 else 0 | ||
val lowPrioAdd = if (order.buryLowPriority && room.isLowPriority) 100 else 0 | ||
val unreadAdd = when { | ||
order.activitySort -> 0 | ||
!order.clientSideSort -> 0 | ||
order.clientSideUnreadCounts -> unreadSort( | ||
room.isMarkedUnread, | ||
room.numberOfUnreadMentions, | ||
room.numberOfUnreadNotifications, | ||
room.numberOfUnreadMessages | ||
) | ||
else -> unreadSort( | ||
room.isMarkedUnread, | ||
room.highlightCount, | ||
room.notificationCount, | ||
room.unreadCount | ||
) | ||
} | ||
inviteAdd + favoriteAdd + lowPrioAdd + unreadAdd | ||
} | ||
} else { | ||
rooms | ||
) { byUnread, pinFavorites, buryLowPriority, clientSideUnreadCounts -> | ||
ScRoomSortOrder( | ||
byUnread = byUnread, | ||
pinFavourites = pinFavorites, | ||
buryLowPriority = buryLowPriority, | ||
clientSideUnreadCounts = clientSideUnreadCounts, | ||
) | ||
}.flatMapLatest { sortOrder -> | ||
// TODO: would be nice to teach the SDK to update sort order without recreating the whole list | ||
// Cancel jobs for previous list | ||
val scope = coroutineScope.childScope(Dispatchers.Default, "sc-sorted-room-list") | ||
lastCoroutineScope.getAndSet(scope)?.cancel() | ||
Timber.d("Create new filtered and sorted room list for $sortOrder") | ||
roomListService.scCreateRoomList( | ||
pageSize = 30, | ||
initialFilter = RoomListFilter.all(), | ||
source = RoomList.Source.All, | ||
sortOrder = sortOrder, | ||
coroutineScope = scope, | ||
).also { | ||
it.loadAllIncrementally(scope) | ||
}.filteredSummaries | ||
} | ||
} | ||
|
||
private fun unreadSort(markedUnread: Boolean, mentionCount: Int, notificationCount: Int, unreadCount: Int): Int { | ||
return when { | ||
markedUnread || notificationCount > 0 || mentionCount > 0 -> 0 | ||
unreadCount > 0 -> 1 | ||
else -> 2 | ||
} | ||
} | ||
} | ||
|
||
data class ScRoomSortOrder( | ||
val pinFavorites: Boolean, | ||
val buryLowPriority: Boolean, | ||
val clientSideSort: Boolean, | ||
val activitySort: Boolean, | ||
val clientSideUnreadCounts: Boolean, | ||
) { | ||
fun needsAction() = pinFavorites || buryLowPriority || clientSideSort || activitySort | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
...x/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/ScRoomSortOrder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package io.element.android.libraries.matrix.api.roomlist | ||
|
||
|
||
data class ScRoomSortOrder( | ||
val byUnread: Boolean = false, | ||
val pinFavourites: Boolean = false, | ||
val buryLowPriority: Boolean = false, | ||
val clientSideUnreadCounts: Boolean = false, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
...n/kotlin/io/element/android/libraries/matrix/impl/roomlist/ScRoomListFactoryExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package io.element.android.libraries.matrix.impl.roomlist | ||
|
||
import io.element.android.libraries.matrix.api.roomlist.ScRoomSortOrder | ||
|
||
fun ScRoomSortOrder.toSdkSortOrder() = uniffi.matrix_sdk_ui.ScSortOrder( | ||
byUnread = byUnread, | ||
pinFavorites = pinFavourites, | ||
buryLowPriority = buryLowPriority, | ||
clientGeneratedUnread = clientSideUnreadCounts, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.