mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Refactor regV5 navigation to remove some unnecessary layers.
This commit is contained in:
committed by
Alex Hart
parent
2ca4748e00
commit
c25f6d0bc4
@@ -4618,6 +4618,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="0a940e79e256cc7fbec69d8eb35362ac79599ab4b21ab4846aba64ba4960a192" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-livedata-ktx" version="2.10.0">
|
||||
<artifact name="lifecycle-livedata-ktx-2.10.0.aar">
|
||||
<sha256 value="3b42f425ab72b1d142ada7e075d78d9ab1500703729c1a342148eff4c0c23dcf" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-livedata-ktx-2.10.0.module">
|
||||
<sha256 value="4d37fcd30801b06d5c508914b01154ee397071b0d5fcd634a48a45ded2dee09e" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-livedata-ktx" version="2.8.7">
|
||||
<artifact name="lifecycle-livedata-ktx-2.8.7.aar">
|
||||
<sha256 value="80af6960fb8b5d5b26bc04086613435e78a7c214be8b68b461bb79dedc431f76" origin="Generated by Gradle"/>
|
||||
@@ -4749,6 +4757,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="f7cd5051bacb3f4b8ec7dc40ac6342a61eea1147592dda9f364a24cf882c7ddb" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-reactivestreams" version="2.10.0">
|
||||
<artifact name="lifecycle-reactivestreams-2.10.0.aar">
|
||||
<sha256 value="a68df4b53f0cc9c063691b2658cd059ec9e7f0d84439f0b458d95efc6cbe605c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-reactivestreams-2.10.0.module">
|
||||
<sha256 value="bc873cdd0c60ed59878fcdd122aeb571171158465454c0e674686d410dcf4f6c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-reactivestreams" version="2.8.7">
|
||||
<artifact name="lifecycle-reactivestreams-2.8.7.aar">
|
||||
<sha256 value="305da124ecc7108bb8ff28b4140a75ce034e81e0ac6e4d51cddb476e2607e92e" origin="Generated by Gradle"/>
|
||||
@@ -4791,6 +4807,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="28b7d48306489ebba7b9e1d65563377f994be708e7a9757e47ddc5c0421ad1a4" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-reactivestreams-ktx" version="2.10.0">
|
||||
<artifact name="lifecycle-reactivestreams-ktx-2.10.0.aar">
|
||||
<sha256 value="a46076ff7cb61666d60ea516236d50886bc06152411277e900c1ff4d9d8b812d" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-reactivestreams-ktx-2.10.0.module">
|
||||
<sha256 value="74cf3d5d8d148203b471b8e749153bb8d8c2ba1118f8f794f7b329d6a6b5341a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-reactivestreams-ktx" version="2.8.7">
|
||||
<artifact name="lifecycle-reactivestreams-ktx-2.8.7.aar">
|
||||
<sha256 value="e7d818e836f21895d65afd982b6a89ce5c7826c696bd273613445429c3da0d7c" origin="Generated by Gradle"/>
|
||||
@@ -5114,6 +5138,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="b6803f906a89fd85c77df343dd4aeeb349125ca79e12d55d68d4cf42f42231f6" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-runtime-compose-desktop" version="2.10.0">
|
||||
<artifact name="lifecycle-runtime-compose-desktop-2.10.0.jar">
|
||||
<sha256 value="4d233eeecc6e2769a76442830c5fd1884057c36d0ce2745167193a10cc8976f8" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-runtime-compose-desktop-2.10.0.module">
|
||||
<sha256 value="257b0bc6df73ad860e6b378b94890867964c7430da9c884a65f667cfe5cbdc10" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-runtime-compose-desktop" version="2.9.4">
|
||||
<artifact name="lifecycle-runtime-compose-desktop-2.9.4.jar">
|
||||
<md5 value="8f8fe81afd5c0e7c0f3e8a38142f8aa2" origin="Generated by Gradle"/>
|
||||
@@ -5141,6 +5173,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="aaadee69ebaa3bae99ba7b5eb46aa7d38bd0be636d63f418cb43ec307a8f31da" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-runtime-desktop" version="2.10.0">
|
||||
<artifact name="lifecycle-runtime-desktop-2.10.0.jar">
|
||||
<sha256 value="6f70b76fb7a262f47b99317c23271c28a89ad18400547b4bfefbd2ef04500f90" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-runtime-desktop-2.10.0.module">
|
||||
<sha256 value="2eeef8084cf67129e199227a3fabacf8506f57faeecb0aab0f765d5c4e59040a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-runtime-desktop" version="2.8.7">
|
||||
<artifact name="lifecycle-runtime-desktop-2.8.7.module">
|
||||
<md5 value="edc88458a7e5ff7fe2314aea7f42d7f5" origin="Generated by Gradle"/>
|
||||
@@ -5374,6 +5414,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="87ae364cb972aa5db8f80a97dde1b8dc5533841c43bfa798abdad82cf2515fe1" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-service" version="2.10.0">
|
||||
<artifact name="lifecycle-service-2.10.0.aar">
|
||||
<sha256 value="60bea13bbea42b6aa007e5a48c0b432c9b3dd05887482a43baa8f5a9042dc2e2" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-service-2.10.0.module">
|
||||
<sha256 value="4f13973559bff5ea98e056556488c526a705df7776559d6551bfefaecf15a79a" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-service" version="2.6.1">
|
||||
<artifact name="lifecycle-service-2.6.1.module">
|
||||
<md5 value="10b87bd8171b0293794b99ed3b9f9d27" origin="Generated by Gradle"/>
|
||||
@@ -5749,6 +5797,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="84450bb22ee6ce369c3ff52042e1d308cac63991782dacd95b8e5e357a97a221" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-compose-jvmstubs" version="2.10.0">
|
||||
<artifact name="lifecycle-viewmodel-compose-jvmstubs-2.10.0.jar">
|
||||
<sha256 value="e7a2558fe359d92d5ad455540589b25b2b5a9d77e4a3df7df26a139c08664c89" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-viewmodel-compose-jvmstubs-2.10.0.module">
|
||||
<sha256 value="9dfac7b9733b7aa0c334571548c74b0cf675daeb31125c4e5131a5e249c4c3e8" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-compose-jvmstubs" version="2.9.0">
|
||||
<artifact name="lifecycle-viewmodel-compose-jvmstubs-2.9.0.jar">
|
||||
<sha256 value="02d761721139eb2d175b0efb44e318408c6a3e38bfa923dde886eaa506069d44" origin="Generated by Gradle"/>
|
||||
@@ -5770,6 +5826,9 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-desktop" version="2.10.0">
|
||||
<artifact name="lifecycle-viewmodel-desktop-2.10.0.jar">
|
||||
<sha256 value="e7c86a5e5c66fd41fd3cc9c9ad31a2997110b1a6380c441ba3f7b6b0b070e32b" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-viewmodel-desktop-2.10.0.module">
|
||||
<sha256 value="cda319d7c9e32602859a72be81c0026e56d1797ef9ba67e9173e905d3f74774f" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
@@ -6067,6 +6126,9 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate-desktop" version="2.10.0">
|
||||
<artifact name="lifecycle-viewmodel-savedstate-desktop-2.10.0.jar">
|
||||
<sha256 value="92944597842a697623d0746d719d8af3acb9f4c780da611062fa60d993944d2c" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="lifecycle-viewmodel-savedstate-desktop-2.10.0.module">
|
||||
<sha256 value="59b7367fbd82b74a6053291a12743cac0c2cf1fe96929378c51d82bf8fe9a95d" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
@@ -6410,6 +6472,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="ec5f820c5856ab72029dc58acd54cee1e1952ec7e6233848dd10e9071f0eedbc" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.navigation3" name="navigation3-runtime-desktop" version="1.0.0">
|
||||
<artifact name="navigation3-runtime-desktop-1.0.0.jar">
|
||||
<sha256 value="db659bc9be9528a8af3ac65f218f632b7bbc1978b039522ae5d51210f4e0ee68" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="navigation3-runtime-desktop-1.0.0.module">
|
||||
<sha256 value="eeab8a14560ab88ff0c96fcc10a142b8beea4cc93704add5627667921a9312e2" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.navigation3" name="navigation3-ui" version="1.0.0">
|
||||
<artifact name="navigation3-ui-1.0.0.module">
|
||||
<md5 value="3777271d1686b054e2464aadb712b084" origin="Generated by Gradle"/>
|
||||
@@ -6851,6 +6921,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="06a0201247847e59303e4ffb468c9419c614708f568787e0abd5a92c6dadad40" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.savedstate" name="savedstate-compose-desktop" version="1.4.0">
|
||||
<artifact name="savedstate-compose-desktop-1.4.0.jar">
|
||||
<sha256 value="c02a98b0c2b35cdde245c0bfe6e7ff453c7b6d06a5eb8681d25b7f54b874ea48" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="savedstate-compose-desktop-1.4.0.module">
|
||||
<sha256 value="808ff723a153acce160489a5bc4b58ca1d7033fe84a9060f52d17db227eaa4cd" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.savedstate" name="savedstate-compose-jvmstubs" version="1.3.0">
|
||||
<artifact name="savedstate-compose-jvmstubs-1.3.0.jar">
|
||||
<sha256 value="4a94787a6e5bcfe143390a4f2737d4425d2ea867f2b34a847de6cda3c6ccc58a" origin="Generated by Gradle"/>
|
||||
@@ -6879,6 +6957,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
|
||||
<sha256 value="945f3c713ab1f3896db216d199f924441453961ee2bbd74bb47ae8919dbaf759" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.savedstate" name="savedstate-desktop" version="1.4.0">
|
||||
<artifact name="savedstate-desktop-1.4.0.jar">
|
||||
<sha256 value="e965ed7a011be83a271ac7d82249a776368479ee3a2b07948c3445b51d640856" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
<artifact name="savedstate-desktop-1.4.0.module">
|
||||
<sha256 value="e73f2cf8818ece347d8b5dff990d0db639a7dfb8fcc85eeecb2618383f7ecef7" origin="Generated by Gradle"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="androidx.savedstate" name="savedstate-ktx" version="1.2.1">
|
||||
<artifact name="savedstate-ktx-1.2.1.aar">
|
||||
<md5 value="232e75b56e6fea8591d591f98b2ecff2" origin="Generated by Gradle"/>
|
||||
|
||||
@@ -82,6 +82,9 @@ dependencies {
|
||||
implementation(libs.androidx.navigation3.runtime)
|
||||
implementation(libs.androidx.navigation3.ui)
|
||||
|
||||
// Permissions
|
||||
implementation(libs.accompanist.permissions)
|
||||
|
||||
// Compose BOM
|
||||
platform(libs.androidx.compose.bom).let { composeBom ->
|
||||
implementation(composeBom)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.sample
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.signal.core.ui.navigation.ResultEventBus
|
||||
|
||||
class AppViewModel : ViewModel() {
|
||||
val resultEventBus = ResultEventBus()
|
||||
}
|
||||
@@ -3,13 +3,13 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPermissionsApi::class)
|
||||
|
||||
package org.signal.registration.sample
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
@@ -39,15 +39,12 @@ import androidx.navigation3.runtime.rememberDecoratedNavEntries
|
||||
import androidx.navigation3.runtime.rememberNavBackStack
|
||||
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
|
||||
import androidx.navigation3.ui.NavDisplay
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.core.ui.navigation.ResultEffect
|
||||
import org.signal.core.ui.navigation.ResultEventBus
|
||||
import org.signal.registration.NetworkController
|
||||
import org.signal.registration.RegistrationActivity
|
||||
import org.signal.registration.RegistrationDependencies
|
||||
import org.signal.registration.StorageController
|
||||
import org.signal.registration.sample.MainActivity.Companion.REGISTRATION_RESULT
|
||||
import org.signal.registration.RegistrationNavHost
|
||||
import org.signal.registration.RegistrationRepository
|
||||
import org.signal.registration.sample.screens.RegistrationCompleteScreen
|
||||
import org.signal.registration.sample.screens.main.MainScreen
|
||||
import org.signal.registration.sample.screens.main.MainScreenViewModel
|
||||
@@ -89,6 +86,9 @@ sealed interface SampleRoute : NavKey {
|
||||
@Serializable
|
||||
data object Main : SampleRoute
|
||||
|
||||
@Serializable
|
||||
data object Registration : SampleRoute
|
||||
|
||||
@Serializable
|
||||
data object RegistrationComplete : SampleRoute
|
||||
|
||||
@@ -104,15 +104,14 @@ class MainActivity : ComponentActivity() {
|
||||
const val REGISTRATION_RESULT = "registration_result"
|
||||
}
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
|
||||
private val registrationLauncher: ActivityResultLauncher<Unit> = registerForActivityResult(RegistrationActivity.RegistrationContract()) { success ->
|
||||
viewModel.resultEventBus.sendResult(REGISTRATION_RESULT, success)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val registrationRepository = RegistrationRepository(
|
||||
networkController = RegistrationDependencies.get().networkController,
|
||||
storageController = RegistrationDependencies.get().storageController
|
||||
)
|
||||
|
||||
setContent {
|
||||
SignalTheme {
|
||||
Surface(
|
||||
@@ -122,11 +121,9 @@ class MainActivity : ComponentActivity() {
|
||||
val backStack = rememberNavBackStack(SampleRoute.Main)
|
||||
|
||||
SampleNavHost(
|
||||
onLaunchRegistration = { registrationLauncher.launch(Unit) },
|
||||
backStack = backStack,
|
||||
resultEventBus = viewModel.resultEventBus,
|
||||
storageController = RegistrationDependencies.get().storageController,
|
||||
networkController = RegistrationDependencies.get().networkController,
|
||||
registrationRepository = registrationRepository,
|
||||
registrationDependencies = RegistrationDependencies.get(),
|
||||
onStartOver = {
|
||||
backStack.clear()
|
||||
backStack.add(SampleRoute.Main)
|
||||
@@ -140,20 +137,18 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
private fun SampleNavHost(
|
||||
onLaunchRegistration: () -> Unit,
|
||||
onStartOver: () -> Unit,
|
||||
registrationRepository: RegistrationRepository,
|
||||
registrationDependencies: RegistrationDependencies,
|
||||
backStack: NavBackStack<NavKey>,
|
||||
resultEventBus: ResultEventBus,
|
||||
storageController: StorageController,
|
||||
networkController: NetworkController,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val entryProvider: (NavKey) -> NavEntry<NavKey> = entryProvider {
|
||||
entry<SampleRoute.Main> {
|
||||
val viewModel: MainScreenViewModel = viewModel(
|
||||
factory = MainScreenViewModel.Factory(
|
||||
storageController = storageController,
|
||||
onLaunchRegistration = onLaunchRegistration,
|
||||
storageController = registrationDependencies.storageController,
|
||||
onLaunchRegistration = { backStack.add(SampleRoute.Registration) },
|
||||
onOpenPinSettings = { backStack.add(SampleRoute.PinSettings) }
|
||||
)
|
||||
)
|
||||
@@ -164,19 +159,22 @@ private fun SampleNavHost(
|
||||
onPauseOrDispose { }
|
||||
}
|
||||
|
||||
ResultEffect<Boolean>(resultEventBus, REGISTRATION_RESULT) { success ->
|
||||
if (success) {
|
||||
viewModel.refreshData()
|
||||
backStack.add(SampleRoute.RegistrationComplete)
|
||||
}
|
||||
}
|
||||
|
||||
MainScreen(
|
||||
state = state,
|
||||
onEvent = { viewModel.onEvent(it) }
|
||||
)
|
||||
}
|
||||
|
||||
entry<SampleRoute.Registration> {
|
||||
RegistrationNavHost(
|
||||
registrationRepository,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onRegistrationComplete = {
|
||||
backStack.add(SampleRoute.RegistrationComplete)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
entry<SampleRoute.RegistrationComplete> {
|
||||
RegistrationCompleteScreen(onStartOver = onStartOver)
|
||||
}
|
||||
@@ -186,7 +184,7 @@ private fun SampleNavHost(
|
||||
) {
|
||||
val viewModel: PinSettingsViewModel = viewModel(
|
||||
factory = PinSettingsViewModel.Factory(
|
||||
networkController = networkController,
|
||||
networkController = registrationDependencies.networkController,
|
||||
onBack = { backStack.removeLastOrNull() }
|
||||
)
|
||||
)
|
||||
|
||||
@@ -7,11 +7,11 @@ import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.screens.RegistrationHostScreen
|
||||
|
||||
/**
|
||||
* Activity entry point for the registration flow.
|
||||
@@ -39,16 +39,11 @@ class RegistrationActivity : ComponentActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
val permissionsState = rememberMultiplePermissionsState(
|
||||
permissions = viewModel.getRequiredPermissions()
|
||||
)
|
||||
|
||||
SignalTheme(incognitoKeyboardEnabled = false) {
|
||||
Surface {
|
||||
RegistrationHostScreen(
|
||||
RegistrationNavHost(
|
||||
registrationRepository = repository,
|
||||
viewModel = viewModel,
|
||||
permissionsState = permissionsState,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onRegistrationComplete = {
|
||||
setResult(RESULT_OK)
|
||||
finish()
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPermissionsApi::class)
|
||||
|
||||
package org.signal.registration
|
||||
|
||||
import android.os.Parcelable
|
||||
@@ -15,7 +17,6 @@ import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -27,6 +28,7 @@ import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
|
||||
import androidx.navigation3.ui.NavDisplay
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.MultiplePermissionsState
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.signal.core.ui.navigation.ResultEffect
|
||||
@@ -48,6 +50,8 @@ import org.signal.registration.screens.pinentry.PinEntryScreen
|
||||
import org.signal.registration.screens.restore.RestoreViaQrScreen
|
||||
import org.signal.registration.screens.restore.RestoreViaQrScreenEvents
|
||||
import org.signal.registration.screens.restore.RestoreViaQrState
|
||||
import org.signal.registration.screens.util.navigateBack
|
||||
import org.signal.registration.screens.util.navigateTo
|
||||
import org.signal.registration.screens.verificationcode.VerificationCodeScreen
|
||||
import org.signal.registration.screens.verificationcode.VerificationCodeViewModel
|
||||
import org.signal.registration.screens.welcome.WelcomeScreen
|
||||
@@ -113,8 +117,9 @@ private const val CAPTCHA_RESULT = "captcha_token"
|
||||
/**
|
||||
* Sets up the navigation graph for the registration flow using Navigation 3.
|
||||
*
|
||||
* @param registrationViewModel The shared ViewModel for the registration flow.
|
||||
* @param permissionsState The permissions state managed at the activity level.
|
||||
* @param registrationRepository The repository for registration data.
|
||||
* @param registrationViewModel Optional ViewModel for testing. If null, creates one internally.
|
||||
* @param permissionsState Optional permissions state for testing. If null, creates one internally.
|
||||
* @param modifier Modifier to be applied to the NavDisplay.
|
||||
* @param onRegistrationComplete Callback invoked when registration is successfully completed.
|
||||
*/
|
||||
@@ -122,20 +127,23 @@ private const val CAPTCHA_RESULT = "captcha_token"
|
||||
@Composable
|
||||
fun RegistrationNavHost(
|
||||
registrationRepository: RegistrationRepository,
|
||||
registrationViewModel: RegistrationViewModel,
|
||||
permissionsState: MultiplePermissionsState,
|
||||
registrationViewModel: RegistrationViewModel? = null,
|
||||
permissionsState: MultiplePermissionsState? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
onRegistrationComplete: () -> Unit = {}
|
||||
) {
|
||||
val registrationState by registrationViewModel.state.collectAsStateWithLifecycle()
|
||||
val navigator = remember { RegistrationNavigator(eventEmitter = registrationViewModel::onEvent) }
|
||||
val viewModel: RegistrationViewModel = registrationViewModel ?: viewModel(
|
||||
factory = RegistrationViewModel.Factory(registrationRepository)
|
||||
)
|
||||
|
||||
val registrationState by viewModel.state.collectAsStateWithLifecycle()
|
||||
val permissions: MultiplePermissionsState = permissionsState ?: rememberMultiplePermissionsState(viewModel.getRequiredPermissions())
|
||||
|
||||
val entryProvider = entryProvider {
|
||||
registrationEntries(
|
||||
navigationEntries(
|
||||
registrationRepository = registrationRepository,
|
||||
registrationViewModel = registrationViewModel,
|
||||
permissionsState = permissionsState,
|
||||
navigator = navigator,
|
||||
registrationViewModel = viewModel,
|
||||
permissionsState = permissions,
|
||||
onRegistrationComplete = onRegistrationComplete
|
||||
)
|
||||
}
|
||||
@@ -152,7 +160,7 @@ fun RegistrationNavHost(
|
||||
|
||||
NavDisplay(
|
||||
entries = entries,
|
||||
onBack = { registrationViewModel.onEvent(RegistrationFlowEvent.NavigateBack) },
|
||||
onBack = { viewModel.onEvent(RegistrationFlowEvent.NavigateBack) },
|
||||
modifier = modifier,
|
||||
transitionSpec = {
|
||||
// Slide in from right and fade in when navigating forward
|
||||
@@ -204,25 +212,22 @@ fun RegistrationNavHost(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines all navigation entries for the registration flow.
|
||||
*/
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
private fun EntryProviderScope<NavKey>.registrationEntries(
|
||||
private fun EntryProviderScope<NavKey>.navigationEntries(
|
||||
registrationRepository: RegistrationRepository,
|
||||
registrationViewModel: RegistrationViewModel,
|
||||
permissionsState: MultiplePermissionsState,
|
||||
navigator: RegistrationNavigator,
|
||||
onRegistrationComplete: () -> Unit
|
||||
) {
|
||||
val parentEventEmitter: (RegistrationFlowEvent) -> Unit = registrationViewModel::onEvent
|
||||
|
||||
// --- Welcome Screen
|
||||
entry<RegistrationRoute.Welcome> {
|
||||
WelcomeScreen(
|
||||
onEvent = { event ->
|
||||
when (event) {
|
||||
WelcomeScreenEvents.Continue -> navigator.navigate(RegistrationRoute.Permissions(forRestore = false))
|
||||
WelcomeScreenEvents.DoesNotHaveOldPhone -> navigator.navigate(RegistrationRoute.Restore)
|
||||
WelcomeScreenEvents.HasOldPhone -> navigator.navigate(RegistrationRoute.Permissions(forRestore = true))
|
||||
WelcomeScreenEvents.Continue -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(forRestore = false))
|
||||
WelcomeScreenEvents.DoesNotHaveOldPhone -> parentEventEmitter.navigateTo(RegistrationRoute.Restore)
|
||||
WelcomeScreenEvents.HasOldPhone -> parentEventEmitter.navigateTo(RegistrationRoute.Permissions(forRestore = true))
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -234,9 +239,9 @@ private fun EntryProviderScope<NavKey>.registrationEntries(
|
||||
permissionsState = permissionsState,
|
||||
onProceed = {
|
||||
if (key.forRestore) {
|
||||
navigator.navigate(RegistrationRoute.RestoreViaQr)
|
||||
parentEventEmitter.navigateTo(RegistrationRoute.RestoreViaQr)
|
||||
} else {
|
||||
navigator.navigate(RegistrationRoute.PhoneNumberEntry)
|
||||
parentEventEmitter.navigateTo(RegistrationRoute.PhoneNumberEntry)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -281,10 +286,10 @@ private fun EntryProviderScope<NavKey>.registrationEntries(
|
||||
when (event) {
|
||||
is CaptchaScreenEvents.CaptchaCompleted -> {
|
||||
registrationViewModel.resultBus.sendResult(CAPTCHA_RESULT, event.token)
|
||||
navigator.goBack()
|
||||
parentEventEmitter.navigateBack()
|
||||
}
|
||||
CaptchaScreenEvents.Cancel -> {
|
||||
navigator.goBack()
|
||||
parentEventEmitter.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,7 +375,7 @@ private fun EntryProviderScope<NavKey>.registrationEntries(
|
||||
when (event) {
|
||||
AccountLockedScreenEvents.Next -> {
|
||||
// TODO: Navigate to appropriate next screen (likely back to welcome or phone entry)
|
||||
navigator.navigate(RegistrationRoute.Welcome)
|
||||
parentEventEmitter.navigateTo(RegistrationRoute.Welcome)
|
||||
}
|
||||
AccountLockedScreenEvents.LearnMore -> {
|
||||
// TODO: Open learn more URL
|
||||
@@ -393,7 +398,7 @@ private fun EntryProviderScope<NavKey>.registrationEntries(
|
||||
// TODO: Retry QR code generation
|
||||
}
|
||||
RestoreViaQrScreenEvents.Cancel -> {
|
||||
navigator.goBack()
|
||||
parentEventEmitter.navigateBack()
|
||||
}
|
||||
RestoreViaQrScreenEvents.UseProxy -> {
|
||||
// TODO: Navigate to proxy settings
|
||||
@@ -420,20 +425,3 @@ private fun EntryProviderScope<NavKey>.registrationEntries(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigator for the registration flow.
|
||||
* Handles navigation events by updating the back stack.
|
||||
*/
|
||||
private class RegistrationNavigator(
|
||||
private val eventEmitter: (RegistrationFlowEvent) -> Unit
|
||||
) {
|
||||
|
||||
fun navigate(route: RegistrationRoute) {
|
||||
eventEmitter(RegistrationFlowEvent.NavigateToScreen(route))
|
||||
}
|
||||
|
||||
fun goBack() {
|
||||
eventEmitter(RegistrationFlowEvent.NavigateBack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.MultiplePermissionsState
|
||||
import org.signal.registration.RegistrationNavHost
|
||||
import org.signal.registration.RegistrationRepository
|
||||
import org.signal.registration.RegistrationViewModel
|
||||
|
||||
/**
|
||||
* Entry point for the registration flow.
|
||||
*
|
||||
* This composable sets up the entire registration navigation flow and can be
|
||||
* embedded into the main app's navigation or launched as a standalone flow.
|
||||
*
|
||||
* @param viewModel The shared ViewModel for the registration flow.
|
||||
* @param permissionsState The permissions state managed at the activity level.
|
||||
* @param modifier Modifier to be applied to the root container.
|
||||
* @param onRegistrationComplete Callback invoked when the registration process is successfully completed.
|
||||
*/
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun RegistrationHostScreen(
|
||||
registrationRepository: RegistrationRepository,
|
||||
viewModel: RegistrationViewModel,
|
||||
permissionsState: MultiplePermissionsState,
|
||||
modifier: Modifier = Modifier,
|
||||
onRegistrationComplete: () -> Unit = {}
|
||||
) {
|
||||
RegistrationNavHost(
|
||||
registrationRepository = registrationRepository,
|
||||
registrationViewModel = viewModel,
|
||||
permissionsState = permissionsState,
|
||||
modifier = modifier.fillMaxSize(),
|
||||
onRegistrationComplete = onRegistrationComplete
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user