Introduce SessionComponent
This commit is contained in:
@@ -3,29 +3,33 @@ package io.element.android.x
|
||||
import android.app.Application
|
||||
import androidx.startup.AppInitializer
|
||||
import io.element.android.x.core.di.DaggerComponentOwner
|
||||
import io.element.android.x.core.di.bindings
|
||||
import io.element.android.x.di.AppBindings
|
||||
import io.element.android.x.di.AppComponent
|
||||
import io.element.android.x.di.DaggerAppComponent
|
||||
import io.element.android.x.di.SessionComponentsOwner
|
||||
import io.element.android.x.initializer.CoilInitializer
|
||||
import io.element.android.x.initializer.MatrixInitializer
|
||||
import io.element.android.x.initializer.MavericksInitializer
|
||||
import io.element.android.x.matrix.MatrixInstance
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.plus
|
||||
|
||||
class ElementXApplication : Application(), DaggerComponentOwner {
|
||||
|
||||
override lateinit var daggerComponent: Any
|
||||
private lateinit var appComponent: AppComponent
|
||||
private var sessionComponentsOwner: SessionComponentsOwner? = null
|
||||
|
||||
private val applicationScope = MainScope() + CoroutineName("ElementX Scope")
|
||||
override val daggerComponent: Any
|
||||
get() = listOfNotNull(sessionComponentsOwner?.activeSessionComponent, appComponent)
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
daggerComponent = DaggerAppComponent.factory().create(applicationContext)
|
||||
MatrixInstance.init(this, applicationScope)
|
||||
appComponent = DaggerAppComponent.factory().create(applicationContext)
|
||||
sessionComponentsOwner = bindings<AppBindings>().sessionComponentsOwner()
|
||||
AppInitializer.getInstance(this).apply {
|
||||
initializeComponent(MatrixInitializer::class.java)
|
||||
initializeComponent(CoilInitializer::class.java)
|
||||
initializeComponent(MavericksInitializer::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import dagger.assisted.AssistedInject
|
||||
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||
import io.element.android.x.di.AppScope
|
||||
import io.element.android.x.features.messages.MessagesViewModel
|
||||
import io.element.android.x.features.messages.model.MessagesViewState
|
||||
import io.element.android.x.di.SessionComponentsOwner
|
||||
import io.element.android.x.matrix.Matrix
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -19,10 +18,12 @@ data class MainState(val fake: Boolean = false) : MavericksState
|
||||
@ContributesViewModel(AppScope::class)
|
||||
class MainViewModel @AssistedInject constructor(
|
||||
private val matrix: Matrix,
|
||||
private val sessionComponentsOwner: SessionComponentsOwner,
|
||||
@Assisted initialState: MainState
|
||||
) : MavericksViewModel<MainState>(initialState) {
|
||||
|
||||
companion object : MavericksViewModelFactory<MainViewModel, MainState> by daggerMavericksViewModelFactory()
|
||||
companion object :
|
||||
MavericksViewModelFactory<MainViewModel, MainState> by daggerMavericksViewModelFactory()
|
||||
|
||||
suspend fun isLoggedIn(): Boolean {
|
||||
return matrix.isLoggedIn().first()
|
||||
@@ -31,19 +32,22 @@ class MainViewModel @AssistedInject constructor(
|
||||
fun startSyncIfLogged() {
|
||||
viewModelScope.launch {
|
||||
if (!isLoggedIn()) return@launch
|
||||
matrix.activeClient().startSync()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopSyncIfLogged() {
|
||||
viewModelScope.launch {
|
||||
if (!isLoggedIn()) return@launch
|
||||
matrix.activeClient().stopSync()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun restoreSession() {
|
||||
matrix.restoreSession()
|
||||
matrix.activeClient().startSync()
|
||||
val matrixClient = matrix.restoreSession()
|
||||
if (matrixClient == null) {
|
||||
throw IllegalStateException("Couldn't restore session...")
|
||||
} else {
|
||||
sessionComponentsOwner.create(matrixClient)
|
||||
matrixClient.startSync()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package io.element.android.x
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import com.ramcosta.composedestinations.navigation.popUpTo
|
||||
import io.element.android.x.core.di.bindings
|
||||
import io.element.android.x.destinations.*
|
||||
import io.element.android.x.di.AppBindings
|
||||
import io.element.android.x.features.login.LoginScreen
|
||||
import io.element.android.x.features.login.changeserver.ChangeServerScreen
|
||||
import io.element.android.x.features.messages.MessagesScreen
|
||||
@@ -29,11 +32,13 @@ fun OnBoardingScreenNavigation(navigator: DestinationsNavigator) {
|
||||
@Destination
|
||||
@Composable
|
||||
fun LoginScreenNavigation(navigator: DestinationsNavigator) {
|
||||
val sessionComponentsOwner = LocalContext.current.bindings<AppBindings>().sessionComponentsOwner()
|
||||
LoginScreen(
|
||||
onChangeServer = {
|
||||
navigator.navigate(ChangeServerScreenNavigationDestination)
|
||||
},
|
||||
onLoginWithSuccess = {
|
||||
sessionComponentsOwner.create(it)
|
||||
navigator.navigate(RoomListScreenNavigationDestination) {
|
||||
popUpTo(OnBoardingScreenNavigationDestination) {
|
||||
inclusive = true
|
||||
@@ -58,11 +63,13 @@ fun ChangeServerScreenNavigation(navigator: DestinationsNavigator) {
|
||||
@Destination
|
||||
@Composable
|
||||
fun RoomListScreenNavigation(navigator: DestinationsNavigator) {
|
||||
val sessionComponentsOwner = LocalContext.current.bindings<AppBindings>().sessionComponentsOwner()
|
||||
RoomListScreen(
|
||||
onRoomClicked = { roomId: RoomId ->
|
||||
navigator.navigate(MessagesScreenNavigationDestination(roomId = roomId.value))
|
||||
},
|
||||
onSuccessLogout = {
|
||||
sessionComponentsOwner.releaseActiveSession()
|
||||
navigator.navigate(OnBoardingScreenNavigationDestination) {
|
||||
popUpTo(RoomListScreenNavigationDestination) {
|
||||
inclusive = true
|
||||
@@ -75,7 +82,7 @@ fun RoomListScreenNavigation(navigator: DestinationsNavigator) {
|
||||
@Destination
|
||||
@Composable
|
||||
fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) {
|
||||
MessagesScreen(roomId, navigator::navigateUp)
|
||||
MessagesScreen(roomId = roomId, onBackPressed = navigator::navigateUp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.x.di.AppScope
|
||||
import io.element.android.x.matrix.Matrix
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@@ -9,4 +8,5 @@ import kotlinx.coroutines.CoroutineScope
|
||||
interface AppBindings {
|
||||
fun coroutineScope(): CoroutineScope
|
||||
fun matrix(): Matrix
|
||||
fun sessionComponentsOwner(): SessionComponentsOwner
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.anvil.annotations.MergeSubcomponent
|
||||
import dagger.BindsInstance
|
||||
import dagger.Subcomponent
|
||||
import io.element.android.x.core.di.DaggerMavericksBindings
|
||||
import io.element.android.x.matrix.MatrixClient
|
||||
|
||||
@SingleIn(SessionScope::class)
|
||||
@MergeSubcomponent(SessionScope::class)
|
||||
interface SessionComponent: DaggerMavericksBindings {
|
||||
|
||||
fun matrixClient(): MatrixClient
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
fun client(matrixClient: MatrixClient): Builder
|
||||
fun build(): SessionComponent
|
||||
}
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface ParentBindings {
|
||||
fun sessionComponentBuilder(): Builder
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package io.element.android.x.di
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.x.core.di.bindings
|
||||
import io.element.android.x.matrix.MatrixClient
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
class SessionComponentsOwner @Inject constructor(@ApplicationContext private val context: Context) {
|
||||
|
||||
private val sessionComponents = ConcurrentHashMap<String, SessionComponent>()
|
||||
var activeSessionComponent: SessionComponent? = null
|
||||
private set
|
||||
|
||||
fun setActive(sessionId: String) {
|
||||
val sessionComponent = sessionComponents[sessionId]
|
||||
if (activeSessionComponent != sessionComponent) {
|
||||
activeSessionComponent = sessionComponent
|
||||
}
|
||||
}
|
||||
|
||||
fun create(matrixClient: MatrixClient) {
|
||||
val sessionId = matrixClient.sessionId
|
||||
val sessionComponent =
|
||||
context.bindings<SessionComponent.ParentBindings>().sessionComponentBuilder()
|
||||
.client(matrixClient).build()
|
||||
sessionComponents[sessionId] = sessionComponent
|
||||
setActive(sessionId)
|
||||
}
|
||||
|
||||
fun releaseActiveSession() {
|
||||
activeSessionComponent?.also {
|
||||
release(it.matrixClient().sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
fun release(sessionId: String) {
|
||||
val sessionComponent = sessionComponents.remove(sessionId)
|
||||
if (activeSessionComponent == sessionComponent) {
|
||||
activeSessionComponent = null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,13 @@ private class ElementImageLoaderFactory(
|
||||
return ImageLoader
|
||||
.Builder(context)
|
||||
.components {
|
||||
context.bindings<AppBindings>().matrix().registerCoilComponents(this)
|
||||
val appBindings = context.bindings<AppBindings>()
|
||||
val matrix = appBindings.matrix()
|
||||
val matrixClientProvider = {
|
||||
appBindings
|
||||
.sessionComponentsOwner().activeSessionComponent?.matrixClient()
|
||||
}
|
||||
matrix.registerCoilComponents(this, matrixClientProvider)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user