lifts room muting to the chat engine
This commit is contained in:
parent
7e184cf200
commit
dc5a46e0cd
|
@ -18,7 +18,6 @@ import app.dapk.st.core.extensions.ErrorTracker
|
||||||
import app.dapk.st.core.extensions.unsafeLazy
|
import app.dapk.st.core.extensions.unsafeLazy
|
||||||
import app.dapk.st.directory.DirectoryModule
|
import app.dapk.st.directory.DirectoryModule
|
||||||
import app.dapk.st.domain.StoreModule
|
import app.dapk.st.domain.StoreModule
|
||||||
import app.dapk.st.domain.room.MutedRoomsStorePersistence
|
|
||||||
import app.dapk.st.engine.MatrixEngine
|
import app.dapk.st.engine.MatrixEngine
|
||||||
import app.dapk.st.firebase.messaging.MessagingModule
|
import app.dapk.st.firebase.messaging.MessagingModule
|
||||||
import app.dapk.st.home.BetaVersionUpgradeUseCase
|
import app.dapk.st.home.BetaVersionUpgradeUseCase
|
||||||
|
@ -164,7 +163,6 @@ internal class FeatureModules internal constructor(
|
||||||
context,
|
context,
|
||||||
storeModule.value.messageStore(),
|
storeModule.value.messageStore(),
|
||||||
deviceMeta,
|
deviceMeta,
|
||||||
MutedRoomsStorePersistence(storeModule.value.cachingPreferences)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val homeModule by unsafeLazy {
|
val homeModule by unsafeLazy {
|
||||||
|
|
|
@ -36,6 +36,8 @@ interface ChatEngine : TaskRunner {
|
||||||
|
|
||||||
fun pushHandler(): PushHandler
|
fun pushHandler(): PushHandler
|
||||||
|
|
||||||
|
suspend fun muteRoom(roomId: RoomId)
|
||||||
|
suspend fun unmuteRoom(roomId: RoomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TaskRunner {
|
interface TaskRunner {
|
||||||
|
|
|
@ -87,7 +87,8 @@ sealed interface ImportResult {
|
||||||
data class MessengerPageState(
|
data class MessengerPageState(
|
||||||
val self: UserId,
|
val self: UserId,
|
||||||
val roomState: RoomState,
|
val roomState: RoomState,
|
||||||
val typing: Typing?
|
val typing: Typing?,
|
||||||
|
val isMuted: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class RoomState(
|
data class RoomState(
|
||||||
|
|
|
@ -13,6 +13,7 @@ import app.dapk.st.domain.preference.CachingPreferences
|
||||||
import app.dapk.st.domain.preference.PropertyCache
|
import app.dapk.st.domain.preference.PropertyCache
|
||||||
import app.dapk.st.domain.profile.ProfilePersistence
|
import app.dapk.st.domain.profile.ProfilePersistence
|
||||||
import app.dapk.st.domain.push.PushTokenRegistrarPreferences
|
import app.dapk.st.domain.push.PushTokenRegistrarPreferences
|
||||||
|
import app.dapk.st.domain.room.MutedStorePersistence
|
||||||
import app.dapk.st.domain.sync.OverviewPersistence
|
import app.dapk.st.domain.sync.OverviewPersistence
|
||||||
import app.dapk.st.domain.sync.RoomPersistence
|
import app.dapk.st.domain.sync.RoomPersistence
|
||||||
import app.dapk.st.matrix.common.CredentialsStore
|
import app.dapk.st.matrix.common.CredentialsStore
|
||||||
|
@ -34,7 +35,13 @@ class StoreModule(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun overviewStore(): OverviewStore = OverviewPersistence(database, coroutineDispatchers)
|
fun overviewStore(): OverviewStore = OverviewPersistence(database, coroutineDispatchers)
|
||||||
fun roomStore(): RoomStore = RoomPersistence(database, OverviewPersistence(database, coroutineDispatchers), coroutineDispatchers)
|
fun roomStore(): RoomStore = RoomPersistence(
|
||||||
|
database = database,
|
||||||
|
overviewPersistence = OverviewPersistence(database, coroutineDispatchers),
|
||||||
|
coroutineDispatchers = coroutineDispatchers,
|
||||||
|
muteableStore = MutedStorePersistence(preferences),
|
||||||
|
)
|
||||||
|
|
||||||
fun credentialsStore(): CredentialsStore = CredentialsPreferences(credentialPreferences)
|
fun credentialsStore(): CredentialsStore = CredentialsPreferences(credentialPreferences)
|
||||||
fun syncStore(): SyncStore = SyncTokenPreferences(preferences)
|
fun syncStore(): SyncStore = SyncTokenPreferences(preferences)
|
||||||
fun filterStore(): FilterStore = FilterPreferences(preferences)
|
fun filterStore(): FilterStore = FilterPreferences(preferences)
|
||||||
|
|
|
@ -4,19 +4,13 @@ import app.dapk.st.core.Preferences
|
||||||
import app.dapk.st.core.append
|
import app.dapk.st.core.append
|
||||||
import app.dapk.st.core.removeFromSet
|
import app.dapk.st.core.removeFromSet
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
import app.dapk.st.matrix.sync.MuteableStore
|
||||||
|
|
||||||
private const val KEY_MUTE = "mute"
|
private const val KEY_MUTE = "mute"
|
||||||
|
|
||||||
interface MutedRoomsStore {
|
internal class MutedStorePersistence(
|
||||||
suspend fun mute(roomId: RoomId)
|
|
||||||
suspend fun unmute(roomId: RoomId)
|
|
||||||
suspend fun isMuted(roomId: RoomId): Boolean
|
|
||||||
suspend fun allMuted(): Set<RoomId>
|
|
||||||
}
|
|
||||||
|
|
||||||
class MutedRoomsStorePersistence(
|
|
||||||
private val preferences: Preferences
|
private val preferences: Preferences
|
||||||
) : MutedRoomsStore {
|
) : MuteableStore {
|
||||||
|
|
||||||
override suspend fun mute(roomId: RoomId) {
|
override suspend fun mute(roomId: RoomId) {
|
||||||
preferences.append(KEY_MUTE, roomId.value)
|
preferences.append(KEY_MUTE, roomId.value)
|
||||||
|
@ -28,8 +22,6 @@ class MutedRoomsStorePersistence(
|
||||||
|
|
||||||
override suspend fun isMuted(roomId: RoomId): Boolean {
|
override suspend fun isMuted(roomId: RoomId): Boolean {
|
||||||
val allMuted = allMuted()
|
val allMuted = allMuted()
|
||||||
println("??? isMuted - $roomId")
|
|
||||||
println("??? all - $allMuted")
|
|
||||||
return allMuted.contains(roomId)
|
return allMuted.contains(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,10 @@ import app.dapk.db.DapkDb
|
||||||
import app.dapk.db.model.RoomEventQueries
|
import app.dapk.db.model.RoomEventQueries
|
||||||
import app.dapk.st.core.CoroutineDispatchers
|
import app.dapk.st.core.CoroutineDispatchers
|
||||||
import app.dapk.st.core.withIoContext
|
import app.dapk.st.core.withIoContext
|
||||||
|
import app.dapk.st.domain.room.MutedStorePersistence
|
||||||
import app.dapk.st.matrix.common.EventId
|
import app.dapk.st.matrix.common.EventId
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
import app.dapk.st.matrix.sync.RoomEvent
|
import app.dapk.st.matrix.sync.*
|
||||||
import app.dapk.st.matrix.sync.RoomOverview
|
|
||||||
import app.dapk.st.matrix.sync.RoomState
|
|
||||||
import app.dapk.st.matrix.sync.RoomStore
|
|
||||||
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
import com.squareup.sqldelight.runtime.coroutines.asFlow
|
||||||
import com.squareup.sqldelight.runtime.coroutines.mapToList
|
import com.squareup.sqldelight.runtime.coroutines.mapToList
|
||||||
import com.squareup.sqldelight.runtime.coroutines.mapToOneNotNull
|
import com.squareup.sqldelight.runtime.coroutines.mapToOneNotNull
|
||||||
|
@ -25,7 +23,8 @@ internal class RoomPersistence(
|
||||||
private val database: DapkDb,
|
private val database: DapkDb,
|
||||||
private val overviewPersistence: OverviewPersistence,
|
private val overviewPersistence: OverviewPersistence,
|
||||||
private val coroutineDispatchers: CoroutineDispatchers,
|
private val coroutineDispatchers: CoroutineDispatchers,
|
||||||
) : RoomStore {
|
private val muteableStore: MutedStorePersistence,
|
||||||
|
) : RoomStore, MuteableStore by muteableStore {
|
||||||
|
|
||||||
override suspend fun persist(roomId: RoomId, events: List<RoomEvent>) {
|
override suspend fun persist(roomId: RoomId, events: List<RoomEvent>) {
|
||||||
coroutineDispatchers.withIoContext {
|
coroutineDispatchers.withIoContext {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||||
import app.dapk.st.engine.ChatEngine
|
import app.dapk.st.engine.ChatEngine
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
import app.dapk.st.messenger.state.MessengerState
|
import app.dapk.st.messenger.state.MessengerState
|
||||||
import app.dapk.st.domain.room.MutedRoomsStore
|
|
||||||
import app.dapk.st.messenger.state.messengerReducer
|
import app.dapk.st.messenger.state.messengerReducer
|
||||||
|
|
||||||
class MessengerModule(
|
class MessengerModule(
|
||||||
|
@ -18,7 +17,6 @@ class MessengerModule(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val messageOptionsStore: MessageOptionsStore,
|
private val messageOptionsStore: MessageOptionsStore,
|
||||||
private val deviceMeta: DeviceMeta,
|
private val deviceMeta: DeviceMeta,
|
||||||
private val mutedRoomsStore: MutedRoomsStore,
|
|
||||||
) : ProvidableModule {
|
) : ProvidableModule {
|
||||||
|
|
||||||
internal fun messengerState(launchPayload: MessagerActivityPayload): MessengerState {
|
internal fun messengerState(launchPayload: MessagerActivityPayload): MessengerState {
|
||||||
|
@ -29,7 +27,6 @@ class MessengerModule(
|
||||||
CopyToClipboard(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager),
|
CopyToClipboard(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager),
|
||||||
deviceMeta,
|
deviceMeta,
|
||||||
messageOptionsStore,
|
messageOptionsStore,
|
||||||
mutedRoomsStore,
|
|
||||||
RoomId(launchPayload.roomId),
|
RoomId(launchPayload.roomId),
|
||||||
launchPayload.attachments,
|
launchPayload.attachments,
|
||||||
it
|
it
|
||||||
|
|
|
@ -87,16 +87,19 @@ internal fun MessengerScreen(
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Toolbar(onNavigate = { navigator.navigate.upToHome() }, roomTitle, actions = {
|
Toolbar(onNavigate = { navigator.navigate.upToHome() }, roomTitle, actions = {
|
||||||
OverflowMenu {
|
state.roomState.takeIfContent()?.let {
|
||||||
when (state.isMuted) {
|
OverflowMenu {
|
||||||
true -> DropdownMenuItem(text = { Text("Unmute notifications", color = MaterialTheme.colorScheme.onSecondaryContainer) }, onClick = {
|
when (it.isMuted) {
|
||||||
viewModel.dispatch(ScreenAction.Notifications.Unmute)
|
true -> DropdownMenuItem(text = { Text("Unmute notifications", color = MaterialTheme.colorScheme.onSecondaryContainer) }, onClick = {
|
||||||
})
|
viewModel.dispatch(ScreenAction.Notifications.Unmute)
|
||||||
|
})
|
||||||
|
|
||||||
false -> DropdownMenuItem(text = { Text("Mute notifications", color = MaterialTheme.colorScheme.onSecondaryContainer) }, onClick = {
|
false -> DropdownMenuItem(text = { Text("Mute notifications", color = MaterialTheme.colorScheme.onSecondaryContainer) }, onClick = {
|
||||||
viewModel.dispatch(ScreenAction.Notifications.Mute)
|
viewModel.dispatch(ScreenAction.Notifications.Mute)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import app.dapk.st.core.asString
|
||||||
import app.dapk.st.core.extensions.takeIfContent
|
import app.dapk.st.core.extensions.takeIfContent
|
||||||
import app.dapk.st.design.components.BubbleModel
|
import app.dapk.st.design.components.BubbleModel
|
||||||
import app.dapk.st.domain.application.message.MessageOptionsStore
|
import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||||
import app.dapk.st.domain.room.MutedRoomsStore
|
|
||||||
import app.dapk.st.engine.ChatEngine
|
import app.dapk.st.engine.ChatEngine
|
||||||
import app.dapk.st.engine.MessengerPageState
|
import app.dapk.st.engine.MessengerPageState
|
||||||
import app.dapk.st.engine.RoomEvent
|
import app.dapk.st.engine.RoomEvent
|
||||||
|
@ -27,7 +26,6 @@ internal fun messengerReducer(
|
||||||
copyToClipboard: CopyToClipboard,
|
copyToClipboard: CopyToClipboard,
|
||||||
deviceMeta: DeviceMeta,
|
deviceMeta: DeviceMeta,
|
||||||
messageOptionsStore: MessageOptionsStore,
|
messageOptionsStore: MessageOptionsStore,
|
||||||
mutedRoomsStore: MutedRoomsStore,
|
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
initialAttachments: List<MessageAttachment>?,
|
initialAttachments: List<MessageAttachment>?,
|
||||||
eventEmitter: suspend (MessengerEvent) -> Unit,
|
eventEmitter: suspend (MessengerEvent) -> Unit,
|
||||||
|
@ -38,7 +36,6 @@ internal fun messengerReducer(
|
||||||
roomState = Lce.Loading(),
|
roomState = Lce.Loading(),
|
||||||
composerState = initialComposerState(initialAttachments),
|
composerState = initialComposerState(initialAttachments),
|
||||||
viewerState = null,
|
viewerState = null,
|
||||||
isMuted = false,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
async(ComponentLifecycle::class) { action ->
|
async(ComponentLifecycle::class) { action ->
|
||||||
|
@ -50,7 +47,6 @@ internal fun messengerReducer(
|
||||||
.onEach { dispatch(MessagesStateChange.Content(it)) }
|
.onEach { dispatch(MessagesStateChange.Content(it)) }
|
||||||
.launchIn(coroutineScope)
|
.launchIn(coroutineScope)
|
||||||
)
|
)
|
||||||
dispatch(MessagesStateChange.MuteContent(mutedRoomsStore.isMuted(roomId)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentLifecycle.Gone -> jobBag.cancel("messages")
|
ComponentLifecycle.Gone -> jobBag.cancel("messages")
|
||||||
|
@ -141,15 +137,17 @@ internal fun messengerReducer(
|
||||||
},
|
},
|
||||||
|
|
||||||
change(MessagesStateChange.MuteContent::class) { action, state ->
|
change(MessagesStateChange.MuteContent::class) { action, state ->
|
||||||
state.copy(isMuted = action.isMuted).also {
|
when (val roomState = state.roomState) {
|
||||||
println("??? action - $action previous state: ${state.isMuted} next: ${it.isMuted}")
|
is Lce.Content -> state.copy(roomState = roomState.copy(value = roomState.value.copy(isMuted = action.isMuted)))
|
||||||
|
is Lce.Error -> state
|
||||||
|
is Lce.Loading -> state
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async(ScreenAction.Notifications::class) { action ->
|
async(ScreenAction.Notifications::class) { action ->
|
||||||
when (action) {
|
when (action) {
|
||||||
ScreenAction.Notifications.Mute -> mutedRoomsStore.mute(roomId)
|
ScreenAction.Notifications.Mute -> chatEngine.muteRoom(roomId)
|
||||||
ScreenAction.Notifications.Unmute -> mutedRoomsStore.unmute(roomId)
|
ScreenAction.Notifications.Unmute -> chatEngine.unmuteRoom(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
|
|
|
@ -15,7 +15,6 @@ data class MessengerScreenState(
|
||||||
val roomState: Lce<MessengerPageState>,
|
val roomState: Lce<MessengerPageState>,
|
||||||
val composerState: ComposerState,
|
val composerState: ComposerState,
|
||||||
val viewerState: ViewerState?,
|
val viewerState: ViewerState?,
|
||||||
val isMuted: Boolean,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ViewerState(
|
data class ViewerState(
|
||||||
|
|
|
@ -3,30 +3,28 @@ package app.dapk.st.engine
|
||||||
import app.dapk.st.core.Base64
|
import app.dapk.st.core.Base64
|
||||||
import app.dapk.st.core.BuildMeta
|
import app.dapk.st.core.BuildMeta
|
||||||
import app.dapk.st.core.CoroutineDispatchers
|
import app.dapk.st.core.CoroutineDispatchers
|
||||||
import app.dapk.st.core.SingletonFlows
|
|
||||||
import app.dapk.st.core.extensions.ErrorTracker
|
import app.dapk.st.core.extensions.ErrorTracker
|
||||||
import app.dapk.st.matrix.MatrixClient
|
import app.dapk.st.matrix.MatrixClient
|
||||||
import app.dapk.st.matrix.MatrixTaskRunner
|
import app.dapk.st.matrix.MatrixTaskRunner
|
||||||
import app.dapk.st.matrix.auth.DeviceDisplayNameGenerator
|
import app.dapk.st.matrix.auth.DeviceDisplayNameGenerator
|
||||||
import app.dapk.st.matrix.auth.authService
|
import app.dapk.st.matrix.auth.authService
|
||||||
import app.dapk.st.matrix.auth.installAuthService
|
import app.dapk.st.matrix.common.CredentialsStore
|
||||||
import app.dapk.st.matrix.common.*
|
import app.dapk.st.matrix.common.MatrixLogger
|
||||||
import app.dapk.st.matrix.crypto.*
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
import app.dapk.st.matrix.crypto.MatrixMediaDecrypter
|
||||||
|
import app.dapk.st.matrix.crypto.cryptoService
|
||||||
import app.dapk.st.matrix.device.KnownDeviceStore
|
import app.dapk.st.matrix.device.KnownDeviceStore
|
||||||
import app.dapk.st.matrix.device.deviceService
|
import app.dapk.st.matrix.message.BackgroundScheduler
|
||||||
import app.dapk.st.matrix.device.installEncryptionService
|
import app.dapk.st.matrix.message.LocalEchoStore
|
||||||
import app.dapk.st.matrix.http.ktor.KtorMatrixHttpClientFactory
|
|
||||||
import app.dapk.st.matrix.message.*
|
|
||||||
import app.dapk.st.matrix.message.internal.ImageContentReader
|
import app.dapk.st.matrix.message.internal.ImageContentReader
|
||||||
import app.dapk.st.matrix.push.installPushService
|
import app.dapk.st.matrix.message.messageService
|
||||||
import app.dapk.st.matrix.push.pushService
|
import app.dapk.st.matrix.push.pushService
|
||||||
import app.dapk.st.matrix.room.*
|
import app.dapk.st.matrix.room.MemberStore
|
||||||
|
import app.dapk.st.matrix.room.ProfileStore
|
||||||
|
import app.dapk.st.matrix.room.profileService
|
||||||
|
import app.dapk.st.matrix.room.roomService
|
||||||
import app.dapk.st.matrix.sync.*
|
import app.dapk.st.matrix.sync.*
|
||||||
import app.dapk.st.matrix.sync.internal.request.ApiToDeviceEvent
|
|
||||||
import app.dapk.st.matrix.sync.internal.room.MessageDecrypter
|
|
||||||
import app.dapk.st.olm.DeviceKeyFactory
|
|
||||||
import app.dapk.st.olm.OlmStore
|
import app.dapk.st.olm.OlmStore
|
||||||
import app.dapk.st.olm.OlmWrapper
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
@ -114,6 +112,10 @@ class MatrixEngine internal constructor(
|
||||||
|
|
||||||
override fun pushHandler() = matrixPushHandler.value
|
override fun pushHandler() = matrixPushHandler.value
|
||||||
|
|
||||||
|
override suspend fun muteRoom(roomId: RoomId) = matrix.value.roomService().muteRoom(roomId)
|
||||||
|
|
||||||
|
override suspend fun unmuteRoom(roomId: RoomId) = matrix.value.roomService().unmuteRoom(roomId)
|
||||||
|
|
||||||
override suspend fun runTask(task: ChatEngineTask): TaskRunner.TaskResult {
|
override suspend fun runTask(task: ChatEngineTask): TaskRunner.TaskResult {
|
||||||
return when (val result = matrix.value.run(MatrixTaskRunner.MatrixTask(task.type, task.jsonPayload))) {
|
return when (val result = matrix.value.run(MatrixTaskRunner.MatrixTask(task.type, task.jsonPayload))) {
|
||||||
is MatrixTaskRunner.TaskResult.Failure -> TaskRunner.TaskResult.Failure(result.canRetry)
|
is MatrixTaskRunner.TaskResult.Failure -> TaskRunner.TaskResult.Failure(result.canRetry)
|
||||||
|
@ -209,222 +211,4 @@ class MatrixEngine internal constructor(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T> unsafeLazy(initializer: () -> T): Lazy<T> = lazy(mode = LazyThreadSafetyMode.NONE, initializer = initializer)
|
||||||
object MatrixFactory {
|
|
||||||
|
|
||||||
fun createMatrix(
|
|
||||||
base64: Base64,
|
|
||||||
buildMeta: BuildMeta,
|
|
||||||
logger: MatrixLogger,
|
|
||||||
nameGenerator: DeviceDisplayNameGenerator,
|
|
||||||
coroutineDispatchers: CoroutineDispatchers,
|
|
||||||
errorTracker: ErrorTracker,
|
|
||||||
imageContentReader: ImageContentReader,
|
|
||||||
backgroundScheduler: BackgroundScheduler,
|
|
||||||
memberStore: MemberStore,
|
|
||||||
roomStore: RoomStore,
|
|
||||||
profileStore: ProfileStore,
|
|
||||||
syncStore: SyncStore,
|
|
||||||
overviewStore: OverviewStore,
|
|
||||||
filterStore: FilterStore,
|
|
||||||
localEchoStore: LocalEchoStore,
|
|
||||||
credentialsStore: CredentialsStore,
|
|
||||||
knownDeviceStore: KnownDeviceStore,
|
|
||||||
olmStore: OlmStore,
|
|
||||||
) = MatrixClient(
|
|
||||||
KtorMatrixHttpClientFactory(
|
|
||||||
credentialsStore,
|
|
||||||
includeLogging = buildMeta.isDebug,
|
|
||||||
),
|
|
||||||
logger
|
|
||||||
).also {
|
|
||||||
it.install {
|
|
||||||
installAuthService(credentialsStore, nameGenerator)
|
|
||||||
installEncryptionService(knownDeviceStore)
|
|
||||||
|
|
||||||
val singletonFlows = SingletonFlows(coroutineDispatchers)
|
|
||||||
val olm = OlmWrapper(
|
|
||||||
olmStore = olmStore,
|
|
||||||
singletonFlows = singletonFlows,
|
|
||||||
jsonCanonicalizer = JsonCanonicalizer(),
|
|
||||||
deviceKeyFactory = DeviceKeyFactory(JsonCanonicalizer()),
|
|
||||||
errorTracker = errorTracker,
|
|
||||||
logger = logger,
|
|
||||||
clock = Clock.systemUTC(),
|
|
||||||
coroutineDispatchers = coroutineDispatchers,
|
|
||||||
)
|
|
||||||
installCryptoService(
|
|
||||||
credentialsStore,
|
|
||||||
olm,
|
|
||||||
roomMembersProvider = { services ->
|
|
||||||
RoomMembersProvider {
|
|
||||||
services.roomService().joinedMembers(it).map { it.userId }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
base64 = base64,
|
|
||||||
coroutineDispatchers = coroutineDispatchers,
|
|
||||||
)
|
|
||||||
installMessageService(
|
|
||||||
localEchoStore,
|
|
||||||
backgroundScheduler,
|
|
||||||
imageContentReader,
|
|
||||||
messageEncrypter = {
|
|
||||||
val cryptoService = it.cryptoService()
|
|
||||||
MessageEncrypter { message ->
|
|
||||||
val result = cryptoService.encrypt(
|
|
||||||
roomId = message.roomId,
|
|
||||||
credentials = credentialsStore.credentials()!!,
|
|
||||||
messageJson = message.contents,
|
|
||||||
)
|
|
||||||
|
|
||||||
MessageEncrypter.EncryptedMessagePayload(
|
|
||||||
result.algorithmName,
|
|
||||||
result.senderKey,
|
|
||||||
result.cipherText,
|
|
||||||
result.sessionId,
|
|
||||||
result.deviceId,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mediaEncrypter = {
|
|
||||||
val cryptoService = it.cryptoService()
|
|
||||||
MediaEncrypter { input ->
|
|
||||||
val result = cryptoService.encrypt(input)
|
|
||||||
MediaEncrypter.Result(
|
|
||||||
uri = result.uri,
|
|
||||||
contentLength = result.contentLength,
|
|
||||||
algorithm = result.algorithm,
|
|
||||||
ext = result.ext,
|
|
||||||
keyOperations = result.keyOperations,
|
|
||||||
kty = result.kty,
|
|
||||||
k = result.k,
|
|
||||||
iv = result.iv,
|
|
||||||
hashes = result.hashes,
|
|
||||||
v = result.v,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
installRoomService(
|
|
||||||
memberStore,
|
|
||||||
roomMessenger = {
|
|
||||||
val messageService = it.messageService()
|
|
||||||
object : RoomMessenger {
|
|
||||||
override suspend fun enableEncryption(roomId: RoomId) {
|
|
||||||
messageService.sendEventMessage(
|
|
||||||
roomId, MessageService.EventMessage.Encryption(
|
|
||||||
algorithm = AlgorithmName("m.megolm.v1.aes-sha2")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
roomInviteRemover = {
|
|
||||||
overviewStore.removeInvites(listOf(it))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
installProfileService(profileStore, singletonFlows, credentialsStore)
|
|
||||||
|
|
||||||
installSyncService(
|
|
||||||
credentialsStore,
|
|
||||||
overviewStore,
|
|
||||||
roomStore,
|
|
||||||
syncStore,
|
|
||||||
filterStore,
|
|
||||||
deviceNotifier = { services ->
|
|
||||||
val encryption = services.deviceService()
|
|
||||||
val crypto = services.cryptoService()
|
|
||||||
DeviceNotifier { userIds, syncToken ->
|
|
||||||
encryption.updateStaleDevices(userIds)
|
|
||||||
crypto.updateOlmSession(userIds, syncToken)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
messageDecrypter = { serviceProvider ->
|
|
||||||
val cryptoService = serviceProvider.cryptoService()
|
|
||||||
MessageDecrypter {
|
|
||||||
cryptoService.decrypt(it)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
keySharer = { serviceProvider ->
|
|
||||||
val cryptoService = serviceProvider.cryptoService()
|
|
||||||
KeySharer { sharedRoomKeys ->
|
|
||||||
cryptoService.importRoomKeys(sharedRoomKeys)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
verificationHandler = { services ->
|
|
||||||
val cryptoService = services.cryptoService()
|
|
||||||
VerificationHandler { apiEvent ->
|
|
||||||
logger.matrixLog(MatrixLogTag.VERIFICATION, "got a verification request $it")
|
|
||||||
cryptoService.onVerificationEvent(
|
|
||||||
when (apiEvent) {
|
|
||||||
is ApiToDeviceEvent.VerificationRequest -> Verification.Event.Requested(
|
|
||||||
apiEvent.sender,
|
|
||||||
apiEvent.content.fromDevice,
|
|
||||||
apiEvent.content.transactionId,
|
|
||||||
apiEvent.content.methods,
|
|
||||||
apiEvent.content.timestampPosix,
|
|
||||||
)
|
|
||||||
|
|
||||||
is ApiToDeviceEvent.VerificationReady -> Verification.Event.Ready(
|
|
||||||
apiEvent.sender,
|
|
||||||
apiEvent.content.fromDevice,
|
|
||||||
apiEvent.content.transactionId,
|
|
||||||
apiEvent.content.methods,
|
|
||||||
)
|
|
||||||
|
|
||||||
is ApiToDeviceEvent.VerificationStart -> Verification.Event.Started(
|
|
||||||
apiEvent.sender,
|
|
||||||
apiEvent.content.fromDevice,
|
|
||||||
apiEvent.content.method,
|
|
||||||
apiEvent.content.protocols,
|
|
||||||
apiEvent.content.hashes,
|
|
||||||
apiEvent.content.codes,
|
|
||||||
apiEvent.content.short,
|
|
||||||
apiEvent.content.transactionId,
|
|
||||||
)
|
|
||||||
|
|
||||||
is ApiToDeviceEvent.VerificationCancel -> TODO()
|
|
||||||
is ApiToDeviceEvent.VerificationAccept -> TODO()
|
|
||||||
is ApiToDeviceEvent.VerificationKey -> Verification.Event.Key(
|
|
||||||
apiEvent.sender,
|
|
||||||
apiEvent.content.transactionId,
|
|
||||||
apiEvent.content.key
|
|
||||||
)
|
|
||||||
|
|
||||||
is ApiToDeviceEvent.VerificationMac -> Verification.Event.Mac(
|
|
||||||
apiEvent.sender,
|
|
||||||
apiEvent.content.transactionId,
|
|
||||||
apiEvent.content.keys,
|
|
||||||
apiEvent.content.mac,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
oneTimeKeyProducer = { services ->
|
|
||||||
val cryptoService = services.cryptoService()
|
|
||||||
MaybeCreateMoreKeys {
|
|
||||||
cryptoService.maybeCreateMoreKeys(it)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
roomMembersService = { services ->
|
|
||||||
val roomService = services.roomService()
|
|
||||||
object : RoomMembersService {
|
|
||||||
override suspend fun find(roomId: RoomId, userIds: List<UserId>) = roomService.findMembers(roomId, userIds)
|
|
||||||
override suspend fun findSummary(roomId: RoomId) = roomService.findMembersSummary(roomId)
|
|
||||||
override suspend fun insert(roomId: RoomId, members: List<RoomMember>) = roomService.insertMembers(roomId, members)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
errorTracker = errorTracker,
|
|
||||||
coroutineDispatchers = coroutineDispatchers,
|
|
||||||
)
|
|
||||||
|
|
||||||
installPushService(credentialsStore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> unsafeLazy(initializer: () -> T): Lazy<T> = lazy(mode = LazyThreadSafetyMode.NONE, initializer = initializer)
|
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
package app.dapk.st.engine
|
||||||
|
|
||||||
|
import app.dapk.st.core.Base64
|
||||||
|
import app.dapk.st.core.BuildMeta
|
||||||
|
import app.dapk.st.core.CoroutineDispatchers
|
||||||
|
import app.dapk.st.core.SingletonFlows
|
||||||
|
import app.dapk.st.core.extensions.ErrorTracker
|
||||||
|
import app.dapk.st.matrix.MatrixClient
|
||||||
|
import app.dapk.st.matrix.auth.DeviceDisplayNameGenerator
|
||||||
|
import app.dapk.st.matrix.auth.installAuthService
|
||||||
|
import app.dapk.st.matrix.common.*
|
||||||
|
import app.dapk.st.matrix.crypto.RoomMembersProvider
|
||||||
|
import app.dapk.st.matrix.crypto.Verification
|
||||||
|
import app.dapk.st.matrix.crypto.cryptoService
|
||||||
|
import app.dapk.st.matrix.crypto.installCryptoService
|
||||||
|
import app.dapk.st.matrix.device.KnownDeviceStore
|
||||||
|
import app.dapk.st.matrix.device.deviceService
|
||||||
|
import app.dapk.st.matrix.device.installEncryptionService
|
||||||
|
import app.dapk.st.matrix.http.ktor.KtorMatrixHttpClientFactory
|
||||||
|
import app.dapk.st.matrix.message.*
|
||||||
|
import app.dapk.st.matrix.message.internal.ImageContentReader
|
||||||
|
import app.dapk.st.matrix.push.installPushService
|
||||||
|
import app.dapk.st.matrix.room.*
|
||||||
|
import app.dapk.st.matrix.room.internal.SingleRoomStore
|
||||||
|
import app.dapk.st.matrix.sync.*
|
||||||
|
import app.dapk.st.matrix.sync.internal.request.ApiToDeviceEvent
|
||||||
|
import app.dapk.st.matrix.sync.internal.room.MessageDecrypter
|
||||||
|
import app.dapk.st.olm.DeviceKeyFactory
|
||||||
|
import app.dapk.st.olm.OlmStore
|
||||||
|
import app.dapk.st.olm.OlmWrapper
|
||||||
|
import java.time.Clock
|
||||||
|
|
||||||
|
internal object MatrixFactory {
|
||||||
|
|
||||||
|
fun createMatrix(
|
||||||
|
base64: Base64,
|
||||||
|
buildMeta: BuildMeta,
|
||||||
|
logger: MatrixLogger,
|
||||||
|
nameGenerator: DeviceDisplayNameGenerator,
|
||||||
|
coroutineDispatchers: CoroutineDispatchers,
|
||||||
|
errorTracker: ErrorTracker,
|
||||||
|
imageContentReader: ImageContentReader,
|
||||||
|
backgroundScheduler: BackgroundScheduler,
|
||||||
|
memberStore: MemberStore,
|
||||||
|
roomStore: RoomStore,
|
||||||
|
profileStore: ProfileStore,
|
||||||
|
syncStore: SyncStore,
|
||||||
|
overviewStore: OverviewStore,
|
||||||
|
filterStore: FilterStore,
|
||||||
|
localEchoStore: LocalEchoStore,
|
||||||
|
credentialsStore: CredentialsStore,
|
||||||
|
knownDeviceStore: KnownDeviceStore,
|
||||||
|
olmStore: OlmStore,
|
||||||
|
) = MatrixClient(
|
||||||
|
KtorMatrixHttpClientFactory(
|
||||||
|
credentialsStore,
|
||||||
|
includeLogging = buildMeta.isDebug,
|
||||||
|
),
|
||||||
|
logger
|
||||||
|
).also {
|
||||||
|
it.install {
|
||||||
|
installAuthService(credentialsStore, nameGenerator)
|
||||||
|
installEncryptionService(knownDeviceStore)
|
||||||
|
|
||||||
|
val singletonFlows = SingletonFlows(coroutineDispatchers)
|
||||||
|
val olm = OlmWrapper(
|
||||||
|
olmStore = olmStore,
|
||||||
|
singletonFlows = singletonFlows,
|
||||||
|
jsonCanonicalizer = JsonCanonicalizer(),
|
||||||
|
deviceKeyFactory = DeviceKeyFactory(JsonCanonicalizer()),
|
||||||
|
errorTracker = errorTracker,
|
||||||
|
logger = logger,
|
||||||
|
clock = Clock.systemUTC(),
|
||||||
|
coroutineDispatchers = coroutineDispatchers,
|
||||||
|
)
|
||||||
|
installCryptoService(
|
||||||
|
credentialsStore,
|
||||||
|
olm,
|
||||||
|
roomMembersProvider = { services ->
|
||||||
|
RoomMembersProvider {
|
||||||
|
services.roomService().joinedMembers(it).map { it.userId }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
base64 = base64,
|
||||||
|
coroutineDispatchers = coroutineDispatchers,
|
||||||
|
)
|
||||||
|
installMessageService(
|
||||||
|
localEchoStore,
|
||||||
|
backgroundScheduler,
|
||||||
|
imageContentReader,
|
||||||
|
messageEncrypter = {
|
||||||
|
val cryptoService = it.cryptoService()
|
||||||
|
MessageEncrypter { message ->
|
||||||
|
val result = cryptoService.encrypt(
|
||||||
|
roomId = message.roomId,
|
||||||
|
credentials = credentialsStore.credentials()!!,
|
||||||
|
messageJson = message.contents,
|
||||||
|
)
|
||||||
|
|
||||||
|
MessageEncrypter.EncryptedMessagePayload(
|
||||||
|
result.algorithmName,
|
||||||
|
result.senderKey,
|
||||||
|
result.cipherText,
|
||||||
|
result.sessionId,
|
||||||
|
result.deviceId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mediaEncrypter = {
|
||||||
|
val cryptoService = it.cryptoService()
|
||||||
|
MediaEncrypter { input ->
|
||||||
|
val result = cryptoService.encrypt(input)
|
||||||
|
MediaEncrypter.Result(
|
||||||
|
uri = result.uri,
|
||||||
|
contentLength = result.contentLength,
|
||||||
|
algorithm = result.algorithm,
|
||||||
|
ext = result.ext,
|
||||||
|
keyOperations = result.keyOperations,
|
||||||
|
kty = result.kty,
|
||||||
|
k = result.k,
|
||||||
|
iv = result.iv,
|
||||||
|
hashes = result.hashes,
|
||||||
|
v = result.v,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
installRoomService(
|
||||||
|
memberStore,
|
||||||
|
roomMessenger = {
|
||||||
|
val messageService = it.messageService()
|
||||||
|
object : RoomMessenger {
|
||||||
|
override suspend fun enableEncryption(roomId: RoomId) {
|
||||||
|
messageService.sendEventMessage(
|
||||||
|
roomId, MessageService.EventMessage.Encryption(
|
||||||
|
algorithm = AlgorithmName("m.megolm.v1.aes-sha2")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
roomInviteRemover = {
|
||||||
|
overviewStore.removeInvites(listOf(it))
|
||||||
|
},
|
||||||
|
singleRoomStore = object : SingleRoomStore {
|
||||||
|
override suspend fun mute(roomId: RoomId) = roomStore.mute(roomId)
|
||||||
|
override suspend fun unmute(roomId: RoomId) = roomStore.unmute(roomId)
|
||||||
|
override suspend fun isMuted(roomId: RoomId) = roomStore.isMuted(roomId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
installProfileService(profileStore, singletonFlows, credentialsStore)
|
||||||
|
|
||||||
|
installSyncService(
|
||||||
|
credentialsStore,
|
||||||
|
overviewStore,
|
||||||
|
roomStore,
|
||||||
|
syncStore,
|
||||||
|
filterStore,
|
||||||
|
deviceNotifier = { services ->
|
||||||
|
val encryption = services.deviceService()
|
||||||
|
val crypto = services.cryptoService()
|
||||||
|
DeviceNotifier { userIds, syncToken ->
|
||||||
|
encryption.updateStaleDevices(userIds)
|
||||||
|
crypto.updateOlmSession(userIds, syncToken)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
messageDecrypter = { serviceProvider ->
|
||||||
|
val cryptoService = serviceProvider.cryptoService()
|
||||||
|
MessageDecrypter {
|
||||||
|
cryptoService.decrypt(it)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keySharer = { serviceProvider ->
|
||||||
|
val cryptoService = serviceProvider.cryptoService()
|
||||||
|
KeySharer { sharedRoomKeys ->
|
||||||
|
cryptoService.importRoomKeys(sharedRoomKeys)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verificationHandler = { services ->
|
||||||
|
val cryptoService = services.cryptoService()
|
||||||
|
VerificationHandler { apiEvent ->
|
||||||
|
logger.matrixLog(MatrixLogTag.VERIFICATION, "got a verification request $it")
|
||||||
|
cryptoService.onVerificationEvent(
|
||||||
|
when (apiEvent) {
|
||||||
|
is ApiToDeviceEvent.VerificationRequest -> Verification.Event.Requested(
|
||||||
|
apiEvent.sender,
|
||||||
|
apiEvent.content.fromDevice,
|
||||||
|
apiEvent.content.transactionId,
|
||||||
|
apiEvent.content.methods,
|
||||||
|
apiEvent.content.timestampPosix,
|
||||||
|
)
|
||||||
|
|
||||||
|
is ApiToDeviceEvent.VerificationReady -> Verification.Event.Ready(
|
||||||
|
apiEvent.sender,
|
||||||
|
apiEvent.content.fromDevice,
|
||||||
|
apiEvent.content.transactionId,
|
||||||
|
apiEvent.content.methods,
|
||||||
|
)
|
||||||
|
|
||||||
|
is ApiToDeviceEvent.VerificationStart -> Verification.Event.Started(
|
||||||
|
apiEvent.sender,
|
||||||
|
apiEvent.content.fromDevice,
|
||||||
|
apiEvent.content.method,
|
||||||
|
apiEvent.content.protocols,
|
||||||
|
apiEvent.content.hashes,
|
||||||
|
apiEvent.content.codes,
|
||||||
|
apiEvent.content.short,
|
||||||
|
apiEvent.content.transactionId,
|
||||||
|
)
|
||||||
|
|
||||||
|
is ApiToDeviceEvent.VerificationCancel -> TODO()
|
||||||
|
is ApiToDeviceEvent.VerificationAccept -> TODO()
|
||||||
|
is ApiToDeviceEvent.VerificationKey -> Verification.Event.Key(
|
||||||
|
apiEvent.sender,
|
||||||
|
apiEvent.content.transactionId,
|
||||||
|
apiEvent.content.key
|
||||||
|
)
|
||||||
|
|
||||||
|
is ApiToDeviceEvent.VerificationMac -> Verification.Event.Mac(
|
||||||
|
apiEvent.sender,
|
||||||
|
apiEvent.content.transactionId,
|
||||||
|
apiEvent.content.keys,
|
||||||
|
apiEvent.content.mac,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
oneTimeKeyProducer = { services ->
|
||||||
|
val cryptoService = services.cryptoService()
|
||||||
|
MaybeCreateMoreKeys {
|
||||||
|
cryptoService.maybeCreateMoreKeys(it)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
roomMembersService = { services ->
|
||||||
|
val roomService = services.roomService()
|
||||||
|
object : RoomMembersService {
|
||||||
|
override suspend fun find(roomId: RoomId, userIds: List<UserId>) = roomService.findMembers(roomId, userIds)
|
||||||
|
override suspend fun findSummary(roomId: RoomId) = roomService.findMembersSummary(roomId)
|
||||||
|
override suspend fun insert(roomId: RoomId, members: List<RoomMember>) = roomService.insertMembers(roomId, members)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorTracker = errorTracker,
|
||||||
|
coroutineDispatchers = coroutineDispatchers,
|
||||||
|
)
|
||||||
|
|
||||||
|
installPushService(credentialsStore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ internal class TimelineUseCaseImpl(
|
||||||
},
|
},
|
||||||
typing = events.filterIsInstance<SyncService.SyncEvent.Typing>().firstOrNull { it.roomId == roomId }?.engine(),
|
typing = events.filterIsInstance<SyncService.SyncEvent.Typing>().firstOrNull { it.roomId == roomId }?.engine(),
|
||||||
self = userId,
|
self = userId,
|
||||||
|
isMuted = roomService.isMuted(roomId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,7 @@ import app.dapk.st.matrix.common.EventId
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
import app.dapk.st.matrix.common.RoomMember
|
import app.dapk.st.matrix.common.RoomMember
|
||||||
import app.dapk.st.matrix.common.UserId
|
import app.dapk.st.matrix.common.UserId
|
||||||
import app.dapk.st.matrix.room.internal.DefaultRoomService
|
import app.dapk.st.matrix.room.internal.*
|
||||||
import app.dapk.st.matrix.room.internal.RoomInviteRemover
|
|
||||||
import app.dapk.st.matrix.room.internal.RoomMembers
|
|
||||||
import app.dapk.st.matrix.room.internal.RoomMembersCache
|
|
||||||
|
|
||||||
private val SERVICE_KEY = RoomService::class
|
private val SERVICE_KEY = RoomService::class
|
||||||
|
|
||||||
|
@ -27,6 +24,10 @@ interface RoomService : MatrixService {
|
||||||
suspend fun joinRoom(roomId: RoomId)
|
suspend fun joinRoom(roomId: RoomId)
|
||||||
suspend fun rejectJoinRoom(roomId: RoomId)
|
suspend fun rejectJoinRoom(roomId: RoomId)
|
||||||
|
|
||||||
|
suspend fun muteRoom(roomId: RoomId)
|
||||||
|
suspend fun unmuteRoom(roomId: RoomId)
|
||||||
|
suspend fun isMuted(roomId: RoomId): Boolean
|
||||||
|
|
||||||
data class JoinedMember(
|
data class JoinedMember(
|
||||||
val userId: UserId,
|
val userId: UserId,
|
||||||
val displayName: String?,
|
val displayName: String?,
|
||||||
|
@ -39,6 +40,7 @@ fun MatrixServiceInstaller.installRoomService(
|
||||||
memberStore: MemberStore,
|
memberStore: MemberStore,
|
||||||
roomMessenger: ServiceDepFactory<RoomMessenger>,
|
roomMessenger: ServiceDepFactory<RoomMessenger>,
|
||||||
roomInviteRemover: RoomInviteRemover,
|
roomInviteRemover: RoomInviteRemover,
|
||||||
|
singleRoomStore: SingleRoomStore,
|
||||||
): InstallExtender<RoomService> {
|
): InstallExtender<RoomService> {
|
||||||
return this.install { (httpClient, _, services, logger) ->
|
return this.install { (httpClient, _, services, logger) ->
|
||||||
SERVICE_KEY to DefaultRoomService(
|
SERVICE_KEY to DefaultRoomService(
|
||||||
|
@ -46,7 +48,8 @@ fun MatrixServiceInstaller.installRoomService(
|
||||||
logger,
|
logger,
|
||||||
RoomMembers(memberStore, RoomMembersCache()),
|
RoomMembers(memberStore, RoomMembersCache()),
|
||||||
roomMessenger.create(services),
|
roomMessenger.create(services),
|
||||||
roomInviteRemover
|
roomInviteRemover,
|
||||||
|
singleRoomStore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ class DefaultRoomService(
|
||||||
private val roomMembers: RoomMembers,
|
private val roomMembers: RoomMembers,
|
||||||
private val roomMessenger: RoomMessenger,
|
private val roomMessenger: RoomMessenger,
|
||||||
private val roomInviteRemover: RoomInviteRemover,
|
private val roomInviteRemover: RoomInviteRemover,
|
||||||
|
private val singleRoomStore: SingleRoomStore,
|
||||||
) : RoomService {
|
) : RoomService {
|
||||||
|
|
||||||
override suspend fun joinedMembers(roomId: RoomId): List<RoomService.JoinedMember> {
|
override suspend fun joinedMembers(roomId: RoomId): List<RoomService.JoinedMember> {
|
||||||
|
@ -82,6 +83,7 @@ class DefaultRoomService(
|
||||||
} else {
|
} else {
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw it
|
else -> throw it
|
||||||
|
@ -90,6 +92,22 @@ class DefaultRoomService(
|
||||||
)
|
)
|
||||||
roomInviteRemover.remove(roomId)
|
roomInviteRemover.remove(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun muteRoom(roomId: RoomId) {
|
||||||
|
singleRoomStore.mute(roomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unmuteRoom(roomId: RoomId) {
|
||||||
|
singleRoomStore.unmute(roomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun isMuted(roomId: RoomId) = singleRoomStore.isMuted(roomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SingleRoomStore {
|
||||||
|
suspend fun mute(roomId: RoomId)
|
||||||
|
suspend fun unmute(roomId: RoomId)
|
||||||
|
suspend fun isMuted(roomId: RoomId): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun joinedMembersRequest(roomId: RoomId) = httpRequest<JoinedMembersResponse>(
|
internal fun joinedMembersRequest(roomId: RoomId) = httpRequest<JoinedMembersResponse>(
|
||||||
|
|
|
@ -5,7 +5,7 @@ import app.dapk.st.matrix.common.RoomId
|
||||||
import app.dapk.st.matrix.common.SyncToken
|
import app.dapk.st.matrix.common.SyncToken
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface RoomStore {
|
interface RoomStore : MuteableStore {
|
||||||
|
|
||||||
suspend fun persist(roomId: RoomId, events: List<RoomEvent>)
|
suspend fun persist(roomId: RoomId, events: List<RoomEvent>)
|
||||||
suspend fun remove(rooms: List<RoomId>)
|
suspend fun remove(rooms: List<RoomId>)
|
||||||
|
@ -21,6 +21,14 @@ interface RoomStore {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MuteableStore {
|
||||||
|
suspend fun mute(roomId: RoomId)
|
||||||
|
suspend fun unmute(roomId: RoomId)
|
||||||
|
suspend fun isMuted(roomId: RoomId): Boolean
|
||||||
|
suspend fun allMuted(): Set<RoomId>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
interface FilterStore {
|
interface FilterStore {
|
||||||
|
|
||||||
suspend fun store(key: String, filterId: String)
|
suspend fun store(key: String, filterId: String)
|
||||||
|
|
Loading…
Reference in New Issue