Add app room state persistence and allow rooms to be marked with bubbles
This commit is contained in:
parent
6a1d360036
commit
d44c331eab
|
@ -180,6 +180,7 @@ internal class FeatureModules internal constructor(
|
|||
chatEngineModule.engine,
|
||||
context,
|
||||
storeModule.value.messageStore(),
|
||||
storeModule.value.appRoomStore(),
|
||||
deviceMeta,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package app.dapk.st.domain
|
|||
import app.dapk.db.app.StDb
|
||||
import app.dapk.st.core.CoroutineDispatchers
|
||||
import app.dapk.st.core.Preferences
|
||||
import app.dapk.st.domain.application.AppRoomPersistence
|
||||
import app.dapk.st.domain.application.eventlog.EventLogPersistence
|
||||
import app.dapk.st.domain.application.eventlog.LoggingStore
|
||||
import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||
|
@ -41,4 +42,6 @@ class StoreModule(
|
|||
|
||||
fun messageStore(): MessageOptionsStore = MessageOptionsStore(cachingPreferences)
|
||||
|
||||
fun appRoomStore(): AppRoomPersistence = AppRoomPersistence(database, coroutineDispatchers)
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package app.dapk.st.domain.application
|
||||
|
||||
import app.dapk.db.app.StDb
|
||||
import app.dapk.st.core.CoroutineDispatchers
|
||||
import app.dapk.st.core.withIoContext
|
||||
import app.dapk.st.matrix.common.RoomId
|
||||
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
||||
import com.squareup.sqldelight.runtime.coroutines.mapToOneOrNull
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
private val DEFAULT_STATE = AppRoomState(isChatBubble = false)
|
||||
|
||||
class AppRoomPersistence(
|
||||
private val database: StDb,
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
|
||||
fun observe(roomId: RoomId): Flow<AppRoomState> {
|
||||
return database.appRoomQueries.select(roomId.value)
|
||||
.asFlow()
|
||||
.mapToOneOrNull(coroutineDispatchers.io)
|
||||
.map { it?.let { AppRoomState(isChatBubble = it.is_bubble == 1) } ?: DEFAULT_STATE }
|
||||
}
|
||||
|
||||
suspend fun markBubble(roomId: RoomId) = coroutineDispatchers.withIoContext {
|
||||
database.appRoomQueries.updateBubble(roomId.value, is_bubble = 1)
|
||||
}
|
||||
|
||||
suspend fun unmarkBubble(roomId: RoomId) = coroutineDispatchers.withIoContext {
|
||||
database.appRoomQueries.updateBubble(roomId.value, is_bubble = 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class AppRoomState(
|
||||
val isChatBubble: Boolean
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
CREATE TABLE IF NOT EXISTS dbAppRoom (
|
||||
room_id TEXT NOT NULL,
|
||||
is_bubble INTEGER AS Int NOT NULL,
|
||||
PRIMARY KEY (room_id)
|
||||
);
|
|
@ -1,18 +1,14 @@
|
|||
CREATE TABLE dbAppRoom (
|
||||
room_id TEXT NOT NULL,
|
||||
is_bubble INTEGER AS Int NOT NULL DEFAULT 0,
|
||||
is_bubble INTEGER AS Int NOT NULL,
|
||||
PRIMARY KEY (room_id)
|
||||
);
|
||||
|
||||
markBubble:
|
||||
INSERT OR REPLACE INTO dbAppRoom(room_id, is_bubble)
|
||||
VALUES (?,?);
|
||||
|
||||
unmarkBubble:
|
||||
updateBubble:
|
||||
INSERT OR REPLACE INTO dbAppRoom(room_id, is_bubble)
|
||||
VALUES (?,?);
|
||||
|
||||
select:
|
||||
SELECT is_bubble
|
||||
SELECT *
|
||||
FROM dbAppRoom
|
||||
WHERE room_id = ?;
|
|
@ -1,4 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS dbMutedRoom (
|
||||
room_id TEXT NOT NULL,
|
||||
PRIMARY KEY (room_id)
|
||||
);
|
|
@ -1,5 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS dbStRoomMeta (
|
||||
room_id TEXT NOT NULL,
|
||||
is_bubble INTEGER AS Int NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (room_id)
|
||||
);
|
|
@ -5,6 +5,7 @@ import android.content.Context
|
|||
import app.dapk.st.core.DeviceMeta
|
||||
import app.dapk.st.core.JobBag
|
||||
import app.dapk.st.core.ProvidableModule
|
||||
import app.dapk.st.domain.application.AppRoomPersistence
|
||||
import app.dapk.st.state.createStateViewModel
|
||||
import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||
import app.dapk.st.engine.ChatEngine
|
||||
|
@ -16,6 +17,7 @@ class MessengerModule(
|
|||
private val chatEngine: ChatEngine,
|
||||
private val context: Context,
|
||||
private val messageOptionsStore: MessageOptionsStore,
|
||||
private val appRoomStore: AppRoomPersistence,
|
||||
val deviceMeta: DeviceMeta,
|
||||
) : ProvidableModule {
|
||||
|
||||
|
@ -29,6 +31,7 @@ class MessengerModule(
|
|||
messageOptionsStore,
|
||||
RoomId(launchPayload.roomId),
|
||||
launchPayload.attachments,
|
||||
appRoomStore,
|
||||
it
|
||||
)
|
||||
}
|
||||
|
|
|
@ -122,13 +122,17 @@ internal fun MessengerScreen(
|
|||
}
|
||||
viewModel.dispatch(action)
|
||||
}
|
||||
BooleanOption(value = it.isMuted, trueText = "Disable bubble", falseText = "Enable bubble") {
|
||||
val action = when (it) {
|
||||
true -> ChatBubble.Disable
|
||||
false -> ChatBubble.Enable
|
||||
|
||||
state.appRoomState.takeIfContent()?.let {
|
||||
BooleanOption(value = it.isChatBubble, trueText = "Disable bubble", falseText = "Enable bubble") {
|
||||
val action = when (it) {
|
||||
true -> ChatBubble.Disable
|
||||
false -> ChatBubble.Enable
|
||||
}
|
||||
viewModel.dispatch(action)
|
||||
}
|
||||
viewModel.dispatch(action)
|
||||
}
|
||||
|
||||
DropdownMenuItem(text = { Text("Leave room", color = MaterialTheme.colorScheme.onSecondaryContainer) }, onClick = {
|
||||
viewModel.dispatch(ScreenAction.LeaveRoom)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package app.dapk.st.messenger.state
|
||||
|
||||
import app.dapk.st.design.components.BubbleModel
|
||||
import app.dapk.st.domain.application.AppRoomState
|
||||
import app.dapk.st.engine.MessengerPageState
|
||||
import app.dapk.st.engine.RoomEvent
|
||||
import app.dapk.st.navigator.MessageAttachment
|
||||
|
@ -37,6 +38,7 @@ sealed interface ComponentLifecycle : Action {
|
|||
|
||||
sealed interface MessagesStateChange : Action {
|
||||
data class Content(val content: MessengerPageState) : MessagesStateChange
|
||||
data class AppRoomContent(val content: AppRoomState) : MessagesStateChange
|
||||
data class MuteContent(val isMuted: Boolean) : MessagesStateChange
|
||||
data class ChatBubbleContent(val isChatBubble: Boolean) : MessagesStateChange
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package app.dapk.st.messenger.state
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import app.dapk.st.core.DeviceMeta
|
||||
import app.dapk.st.core.JobBag
|
||||
import app.dapk.st.core.Lce
|
||||
import app.dapk.st.core.asString
|
||||
import app.dapk.st.core.extensions.takeIfContent
|
||||
import app.dapk.st.design.components.BubbleModel
|
||||
import app.dapk.st.domain.application.AppRoomPersistence
|
||||
import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||
import app.dapk.st.engine.ChatEngine
|
||||
import app.dapk.st.engine.MessengerPageState
|
||||
|
@ -29,6 +31,7 @@ internal fun messengerReducer(
|
|||
messageOptionsStore: MessageOptionsStore,
|
||||
roomId: RoomId,
|
||||
initialAttachments: List<MessageAttachment>?,
|
||||
appRoomStore: AppRoomPersistence,
|
||||
eventEmitter: suspend (MessengerEvent) -> Unit,
|
||||
): ReducerFactory<MessengerScreenState> {
|
||||
return createReducer(
|
||||
|
@ -45,6 +48,14 @@ internal fun messengerReducer(
|
|||
val state = getState()
|
||||
when (action) {
|
||||
is ComponentLifecycle.Visible -> {
|
||||
jobBag.replace(
|
||||
"appRoomState",
|
||||
appRoomStore.observe(state.roomId)
|
||||
.onEach { dispatch(MessagesStateChange.AppRoomContent(it)) }
|
||||
.launchIn(coroutineScope)
|
||||
)
|
||||
|
||||
|
||||
jobBag.replace(
|
||||
"messages", chatEngine.messages(state.roomId, disableReadReceipts = messageOptionsStore.isReadReceiptsDisabled())
|
||||
.onEach { dispatch(MessagesStateChange.Content(it)) }
|
||||
|
@ -52,10 +63,14 @@ internal fun messengerReducer(
|
|||
)
|
||||
}
|
||||
|
||||
ComponentLifecycle.Gone -> jobBag.cancel("messages")
|
||||
ComponentLifecycle.Gone -> jobBag.cancelAll()
|
||||
}
|
||||
},
|
||||
|
||||
change(MessagesStateChange.AppRoomContent::class) { action, state ->
|
||||
state.copy(appRoomState = Lce.Content(action.content))
|
||||
},
|
||||
|
||||
change(MessagesStateChange.Content::class) { action, state ->
|
||||
state.copy(roomState = Lce.Content(action.content))
|
||||
},
|
||||
|
@ -174,9 +189,11 @@ internal fun messengerReducer(
|
|||
},
|
||||
|
||||
async(ScreenAction.ChatBubble::class) { action ->
|
||||
Log.e("!!!", "$action")
|
||||
val state = getState()
|
||||
when (action) {
|
||||
ScreenAction.ChatBubble.Disable -> {}
|
||||
ScreenAction.ChatBubble.Enable -> {}
|
||||
ScreenAction.ChatBubble.Disable -> appRoomStore.unmarkBubble(state.roomId)
|
||||
ScreenAction.ChatBubble.Enable -> appRoomStore.markBubble(state.roomId)
|
||||
}
|
||||
|
||||
dispatch(
|
||||
|
|
|
@ -2,6 +2,7 @@ package app.dapk.st.messenger.state
|
|||
|
||||
import app.dapk.st.core.Lce
|
||||
import app.dapk.st.design.components.BubbleModel
|
||||
import app.dapk.st.domain.application.AppRoomState
|
||||
import app.dapk.st.engine.MessengerPageState
|
||||
import app.dapk.st.engine.RoomEvent
|
||||
import app.dapk.st.matrix.common.RoomId
|
||||
|
@ -20,10 +21,6 @@ data class MessengerScreenState(
|
|||
val appRoomState: Lce<AppRoomState>,
|
||||
)
|
||||
|
||||
data class AppRoomState(
|
||||
val isChatBubble: Boolean
|
||||
)
|
||||
|
||||
data class ViewerState(
|
||||
val event: BubbleModel.Image,
|
||||
)
|
||||
|
|
|
@ -63,6 +63,7 @@ class MessengerReducerTest {
|
|||
fakeMessageOptionsStore.instance,
|
||||
A_ROOM_ID,
|
||||
emptyList(),
|
||||
mockk(),
|
||||
fakeEventSource,
|
||||
)
|
||||
}
|
||||
|
@ -405,6 +406,7 @@ class MessengerReducerTest {
|
|||
fakeMessageOptionsStore.instance,
|
||||
A_ROOM_ID,
|
||||
initialAttachments = initialAttachments,
|
||||
appRoomStore = mockk(),
|
||||
fakeEventSource,
|
||||
)
|
||||
}(block)
|
||||
|
|
Loading…
Reference in New Issue