2 replace all actions have been performed: - "SPDX-License-Identifier: AGPL-3.0-only" to "SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial" - "Please see LICENSE in the repository root for full details." to "Please see LICENSE files in the repository root for full details."
157 lines
5.8 KiB
Kotlin
157 lines
5.8 KiB
Kotlin
/*
|
|
* Copyright 2022-2024 New Vector Ltd.
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
* Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
package io.element.android.x
|
|
|
|
import android.content.Intent
|
|
import android.os.Bundle
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
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.runtime.CompositionLocalProvider
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.platform.LocalUriHandler
|
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
import androidx.lifecycle.Lifecycle
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.lifecycle.repeatOnLifecycle
|
|
import com.bumble.appyx.core.integration.NodeHost
|
|
import com.bumble.appyx.core.integrationpoint.NodeActivity
|
|
import com.bumble.appyx.core.plugin.NodeReadyObserver
|
|
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
|
import io.element.android.features.lockscreen.api.LockScreenLockState
|
|
import io.element.android.features.lockscreen.api.LockScreenService
|
|
import io.element.android.features.lockscreen.api.handleSecureFlag
|
|
import io.element.android.libraries.architecture.bindings
|
|
import io.element.android.libraries.core.log.logger.LoggerTag
|
|
import io.element.android.libraries.designsystem.theme.ElementThemeApp
|
|
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
|
|
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
|
import io.element.android.x.di.AppBindings
|
|
import io.element.android.x.intent.SafeUriHandler
|
|
import kotlinx.coroutines.launch
|
|
import timber.log.Timber
|
|
|
|
private val loggerTag = LoggerTag("MainActivity")
|
|
|
|
class MainActivity : NodeActivity() {
|
|
private lateinit var mainNode: MainNode
|
|
private lateinit var appBindings: AppBindings
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
Timber.tag(loggerTag.value).w("onCreate, with savedInstanceState: ${savedInstanceState != null}")
|
|
installSplashScreen()
|
|
super.onCreate(savedInstanceState)
|
|
appBindings = bindings()
|
|
setupLockManagement(appBindings.lockScreenService(), appBindings.lockScreenEntryPoint())
|
|
enableEdgeToEdge()
|
|
setContent {
|
|
MainContent(appBindings)
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun MainContent(appBindings: AppBindings) {
|
|
val migrationState = appBindings.migrationEntryPoint().present()
|
|
ElementThemeApp(appBindings.preferencesStore()) {
|
|
CompositionLocalProvider(
|
|
LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(),
|
|
LocalUriHandler provides SafeUriHandler(this),
|
|
LocalAnalyticsService provides appBindings.analyticsService(),
|
|
) {
|
|
Box(
|
|
modifier = Modifier
|
|
.fillMaxSize()
|
|
.background(MaterialTheme.colorScheme.background),
|
|
) {
|
|
if (migrationState.migrationAction.isSuccess()) {
|
|
MainNodeHost()
|
|
} else {
|
|
appBindings.migrationEntryPoint().Render(
|
|
state = migrationState,
|
|
modifier = Modifier,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun MainNodeHost() {
|
|
NodeHost(integrationPoint = appyxV1IntegrationPoint) {
|
|
MainNode(
|
|
it,
|
|
plugins = listOf(
|
|
object : NodeReadyObserver<MainNode> {
|
|
override fun init(node: MainNode) {
|
|
Timber.tag(loggerTag.value).w("onMainNodeInit")
|
|
mainNode = node
|
|
mainNode.handleIntent(intent)
|
|
}
|
|
}
|
|
),
|
|
context = applicationContext
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun setupLockManagement(
|
|
lockScreenService: LockScreenService,
|
|
lockScreenEntryPoint: LockScreenEntryPoint
|
|
) {
|
|
lockScreenService.handleSecureFlag(this)
|
|
lifecycleScope.launch {
|
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
|
lockScreenService.lockState.collect { state ->
|
|
if (state == LockScreenLockState.Locked) {
|
|
startActivity(lockScreenEntryPoint.pinUnlockIntent(this@MainActivity))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called when:
|
|
* - the launcher icon is clicked (if the app is already running);
|
|
* - a notification is clicked.
|
|
* - a deep link have been clicked
|
|
* - the app is going to background (<- this is strange)
|
|
*/
|
|
override fun onNewIntent(intent: Intent) {
|
|
super.onNewIntent(intent)
|
|
Timber.tag(loggerTag.value).w("onNewIntent")
|
|
// 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() {
|
|
super.onPause()
|
|
Timber.tag(loggerTag.value).w("onPause")
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
Timber.tag(loggerTag.value).w("onResume")
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
Timber.tag(loggerTag.value).w("onDestroy")
|
|
}
|
|
}
|