porting the messenger module to chat-engine

This commit is contained in:
Adam Brown 2022-10-09 19:22:03 +01:00
parent baf7cfc17a
commit e61dea7ba7
8 changed files with 102 additions and 59 deletions

View File

@ -178,11 +178,8 @@ internal class FeatureModules internal constructor(
val messengerModule by unsafeLazy { val messengerModule by unsafeLazy {
MessengerModule( MessengerModule(
matrixModules.engine, matrixModules.engine,
matrixModules.message,
clock,
context, context,
base64, base64,
imageContentReader,
storeModule.value.messageStore(), storeModule.value.messageStore(),
) )
} }

View File

@ -20,4 +20,5 @@ interface ChatEngine {
suspend fun InputStream.importRoomKeys(password: String): Flow<ImportResult> suspend fun InputStream.importRoomKeys(password: String): Flow<ImportResult>
suspend fun send(message: SendMessage, room: RoomOverview)
} }

View File

@ -198,3 +198,24 @@ 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
}

View File

@ -3,10 +3,6 @@ apply plugin: 'kotlin-parcelize'
dependencies { dependencies {
implementation project(":chat-engine") 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:compose-core")
implementation project(":domains:android:viewmodel") implementation project(":domains:android:viewmodel")
implementation project(":domains:store") implementation project(":domains:store")

View File

@ -5,33 +5,19 @@ import app.dapk.st.core.Base64
import app.dapk.st.core.ProvidableModule import app.dapk.st.core.ProvidableModule
import app.dapk.st.domain.application.message.MessageOptionsStore 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.CredentialsStore
import app.dapk.st.matrix.common.RoomId 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( class MessengerModule(
private val chatEngine: ChatEngine, private val chatEngine: ChatEngine,
private val messageService: MessageService,
private val clock: Clock,
private val context: Context, private val context: Context,
private val base64: Base64, private val base64: Base64,
private val imageMetaReader: ImageContentReader,
private val messageOptionsStore: MessageOptionsStore, private val messageOptionsStore: MessageOptionsStore,
) : ProvidableModule { ) : ProvidableModule {
internal fun messengerViewModel(): MessengerViewModel { internal fun messengerViewModel(): MessengerViewModel {
return MessengerViewModel( return MessengerViewModel(
chatEngine, chatEngine,
messageService,
LocalIdFactory(),
imageMetaReader,
messageOptionsStore, messageOptionsStore,
clock
) )
} }

View File

@ -6,9 +6,8 @@ import app.dapk.st.core.extensions.takeIfContent
import app.dapk.st.domain.application.message.MessageOptionsStore import app.dapk.st.domain.application.message.MessageOptionsStore
import app.dapk.st.engine.ChatEngine import app.dapk.st.engine.ChatEngine
import app.dapk.st.engine.RoomEvent import app.dapk.st.engine.RoomEvent
import app.dapk.st.engine.SendMessage
import app.dapk.st.matrix.common.RoomId 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.navigator.MessageAttachment
import app.dapk.st.viewmodel.DapkViewModel import app.dapk.st.viewmodel.DapkViewModel
import app.dapk.st.viewmodel.MutableStateFactory import app.dapk.st.viewmodel.MutableStateFactory
@ -17,15 +16,10 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.Clock
internal class MessengerViewModel( internal class MessengerViewModel(
private val chatEngine: ChatEngine, private val chatEngine: ChatEngine,
private val messageService: MessageService,
private val localIdFactory: LocalIdFactory,
private val imageContentReader: ImageContentReader,
private val messageOptionsStore: MessageOptionsStore, private val messageOptionsStore: MessageOptionsStore,
private val clock: Clock,
factory: MutableStateFactory<MessengerScreenState> = defaultStateFactory(), factory: MutableStateFactory<MessengerScreenState> = defaultStateFactory(),
) : DapkViewModel<MessengerScreenState, MessengerEvent>( ) : DapkViewModel<MessengerScreenState, MessengerEvent>(
initialState = MessengerScreenState( initialState = MessengerScreenState(
@ -83,6 +77,7 @@ internal class MessengerViewModel(
} }
} }
private fun sendMessage() { private fun sendMessage() {
when (val composerState = state.composerState) { when (val composerState = state.composerState) {
is ComposerState.Text -> { is ComposerState.Text -> {
@ -92,27 +87,23 @@ internal class MessengerViewModel(
state.roomState.takeIfContent()?.let { content -> state.roomState.takeIfContent()?.let { content ->
val roomState = content.roomState val roomState = content.roomState
viewModelScope.launch { viewModelScope.launch {
messageService.scheduleMessage( chatEngine.send(
MessageService.Message.TextMessage( message = SendMessage.TextMessage(
MessageService.Message.Content.TextContent(body = copy.value), content = copy.value,
roomId = roomState.roomOverview.roomId,
sendEncrypted = roomState.roomOverview.isEncrypted,
localId = localIdFactory.create(),
timestampUtc = clock.millis(),
reply = copy.reply?.let { reply = copy.reply?.let {
MessageService.Message.TextMessage.Reply( SendMessage.TextMessage.Reply(
author = it.author, author = it.author,
originalMessage = when (it) { originalMessage = when (it) {
is RoomEvent.Image -> TODO() is RoomEvent.Image -> TODO()
is RoomEvent.Reply -> TODO() is RoomEvent.Reply -> TODO()
is RoomEvent.Message -> it.content is RoomEvent.Message -> it.content
}, },
replyContent = copy.value,
eventId = it.eventId, eventId = it.eventId,
timestampUtc = it.utcTimestamp, timestampUtc = it.utcTimestamp,
) )
} }
) ),
room = roomState.roomOverview,
) )
} }
} }
@ -125,26 +116,7 @@ internal class MessengerViewModel(
state.roomState.takeIfContent()?.let { content -> state.roomState.takeIfContent()?.let { content ->
val roomState = content.roomState val roomState = content.roomState
viewModelScope.launch { viewModelScope.launch {
val imageUri = copy.values.first().uri.value chatEngine.send(SendMessage.ImageMessage(uri = copy.values.first().uri.value), roomState.roomOverview)
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(),
)
)
} }
} }

View File

@ -37,6 +37,7 @@ class MatrixEngine internal constructor(
private val directoryUseCase: Lazy<DirectoryUseCase>, private val directoryUseCase: Lazy<DirectoryUseCase>,
private val matrix: Lazy<MatrixClient>, private val matrix: Lazy<MatrixClient>,
private val timelineUseCase: Lazy<ReadMarkingTimeline>, private val timelineUseCase: Lazy<ReadMarkingTimeline>,
private val sendMessageUseCase: Lazy<SendMessageUseCase>,
) : ChatEngine { ) : ChatEngine {
override fun directory() = directoryUseCase.value.state() 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 { class Factory {
fun create( fun create(
@ -128,7 +133,12 @@ class MatrixEngine internal constructor(
ReadMarkingTimeline(roomStore, credentialsStore, timeline, matrix.roomService()) 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)
} }

View File

@ -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,
)
}
)
}