moving login and home modules to the chat engine
This commit is contained in:
parent
128c2db432
commit
492d7df9ac
|
@ -25,7 +25,6 @@ import app.dapk.st.imageloader.ImageLoaderModule
|
|||
import app.dapk.st.login.LoginModule
|
||||
import app.dapk.st.matrix.MatrixClient
|
||||
import app.dapk.st.matrix.auth.DeviceDisplayNameGenerator
|
||||
import app.dapk.st.matrix.auth.authService
|
||||
import app.dapk.st.matrix.auth.installAuthService
|
||||
import app.dapk.st.matrix.common.*
|
||||
import app.dapk.st.matrix.crypto.RoomMembersProvider
|
||||
|
@ -171,9 +170,8 @@ internal class FeatureModules internal constructor(
|
|||
}
|
||||
val loginModule by unsafeLazy {
|
||||
LoginModule(
|
||||
matrixModules.auth,
|
||||
matrixModules.engine,
|
||||
domainModules.pushModule,
|
||||
matrixModules.profile,
|
||||
trackingModule.errorTracker
|
||||
)
|
||||
}
|
||||
|
@ -191,7 +189,7 @@ internal class FeatureModules internal constructor(
|
|||
storeModule.value.messageStore(),
|
||||
)
|
||||
}
|
||||
val homeModule by unsafeLazy { HomeModule(storeModule.value, matrixModules.profile, matrixModules.sync, buildMeta) }
|
||||
val homeModule by unsafeLazy { HomeModule(matrixModules.engine, storeModule.value, buildMeta) }
|
||||
val settingsModule by unsafeLazy {
|
||||
SettingsModule(
|
||||
storeModule.value,
|
||||
|
@ -473,7 +471,6 @@ internal class MatrixModules(
|
|||
}
|
||||
}
|
||||
|
||||
val auth by unsafeLazy { matrix.authService() }
|
||||
val push by unsafeLazy { matrix.pushService() }
|
||||
val sync by unsafeLazy { matrix.syncService() }
|
||||
val message by unsafeLazy { matrix.messageService() }
|
||||
|
|
|
@ -5,8 +5,4 @@ plugins {
|
|||
dependencies {
|
||||
api Dependencies.mavenCentral.kotlinCoroutinesCore
|
||||
api project(":matrix:common")
|
||||
|
||||
implementation project(":matrix:services:sync")
|
||||
implementation project(":matrix:services:message")
|
||||
implementation project(":matrix:services:room")
|
||||
}
|
|
@ -1,46 +1,14 @@
|
|||
package app.dapk.st.engine
|
||||
|
||||
import app.dapk.st.matrix.common.AvatarUrl
|
||||
import app.dapk.st.matrix.common.EventId
|
||||
import app.dapk.st.matrix.common.RoomId
|
||||
import app.dapk.st.matrix.common.RoomMember
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface ChatEngine {
|
||||
|
||||
fun directory(): Flow<DirectoryState>
|
||||
fun invites(): Flow<InviteState>
|
||||
|
||||
suspend fun login(request: LoginRequest): LoginResult
|
||||
|
||||
suspend fun me(forceRefresh: Boolean): Me
|
||||
|
||||
}
|
||||
|
||||
typealias DirectoryState = List<DirectoryItem>
|
||||
typealias OverviewState = List<RoomOverview>
|
||||
|
||||
data class DirectoryItem(
|
||||
val overview: RoomOverview,
|
||||
val unreadCount: UnreadCount,
|
||||
val typing: Typing?
|
||||
)
|
||||
|
||||
data class RoomOverview(
|
||||
val roomId: RoomId,
|
||||
val roomCreationUtc: Long,
|
||||
val roomName: String?,
|
||||
val roomAvatarUrl: AvatarUrl?,
|
||||
val lastMessage: LastMessage?,
|
||||
val isGroup: Boolean,
|
||||
val readMarker: EventId?,
|
||||
val isEncrypted: Boolean,
|
||||
) {
|
||||
|
||||
data class LastMessage(
|
||||
val content: String,
|
||||
val utcTimestamp: Long,
|
||||
val author: RoomMember,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class UnreadCount(val value: Int)
|
||||
|
||||
data class Typing(val roomId: RoomId, val members: List<RoomMember>)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package app.dapk.st.engine
|
||||
|
||||
import app.dapk.st.matrix.common.*
|
||||
|
||||
typealias DirectoryState = List<DirectoryItem>
|
||||
typealias OverviewState = List<RoomOverview>
|
||||
typealias InviteState = List<RoomInvite>
|
||||
|
||||
data class DirectoryItem(
|
||||
val overview: RoomOverview,
|
||||
val unreadCount: UnreadCount,
|
||||
val typing: Typing?
|
||||
)
|
||||
|
||||
data class RoomOverview(
|
||||
val roomId: RoomId,
|
||||
val roomCreationUtc: Long,
|
||||
val roomName: String?,
|
||||
val roomAvatarUrl: AvatarUrl?,
|
||||
val lastMessage: LastMessage?,
|
||||
val isGroup: Boolean,
|
||||
val readMarker: EventId?,
|
||||
val isEncrypted: Boolean,
|
||||
) {
|
||||
|
||||
data class LastMessage(
|
||||
val content: String,
|
||||
val utcTimestamp: Long,
|
||||
val author: RoomMember,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
data class RoomInvite(
|
||||
val from: RoomMember,
|
||||
val roomId: RoomId,
|
||||
val inviteMeta: InviteMeta,
|
||||
) {
|
||||
sealed class InviteMeta {
|
||||
object DirectMessage : InviteMeta()
|
||||
data class Room(val roomName: String? = null) : InviteMeta()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class UnreadCount(val value: Int)
|
||||
|
||||
data class Typing(val roomId: RoomId, val members: List<RoomMember>)
|
||||
|
||||
data class LoginRequest(val userName: String, val password: String, val serverUrl: String?)
|
||||
|
||||
sealed interface LoginResult {
|
||||
data class Success(val userCredentials: UserCredentials) : LoginResult
|
||||
object MissingWellKnown : LoginResult
|
||||
data class Error(val cause: Throwable) : LoginResult
|
||||
}
|
||||
|
||||
data class Me(
|
||||
val userId: UserId,
|
||||
val displayName: String?,
|
||||
val avatarUrl: AvatarUrl?,
|
||||
val homeServerUrl: HomeServerUrl,
|
||||
)
|
|
@ -1,9 +1,7 @@
|
|||
applyAndroidComposeLibraryModule(project)
|
||||
|
||||
dependencies {
|
||||
implementation project(":matrix:services:profile")
|
||||
implementation project(":matrix:services:crypto")
|
||||
implementation project(":matrix:services:sync")
|
||||
implementation project(":chat-engine")
|
||||
implementation project(":features:directory")
|
||||
implementation project(":features:login")
|
||||
implementation project(":features:settings")
|
||||
|
|
|
@ -4,31 +4,28 @@ import app.dapk.st.core.BuildMeta
|
|||
import app.dapk.st.core.ProvidableModule
|
||||
import app.dapk.st.directory.DirectoryViewModel
|
||||
import app.dapk.st.domain.StoreModule
|
||||
import app.dapk.st.engine.ChatEngine
|
||||
import app.dapk.st.login.LoginViewModel
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.matrix.sync.SyncService
|
||||
import app.dapk.st.profile.ProfileViewModel
|
||||
|
||||
class HomeModule(
|
||||
private val chatEngine: ChatEngine,
|
||||
private val storeModule: StoreModule,
|
||||
private val profileService: ProfileService,
|
||||
private val syncService: SyncService,
|
||||
private val buildMeta: BuildMeta,
|
||||
) : ProvidableModule {
|
||||
|
||||
fun homeViewModel(directory: DirectoryViewModel, login: LoginViewModel, profileViewModel: ProfileViewModel): HomeViewModel {
|
||||
return HomeViewModel(
|
||||
chatEngine,
|
||||
storeModule.credentialsStore(),
|
||||
directory,
|
||||
login,
|
||||
profileViewModel,
|
||||
profileService,
|
||||
storeModule.cacheCleaner(),
|
||||
BetaVersionUpgradeUseCase(
|
||||
storeModule.applicationStore(),
|
||||
buildMeta,
|
||||
),
|
||||
syncService,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.engine.Me
|
||||
|
||||
sealed interface HomeScreenState {
|
||||
|
||||
object Loading : HomeScreenState
|
||||
object SignedOut : HomeScreenState
|
||||
data class SignedIn(val page: Page, val me: ProfileService.Me, val invites: Int) : HomeScreenState
|
||||
data class SignedIn(val page: Page, val me: Me, val invites: Int) : HomeScreenState
|
||||
|
||||
enum class Page(val icon: ImageVector) {
|
||||
Directory(Icons.Filled.Menu),
|
||||
|
|
|
@ -3,12 +3,11 @@ package app.dapk.st.home
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import app.dapk.st.directory.DirectoryViewModel
|
||||
import app.dapk.st.domain.StoreCleaner
|
||||
import app.dapk.st.engine.ChatEngine
|
||||
import app.dapk.st.home.HomeScreenState.*
|
||||
import app.dapk.st.login.LoginViewModel
|
||||
import app.dapk.st.matrix.common.CredentialsStore
|
||||
import app.dapk.st.matrix.common.isSignedIn
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.matrix.sync.SyncService
|
||||
import app.dapk.st.profile.ProfileViewModel
|
||||
import app.dapk.st.viewmodel.DapkViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -20,14 +19,13 @@ import kotlinx.coroutines.flow.onEach
|
|||
import kotlinx.coroutines.launch
|
||||
|
||||
class HomeViewModel(
|
||||
private val chatEngine: ChatEngine,
|
||||
private val credentialsProvider: CredentialsStore,
|
||||
private val directoryViewModel: DirectoryViewModel,
|
||||
private val loginViewModel: LoginViewModel,
|
||||
private val profileViewModel: ProfileViewModel,
|
||||
private val profileService: ProfileService,
|
||||
private val cacheCleaner: StoreCleaner,
|
||||
private val betaVersionUpgradeUseCase: BetaVersionUpgradeUseCase,
|
||||
private val syncService: SyncService,
|
||||
) : DapkViewModel<HomeScreenState, HomeEvent>(
|
||||
initialState = Loading
|
||||
) {
|
||||
|
@ -56,8 +54,8 @@ class HomeViewModel(
|
|||
}
|
||||
|
||||
private suspend fun initialHomeContent(): SignedIn {
|
||||
val me = profileService.me(forceRefresh = false)
|
||||
val initialInvites = syncService.invites().first().size
|
||||
val me = chatEngine.me(forceRefresh = false)
|
||||
val initialInvites = chatEngine.invites().first().size
|
||||
return SignedIn(Page.Directory, me, invites = initialInvites)
|
||||
}
|
||||
|
||||
|
@ -70,7 +68,7 @@ class HomeViewModel(
|
|||
|
||||
private fun CoroutineScope.listenForInviteChanges() {
|
||||
listenForInvitesJob?.cancel()
|
||||
listenForInvitesJob = syncService.invites()
|
||||
listenForInvitesJob = chatEngine.invites()
|
||||
.onEach { invites ->
|
||||
when (val currentState = state) {
|
||||
is SignedIn -> updateState { currentState.copy(invites = invites.size) }
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
applyAndroidComposeLibraryModule(project)
|
||||
|
||||
dependencies {
|
||||
implementation project(":chat-engine")
|
||||
implementation project(":domains:android:compose-core")
|
||||
implementation project(":domains:android:push")
|
||||
implementation project(":domains:android:viewmodel")
|
||||
implementation project(":matrix:services:auth")
|
||||
implementation project(":matrix:services:profile")
|
||||
implementation project(":matrix:services:crypto")
|
||||
implementation project(":design-library")
|
||||
implementation project(":core")
|
||||
}
|
|
@ -2,18 +2,16 @@ package app.dapk.st.login
|
|||
|
||||
import app.dapk.st.core.ProvidableModule
|
||||
import app.dapk.st.core.extensions.ErrorTracker
|
||||
import app.dapk.st.matrix.auth.AuthService
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.engine.ChatEngine
|
||||
import app.dapk.st.push.PushModule
|
||||
|
||||
class LoginModule(
|
||||
private val authService: AuthService,
|
||||
private val chatEngine: ChatEngine,
|
||||
private val pushModule: PushModule,
|
||||
private val profileService: ProfileService,
|
||||
private val errorTracker: ErrorTracker,
|
||||
) : ProvidableModule {
|
||||
|
||||
fun loginViewModel(): LoginViewModel {
|
||||
return LoginViewModel(authService, pushModule.pushTokenRegistrar(), profileService, errorTracker)
|
||||
return LoginViewModel(chatEngine, pushModule.pushTokenRegistrar(), errorTracker)
|
||||
}
|
||||
}
|
|
@ -3,10 +3,11 @@ package app.dapk.st.login
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import app.dapk.st.core.extensions.ErrorTracker
|
||||
import app.dapk.st.core.logP
|
||||
import app.dapk.st.engine.ChatEngine
|
||||
import app.dapk.st.engine.LoginRequest
|
||||
import app.dapk.st.engine.LoginResult
|
||||
import app.dapk.st.login.LoginEvent.LoginComplete
|
||||
import app.dapk.st.login.LoginScreenState.*
|
||||
import app.dapk.st.matrix.auth.AuthService
|
||||
import app.dapk.st.matrix.room.ProfileService
|
||||
import app.dapk.st.push.PushTokenRegistrar
|
||||
import app.dapk.st.viewmodel.DapkViewModel
|
||||
import kotlinx.coroutines.async
|
||||
|
@ -14,9 +15,8 @@ import kotlinx.coroutines.awaitAll
|
|||
import kotlinx.coroutines.launch
|
||||
|
||||
class LoginViewModel(
|
||||
private val authService: AuthService,
|
||||
private val chatEngine: ChatEngine,
|
||||
private val pushTokenRegistrar: PushTokenRegistrar,
|
||||
private val profileService: ProfileService,
|
||||
private val errorTracker: ErrorTracker,
|
||||
) : DapkViewModel<LoginScreenState, LoginEvent>(
|
||||
initialState = Content(showServerUrl = false)
|
||||
|
@ -28,8 +28,8 @@ class LoginViewModel(
|
|||
state = Loading
|
||||
viewModelScope.launch {
|
||||
logP("login") {
|
||||
when (val result = authService.login(AuthService.LoginRequest(userName, password, serverUrl.takeIfNotEmpty()))) {
|
||||
is AuthService.LoginResult.Success -> {
|
||||
when (val result = chatEngine.login(LoginRequest(userName, password, serverUrl.takeIfNotEmpty()))) {
|
||||
is LoginResult.Success -> {
|
||||
runCatching {
|
||||
listOf(
|
||||
async { pushTokenRegistrar.registerCurrentToken() },
|
||||
|
@ -38,11 +38,13 @@ class LoginViewModel(
|
|||
}
|
||||
_events.tryEmit(LoginComplete)
|
||||
}
|
||||
is AuthService.LoginResult.Error -> {
|
||||
|
||||
is LoginResult.Error -> {
|
||||
errorTracker.track(result.cause)
|
||||
state = Error(result.cause)
|
||||
}
|
||||
AuthService.LoginResult.MissingWellKnown -> {
|
||||
|
||||
LoginResult.MissingWellKnown -> {
|
||||
_events.tryEmit(LoginEvent.WellKnownMissing)
|
||||
state = Content(showServerUrl = true)
|
||||
}
|
||||
|
@ -51,7 +53,7 @@ class LoginViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun preloadMe() = profileService.me(forceRefresh = false)
|
||||
private suspend fun preloadMe() = chatEngine.me(forceRefresh = false)
|
||||
|
||||
fun start() {
|
||||
val showServerUrl = previousState?.let { it is Content && it.showServerUrl } ?: false
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
package app.dapk.st.engine
|
||||
|
||||
import app.dapk.st.matrix.auth.AuthService
|
||||
import app.dapk.st.matrix.sync.InviteMeta
|
||||
import app.dapk.st.matrix.auth.AuthService.LoginRequest as MatrixLoginRequest
|
||||
import app.dapk.st.matrix.auth.AuthService.LoginResult as MatrixLoginResult
|
||||
import app.dapk.st.matrix.room.ProfileService.Me as MatrixMe
|
||||
import app.dapk.st.matrix.sync.LastMessage as MatrixLastMessage
|
||||
import app.dapk.st.matrix.sync.RoomInvite as MatrixRoomInvite
|
||||
import app.dapk.st.matrix.sync.RoomOverview as MatrixRoomOverview
|
||||
import app.dapk.st.matrix.sync.SyncService.SyncEvent.Typing as MatrixTyping
|
||||
|
||||
|
@ -24,4 +30,35 @@ fun MatrixLastMessage.engine() = RoomOverview.LastMessage(
|
|||
fun MatrixTyping.engine() = Typing(
|
||||
this.roomId,
|
||||
this.members,
|
||||
)
|
||||
)
|
||||
|
||||
fun LoginRequest.engine() = MatrixLoginRequest(
|
||||
this.userName,
|
||||
this.password,
|
||||
this.serverUrl
|
||||
)
|
||||
|
||||
fun MatrixLoginResult.engine() = when (this) {
|
||||
is AuthService.LoginResult.Error -> LoginResult.Error(this.cause)
|
||||
AuthService.LoginResult.MissingWellKnown -> LoginResult.MissingWellKnown
|
||||
is AuthService.LoginResult.Success -> LoginResult.Success(this.userCredentials)
|
||||
}
|
||||
|
||||
fun MatrixMe.engine() = Me(
|
||||
this.userId,
|
||||
this.displayName,
|
||||
this.avatarUrl,
|
||||
this.homeServerUrl,
|
||||
)
|
||||
|
||||
fun MatrixRoomInvite.engine() = RoomInvite(
|
||||
this.from,
|
||||
this.roomId,
|
||||
this.inviteMeta.engine(),
|
||||
)
|
||||
|
||||
fun InviteMeta.engine() = when (this) {
|
||||
InviteMeta.DirectMessage -> RoomInvite.InviteMeta.DirectMessage
|
||||
is InviteMeta.Room -> RoomInvite.InviteMeta.Room(this.roomName)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ 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.authService
|
||||
import app.dapk.st.matrix.auth.installAuthService
|
||||
import app.dapk.st.matrix.common.*
|
||||
import app.dapk.st.matrix.crypto.RoomMembersProvider
|
||||
|
@ -27,13 +28,27 @@ 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 kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.time.Clock
|
||||
|
||||
class MatrixEngine internal constructor(
|
||||
private val directoryUseCase: Lazy<DirectoryUseCase>,
|
||||
private val matrix: Lazy<MatrixClient>,
|
||||
) : ChatEngine {
|
||||
|
||||
override fun directory() = directoryUseCase.value.state()
|
||||
override fun invites(): Flow<InviteState> {
|
||||
return matrix.value.syncService().invites().map { it.map { it.engine() } }
|
||||
}
|
||||
|
||||
override suspend fun login(request: LoginRequest): LoginResult {
|
||||
return matrix.value.authService().login(request.engine()).engine()
|
||||
}
|
||||
|
||||
override suspend fun me(forceRefresh: Boolean): Me {
|
||||
return matrix.value.profileService().me(forceRefresh).engine()
|
||||
}
|
||||
|
||||
class Factory {
|
||||
|
||||
|
@ -57,28 +72,30 @@ class MatrixEngine internal constructor(
|
|||
knownDeviceStore: KnownDeviceStore,
|
||||
olmStore: OlmStore,
|
||||
): ChatEngine {
|
||||
val matrix = MatrixFactory.createMatrix(
|
||||
base64,
|
||||
buildMeta,
|
||||
logger,
|
||||
nameGenerator,
|
||||
coroutineDispatchers,
|
||||
errorTracker,
|
||||
imageContentReader,
|
||||
backgroundScheduler,
|
||||
memberStore,
|
||||
roomStore,
|
||||
profileStore,
|
||||
syncStore,
|
||||
overviewStore,
|
||||
filterStore,
|
||||
localEchoStore,
|
||||
credentialsStore,
|
||||
knownDeviceStore,
|
||||
olmStore
|
||||
)
|
||||
|
||||
val lazyMatrix = unsafeLazy {
|
||||
MatrixFactory.createMatrix(
|
||||
base64,
|
||||
buildMeta,
|
||||
logger,
|
||||
nameGenerator,
|
||||
coroutineDispatchers,
|
||||
errorTracker,
|
||||
imageContentReader,
|
||||
backgroundScheduler,
|
||||
memberStore,
|
||||
roomStore,
|
||||
profileStore,
|
||||
syncStore,
|
||||
overviewStore,
|
||||
filterStore,
|
||||
localEchoStore,
|
||||
credentialsStore,
|
||||
knownDeviceStore,
|
||||
olmStore
|
||||
)
|
||||
}
|
||||
val directoryUseCase = unsafeLazy {
|
||||
val matrix = lazyMatrix.value
|
||||
DirectoryUseCase(
|
||||
matrix.syncService(),
|
||||
matrix.messageService(),
|
||||
|
@ -88,7 +105,7 @@ class MatrixEngine internal constructor(
|
|||
)
|
||||
}
|
||||
|
||||
return MatrixEngine(directoryUseCase)
|
||||
return MatrixEngine(directoryUseCase, lazyMatrix)
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue