diff --git a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt index e9f20f1..e904613 100644 --- a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt +++ b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt @@ -178,11 +178,8 @@ internal class FeatureModules internal constructor( val messengerModule by unsafeLazy { MessengerModule( matrixModules.engine, - matrixModules.message, - clock, context, base64, - imageContentReader, storeModule.value.messageStore(), ) } diff --git a/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt b/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt index 76a89aa..a47c76e 100644 --- a/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt +++ b/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt @@ -20,4 +20,5 @@ interface ChatEngine { suspend fun InputStream.importRoomKeys(password: String): Flow + suspend fun send(message: SendMessage, room: RoomOverview) } diff --git a/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt b/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt index fa975d1..dcc9b65 100644 --- a/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt +++ b/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt @@ -197,4 +197,25 @@ sealed class MessageMeta { } } } +} + +sealed interface SendMessage { + + data class TextMessage( + val content: String, + val reply: Reply? = null, + ) : SendMessage { + + data class Reply( + val author: RoomMember, + val originalMessage: String, + val eventId: EventId, + val timestampUtc: Long, + ) + } + + data class ImageMessage( + val uri: String, + ) : SendMessage + } \ No newline at end of file diff --git a/features/messenger/build.gradle b/features/messenger/build.gradle index e2a2096..13f5e1b 100644 --- a/features/messenger/build.gradle +++ b/features/messenger/build.gradle @@ -3,10 +3,6 @@ apply plugin: 'kotlin-parcelize' dependencies { implementation project(":chat-engine") - implementation project(":matrix:services:sync") - implementation project(":matrix:services:message") - implementation project(":matrix:services:crypto") - implementation project(":matrix:services:room") implementation project(":domains:android:compose-core") implementation project(":domains:android:viewmodel") implementation project(":domains:store") diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerModule.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerModule.kt index 292cfae..85b10ac 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerModule.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerModule.kt @@ -5,33 +5,19 @@ import app.dapk.st.core.Base64 import app.dapk.st.core.ProvidableModule import app.dapk.st.domain.application.message.MessageOptionsStore import app.dapk.st.engine.ChatEngine -import app.dapk.st.matrix.common.CredentialsStore import app.dapk.st.matrix.common.RoomId -import app.dapk.st.matrix.message.MessageService -import app.dapk.st.matrix.message.internal.ImageContentReader -import app.dapk.st.matrix.room.RoomService -import app.dapk.st.matrix.sync.RoomStore -import app.dapk.st.matrix.sync.SyncService -import java.time.Clock class MessengerModule( private val chatEngine: ChatEngine, - private val messageService: MessageService, - private val clock: Clock, private val context: Context, private val base64: Base64, - private val imageMetaReader: ImageContentReader, private val messageOptionsStore: MessageOptionsStore, ) : ProvidableModule { internal fun messengerViewModel(): MessengerViewModel { return MessengerViewModel( chatEngine, - messageService, - LocalIdFactory(), - imageMetaReader, messageOptionsStore, - clock ) } diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt index 03ecc8f..cb27a18 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerViewModel.kt @@ -6,9 +6,8 @@ import app.dapk.st.core.extensions.takeIfContent import app.dapk.st.domain.application.message.MessageOptionsStore import app.dapk.st.engine.ChatEngine import app.dapk.st.engine.RoomEvent +import app.dapk.st.engine.SendMessage import app.dapk.st.matrix.common.RoomId -import app.dapk.st.matrix.message.MessageService -import app.dapk.st.matrix.message.internal.ImageContentReader import app.dapk.st.navigator.MessageAttachment import app.dapk.st.viewmodel.DapkViewModel import app.dapk.st.viewmodel.MutableStateFactory @@ -17,15 +16,10 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import java.time.Clock internal class MessengerViewModel( private val chatEngine: ChatEngine, - private val messageService: MessageService, - private val localIdFactory: LocalIdFactory, - private val imageContentReader: ImageContentReader, private val messageOptionsStore: MessageOptionsStore, - private val clock: Clock, factory: MutableStateFactory = defaultStateFactory(), ) : DapkViewModel( initialState = MessengerScreenState( @@ -83,6 +77,7 @@ internal class MessengerViewModel( } } + private fun sendMessage() { when (val composerState = state.composerState) { is ComposerState.Text -> { @@ -92,27 +87,23 @@ internal class MessengerViewModel( state.roomState.takeIfContent()?.let { content -> val roomState = content.roomState viewModelScope.launch { - messageService.scheduleMessage( - MessageService.Message.TextMessage( - MessageService.Message.Content.TextContent(body = copy.value), - roomId = roomState.roomOverview.roomId, - sendEncrypted = roomState.roomOverview.isEncrypted, - localId = localIdFactory.create(), - timestampUtc = clock.millis(), + chatEngine.send( + message = SendMessage.TextMessage( + content = copy.value, reply = copy.reply?.let { - MessageService.Message.TextMessage.Reply( + SendMessage.TextMessage.Reply( author = it.author, originalMessage = when (it) { is RoomEvent.Image -> TODO() is RoomEvent.Reply -> TODO() is RoomEvent.Message -> it.content }, - replyContent = copy.value, eventId = it.eventId, timestampUtc = it.utcTimestamp, ) } - ) + ), + room = roomState.roomOverview, ) } } @@ -125,26 +116,7 @@ internal class MessengerViewModel( state.roomState.takeIfContent()?.let { content -> val roomState = content.roomState viewModelScope.launch { - val imageUri = copy.values.first().uri.value - val meta = imageContentReader.meta(imageUri) - - messageService.scheduleMessage( - MessageService.Message.ImageMessage( - MessageService.Message.Content.ImageContent( - uri = imageUri, MessageService.Message.Content.ImageContent.Meta( - height = meta.height, - width = meta.width, - size = meta.size, - fileName = meta.fileName, - mimeType = meta.mimeType, - ) - ), - roomId = roomState.roomOverview.roomId, - sendEncrypted = roomState.roomOverview.isEncrypted, - localId = localIdFactory.create(), - timestampUtc = clock.millis(), - ) - ) + chatEngine.send(SendMessage.ImageMessage(uri = copy.values.first().uri.value), roomState.roomOverview) } } diff --git a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt index b4f9e0e..6312713 100644 --- a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt @@ -37,6 +37,7 @@ class MatrixEngine internal constructor( private val directoryUseCase: Lazy, private val matrix: Lazy, private val timelineUseCase: Lazy, + private val sendMessageUseCase: Lazy, ) : ChatEngine { override fun directory() = directoryUseCase.value.state() @@ -67,6 +68,10 @@ class MatrixEngine internal constructor( } } + override suspend fun send(message: SendMessage, room: RoomOverview) { + sendMessageUseCase.value.send(message, room) + } + class Factory { fun create( @@ -128,7 +133,12 @@ class MatrixEngine internal constructor( ReadMarkingTimeline(roomStore, credentialsStore, timeline, matrix.roomService()) } - return MatrixEngine(directoryUseCase, lazyMatrix, timelineUseCase) + val sendMessageUseCase = unsafeLazy { + val matrix = lazyMatrix.value + SendMessageUseCase(matrix.messageService(), LocalIdFactory(), imageContentReader, Clock.systemUTC()) + } + + return MatrixEngine(directoryUseCase, lazyMatrix, timelineUseCase, sendMessageUseCase) } diff --git a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/SendMessageUseCase.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/SendMessageUseCase.kt new file mode 100644 index 0000000..4c4054d --- /dev/null +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/SendMessageUseCase.kt @@ -0,0 +1,60 @@ +package app.dapk.st.engine + +import app.dapk.st.matrix.message.MessageService +import app.dapk.st.matrix.message.internal.ImageContentReader +import java.time.Clock + +internal class SendMessageUseCase( + private val messageService: MessageService, + private val localIdFactory: LocalIdFactory, + private val imageContentReader: ImageContentReader, + private val clock: Clock, +) { + + suspend fun send(message: SendMessage, room: RoomOverview) { + when (message) { + is SendMessage.ImageMessage -> createImageMessage(message, room) + is SendMessage.TextMessage -> messageService.scheduleMessage(createTextMessage(message, room)) + } + } + + private suspend fun createImageMessage(message: SendMessage.ImageMessage, room: RoomOverview) { + val meta = imageContentReader.meta(message.uri) + messageService.scheduleMessage( + MessageService.Message.ImageMessage( + MessageService.Message.Content.ImageContent( + uri = message.uri, + MessageService.Message.Content.ImageContent.Meta( + height = meta.height, + width = meta.width, + size = meta.size, + fileName = meta.fileName, + mimeType = meta.mimeType, + ) + ), + roomId = room.roomId, + sendEncrypted = room.isEncrypted, + localId = localIdFactory.create(), + timestampUtc = clock.millis(), + ) + ) + } + + private fun createTextMessage(message: SendMessage.TextMessage, room: RoomOverview) = MessageService.Message.TextMessage( + content = MessageService.Message.Content.TextContent(message.content), + roomId = room.roomId, + sendEncrypted = room.isEncrypted, + localId = localIdFactory.create(), + timestampUtc = clock.millis(), + reply = message.reply?.let { + MessageService.Message.TextMessage.Reply( + author = it.author, + originalMessage = it.originalMessage, + replyContent = message.content, + eventId = it.eventId, + timestampUtc = it.timestampUtc, + ) + } + ) + +} \ No newline at end of file