adding room join/leaving based on sync status

- means the invitations page should work!
This commit is contained in:
Adam Brown 2022-03-17 23:01:40 +00:00
parent 271727dda7
commit f0a856eb20
11 changed files with 81 additions and 12 deletions

View File

@ -29,6 +29,18 @@ internal class OverviewPersistence(
.map { it.map { json.decodeFromString(RoomOverview.serializer(), it.blob) } }
}
override suspend fun removeRooms(roomsToRemove: List<RoomId>) {
dispatchers.withIoContext {
database.transaction {
roomsToRemove.forEach {
database.inviteStateQueries.remove(it.value)
database.overviewStateQueries.remove(it.value)
database.roomEventQueries.remove(it.value)
}
}
}
}
override suspend fun persistInvites(invites: List<RoomInvite>) {
dispatchers.withIoContext {
database.inviteStateQueries.transaction {
@ -46,6 +58,14 @@ internal class OverviewPersistence(
.map { it.map { json.decodeFromString(RoomInvite.serializer(), it.blob) } }
}
override suspend fun removeInvites(invites: List<RoomId>) {
dispatchers.withIoContext {
database.inviteStateQueries.transaction {
invites.forEach { database.inviteStateQueries.remove(it.value) }
}
}
}
override suspend fun persist(overviewState: OverviewState) {
dispatchers.withIoContext {
database.transaction {

View File

@ -10,4 +10,8 @@ FROM dbInviteState;
insert:
INSERT OR REPLACE INTO dbInviteState(room_id, blob)
VALUES (?, ?);
VALUES (?, ?);
remove:
DELETE FROM dbInviteState
WHERE room_id = ?;

View File

@ -18,4 +18,8 @@ WHERE room_id = ?;
insert:
INSERT OR REPLACE INTO dbOverviewState(room_id, latest_activity_timestamp_utc, read_marker, blob)
VALUES (?, ?, ?, ?);
VALUES (?, ?, ?, ?);
remove:
DELETE FROM dbOverviewState
WHERE room_id = ?;

View File

@ -33,3 +33,7 @@ FROM dbUnreadEvent
INNER JOIN dbRoomEvent ON dbUnreadEvent.event_id = dbRoomEvent.event_id
ORDER BY dbRoomEvent.timestamp_utc DESC
LIMIT 100;
remove:
DELETE FROM dbRoomEvent
WHERE room_id = ?;

View File

@ -32,7 +32,8 @@ class NotificationsUseCase(
val asRooms = changes.keys
val removedRooms = inferredCurrentNotifications.keys - asRooms
val onlyContainsRemovals = inferredCurrentNotifications.filterKeys { !removedRooms.contains(it) } == changes.filterKeys { !removedRooms.contains(it) }
val onlyContainsRemovals =
inferredCurrentNotifications.filterKeys { !removedRooms.contains(it) } == changes.filterKeys { !removedRooms.contains(it) }
inferredCurrentNotifications.clear()
inferredCurrentNotifications.putAll(changes)

View File

@ -28,8 +28,10 @@ class PushAndroidService : FirebaseMessagingService() {
}
override fun onNewToken(token: String) {
log(PUSH, "new push token received")
GlobalScope.launch {
module.pushUseCase().registerPush(token)
log(PUSH, "token registered")
}
}

View File

@ -79,15 +79,15 @@ class ProfileViewModel(
}
fun acceptRoomInvite(roomId: RoomId) {
viewModelScope.launch {
roomService.joinRoom(roomId)
}
launchCatching { roomService.joinRoom(roomId) }.fold(
onError = {}
)
}
fun rejectRoomInvite(roomId: RoomId) {
viewModelScope.launch {
roomService.rejectJoinRoom(roomId)
}
launchCatching { roomService.rejectJoinRoom(roomId) }.fold(
onError = {}
)
}
fun stop() {
@ -103,3 +103,15 @@ class ProfileViewModel(
}
}
fun <S, VE, T> DapkViewModel<S, VE>.launchCatching(block: suspend () -> T): LaunchCatching<T> {
return object : LaunchCatching<T> {
override fun fold(onSuccess: (T) -> Unit, onError: (Throwable) -> Unit) {
viewModelScope.launch { runCatching { block() }.fold(onSuccess, onError) }
}
}
}
interface LaunchCatching<T> {
fun fold(onSuccess: (T) -> Unit = {}, onError: (Throwable) -> Unit = {})
}

View File

@ -28,6 +28,7 @@ interface FilterStore {
interface OverviewStore {
suspend fun removeRooms(roomsToRemove: List<RoomId>)
suspend fun persistInvites(invite: List<RoomInvite>)
suspend fun persist(overviewState: OverviewState)
@ -35,6 +36,7 @@ interface OverviewStore {
fun latest(): Flow<OverviewState>
fun latestInvites(): Flow<List<RoomInvite>>
suspend fun removeInvites(map: List<RoomId>)
}
interface SyncStore {

View File

@ -214,6 +214,7 @@ sealed class ApiToDeviceEvent {
internal data class ApiSyncRooms(
@SerialName("join") val join: Map<RoomId, ApiSyncRoom>? = null,
@SerialName("invite") val invite: Map<RoomId, ApiSyncRoomInvite>? = null,
@SerialName("leave") val leave: Map<RoomId, ApiSyncRoom>? = null,
)
@Serializable

View File

@ -20,13 +20,16 @@ internal class SyncReducer(
data class ReducerResult(
val roomState: List<RoomState>,
val invites: List<RoomInvite>
val invites: List<RoomInvite>,
val roomsLeft: List<RoomId>
)
suspend fun reduce(isInitialSync: Boolean, sideEffects: SideEffectResult, response: ApiSyncResponse, userCredentials: UserCredentials): ReducerResult {
val directMessages = response.directMessages()
val invites = response.rooms?.invite?.map { roomInvite(it, userCredentials) } ?: emptyList()
val roomsLeft = findRoomsLeft(response, userCredentials)
val apiUpdatedRooms = response.rooms?.join?.keepRoomsWithChanges()
val apiRoomsToProcess = apiUpdatedRooms?.map { (roomId, apiRoom) ->
logger.matrixLog(SYNC, "reducing: $roomId")
@ -49,9 +52,15 @@ internal class SyncReducer(
}
}
return ReducerResult((apiRoomsToProcess + roomsWithSideEffects).awaitAll().filterNotNull(), invites)
return ReducerResult((apiRoomsToProcess + roomsWithSideEffects).awaitAll().filterNotNull(), invites, roomsLeft)
}
private fun findRoomsLeft(response: ApiSyncResponse, userCredentials: UserCredentials) = response.rooms?.leave?.filter {
it.value.state.stateEvents.filterIsInstance<ApiTimelineEvent.RoomMember>().any {
it.content.membership.isLeave() && it.senderId == userCredentials.userId
}
}?.map { it.key } ?: emptyList()
private fun roomInvite(entry: Map.Entry<RoomId, ApiSyncRoomInvite>, userCredentials: UserCredentials): RoomInvite {
val memberEvents = entry.value.state.events.filterIsInstance<ApiStrippedEvent.RoomMember>()
val invitee = memberEvents.first { it.content.membership?.isInvite() ?: false }

View File

@ -46,13 +46,23 @@ internal class SyncUseCase(
val nextState = logger.logP("reducing") { syncReducer.reduce(isInitialSync, sideEffects, response, credentials) }
val overview = nextState.roomState.map { it.roomOverview }
if (nextState.roomsLeft.isNotEmpty()) {
persistence.removeRooms(nextState.roomsLeft)
}
if (nextState.invites.isNotEmpty()) {
persistence.persistInvites(nextState.invites)
}
when {
previousState == overview -> previousState.also { logger.matrixLog(SYNC, "no changes, not persisting new state") }
overview.isNotEmpty() -> overview.also { persistence.persist(overview) }
overview.isNotEmpty() -> overview.also {
val newRooms = overview - (previousState ?: emptyList()).toSet()
if (newRooms.isNotEmpty()) {
persistence.removeInvites(newRooms.map { it.roomId })
}
persistence.persist(overview)
}
else -> previousState.also { logger.matrixLog(SYNC, "nothing to do") }
}
}