Navigation refactor - NavigationRouter added (#1698)

This commit is contained in:
Milan 2024-12-02 13:32:47 +01:00 committed by GitHub
parent 8a77a38133
commit f60ba7597b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 131 additions and 268 deletions

View File

@ -7,6 +7,8 @@ import co.electriccoin.zcash.global.newInstance
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.StandardPreferenceProvider import co.electriccoin.zcash.preference.StandardPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.PreferenceKey import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.NavigationRouterImpl
import co.electriccoin.zcash.ui.preference.PersistableWalletPreferenceDefault import co.electriccoin.zcash.ui.preference.PersistableWalletPreferenceDefault
import co.electriccoin.zcash.ui.screen.update.AppUpdateChecker import co.electriccoin.zcash.ui.screen.update.AppUpdateChecker
import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImpl import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImpl
@ -37,4 +39,6 @@ val coreModule =
factoryOf(::AppUpdateCheckerImpl) bind AppUpdateChecker::class factoryOf(::AppUpdateCheckerImpl) bind AppUpdateChecker::class
factory { AndroidConfigurationFactory.new() } factory { AndroidConfigurationFactory.new() }
singleOf(::NavigationRouterImpl) bind NavigationRouter::class
} }

View File

@ -67,6 +67,7 @@ val viewModelModule =
args = args, args = args,
observeAddressBookContacts = get(), observeAddressBookContacts = get(),
observeContactPicked = get(), observeContactPicked = get(),
navigationRouter = get()
) )
} }
viewModel { (address: String?) -> viewModel { (address: String?) ->
@ -75,6 +76,7 @@ val viewModelModule =
validateContactAddress = get(), validateContactAddress = get(),
validateContactName = get(), validateContactName = get(),
saveContact = get(), saveContact = get(),
navigationRouter = get()
) )
} }
viewModelOf(::UpdateContactViewModel) viewModelOf(::UpdateContactViewModel)

View File

@ -10,6 +10,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavBackStackEntry import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.NavOptionsBuilder import androidx.navigation.NavOptionsBuilder
import androidx.navigation.NavType import androidx.navigation.NavType
@ -101,6 +102,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.koin.compose.koinInject
// TODO [#1297]: Consider: Navigation passing complex data arguments different way // TODO [#1297]: Consider: Navigation passing complex data arguments different way
// TODO [#1297]: https://github.com/Electric-Coin-Company/zashi-android/issues/1297 // TODO [#1297]: https://github.com/Electric-Coin-Company/zashi-android/issues/1297
@ -117,16 +119,21 @@ internal fun MainActivity.Navigation() {
rememberSaveable { mutableStateOf(false) } rememberSaveable { mutableStateOf(false) }
val (deleteWalletAuthentication, setDeleteWalletAuthentication) = val (deleteWalletAuthentication, setDeleteWalletAuthentication) =
rememberSaveable { mutableStateOf(false) } rememberSaveable { mutableStateOf(false) }
val navigationRouter = koinInject<NavigationRouter>()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
walletViewModel.navigationCommand.collect { navigationRouter.observe().collect {
navController.navigateJustOnce(it) when (it) {
} is NavigationCommand.Forward -> navController.navigate(it.route)
} is NavigationCommand.Replace ->
navController.navigate(it.route) {
LaunchedEffect(Unit) { popUpTo(navController.graph.findStartDestination().id) {
walletViewModel.backNavigationCommand.collect { saveState = true
navController.popBackStack() }
restoreState = true
}
NavigationCommand.Back -> navController.popBackStack()
}
} }
} }

View File

@ -0,0 +1,53 @@
package co.electriccoin.zcash.ui
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.launch
interface NavigationRouter {
fun forward(route: String)
fun replace(route: String)
fun back()
fun observe(): Flow<NavigationCommand>
}
class NavigationRouterImpl : NavigationRouter {
private val scope = CoroutineScope(Dispatchers.Main.immediate + SupervisorJob())
private val channel = Channel<NavigationCommand>()
override fun forward(route: String) {
scope.launch {
channel.send(NavigationCommand.Forward(route))
}
}
override fun replace(route: String) {
scope.launch {
channel.send(NavigationCommand.Replace(route))
}
}
override fun back() {
scope.launch {
channel.send(NavigationCommand.Back)
}
}
override fun observe() = channel.consumeAsFlow()
}
sealed interface NavigationCommand {
data class Forward(val route: String) : NavigationCommand
data class Replace(val route: String) : NavigationCommand
data object Back : NavigationCommand
}

View File

@ -5,6 +5,7 @@ import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.preference.StandardPreferenceProvider import co.electriccoin.zcash.preference.StandardPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.NullableBooleanPreferenceDefault import co.electriccoin.zcash.preference.model.entry.NullableBooleanPreferenceDefault
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.NavigationTargets.EXCHANGE_RATE_OPT_IN import co.electriccoin.zcash.ui.NavigationTargets.EXCHANGE_RATE_OPT_IN
import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState
import co.electriccoin.zcash.ui.common.wallet.RefreshLock import co.electriccoin.zcash.ui.common.wallet.RefreshLock
@ -15,7 +16,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
@ -36,10 +36,6 @@ import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.minutes
interface ExchangeRateRepository { interface ExchangeRateRepository {
val navigationCommand: MutableSharedFlow<String>
val backNavigationCommand: MutableSharedFlow<Unit>
val isExchangeRateUsdOptedIn: StateFlow<Boolean?> val isExchangeRateUsdOptedIn: StateFlow<Boolean?>
val state: StateFlow<ExchangeRateState> val state: StateFlow<ExchangeRateState>
@ -54,6 +50,7 @@ interface ExchangeRateRepository {
class ExchangeRateRepositoryImpl( class ExchangeRateRepositoryImpl(
private val walletRepository: WalletRepository, private val walletRepository: WalletRepository,
private val standardPreferenceProvider: StandardPreferenceProvider, private val standardPreferenceProvider: StandardPreferenceProvider,
private val navigationRouter: NavigationRouter,
) : ExchangeRateRepository { ) : ExchangeRateRepository {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
@ -164,10 +161,6 @@ class ExchangeRateRepositoryImpl(
initialValue = ExchangeRateState.OptedOut initialValue = ExchangeRateState.OptedOut
) )
override val navigationCommand = MutableSharedFlow<String>()
override val backNavigationCommand = MutableSharedFlow<Unit>()
override fun refreshExchangeRateUsd() { override fun refreshExchangeRateUsd() {
refreshExchangeRateUsdInternal() refreshExchangeRateUsdInternal()
} }
@ -182,27 +175,20 @@ class ExchangeRateRepositoryImpl(
} }
override fun optInExchangeRateUsd(optIn: Boolean) { override fun optInExchangeRateUsd(optIn: Boolean) {
scope.launch { setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, optIn)
setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, optIn) navigationRouter.back()
backNavigationCommand.emit(Unit)
}
} }
override fun dismissOptInExchangeRateUsd() { override fun dismissOptInExchangeRateUsd() {
scope.launch { setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, false)
setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, false) navigationRouter.back()
backNavigationCommand.emit(Unit)
}
} }
private fun dismissWidgetOptInExchangeRateUsd() { private fun dismissWidgetOptInExchangeRateUsd() {
setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, false) setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, false)
} }
private fun showOptInExchangeRateUsd() = private fun showOptInExchangeRateUsd() = navigationRouter.forward(EXCHANGE_RATE_OPT_IN)
scope.launch {
navigationCommand.emit(EXCHANGE_RATE_OPT_IN)
}
private fun nullableBooleanStateFlow(default: NullableBooleanPreferenceDefault): StateFlow<Boolean?> = private fun nullableBooleanStateFlow(default: NullableBooleanPreferenceDefault): StateFlow<Boolean?> =
flow { flow {

View File

@ -68,10 +68,6 @@ class WalletViewModel(
private val isFlexaAvailable: IsFlexaAvailableUseCase, private val isFlexaAvailable: IsFlexaAvailableUseCase,
private val getSynchronizer: GetSynchronizerUseCase private val getSynchronizer: GetSynchronizerUseCase
) : AndroidViewModel(application) { ) : AndroidViewModel(application) {
val navigationCommand = exchangeRateRepository.navigationCommand
val backNavigationCommand = exchangeRateRepository.backNavigationCommand
val synchronizer = walletRepository.synchronizer val synchronizer = walletRepository.synchronizer
val walletRestoringState = walletRepository.walletRestoringState val walletRestoringState = walletRepository.walletRestoringState

View File

@ -4,11 +4,9 @@ package co.electriccoin.zcash.ui.screen.addressbook
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.addressbook.view.AddressBookView import co.electriccoin.zcash.ui.screen.addressbook.view.AddressBookView
import co.electriccoin.zcash.ui.screen.addressbook.viewmodel.AddressBookViewModel import co.electriccoin.zcash.ui.screen.addressbook.viewmodel.AddressBookViewModel
@ -17,24 +15,11 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapAddressBook(args: AddressBookArgs) { internal fun WrapAddressBook(args: AddressBookArgs) {
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<AddressBookViewModel> { parametersOf(args) } val viewModel = koinViewModel<AddressBookViewModel> { parametersOf(args) }
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle() val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.navigationCommand.collect {
navController.navigate(it)
}
}
LaunchedEffect(Unit) {
viewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
BackHandler { BackHandler {
state.onBack() state.onBack()
} }

View File

@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.addressbook.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.AddressBookContact import co.electriccoin.zcash.ui.common.model.AddressBookContact
import co.electriccoin.zcash.ui.common.usecase.ObserveAddressBookContactsUseCase import co.electriccoin.zcash.ui.common.usecase.ObserveAddressBookContactsUseCase
@ -16,7 +17,6 @@ import co.electriccoin.zcash.ui.screen.contact.AddContactArgs
import co.electriccoin.zcash.ui.screen.contact.UpdateContactArgs import co.electriccoin.zcash.ui.screen.contact.UpdateContactArgs
import co.electriccoin.zcash.ui.screen.scan.ScanNavigationArgs import co.electriccoin.zcash.ui.screen.scan.ScanNavigationArgs
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
@ -27,7 +27,8 @@ import kotlinx.coroutines.launch
class AddressBookViewModel( class AddressBookViewModel(
observeAddressBookContacts: ObserveAddressBookContactsUseCase, observeAddressBookContacts: ObserveAddressBookContactsUseCase,
private val args: AddressBookArgs, private val args: AddressBookArgs,
private val observeContactPicked: ObserveContactPickedUseCase private val observeContactPicked: ObserveContactPickedUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
val state = val state =
observeAddressBookContacts() observeAddressBookContacts()
@ -39,10 +40,6 @@ class AddressBookViewModel(
initialValue = createState(contacts = null) initialValue = createState(contacts = null)
) )
val navigationCommand = MutableSharedFlow<String>()
val backNavigationCommand = MutableSharedFlow<Unit>()
private fun createState(contacts: List<AddressBookContact>?) = private fun createState(contacts: List<AddressBookContact>?) =
AddressBookState( AddressBookState(
isLoading = contacts == null, isLoading = contacts == null,
@ -80,34 +77,25 @@ class AddressBookViewModel(
.joinToString(separator = "") .joinToString(separator = "")
) )
private fun onBack() = private fun onBack() = navigationRouter.back()
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onContactClick(contact: AddressBookContact) = private fun onContactClick(contact: AddressBookContact) =
viewModelScope.launch { viewModelScope.launch {
when (args) { when (args) {
AddressBookArgs.DEFAULT -> { AddressBookArgs.DEFAULT -> {
navigationCommand.emit(UpdateContactArgs(contact.address)) navigationRouter.forward(UpdateContactArgs(contact.address))
} }
AddressBookArgs.PICK_CONTACT -> { AddressBookArgs.PICK_CONTACT -> {
observeContactPicked.onContactPicked(contact) observeContactPicked.onContactPicked(contact)
backNavigationCommand.emit(Unit) navigationRouter.back()
} }
} }
} }
private fun onAddContactManuallyClick() = private fun onAddContactManuallyClick() = navigationRouter.forward(AddContactArgs(null))
viewModelScope.launch {
navigationCommand.emit(AddContactArgs(null))
}
private fun onScanContactClick() = private fun onScanContactClick() = navigationRouter.forward(ScanNavigationArgs(ScanNavigationArgs.ADDRESS_BOOK))
viewModelScope.launch {
navigationCommand.emit(ScanNavigationArgs(ScanNavigationArgs.ADDRESS_BOOK))
}
} }
private const val ADDRESS_MAX_LENGTH = 20 private const val ADDRESS_MAX_LENGTH = 20

View File

@ -4,10 +4,8 @@ package co.electriccoin.zcash.ui.screen.advancedsettings
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.advancedsettings.view.AdvancedSettings import co.electriccoin.zcash.ui.screen.advancedsettings.view.AdvancedSettings
import co.electriccoin.zcash.ui.screen.advancedsettings.viewmodel.AdvancedSettingsViewModel import co.electriccoin.zcash.ui.screen.advancedsettings.viewmodel.AdvancedSettingsViewModel
@ -20,7 +18,6 @@ internal fun WrapAdvancedSettings(
goExportPrivateData: () -> Unit, goExportPrivateData: () -> Unit,
goSeedRecovery: () -> Unit, goSeedRecovery: () -> Unit,
) { ) {
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<AdvancedSettingsViewModel>() val viewModel = koinViewModel<AdvancedSettingsViewModel>()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
@ -42,18 +39,6 @@ internal fun WrapAdvancedSettings(
viewModel.onBack() viewModel.onBack()
} }
LaunchedEffect(Unit) {
viewModel.navigationCommand.collect {
navController.navigate(it)
}
}
LaunchedEffect(Unit) {
viewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
AdvancedSettings( AdvancedSettings(
state = state, state = state,
topAppBarSubTitleState = walletState, topAppBarSubTitleState = walletState,

View File

@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.advancedsettings.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.NavigationTargets import co.electriccoin.zcash.ui.NavigationTargets
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.usecase.SensitiveSettingsVisibleUseCase import co.electriccoin.zcash.ui.common.usecase.SensitiveSettingsVisibleUseCase
@ -11,16 +12,15 @@ import co.electriccoin.zcash.ui.design.component.ZashiSettingsListItemState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.advancedsettings.model.AdvancedSettingsState import co.electriccoin.zcash.ui.screen.advancedsettings.model.AdvancedSettingsState
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class AdvancedSettingsViewModel( class AdvancedSettingsViewModel(
isSensitiveSettingsVisible: SensitiveSettingsVisibleUseCase isSensitiveSettingsVisible: SensitiveSettingsVisibleUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
val state: StateFlow<AdvancedSettingsState> = val state: StateFlow<AdvancedSettingsState> =
isSensitiveSettingsVisible() isSensitiveSettingsVisible()
@ -68,21 +68,9 @@ class AdvancedSettingsViewModel(
), ),
) )
val navigationCommand = MutableSharedFlow<String>() private fun onChooseServerClick() = navigationRouter.forward(NavigationTargets.CHOOSE_SERVER)
val backNavigationCommand = MutableSharedFlow<Unit>()
private fun onChooseServerClick() = private fun onCurrencyConversionClick() = navigationRouter.forward(NavigationTargets.SETTINGS_EXCHANGE_RATE_OPT_IN)
viewModelScope.launch {
navigationCommand.emit(NavigationTargets.CHOOSE_SERVER)
}
private fun onCurrencyConversionClick() = fun onBack() = navigationRouter.back()
viewModelScope.launch {
navigationCommand.emit(NavigationTargets.SETTINGS_EXCHANGE_RATE_OPT_IN)
}
fun onBack() =
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
} }

View File

@ -4,11 +4,9 @@ package co.electriccoin.zcash.ui.screen.contact
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.contact.view.ContactView import co.electriccoin.zcash.ui.screen.contact.view.ContactView
import co.electriccoin.zcash.ui.screen.contact.viewmodel.AddContactViewModel import co.electriccoin.zcash.ui.screen.contact.viewmodel.AddContactViewModel
@ -17,24 +15,11 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapAddContact(address: String?) { internal fun WrapAddContact(address: String?) {
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<AddContactViewModel> { parametersOf(address) } val viewModel = koinViewModel<AddContactViewModel> { parametersOf(address) }
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle() val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.navigationCommand.collect {
navController.navigate(it)
}
}
LaunchedEffect(Unit) {
viewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
BackHandler { BackHandler {
state?.onBack?.invoke() state?.onBack?.invoke()
} }

View File

@ -4,11 +4,9 @@ package co.electriccoin.zcash.ui.screen.contact
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.contact.view.ContactView import co.electriccoin.zcash.ui.screen.contact.view.ContactView
import co.electriccoin.zcash.ui.screen.contact.viewmodel.UpdateContactViewModel import co.electriccoin.zcash.ui.screen.contact.viewmodel.UpdateContactViewModel
@ -17,24 +15,11 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapUpdateContact(contactAddress: String) { internal fun WrapUpdateContact(contactAddress: String) {
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<UpdateContactViewModel> { parametersOf(contactAddress) } val viewModel = koinViewModel<UpdateContactViewModel> { parametersOf(contactAddress) }
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle() val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.navigationCommand.collect {
navController.navigate(it)
}
}
LaunchedEffect(Unit) {
viewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
BackHandler { BackHandler {
state?.onBack?.invoke() state?.onBack?.invoke()
} }

View File

@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.contact.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.usecase.SaveContactUseCase import co.electriccoin.zcash.ui.common.usecase.SaveContactUseCase
import co.electriccoin.zcash.ui.common.usecase.ValidateContactAddressUseCase import co.electriccoin.zcash.ui.common.usecase.ValidateContactAddressUseCase
@ -12,7 +13,6 @@ import co.electriccoin.zcash.ui.design.component.TextFieldState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.contact.model.ContactState import co.electriccoin.zcash.ui.screen.contact.model.ContactState
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
@ -26,7 +26,8 @@ class AddContactViewModel(
address: String? = null, address: String? = null,
private val validateContactAddress: ValidateContactAddressUseCase, private val validateContactAddress: ValidateContactAddressUseCase,
private val validateContactName: ValidateContactNameUseCase, private val validateContactName: ValidateContactNameUseCase,
private val saveContact: SaveContactUseCase private val saveContact: SaveContactUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
private val contactAddress = MutableStateFlow(address.orEmpty()) private val contactAddress = MutableStateFlow(address.orEmpty())
private val contactName = MutableStateFlow("") private val contactName = MutableStateFlow("")
@ -131,14 +132,7 @@ class AddContactViewModel(
initialValue = null initialValue = null
) )
val navigationCommand = MutableSharedFlow<String>() private fun onBack() = navigationRouter.back()
val backNavigationCommand = MutableSharedFlow<Unit>()
private fun onBack() =
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onSaveButtonClick() = private fun onSaveButtonClick() =
viewModelScope.launch { viewModelScope.launch {
@ -146,7 +140,7 @@ class AddContactViewModel(
isSavingContact.update { true } isSavingContact.update { true }
saveContact(name = contactName.value, address = contactAddress.value) saveContact(name = contactName.value, address = contactAddress.value)
backNavigationCommand.emit(Unit) navigationRouter.back()
isSavingContact.update { false } isSavingContact.update { false }
} }
} }

View File

@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.contact.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.AddressBookContact import co.electriccoin.zcash.ui.common.model.AddressBookContact
import co.electriccoin.zcash.ui.common.usecase.DeleteContactUseCase import co.electriccoin.zcash.ui.common.usecase.DeleteContactUseCase
@ -14,7 +15,6 @@ import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.TextFieldState import co.electriccoin.zcash.ui.design.component.TextFieldState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.contact.model.ContactState import co.electriccoin.zcash.ui.screen.contact.model.ContactState
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
@ -30,7 +30,8 @@ class UpdateContactViewModel(
private val validateContactName: ValidateContactNameUseCase, private val validateContactName: ValidateContactNameUseCase,
private val updateContact: UpdateContactUseCase, private val updateContact: UpdateContactUseCase,
private val deleteContact: DeleteContactUseCase, private val deleteContact: DeleteContactUseCase,
private val getContactByAddress: GetContactByAddressUseCase private val getContactByAddress: GetContactByAddressUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
private var contact = MutableStateFlow<AddressBookContact?>(null) private var contact = MutableStateFlow<AddressBookContact?>(null)
private val contactAddress = MutableStateFlow("") private val contactAddress = MutableStateFlow("")
@ -148,10 +149,6 @@ class UpdateContactViewModel(
initialValue = null initialValue = null
) )
val navigationCommand = MutableSharedFlow<String>()
val backNavigationCommand = MutableSharedFlow<Unit>()
init { init {
viewModelScope.launch { viewModelScope.launch {
getContactByAddress(originalContactAddress).let { contact -> getContactByAddress(originalContactAddress).let { contact ->
@ -163,10 +160,7 @@ class UpdateContactViewModel(
} }
} }
private fun onBack() = private fun onBack() = navigationRouter.back()
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onUpdateButtonClick() = private fun onUpdateButtonClick() =
viewModelScope.launch { viewModelScope.launch {
@ -174,7 +168,7 @@ class UpdateContactViewModel(
contact.value?.let { contact.value?.let {
isUpdatingContact.update { true } isUpdatingContact.update { true }
updateContact(contact = it, name = contactName.value, address = contactAddress.value) updateContact(contact = it, name = contactName.value, address = contactAddress.value)
backNavigationCommand.emit(Unit) navigationRouter.back()
isUpdatingContact.update { false } isUpdatingContact.update { false }
} }
} }
@ -185,7 +179,7 @@ class UpdateContactViewModel(
contact.value?.let { contact.value?.let {
isDeletingContact.update { true } isDeletingContact.update { true }
deleteContact(it) deleteContact(it)
backNavigationCommand.emit(Unit) navigationRouter.back()
isDeletingContact.update { false } isDeletingContact.update { false }
} }
} }

View File

@ -7,7 +7,6 @@ import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalActivity import co.electriccoin.zcash.ui.common.compose.LocalActivity
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.about.util.WebBrowserUtil import co.electriccoin.zcash.ui.screen.about.util.WebBrowserUtil
import co.electriccoin.zcash.ui.screen.integrations.view.Integrations import co.electriccoin.zcash.ui.screen.integrations.view.Integrations
@ -19,18 +18,11 @@ import org.koin.androidx.compose.koinViewModel
@Composable @Composable
internal fun WrapIntegrations() { internal fun WrapIntegrations() {
val activity = LocalActivity.current val activity = LocalActivity.current
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<IntegrationsViewModel>() val viewModel = koinViewModel<IntegrationsViewModel>()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
LaunchedEffect(Unit) {
viewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
viewModel.coinbaseNavigationCommand.collect { uri -> viewModel.coinbaseNavigationCommand.collect { uri ->
WebBrowserUtil.startActivity(activity, uri) WebBrowserUtil.startActivity(activity, uri)

View File

@ -16,6 +16,7 @@ import cash.z.ecc.android.sdk.type.AddressType
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.BuildConfig import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
@ -57,9 +58,9 @@ class IntegrationsViewModel(
private val isCoinbaseAvailable: IsCoinbaseAvailableUseCase, private val isCoinbaseAvailable: IsCoinbaseAvailableUseCase,
private val getSpendingKey: GetSpendingKeyUseCase, private val getSpendingKey: GetSpendingKeyUseCase,
private val context: Context, private val context: Context,
private val biometricRepository: BiometricRepository private val biometricRepository: BiometricRepository,
private val navigationRouter: NavigationRouter
) : ViewModel() { ) : ViewModel() {
val backNavigationCommand = MutableSharedFlow<Unit>()
val flexaNavigationCommand = MutableSharedFlow<Unit>() val flexaNavigationCommand = MutableSharedFlow<Unit>()
val coinbaseNavigationCommand = MutableSharedFlow<String>() val coinbaseNavigationCommand = MutableSharedFlow<String>()
@ -113,10 +114,7 @@ class IntegrationsViewModel(
initialValue = null initialValue = null
) )
fun onBack() = fun onBack() = navigationRouter.back()
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onBuyWithCoinbaseClicked() = private fun onBuyWithCoinbaseClicked() =
viewModelScope.launch { viewModelScope.launch {

View File

@ -10,7 +10,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.qrcode.model.QrCodeState import co.electriccoin.zcash.ui.screen.qrcode.model.QrCodeState
import co.electriccoin.zcash.ui.screen.qrcode.view.QrCodeView import co.electriccoin.zcash.ui.screen.qrcode.view.QrCodeView
@ -21,7 +20,6 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapQrCode(addressType: Int) { internal fun WrapQrCode(addressType: Int) {
val context = LocalContext.current val context = LocalContext.current
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle() val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
@ -31,11 +29,6 @@ internal fun WrapQrCode(addressType: Int) {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(Unit) {
qrCodeViewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
qrCodeViewModel.shareResultCommand.collect { sharedSuccessfully -> qrCodeViewModel.shareResultCommand.collect { sharedSuccessfully ->
if (!sharedSuccessfully) { if (!sharedSuccessfully) {

View File

@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.spackle.getInternalCacheDirSuspend import co.electriccoin.zcash.spackle.getInternalCacheDirSuspend
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.VersionInfo import co.electriccoin.zcash.ui.common.model.VersionInfo
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
@ -39,6 +40,7 @@ class QrCodeViewModel(
getAddresses: GetAddressesUseCase, getAddresses: GetAddressesUseCase,
getVersionInfo: GetVersionInfoProvider, getVersionInfo: GetVersionInfoProvider,
private val copyToClipboard: CopyToClipboardUseCase, private val copyToClipboard: CopyToClipboardUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
private val versionInfo by lazy { getVersionInfo() } private val versionInfo by lazy { getVersionInfo() }
@ -57,14 +59,9 @@ class QrCodeViewModel(
initialValue = QrCodeState.Loading initialValue = QrCodeState.Loading
) )
val backNavigationCommand = MutableSharedFlow<Unit>()
val shareResultCommand = MutableSharedFlow<Boolean>() val shareResultCommand = MutableSharedFlow<Boolean>()
private fun onBack() = private fun onBack() = navigationRouter.back()
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onQrCodeShareClick( private fun onQrCodeShareClick(
bitmap: ImageBitmap, bitmap: ImageBitmap,

View File

@ -4,20 +4,16 @@ package co.electriccoin.zcash.ui.screen.receive
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.receive.view.ReceiveView import co.electriccoin.zcash.ui.screen.receive.view.ReceiveView
import co.electriccoin.zcash.ui.screen.receive.viewmodel.ReceiveViewModel import co.electriccoin.zcash.ui.screen.receive.viewmodel.ReceiveViewModel
@Composable @Composable
internal fun WrapReceive() { internal fun WrapReceive() {
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
@ -26,12 +22,6 @@ internal fun WrapReceive() {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(Unit) {
receiveViewModel.navigationCommand.collect {
navController.navigate(it)
}
}
ReceiveView( ReceiveView(
state = receiveState, state = receiveState,
topAppBarSubTitleState = walletState, topAppBarSubTitleState = walletState,

View File

@ -4,6 +4,7 @@ import android.app.Application
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.NavigationTargets import co.electriccoin.zcash.ui.NavigationTargets
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
@ -12,18 +13,17 @@ import co.electriccoin.zcash.ui.common.usecase.GetAddressesUseCase
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveState import co.electriccoin.zcash.ui.screen.receive.model.ReceiveState
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class ReceiveViewModel( class ReceiveViewModel(
private val application: Application, private val application: Application,
getVersionInfo: GetVersionInfoProvider, getVersionInfo: GetVersionInfoProvider,
getAddresses: GetAddressesUseCase, getAddresses: GetAddressesUseCase,
private val copyToClipboard: CopyToClipboardUseCase, private val copyToClipboard: CopyToClipboardUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
internal val state = internal val state =
@ -47,20 +47,11 @@ class ReceiveViewModel(
initialValue = ReceiveState.Loading initialValue = ReceiveState.Loading
) )
val navigationCommand = MutableSharedFlow<String>()
private fun onRequestClick(addressType: ReceiveAddressType) = private fun onRequestClick(addressType: ReceiveAddressType) =
viewModelScope.launch { navigationRouter.forward("${NavigationTargets.REQUEST}/${addressType.ordinal}")
navigationCommand.emit("${NavigationTargets.REQUEST}/${addressType.ordinal}")
}
private fun onQrCodeClick(addressType: ReceiveAddressType) = private fun onQrCodeClick(addressType: ReceiveAddressType) =
viewModelScope.launch { navigationRouter.forward("${NavigationTargets.QR_CODE}/${addressType.ordinal}")
navigationCommand.emit("${NavigationTargets.QR_CODE}/${addressType.ordinal}")
}
private fun onSettingsClick() = private fun onSettingsClick() = navigationRouter.forward(NavigationTargets.SETTINGS)
viewModelScope.launch {
navigationCommand.emit(NavigationTargets.SETTINGS)
}
} }

View File

@ -12,7 +12,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.request.model.RequestState import co.electriccoin.zcash.ui.screen.request.model.RequestState
import co.electriccoin.zcash.ui.screen.request.view.RequestView import co.electriccoin.zcash.ui.screen.request.view.RequestView
@ -23,7 +22,6 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapRequest(addressType: Int) { internal fun WrapRequest(addressType: Int) {
val context = LocalContext.current val context = LocalContext.current
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle() val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
@ -33,11 +31,6 @@ internal fun WrapRequest(addressType: Int) {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(Unit) {
requestViewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
requestViewModel.shareResultCommand.collect { sharedSuccessfully -> requestViewModel.shareResultCommand.collect { sharedSuccessfully ->
if (!sharedSuccessfully) { if (!sharedSuccessfully) {

View File

@ -9,6 +9,7 @@ import cash.z.ecc.android.sdk.model.FiatCurrencyConversion
import cash.z.ecc.android.sdk.model.WalletAddress import cash.z.ecc.android.sdk.model.WalletAddress
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.provider.GetMonetarySeparatorProvider import co.electriccoin.zcash.ui.common.provider.GetMonetarySeparatorProvider
import co.electriccoin.zcash.ui.common.provider.GetZcashCurrencyProvider import co.electriccoin.zcash.ui.common.provider.GetZcashCurrencyProvider
@ -48,6 +49,7 @@ class RequestViewModel(
getMonetarySeparators: GetMonetarySeparatorProvider, getMonetarySeparators: GetMonetarySeparatorProvider,
shareImageBitmap: ShareImageUseCase, shareImageBitmap: ShareImageUseCase,
zip321BuildUriUseCase: Zip321BuildUriUseCase, zip321BuildUriUseCase: Zip321BuildUriUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
companion object { companion object {
private const val MAX_ZCASH_SUPPLY = 21_000_000 private const val MAX_ZCASH_SUPPLY = 21_000_000
@ -132,8 +134,6 @@ class RequestViewModel(
initialValue = RequestState.Loading initialValue = RequestState.Loading
) )
val backNavigationCommand = MutableSharedFlow<Unit>()
val shareResultCommand = MutableSharedFlow<Boolean>() val shareResultCommand = MutableSharedFlow<Boolean>()
private fun resolveExchangeRateValue(exchangeRateUsd: ExchangeRateState): FiatCurrencyConversion? { private fun resolveExchangeRateValue(exchangeRateUsd: ExchangeRateState): FiatCurrencyConversion? {
@ -247,7 +247,7 @@ class RequestViewModel(
viewModelScope.launch { viewModelScope.launch {
when (stage.value) { when (stage.value) {
RequestStage.AMOUNT -> { RequestStage.AMOUNT -> {
backNavigationCommand.emit(Unit) navigationRouter.back()
} }
RequestStage.MEMO -> { RequestStage.MEMO -> {
stage.emit(RequestStage.AMOUNT) stage.emit(RequestStage.AMOUNT)
@ -265,10 +265,7 @@ class RequestViewModel(
} }
} }
private fun onClose() = private fun onClose() = navigationRouter.back()
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onAmountDone(conversion: FiatCurrencyConversion?) = private fun onAmountDone(conversion: FiatCurrencyConversion?) =
viewModelScope.launch { viewModelScope.launch {

View File

@ -2,11 +2,9 @@ package co.electriccoin.zcash.ui.screen.settings
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.settings.view.Settings import co.electriccoin.zcash.ui.screen.settings.view.Settings
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
@ -14,24 +12,11 @@ import org.koin.androidx.compose.koinViewModel
@Composable @Composable
internal fun WrapSettings() { internal fun WrapSettings() {
val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val settingsViewModel = koinViewModel<SettingsViewModel>() val settingsViewModel = koinViewModel<SettingsViewModel>()
val state by settingsViewModel.state.collectAsStateWithLifecycle() val state by settingsViewModel.state.collectAsStateWithLifecycle()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
LaunchedEffect(Unit) {
settingsViewModel.navigationCommand.collect {
navController.navigate(it)
}
}
LaunchedEffect(Unit) {
settingsViewModel.backNavigationCommand.collect {
navController.popBackStack()
}
}
BackHandler { BackHandler {
settingsViewModel.onBack() settingsViewModel.onBack()
} }

View File

@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.preference.StandardPreferenceProvider import co.electriccoin.zcash.preference.StandardPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.NavigationTargets.ABOUT import co.electriccoin.zcash.ui.NavigationTargets.ABOUT
import co.electriccoin.zcash.ui.NavigationTargets.ADVANCED_SETTINGS import co.electriccoin.zcash.ui.NavigationTargets.ADVANCED_SETTINGS
import co.electriccoin.zcash.ui.NavigationTargets.INTEGRATIONS import co.electriccoin.zcash.ui.NavigationTargets.INTEGRATIONS
@ -25,7 +26,6 @@ import co.electriccoin.zcash.ui.screen.settings.model.SettingsState
import co.electriccoin.zcash.ui.screen.settings.model.SettingsTroubleshootingState import co.electriccoin.zcash.ui.screen.settings.model.SettingsTroubleshootingState
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingItemState import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingItemState
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.WhileSubscribed import kotlinx.coroutines.flow.WhileSubscribed
@ -43,6 +43,7 @@ class SettingsViewModel(
private val standardPreferenceProvider: StandardPreferenceProvider, private val standardPreferenceProvider: StandardPreferenceProvider,
private val getVersionInfo: GetVersionInfoProvider, private val getVersionInfo: GetVersionInfoProvider,
private val rescanBlockchain: RescanBlockchainUseCase, private val rescanBlockchain: RescanBlockchainUseCase,
private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
private val versionInfo by lazy { getVersionInfo() } private val versionInfo by lazy { getVersionInfo() }
@ -160,9 +161,6 @@ class SettingsViewModel(
version = stringRes(R.string.settings_version, versionInfo.versionName) version = stringRes(R.string.settings_version, versionInfo.versionName)
) )
val navigationCommand = MutableSharedFlow<String>()
val backNavigationCommand = MutableSharedFlow<Unit>()
private fun setAnalyticsEnabled(enabled: Boolean) { private fun setAnalyticsEnabled(enabled: Boolean) {
setBooleanPreference(StandardPreferenceKeys.IS_ANALYTICS_ENABLED, enabled) setBooleanPreference(StandardPreferenceKeys.IS_ANALYTICS_ENABLED, enabled)
} }
@ -189,42 +187,19 @@ class SettingsViewModel(
} }
} }
fun onBack() = fun onBack() = navigationRouter.back()
viewModelScope.launch {
backNavigationCommand.emit(Unit)
}
private fun onIntegrationsClick() = private fun onIntegrationsClick() = navigationRouter.forward(INTEGRATIONS)
viewModelScope.launch {
navigationCommand.emit(INTEGRATIONS)
}
private fun onAdvancedSettingsClick() = private fun onAdvancedSettingsClick() = navigationRouter.forward(ADVANCED_SETTINGS)
viewModelScope.launch {
navigationCommand.emit(ADVANCED_SETTINGS)
}
private fun onAboutUsClick() = private fun onAboutUsClick() = navigationRouter.forward(ABOUT)
viewModelScope.launch {
navigationCommand.emit(ABOUT)
}
private fun onSendUsFeedbackClick() = private fun onSendUsFeedbackClick() = navigationRouter.forward(SUPPORT)
viewModelScope.launch {
navigationCommand.emit(SUPPORT)
}
private fun onAddressBookClick() { private fun onAddressBookClick() = navigationRouter.forward(AddressBookArgs(AddressBookArgs.DEFAULT))
viewModelScope.launch {
navigationCommand.emit(AddressBookArgs(AddressBookArgs.DEFAULT))
}
}
private fun onWhatsNewClick() { private fun onWhatsNewClick() = navigationRouter.forward(WHATS_NEW)
viewModelScope.launch {
navigationCommand.emit(WHATS_NEW)
}
}
private fun booleanStateFlow(default: BooleanPreferenceDefault): StateFlow<Boolean?> = private fun booleanStateFlow(default: BooleanPreferenceDefault): StateFlow<Boolean?> =
flow<Boolean?> { flow<Boolean?> {