diff --git a/app/src/main/kotlin/io/element/android/x/MainActivity.kt b/app/src/main/kotlin/io/element/android/x/MainActivity.kt index a969c8e0ba..e8a51cca22 100644 --- a/app/src/main/kotlin/io/element/android/x/MainActivity.kt +++ b/app/src/main/kotlin/io/element/android/x/MainActivity.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat @@ -39,7 +40,7 @@ private val loggerTag = LoggerTag("MainActivity") class MainActivity : NodeComponentActivity() { - lateinit var mainNode: MainNode + private lateinit var mainNode: MainNode override fun onCreate(savedInstanceState: Bundle?) { Timber.tag(loggerTag.value).w("onCreate, with savedInstanceState: ${savedInstanceState != null}") @@ -49,26 +50,32 @@ class MainActivity : NodeComponentActivity() { appBindings.matrixClientsHolder().restore(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) setContent { - ElementTheme { - Box( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background), - ) { - NodeHost(integrationPoint = appyxIntegrationPoint) { - MainNode( - it, - appBindings.mainDaggerComponentOwner(), - plugins = listOf( - object : NodeReadyObserver { - override fun init(node: MainNode) { - mainNode = node - mainNode.handleIntent(intent) - } + MainContent(appBindings) + } + } + + @Composable + private fun MainContent(appBindings: AppBindings) { + ElementTheme { + Box( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background), + ) { + NodeHost(integrationPoint = appyxIntegrationPoint) { + MainNode( + it, + appBindings.mainDaggerComponentOwner(), + plugins = listOf( + object : NodeReadyObserver { + override fun init(node: MainNode) { + Timber.tag(loggerTag.value).w("onMainNodeInit") + mainNode = node + mainNode.handleIntent(intent) } - ) + } ) - } + ) } } } @@ -80,11 +87,17 @@ class MainActivity : NodeComponentActivity() { * - a notification is clicked. * - the app is going to background (<- this is strange) */ - override fun onNewIntent(intent: Intent?) { + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) Timber.tag(loggerTag.value).w("onNewIntent") - intent ?: return - mainNode.handleIntent(intent) + // If the mainNode is not init yet, keep the intent for later. + // It can happen when the activity is killed by the system. The methods are called in this order : + // onCreate(savedInstanceState=true) -> onNewIntent -> onResume -> onMainNodeInit + if (::mainNode.isInitialized) { + mainNode.handleIntent(intent) + } else { + setIntent(intent) + } } override fun onPause() { diff --git a/app/src/main/kotlin/io/element/android/x/MainNode.kt b/app/src/main/kotlin/io/element/android/x/MainNode.kt index fb551f326d..7f56ef4d63 100644 --- a/app/src/main/kotlin/io/element/android/x/MainNode.kt +++ b/app/src/main/kotlin/io/element/android/x/MainNode.kt @@ -57,24 +57,24 @@ class MainNode( DaggerComponentOwner by mainDaggerComponentOwner { private val loggedInFlowNodeCallback = object : LoggedInFlowNode.LifecycleCallback { - override fun onFlowCreated(client: MatrixClient) { + override fun onFlowCreated(identifier: String, client: MatrixClient) { val component = bindings().sessionComponentBuilder().client(client).build() - mainDaggerComponentOwner.addComponent(client.sessionId.value, component) + mainDaggerComponentOwner.addComponent(identifier, component) } - override fun onFlowReleased(client: MatrixClient) { - mainDaggerComponentOwner.removeComponent(client.sessionId.value) + override fun onFlowReleased(identifier: String, client: MatrixClient) { + mainDaggerComponentOwner.removeComponent(identifier) } } private val roomFlowNodeCallback = object : RoomFlowNode.LifecycleCallback { - override fun onFlowCreated(room: MatrixRoom) { + override fun onFlowCreated(identifier: String, room: MatrixRoom) { val component = bindings().roomComponentBuilder().room(room).build() - mainDaggerComponentOwner.addComponent(room.roomId.value, component) + mainDaggerComponentOwner.addComponent(identifier, component) } - override fun onFlowReleased(room: MatrixRoom) { - mainDaggerComponentOwner.removeComponent(room.roomId.value) + override fun onFlowReleased(identifier: String, room: MatrixRoom) { + mainDaggerComponentOwner.removeComponent(identifier) } } diff --git a/app/src/main/kotlin/io/element/android/x/di/MainDaggerComponentsOwner.kt b/app/src/main/kotlin/io/element/android/x/di/MainDaggerComponentsOwner.kt index 5489b07830..de800bb587 100644 --- a/app/src/main/kotlin/io/element/android/x/di/MainDaggerComponentsOwner.kt +++ b/app/src/main/kotlin/io/element/android/x/di/MainDaggerComponentsOwner.kt @@ -38,6 +38,10 @@ class MainDaggerComponentsOwner @Inject constructor(@ApplicationContext context: daggerComponents.remove(identifier) } + /** + * We expose the dagger components in the opposite order they arrived. + * So we pick the most recent component when searching with the [io.element.android.libraries.architecture.bindings] methods. + */ override val daggerComponent: Any get() = daggerComponents.values.reversed() } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index d23cbaabce..ba002b78ac 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -64,7 +64,6 @@ import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.appnavstate.api.AppNavigationStateService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.parcelize.Parcelize @@ -118,9 +117,9 @@ class LoggedInFlowNode @AssistedInject constructor( } interface LifecycleCallback : NodeLifecycleCallback { - fun onFlowCreated(client: MatrixClient) = Unit + fun onFlowCreated(identifier: String, client: MatrixClient) = Unit - fun onFlowReleased(client: MatrixClient) = Unit + fun onFlowReleased(identifier: String, client: MatrixClient) = Unit } data class Inputs( @@ -139,7 +138,7 @@ class LoggedInFlowNode @AssistedInject constructor( observeAnalyticsState() lifecycle.subscribe( onCreate = { - plugins().forEach { it.onFlowCreated(inputs.matrixClient) } + plugins().forEach { it.onFlowCreated(id, inputs.matrixClient) } val imageLoaderFactory = bindings().loggedInImageLoaderFactory() Coil.setImageLoader(imageLoaderFactory) inputs.matrixClient.startSync() @@ -151,7 +150,7 @@ class LoggedInFlowNode @AssistedInject constructor( onDestroy = { val imageLoaderFactory = bindings().notLoggedInImageLoaderFactory() Coil.setImageLoader(imageLoaderFactory) - plugins().forEach { it.onFlowReleased(inputs.matrixClient) } + plugins().forEach { it.onFlowReleased(id, inputs.matrixClient) } appNavigationStateService.onLeavingSpace(id) appNavigationStateService.onLeavingSession(id) loggedInFlowProcessor.stopObserving() diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt index fb3a8d566e..0bcf9000e7 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RoomFlowNode.kt @@ -68,8 +68,8 @@ class RoomFlowNode @AssistedInject constructor( ) { interface LifecycleCallback : NodeLifecycleCallback { - fun onFlowCreated(room: MatrixRoom) = Unit - fun onFlowReleased(room: MatrixRoom) = Unit + fun onFlowCreated(identifier: String, room: MatrixRoom) = Unit + fun onFlowReleased(identifier: String, room: MatrixRoom) = Unit } data class Inputs( @@ -83,14 +83,14 @@ class RoomFlowNode @AssistedInject constructor( lifecycle.subscribe( onCreate = { Timber.v("OnCreate") - plugins().forEach { it.onFlowCreated(inputs.room) } + plugins().forEach { it.onFlowCreated(id, inputs.room) } appNavigationStateService.onNavigateToRoom(id, inputs.room.roomId) fetchRoomMembers() }, onDestroy = { Timber.v("OnDestroy") inputs.room.close() - plugins().forEach { it.onFlowReleased(inputs.room) } + plugins().forEach { it.onFlowReleased(id, inputs.room) } appNavigationStateService.onLeavingRoom(id) } )