accumulating and storing the invite event metadata for member and room names
This commit is contained in:
parent
423ee3afd9
commit
38c9e33a59
|
@ -11,10 +11,8 @@ import app.dapk.st.matrix.sync.RoomInvite
|
|||
import app.dapk.st.matrix.sync.RoomOverview
|
||||
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private val json = Json
|
||||
|
@ -35,7 +33,7 @@ internal class OverviewPersistence(
|
|||
dispatchers.withIoContext {
|
||||
database.inviteStateQueries.transaction {
|
||||
invites.forEach {
|
||||
database.inviteStateQueries.insert(it.roomId.value)
|
||||
database.inviteStateQueries.insert(it.roomId.value, json.encodeToString(RoomInvite.serializer(), it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +43,7 @@ internal class OverviewPersistence(
|
|||
return database.inviteStateQueries.selectAll()
|
||||
.asFlow()
|
||||
.mapToList()
|
||||
.map { it.map { RoomInvite(RoomId(it)) } }
|
||||
.map { it.map { json.decodeFromString(RoomInvite.serializer(), it.blob) } }
|
||||
}
|
||||
|
||||
override suspend fun persist(overviewState: OverviewState) {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
CREATE TABLE dbInviteState (
|
||||
room_id TEXT NOT NULL,
|
||||
blob TEXT NOT NULL,
|
||||
PRIMARY KEY (room_id)
|
||||
);
|
||||
|
||||
selectAll:
|
||||
SELECT room_id
|
||||
SELECT room_id, blob
|
||||
FROM dbInviteState;
|
||||
|
||||
insert:
|
||||
INSERT OR REPLACE INTO dbInviteState(room_id)
|
||||
VALUES (?);
|
||||
INSERT OR REPLACE INTO dbInviteState(room_id, blob)
|
||||
VALUES (?, ?);
|
|
@ -22,6 +22,8 @@ import app.dapk.st.core.LifecycleEffect
|
|||
import app.dapk.st.core.StartObserving
|
||||
import app.dapk.st.core.components.CenteredLoading
|
||||
import app.dapk.st.design.components.*
|
||||
import app.dapk.st.matrix.sync.InviteMeta
|
||||
import app.dapk.st.matrix.sync.RoomInvite
|
||||
import app.dapk.st.settings.SettingsActivity
|
||||
|
||||
@Composable
|
||||
|
@ -122,14 +124,20 @@ private fun Invitations(viewModel: ProfileViewModel, invitations: Page.Invitatio
|
|||
is Lce.Content -> {
|
||||
LazyColumn {
|
||||
items(state.value) {
|
||||
TextRow(title = it.value, includeDivider = false) {
|
||||
val text = when (val meta = it.inviteMeta) {
|
||||
InviteMeta.DirectMessage -> "${it.inviterName()} has invited you to chat"
|
||||
is InviteMeta.Room -> "${it.inviterName()} has invited you to ${meta.roomName ?: "unnamed room"}"
|
||||
}
|
||||
|
||||
TextRow(title = text, includeDivider = false) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row {
|
||||
Button(modifier = Modifier.weight(1f), onClick = { viewModel.acceptRoomInvite(it) }) {
|
||||
Text("Accept".uppercase())
|
||||
Button(modifier = Modifier.weight(1f), onClick = { viewModel.rejectRoomInvite(it.roomId) }) {
|
||||
Text("Reject".uppercase())
|
||||
}
|
||||
Spacer(modifier = Modifier.fillMaxWidth(0.1f))
|
||||
Button(modifier = Modifier.weight(1f), onClick = { viewModel.rejectRoomInvite(it) }) {
|
||||
Text("Reject".uppercase())
|
||||
Button(modifier = Modifier.weight(1f), onClick = { viewModel.acceptRoomInvite(it.roomId) }) {
|
||||
Text("Accept".uppercase())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +149,8 @@ private fun Invitations(viewModel: ProfileViewModel, invitations: Page.Invitatio
|
|||
}
|
||||
}
|
||||
|
||||
private fun RoomInvite.inviterName() = this.from.displayName?.let { "$it (${this.from.id.value})" } ?: this.from.id.value
|
||||
|
||||
@Composable
|
||||
private fun ProfileViewModel.ObserveEvents() {
|
||||
val context = LocalContext.current
|
||||
|
|
|
@ -5,6 +5,7 @@ import app.dapk.st.design.components.Route
|
|||
import app.dapk.st.design.components.SpiderPage
|
||||
import app.dapk.st.matrix.common.RoomId
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.matrix.sync.RoomInvite
|
||||
|
||||
data class ProfileScreenState(
|
||||
val page: SpiderPage<out Page>,
|
||||
|
@ -18,7 +19,7 @@ sealed interface Page {
|
|||
)
|
||||
}
|
||||
|
||||
data class Invitations(val content: Lce<List<RoomId>>): Page
|
||||
data class Invitations(val content: Lce<List<RoomInvite>>): Page
|
||||
|
||||
object Routes {
|
||||
val profile = Route<Profile>("Profile")
|
||||
|
|
|
@ -50,7 +50,7 @@ class ProfileViewModel(
|
|||
syncService.invites()
|
||||
.onEach {
|
||||
updatePageState<Page.Invitations> {
|
||||
copy(content = Lce.Content(it.map { it.roomId }))
|
||||
copy(content = Lce.Content(it))
|
||||
}
|
||||
}
|
||||
.launchPageJob()
|
||||
|
|
|
@ -31,5 +31,18 @@ data class LastMessage(
|
|||
|
||||
@Serializable
|
||||
data class RoomInvite(
|
||||
@SerialName("from") val from: RoomMember,
|
||||
@SerialName("room_id") val roomId: RoomId,
|
||||
@SerialName("meta") val inviteMeta: InviteMeta,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
sealed class InviteMeta {
|
||||
@Serializable
|
||||
@SerialName("direct_message")
|
||||
object DirectMessage : InviteMeta()
|
||||
|
||||
@Serializable
|
||||
@SerialName("room")
|
||||
data class Room(val roomName: String? = null) : InviteMeta()
|
||||
}
|
||||
|
|
|
@ -230,14 +230,30 @@ internal data class ApiInviteEvents(
|
|||
sealed class ApiStrippedEvent {
|
||||
|
||||
@Serializable
|
||||
@SerialName("m.room.create")
|
||||
internal data class RoomCreate(
|
||||
@SerialName("m.room.member")
|
||||
internal data class RoomMember(
|
||||
@SerialName("content") val content: Content,
|
||||
@SerialName("sender") val sender: UserId,
|
||||
) : ApiStrippedEvent() {
|
||||
|
||||
@Serializable
|
||||
internal data class Content(
|
||||
@SerialName("displayname") val displayName: String? = null,
|
||||
@SerialName("membership") val membership: ApiTimelineEvent.RoomMember.Content.Membership? = null,
|
||||
@SerialName("is_direct") val isDirect: Boolean? = null,
|
||||
@SerialName("avatar_url") val avatarUrl: MxUrl? = null,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("m.room.name")
|
||||
internal data class RoomName(
|
||||
@SerialName("content") val content: Content,
|
||||
) : ApiStrippedEvent() {
|
||||
|
||||
@Serializable
|
||||
internal data class Content(
|
||||
@SerialName("type") val type: String? = null
|
||||
@SerialName("name") val name: String? = null
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -407,6 +423,7 @@ internal sealed class ApiTimelineEvent {
|
|||
value class Membership(val value: String) {
|
||||
fun isJoin() = value == "join"
|
||||
fun isInvite() = value == "invite"
|
||||
fun isLeave() = value == "leave"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,11 +4,10 @@ import app.dapk.st.core.CoroutineDispatchers
|
|||
import app.dapk.st.core.withIoContextAsync
|
||||
import app.dapk.st.matrix.common.*
|
||||
import app.dapk.st.matrix.common.MatrixLogTag.SYNC
|
||||
import app.dapk.st.matrix.sync.InviteMeta
|
||||
import app.dapk.st.matrix.sync.RoomInvite
|
||||
import app.dapk.st.matrix.sync.RoomState
|
||||
import app.dapk.st.matrix.sync.internal.request.ApiAccountEvent
|
||||
import app.dapk.st.matrix.sync.internal.request.ApiSyncResponse
|
||||
import app.dapk.st.matrix.sync.internal.request.ApiSyncRoom
|
||||
import app.dapk.st.matrix.sync.internal.request.*
|
||||
import app.dapk.st.matrix.sync.internal.room.SideEffectResult
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
||||
|
@ -27,7 +26,7 @@ internal class SyncReducer(
|
|||
suspend fun reduce(isInitialSync: Boolean, sideEffects: SideEffectResult, response: ApiSyncResponse, userCredentials: UserCredentials): ReducerResult {
|
||||
val directMessages = response.directMessages()
|
||||
|
||||
val invites = response.rooms?.invite?.keys?.map { RoomInvite(it) } ?: emptyList()
|
||||
val invites = response.rooms?.invite?.map { roomInvite(it, userCredentials) } ?: emptyList()
|
||||
val apiUpdatedRooms = response.rooms?.join?.keepRoomsWithChanges()
|
||||
val apiRoomsToProcess = apiUpdatedRooms?.map { (roomId, apiRoom) ->
|
||||
logger.matrixLog(SYNC, "reducing: $roomId")
|
||||
|
@ -52,6 +51,20 @@ internal class SyncReducer(
|
|||
|
||||
return ReducerResult((apiRoomsToProcess + roomsWithSideEffects).awaitAll().filterNotNull(), invites)
|
||||
}
|
||||
|
||||
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 }
|
||||
val from = memberEvents.first { it.sender == invitee.sender }
|
||||
return RoomInvite(
|
||||
RoomMember(from.sender, from.content.displayName, from.content.avatarUrl?.convertMxUrToUrl(userCredentials.homeServer)?.let { AvatarUrl(it) }),
|
||||
roomId = entry.key,
|
||||
inviteMeta = when (invitee.content.isDirect) {
|
||||
true -> InviteMeta.DirectMessage
|
||||
null, false -> InviteMeta.Room(entry.value.state.events.filterIsInstance<ApiStrippedEvent.RoomName>().firstOrNull()?.content?.name)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map<RoomId, ApiSyncRoom>.keepRoomsWithChanges() = this.filter {
|
||||
|
|
Loading…
Reference in New Issue