Home messages business logic, wallet info removed from status bar and general refactoring

This commit is contained in:
Milan Cerovsky 2025-04-10 12:53:34 +02:00
parent 2f12bea435
commit d6d500eaed
143 changed files with 1296 additions and 1206 deletions

View File

@ -29,5 +29,7 @@ interface PreferenceProvider {
fun observe(key: PreferenceKey): Flow<String?> fun observe(key: PreferenceKey): Flow<String?>
suspend fun remove(key: PreferenceKey)
suspend fun clearPreferences(): Boolean suspend fun clearPreferences(): Boolean
} }

View File

@ -22,6 +22,6 @@ data class NullableBooleanPreferenceDefault(
preferenceProvider: PreferenceProvider, preferenceProvider: PreferenceProvider,
newValue: Boolean? newValue: Boolean?
) { ) {
preferenceProvider.putString(key, newValue.toString()) preferenceProvider.putString(key, newValue?.toString())
} }
} }

View File

@ -0,0 +1,14 @@
package co.electriccoin.zcash.preference.model.entry
import co.electriccoin.zcash.preference.api.PreferenceProvider
import java.time.Instant
class TimestampPreferenceDefault(override val key: PreferenceKey): PreferenceDefault<Instant?> {
override suspend fun getValue(preferenceProvider: PreferenceProvider) =
preferenceProvider.getLong(key)?.let { Instant.ofEpochMilli(it) }
override suspend fun putValue(
preferenceProvider: PreferenceProvider,
newValue: Instant?
) = preferenceProvider.putLong(key, newValue?.toEpochMilli())
}

View File

@ -22,6 +22,10 @@ class MockPreferenceProvider(
// For the mock implementation, does not support observability of changes // For the mock implementation, does not support observability of changes
override fun observe(key: PreferenceKey): Flow<String?> = flow { emit(getString(key)) } override fun observe(key: PreferenceKey): Flow<String?> = flow { emit(getString(key)) }
override suspend fun remove(key: PreferenceKey) {
map.remove(key.key)
}
override suspend fun clearPreferences(): Boolean { override suspend fun clearPreferences(): Boolean {
map.clear() map.clear()
return true return true

View File

@ -140,6 +140,17 @@ class AndroidPreferenceProvider private constructor(
}.flowOn(dispatcher) }.flowOn(dispatcher)
.map { getString(key) } .map { getString(key) }
@SuppressLint("ApplySharedPref")
override suspend fun remove(key: PreferenceKey) {
withContext(dispatcher) {
val editor = sharedPreferences.edit()
editor.remove(key.key)
editor.commit()
}
}
companion object { companion object {
suspend fun newStandard( suspend fun newStandard(
context: Context, context: Context,

View File

@ -1,6 +1,5 @@
package co.electriccoin.zcash.ui.design.component package co.electriccoin.zcash.ui.design.component
import androidx.annotation.IntRange
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ProgressIndicatorDefaults import androidx.compose.material3.ProgressIndicatorDefaults
@ -36,8 +35,8 @@ fun ZashiCircularProgressIndicator(
} }
@Composable @Composable
fun ZashiCircularProgressIndicator( fun ZashiCircularProgressIndicatorByPercent(
@IntRange(from = 0, to = 100) progressPercent: Int, progressPercent: Float,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
colors: ZashiCircularProgressIndicatorColors = colors: ZashiCircularProgressIndicatorColors =
LocalZashiCircularProgressIndicatorColors.current LocalZashiCircularProgressIndicatorColors.current

View File

@ -28,8 +28,7 @@ val DarkZashiColorsInternal =
textError = ErrorRed.`300`, textError = ErrorRed.`300`,
textLink = HyperBlue.`300`, textLink = HyperBlue.`300`,
textLight = Shark.`50`, textLight = Shark.`50`,
textLightSupport = Shark.`200`, textLightSupport = Shark.`200`
textOpposite = Base.Bone
), ),
Btns = Btns =
Btns( Btns(

View File

@ -28,8 +28,7 @@ val LightZashiColorsInternal =
textError = ErrorRed.`500`, textError = ErrorRed.`500`,
textLink = HyperBlue.`500`, textLink = HyperBlue.`500`,
textLight = Gray.`25`, textLight = Gray.`25`,
textLightSupport = Gray.`200`, textLightSupport = Gray.`200`
textOpposite = Base.Bone
), ),
Btns = Btns =
Btns( Btns(

View File

@ -145,7 +145,7 @@ internal object Indigo {
val `950` = Color(0xFF1F235B) val `950` = Color(0xFF1F235B)
} }
object Purple { internal object Purple {
val `25` = Color(0xFFFAFAFF) val `25` = Color(0xFFFAFAFF)
val `50` = Color(0xFFF4F3FF) val `50` = Color(0xFFF4F3FF)
val `100` = Color(0xFFEBE9FE) val `100` = Color(0xFFEBE9FE)

View File

@ -56,8 +56,7 @@ data class Text(
val textError: Color, val textError: Color,
val textLink: Color, val textLink: Color,
val textLight: Color, val textLight: Color,
val textLightSupport: Color, val textLightSupport: Color
val textOpposite: Color
) )
@Immutable @Immutable

View File

@ -3,7 +3,6 @@ package co.electriccoin.zcash.ui.integration.test.screen.scan.view
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.integration.test.common.getPermissionNegativeButtonUiObject import co.electriccoin.zcash.ui.integration.test.common.getPermissionNegativeButtonUiObject
import co.electriccoin.zcash.ui.integration.test.common.getPermissionPositiveButtonUiObject import co.electriccoin.zcash.ui.integration.test.common.getPermissionPositiveButtonUiObject
@ -60,7 +59,6 @@ class ScanViewTestSetup(
onScanStateChange = { onScanStateChange = {
scanState.set(it) scanState.set(it)
}, },
topAppBarSubTitleState = TopAppBarSubTitleState.None,
validationResult = ScanValidationState.VALID validationResult = ScanValidationState.VALID
) )
} }

View File

@ -2,7 +2,6 @@ package co.electriccoin.zcash.ui.screen.about.view
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.model.VersionInfo import co.electriccoin.zcash.ui.common.model.VersionInfo
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
@ -28,7 +27,6 @@ class AboutViewTestSetup(
configInfo = configInfo, configInfo = configInfo,
onPrivacyPolicy = {}, onPrivacyPolicy = {},
snackbarHostState = SnackbarHostState(), snackbarHostState = SnackbarHostState(),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
versionInfo = versionInfo, versionInfo = versionInfo,
) )
} }

View File

@ -3,7 +3,6 @@ package co.electriccoin.zcash.ui.screen.exportdata.view
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
@ -46,7 +45,6 @@ class ExportPrivateDataViewTestSetup(
onConfirm = { onConfirm = {
onConfirmCount.incrementAndGet() onConfirmCount.incrementAndGet()
}, },
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }

View File

@ -3,7 +3,6 @@ package co.electriccoin.zcash.ui.screen.scan.view
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.scan.model.ScanScreenState import co.electriccoin.zcash.ui.screen.scan.model.ScanScreenState
import co.electriccoin.zcash.ui.screen.scan.model.ScanValidationState import co.electriccoin.zcash.ui.screen.scan.model.ScanValidationState
@ -30,7 +29,7 @@ class ScanViewBasicTestSetup(
@Suppress("TestFunctionName") @Suppress("TestFunctionName")
fun DefaultContent() { fun DefaultContent() {
Scan( Scan(
validationResult = ScanValidationState.VALID, snackbarHostState = SnackbarHostState(),
onBack = { onBack = {
onBackCount.incrementAndGet() onBackCount.incrementAndGet()
}, },
@ -40,8 +39,7 @@ class ScanViewBasicTestSetup(
onScanStateChange = { onScanStateChange = {
scanState.set(it) scanState.set(it)
}, },
snackbarHostState = SnackbarHostState(), validationResult = ScanValidationState.VALID,
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }

View File

@ -2,7 +2,6 @@ package co.electriccoin.zcash.ui.screen.settings
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
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.design.component.listitem.ZashiListItemState import co.electriccoin.zcash.ui.design.component.listitem.ZashiListItemState
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
@ -149,7 +148,6 @@ class SettingsViewTestSetup(
), ),
) )
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }

View File

@ -6,6 +6,8 @@ import co.electriccoin.zcash.ui.common.datasource.ProposalDataSource
import co.electriccoin.zcash.ui.common.datasource.ProposalDataSourceImpl import co.electriccoin.zcash.ui.common.datasource.ProposalDataSourceImpl
import co.electriccoin.zcash.ui.common.datasource.RestoreTimestampDataSource import co.electriccoin.zcash.ui.common.datasource.RestoreTimestampDataSource
import co.electriccoin.zcash.ui.common.datasource.RestoreTimestampDataSourceImpl import co.electriccoin.zcash.ui.common.datasource.RestoreTimestampDataSourceImpl
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSourceImpl
import co.electriccoin.zcash.ui.common.datasource.ZashiSpendingKeyDataSource import co.electriccoin.zcash.ui.common.datasource.ZashiSpendingKeyDataSource
import co.electriccoin.zcash.ui.common.datasource.ZashiSpendingKeyDataSourceImpl import co.electriccoin.zcash.ui.common.datasource.ZashiSpendingKeyDataSourceImpl
import org.koin.core.module.dsl.singleOf import org.koin.core.module.dsl.singleOf
@ -18,4 +20,5 @@ val dataSourceModule =
singleOf(::ZashiSpendingKeyDataSourceImpl) bind ZashiSpendingKeyDataSource::class singleOf(::ZashiSpendingKeyDataSourceImpl) bind ZashiSpendingKeyDataSource::class
singleOf(::ProposalDataSourceImpl) bind ProposalDataSource::class singleOf(::ProposalDataSourceImpl) bind ProposalDataSource::class
singleOf(::RestoreTimestampDataSourceImpl) bind RestoreTimestampDataSource::class singleOf(::RestoreTimestampDataSourceImpl) bind RestoreTimestampDataSource::class
singleOf(::WalletBackupDataSourceImpl) bind WalletBackupDataSource::class
} }

View File

@ -12,8 +12,18 @@ import co.electriccoin.zcash.ui.common.provider.RestoreTimestampStorageProvider
import co.electriccoin.zcash.ui.common.provider.RestoreTimestampStorageProviderImpl import co.electriccoin.zcash.ui.common.provider.RestoreTimestampStorageProviderImpl
import co.electriccoin.zcash.ui.common.provider.SelectedAccountUUIDProvider import co.electriccoin.zcash.ui.common.provider.SelectedAccountUUIDProvider
import co.electriccoin.zcash.ui.common.provider.SelectedAccountUUIDProviderImpl import co.electriccoin.zcash.ui.common.provider.SelectedAccountUUIDProviderImpl
import co.electriccoin.zcash.ui.common.provider.ShieldFundsRemindMeCountStorageProvider
import co.electriccoin.zcash.ui.common.provider.ShieldFundsRemindMeCountStorageProviderImpl
import co.electriccoin.zcash.ui.common.provider.ShieldFundsRemindMeTimestampStorageProvider
import co.electriccoin.zcash.ui.common.provider.ShieldFundsRemindMeTimestampStorageProviderImpl
import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider
import co.electriccoin.zcash.ui.common.provider.SynchronizerProviderImpl import co.electriccoin.zcash.ui.common.provider.SynchronizerProviderImpl
import co.electriccoin.zcash.ui.common.provider.WalletBackupFlagStorageProvider
import co.electriccoin.zcash.ui.common.provider.WalletBackupFlagStorageProviderImpl
import co.electriccoin.zcash.ui.common.provider.WalletBackupRemindMeCountStorageProvider
import co.electriccoin.zcash.ui.common.provider.WalletBackupRemindMeCountStorageProviderImpl
import co.electriccoin.zcash.ui.common.provider.WalletBackupRemindMeTimestampStorageProvider
import co.electriccoin.zcash.ui.common.provider.WalletBackupRemindMeTimestampStorageProviderImpl
import org.koin.core.module.dsl.factoryOf import org.koin.core.module.dsl.factoryOf
import org.koin.core.module.dsl.singleOf import org.koin.core.module.dsl.singleOf
import org.koin.dsl.bind import org.koin.dsl.bind
@ -30,4 +40,13 @@ val providerModule =
singleOf(::SynchronizerProviderImpl) bind SynchronizerProvider::class singleOf(::SynchronizerProviderImpl) bind SynchronizerProvider::class
singleOf(::ApplicationStateProviderImpl) bind ApplicationStateProvider::class singleOf(::ApplicationStateProviderImpl) bind ApplicationStateProvider::class
factoryOf(::RestoreTimestampStorageProviderImpl) bind RestoreTimestampStorageProvider::class factoryOf(::RestoreTimestampStorageProviderImpl) bind RestoreTimestampStorageProvider::class
factoryOf(::ShieldFundsRemindMeCountStorageProviderImpl) bind
ShieldFundsRemindMeCountStorageProvider::class
factoryOf(::ShieldFundsRemindMeTimestampStorageProviderImpl) bind
ShieldFundsRemindMeTimestampStorageProvider::class
factoryOf(::WalletBackupRemindMeCountStorageProviderImpl) bind
WalletBackupRemindMeCountStorageProvider::class
factoryOf(::WalletBackupRemindMeTimestampStorageProviderImpl) bind
WalletBackupRemindMeTimestampStorageProvider::class
factoryOf(::WalletBackupFlagStorageProviderImpl) bind WalletBackupFlagStorageProvider::class
} }

View File

@ -23,6 +23,7 @@ import co.electriccoin.zcash.ui.common.usecase.GetCurrentFilteredTransactionsUse
import co.electriccoin.zcash.ui.common.usecase.GetCurrentTransactionsUseCase import co.electriccoin.zcash.ui.common.usecase.GetCurrentTransactionsUseCase
import co.electriccoin.zcash.ui.common.usecase.GetExchangeRateUseCase import co.electriccoin.zcash.ui.common.usecase.GetExchangeRateUseCase
import co.electriccoin.zcash.ui.common.usecase.GetFlexaStatusUseCase import co.electriccoin.zcash.ui.common.usecase.GetFlexaStatusUseCase
import co.electriccoin.zcash.ui.common.usecase.GetHomeMessageUseCase
import co.electriccoin.zcash.ui.common.usecase.GetKeystoneStatusUseCase import co.electriccoin.zcash.ui.common.usecase.GetKeystoneStatusUseCase
import co.electriccoin.zcash.ui.common.usecase.GetMetadataUseCase import co.electriccoin.zcash.ui.common.usecase.GetMetadataUseCase
import co.electriccoin.zcash.ui.common.usecase.GetPersistableWalletUseCase import co.electriccoin.zcash.ui.common.usecase.GetPersistableWalletUseCase
@ -37,7 +38,6 @@ import co.electriccoin.zcash.ui.common.usecase.GetTransactionMetadataUseCase
import co.electriccoin.zcash.ui.common.usecase.GetTransparentAddressUseCase import co.electriccoin.zcash.ui.common.usecase.GetTransparentAddressUseCase
import co.electriccoin.zcash.ui.common.usecase.GetWalletAccountsUseCase import co.electriccoin.zcash.ui.common.usecase.GetWalletAccountsUseCase
import co.electriccoin.zcash.ui.common.usecase.GetWalletRestoringStateUseCase import co.electriccoin.zcash.ui.common.usecase.GetWalletRestoringStateUseCase
import co.electriccoin.zcash.ui.common.usecase.GetWalletStateInformationUseCase
import co.electriccoin.zcash.ui.common.usecase.GetZashiAccountUseCase import co.electriccoin.zcash.ui.common.usecase.GetZashiAccountUseCase
import co.electriccoin.zcash.ui.common.usecase.GetZashiSpendingKeyUseCase import co.electriccoin.zcash.ui.common.usecase.GetZashiSpendingKeyUseCase
import co.electriccoin.zcash.ui.common.usecase.IsCoinbaseAvailableUseCase import co.electriccoin.zcash.ui.common.usecase.IsCoinbaseAvailableUseCase
@ -46,7 +46,7 @@ import co.electriccoin.zcash.ui.common.usecase.IsRestoreSuccessDialogVisibleUseC
import co.electriccoin.zcash.ui.common.usecase.MarkTxMemoAsReadUseCase import co.electriccoin.zcash.ui.common.usecase.MarkTxMemoAsReadUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToAddressBookUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToAddressBookUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToSeedRecoveryUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToWalletBackupUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToTaxExportUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToTaxExportUseCase
import co.electriccoin.zcash.ui.common.usecase.ObserveAddressBookContactsUseCase import co.electriccoin.zcash.ui.common.usecase.ObserveAddressBookContactsUseCase
import co.electriccoin.zcash.ui.common.usecase.ObserveClearSendUseCase import co.electriccoin.zcash.ui.common.usecase.ObserveClearSendUseCase
@ -62,6 +62,7 @@ import co.electriccoin.zcash.ui.common.usecase.ObserveSynchronizerUseCase
import co.electriccoin.zcash.ui.common.usecase.ObserveTransactionSubmitStateUseCase import co.electriccoin.zcash.ui.common.usecase.ObserveTransactionSubmitStateUseCase
import co.electriccoin.zcash.ui.common.usecase.ObserveZashiAccountUseCase import co.electriccoin.zcash.ui.common.usecase.ObserveZashiAccountUseCase
import co.electriccoin.zcash.ui.common.usecase.OnAddressScannedUseCase import co.electriccoin.zcash.ui.common.usecase.OnAddressScannedUseCase
import co.electriccoin.zcash.ui.common.usecase.OnUserSavedWalletBackupUseCase
import co.electriccoin.zcash.ui.common.usecase.OnZip321ScannedUseCase import co.electriccoin.zcash.ui.common.usecase.OnZip321ScannedUseCase
import co.electriccoin.zcash.ui.common.usecase.ParseKeystonePCZTUseCase import co.electriccoin.zcash.ui.common.usecase.ParseKeystonePCZTUseCase
import co.electriccoin.zcash.ui.common.usecase.ParseKeystoneSignInRequestUseCase import co.electriccoin.zcash.ui.common.usecase.ParseKeystoneSignInRequestUseCase
@ -69,6 +70,7 @@ import co.electriccoin.zcash.ui.common.usecase.ParseKeystoneUrToZashiAccountsUse
import co.electriccoin.zcash.ui.common.usecase.PersistEndpointUseCase import co.electriccoin.zcash.ui.common.usecase.PersistEndpointUseCase
import co.electriccoin.zcash.ui.common.usecase.PrefillSendUseCase import co.electriccoin.zcash.ui.common.usecase.PrefillSendUseCase
import co.electriccoin.zcash.ui.common.usecase.RefreshFastestServersUseCase import co.electriccoin.zcash.ui.common.usecase.RefreshFastestServersUseCase
import co.electriccoin.zcash.ui.common.usecase.RemindWalletBackupLaterUseCase
import co.electriccoin.zcash.ui.common.usecase.RescanBlockchainUseCase import co.electriccoin.zcash.ui.common.usecase.RescanBlockchainUseCase
import co.electriccoin.zcash.ui.common.usecase.ResetInMemoryDataUseCase import co.electriccoin.zcash.ui.common.usecase.ResetInMemoryDataUseCase
import co.electriccoin.zcash.ui.common.usecase.ResetSharedPrefsDataUseCase import co.electriccoin.zcash.ui.common.usecase.ResetSharedPrefsDataUseCase
@ -122,7 +124,6 @@ val useCaseModule =
factoryOf(::ShareImageUseCase) factoryOf(::ShareImageUseCase)
factoryOf(::Zip321BuildUriUseCase) factoryOf(::Zip321BuildUriUseCase)
factoryOf(::Zip321ParseUriValidationUseCase) factoryOf(::Zip321ParseUriValidationUseCase)
factoryOf(::GetWalletStateInformationUseCase)
factoryOf(::IsCoinbaseAvailableUseCase) factoryOf(::IsCoinbaseAvailableUseCase)
factoryOf(::GetZashiSpendingKeyUseCase) factoryOf(::GetZashiSpendingKeyUseCase)
factoryOf(::ObservePersistableWalletUseCase) factoryOf(::ObservePersistableWalletUseCase)
@ -184,8 +185,11 @@ val useCaseModule =
factoryOf(::IsRestoreSuccessDialogVisibleUseCase) factoryOf(::IsRestoreSuccessDialogVisibleUseCase)
factoryOf(::ValidateSeedUseCase) factoryOf(::ValidateSeedUseCase)
factoryOf(::RestoreWalletUseCase) factoryOf(::RestoreWalletUseCase)
factoryOf(::NavigateToSeedRecoveryUseCase) factoryOf(::NavigateToWalletBackupUseCase)
factoryOf(::GetKeystoneStatusUseCase) factoryOf(::GetKeystoneStatusUseCase)
factoryOf(::GetCoinbaseStatusUseCase) factoryOf(::GetCoinbaseStatusUseCase)
factoryOf(::GetFlexaStatusUseCase) factoryOf(::GetFlexaStatusUseCase)
factoryOf(::GetHomeMessageUseCase)
factoryOf(::OnUserSavedWalletBackupUseCase)
factoryOf(::RemindWalletBackupLaterUseCase)
} }

View File

@ -12,10 +12,14 @@ import co.electriccoin.zcash.ui.screen.balances.BalanceViewModel
import co.electriccoin.zcash.ui.screen.chooseserver.ChooseServerViewModel import co.electriccoin.zcash.ui.screen.chooseserver.ChooseServerViewModel
import co.electriccoin.zcash.ui.screen.contact.viewmodel.AddContactViewModel import co.electriccoin.zcash.ui.screen.contact.viewmodel.AddContactViewModel
import co.electriccoin.zcash.ui.screen.contact.viewmodel.UpdateContactViewModel import co.electriccoin.zcash.ui.screen.contact.viewmodel.UpdateContactViewModel
import co.electriccoin.zcash.ui.screen.exchangerate.optin.ExchangeRateOptInViewModel
import co.electriccoin.zcash.ui.screen.exchangerate.settings.ExchangeRateSettingsViewModel
import co.electriccoin.zcash.ui.screen.feedback.viewmodel.FeedbackViewModel import co.electriccoin.zcash.ui.screen.feedback.viewmodel.FeedbackViewModel
import co.electriccoin.zcash.ui.screen.flexa.FlexaViewModel import co.electriccoin.zcash.ui.screen.flexa.FlexaViewModel
import co.electriccoin.zcash.ui.screen.home.HomeViewModel import co.electriccoin.zcash.ui.screen.home.HomeViewModel
import co.electriccoin.zcash.ui.screen.home.balance.TransparentBalanceInfoViewModel import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupDetailViewModel
import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupInfoViewModel
import co.electriccoin.zcash.ui.screen.home.transparentbalance.TransparentBalanceInfoViewModel
import co.electriccoin.zcash.ui.screen.integrations.IntegrationsViewModel import co.electriccoin.zcash.ui.screen.integrations.IntegrationsViewModel
import co.electriccoin.zcash.ui.screen.qrcode.viewmodel.QrCodeViewModel import co.electriccoin.zcash.ui.screen.qrcode.viewmodel.QrCodeViewModel
import co.electriccoin.zcash.ui.screen.receive.viewmodel.ReceiveViewModel import co.electriccoin.zcash.ui.screen.receive.viewmodel.ReceiveViewModel
@ -24,13 +28,13 @@ import co.electriccoin.zcash.ui.screen.restore.date.RestoreBDDateViewModel
import co.electriccoin.zcash.ui.screen.restore.estimation.RestoreBDEstimationViewModel import co.electriccoin.zcash.ui.screen.restore.estimation.RestoreBDEstimationViewModel
import co.electriccoin.zcash.ui.screen.restore.height.RestoreBDHeightViewModel import co.electriccoin.zcash.ui.screen.restore.height.RestoreBDHeightViewModel
import co.electriccoin.zcash.ui.screen.restore.seed.RestoreSeedViewModel import co.electriccoin.zcash.ui.screen.restore.seed.RestoreSeedViewModel
import co.electriccoin.zcash.ui.screen.restoresuccess.viewmodel.RestoreSuccessViewModel import co.electriccoin.zcash.ui.screen.restoresuccess.RestoreSuccessViewModel
import co.electriccoin.zcash.ui.screen.reviewtransaction.ReviewTransactionViewModel import co.electriccoin.zcash.ui.screen.reviewtransaction.ReviewTransactionViewModel
import co.electriccoin.zcash.ui.screen.scan.Scan import co.electriccoin.zcash.ui.screen.scan.Scan
import co.electriccoin.zcash.ui.screen.scan.viewmodel.ScanViewModel import co.electriccoin.zcash.ui.screen.scan.viewmodel.ScanViewModel
import co.electriccoin.zcash.ui.screen.scankeystone.viewmodel.ScanKeystonePCZTViewModel import co.electriccoin.zcash.ui.screen.scankeystone.viewmodel.ScanKeystonePCZTViewModel
import co.electriccoin.zcash.ui.screen.scankeystone.viewmodel.ScanKeystoneSignInRequestViewModel import co.electriccoin.zcash.ui.screen.scankeystone.viewmodel.ScanKeystoneSignInRequestViewModel
import co.electriccoin.zcash.ui.screen.seed.SeedRecoveryViewModel import co.electriccoin.zcash.ui.screen.walletbackup.WalletBackupViewModel
import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.SelectKeystoneAccount import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.SelectKeystoneAccount
import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.viewmodel.SelectKeystoneAccountViewModel import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.viewmodel.SelectKeystoneAccountViewModel
import co.electriccoin.zcash.ui.screen.send.SendViewModel import co.electriccoin.zcash.ui.screen.send.SendViewModel
@ -96,7 +100,7 @@ val viewModelModule =
viewModelOf(::IntegrationsViewModel) viewModelOf(::IntegrationsViewModel)
viewModelOf(::FlexaViewModel) viewModelOf(::FlexaViewModel)
viewModelOf(::SendViewModel) viewModelOf(::SendViewModel)
viewModelOf(::SeedRecoveryViewModel) viewModelOf(::WalletBackupViewModel)
viewModelOf(::FeedbackViewModel) viewModelOf(::FeedbackViewModel)
viewModelOf(::SignKeystoneTransactionViewModel) viewModelOf(::SignKeystoneTransactionViewModel)
viewModelOf(::AccountListViewModel) viewModelOf(::AccountListViewModel)
@ -144,4 +148,8 @@ val viewModelModule =
viewModelOf(::RestoreBDDateViewModel) viewModelOf(::RestoreBDDateViewModel)
viewModelOf(::RestoreBDEstimationViewModel) viewModelOf(::RestoreBDEstimationViewModel)
viewModelOf(::TransparentBalanceInfoViewModel) viewModelOf(::TransparentBalanceInfoViewModel)
viewModelOf(::WalletBackupInfoViewModel)
viewModelOf(::ExchangeRateOptInViewModel)
viewModelOf(::ExchangeRateSettingsViewModel)
viewModelOf(::WalletBackupDetailViewModel)
} }

View File

@ -67,19 +67,19 @@ import co.electriccoin.zcash.ui.screen.exportdata.WrapExportPrivateData
import co.electriccoin.zcash.ui.screen.feedback.WrapFeedback import co.electriccoin.zcash.ui.screen.feedback.WrapFeedback
import co.electriccoin.zcash.ui.screen.flexa.FlexaViewModel import co.electriccoin.zcash.ui.screen.flexa.FlexaViewModel
import co.electriccoin.zcash.ui.screen.home.AndroidHome import co.electriccoin.zcash.ui.screen.home.AndroidHome
import co.electriccoin.zcash.ui.screen.home.AndroidSeedBackupInfo import co.electriccoin.zcash.ui.screen.home.backup.AndroidWalletBackupInfo
import co.electriccoin.zcash.ui.screen.home.AndroidWalletDisconnectedInfo import co.electriccoin.zcash.ui.screen.home.disconnected.AndroidWalletDisconnectedInfo
import co.electriccoin.zcash.ui.screen.home.AndroidWalletRestoringInfo import co.electriccoin.zcash.ui.screen.home.restoring.AndroidWalletRestoringInfo
import co.electriccoin.zcash.ui.screen.home.AndroidWalletSyncingInfo import co.electriccoin.zcash.ui.screen.home.syncing.AndroidWalletSyncingInfo
import co.electriccoin.zcash.ui.screen.home.AndroidWalletUpdatingInfo import co.electriccoin.zcash.ui.screen.home.updating.AndroidWalletUpdatingInfo
import co.electriccoin.zcash.ui.screen.home.Home import co.electriccoin.zcash.ui.screen.home.Home
import co.electriccoin.zcash.ui.screen.home.SeedBackupInfo import co.electriccoin.zcash.ui.screen.home.backup.SeedBackupInfo
import co.electriccoin.zcash.ui.screen.home.WalletDisconnectedInfo import co.electriccoin.zcash.ui.screen.home.disconnected.WalletDisconnectedInfo
import co.electriccoin.zcash.ui.screen.home.WalletRestoringInfo import co.electriccoin.zcash.ui.screen.home.restoring.WalletRestoringInfo
import co.electriccoin.zcash.ui.screen.home.WalletSyncingInfo import co.electriccoin.zcash.ui.screen.home.syncing.WalletSyncingInfo
import co.electriccoin.zcash.ui.screen.home.WalletUpdatingInfo import co.electriccoin.zcash.ui.screen.home.updating.WalletUpdatingInfo
import co.electriccoin.zcash.ui.screen.home.balance.AndroidTransparentBalanceInfo import co.electriccoin.zcash.ui.screen.home.transparentbalance.AndroidTransparentBalanceInfo
import co.electriccoin.zcash.ui.screen.home.balance.TransparentBalanceInfo import co.electriccoin.zcash.ui.screen.home.transparentbalance.TransparentBalanceInfo
import co.electriccoin.zcash.ui.screen.integrations.AndroidDialogIntegrations import co.electriccoin.zcash.ui.screen.integrations.AndroidDialogIntegrations
import co.electriccoin.zcash.ui.screen.integrations.AndroidIntegrations import co.electriccoin.zcash.ui.screen.integrations.AndroidIntegrations
import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations
@ -99,10 +99,10 @@ import co.electriccoin.zcash.ui.screen.scankeystone.ScanKeystonePCZTRequest
import co.electriccoin.zcash.ui.screen.scankeystone.ScanKeystoneSignInRequest import co.electriccoin.zcash.ui.screen.scankeystone.ScanKeystoneSignInRequest
import co.electriccoin.zcash.ui.screen.scankeystone.WrapScanKeystonePCZTRequest import co.electriccoin.zcash.ui.screen.scankeystone.WrapScanKeystonePCZTRequest
import co.electriccoin.zcash.ui.screen.scankeystone.WrapScanKeystoneSignInRequest import co.electriccoin.zcash.ui.screen.scankeystone.WrapScanKeystoneSignInRequest
import co.electriccoin.zcash.ui.screen.seed.AndroidSeedRecovery import co.electriccoin.zcash.ui.screen.walletbackup.AndroidWalletBackup
import co.electriccoin.zcash.ui.screen.seed.SeedRecovery import co.electriccoin.zcash.ui.screen.walletbackup.WalletBackup
import co.electriccoin.zcash.ui.screen.seed.backup.AndroidSeedBackup import co.electriccoin.zcash.ui.screen.home.backup.AndroidWalletBackupDetail
import co.electriccoin.zcash.ui.screen.seed.backup.SeedBackup import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupDetail
import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.AndroidSelectKeystoneAccount import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.AndroidSelectKeystoneAccount
import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.SelectKeystoneAccount import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.SelectKeystoneAccount
import co.electriccoin.zcash.ui.screen.send.Send import co.electriccoin.zcash.ui.screen.send.Send
@ -227,8 +227,8 @@ internal fun MainActivity.Navigation() {
composable(CHOOSE_SERVER) { composable(CHOOSE_SERVER) {
WrapChooseServer() WrapChooseServer()
} }
composable<SeedRecovery> { composable<WalletBackup> {
AndroidSeedRecovery() AndroidWalletBackup(it.toRoute())
} }
composable(SUPPORT) { composable(SUPPORT) {
// Pop back stack won't be right if we deep link into support // Pop back stack won't be right if we deep link into support
@ -410,8 +410,8 @@ internal fun MainActivity.Navigation() {
) { ) {
AndroidSeedInfo() AndroidSeedInfo()
} }
composable<SeedBackup> { composable<WalletBackupDetail> {
AndroidSeedBackup(it.toRoute()) AndroidWalletBackupDetail(it.toRoute())
} }
dialog<SeedBackupInfo>( dialog<SeedBackupInfo>(
dialogProperties = dialogProperties =
@ -420,7 +420,7 @@ internal fun MainActivity.Navigation() {
dismissOnClickOutside = false dismissOnClickOutside = false
) )
) { ) {
AndroidSeedBackupInfo() AndroidWalletBackupInfo()
} }
dialog<TransparentBalanceInfo>( dialog<TransparentBalanceInfo>(
dialogProperties = dialogProperties =

View File

@ -8,12 +8,10 @@ import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
import co.electriccoin.zcash.ui.NavigationRouter import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.NavigationTargets.SETTINGS import co.electriccoin.zcash.ui.NavigationTargets.SETTINGS
import co.electriccoin.zcash.ui.common.model.KeystoneAccount import co.electriccoin.zcash.ui.common.model.KeystoneAccount
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.model.WalletAccount import co.electriccoin.zcash.ui.common.model.WalletAccount
import co.electriccoin.zcash.ui.common.model.ZashiAccount import co.electriccoin.zcash.ui.common.model.ZashiAccount
import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase
import co.electriccoin.zcash.ui.common.usecase.GetWalletAccountsUseCase import co.electriccoin.zcash.ui.common.usecase.GetWalletAccountsUseCase
import co.electriccoin.zcash.ui.common.usecase.GetWalletStateInformationUseCase
import co.electriccoin.zcash.ui.design.R import co.electriccoin.zcash.ui.design.R
import co.electriccoin.zcash.ui.design.component.IconButtonState import co.electriccoin.zcash.ui.design.component.IconButtonState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
@ -33,7 +31,6 @@ import kotlinx.coroutines.launch
class ZashiTopAppBarViewModel( class ZashiTopAppBarViewModel(
getWalletAccountUseCase: GetWalletAccountsUseCase, getWalletAccountUseCase: GetWalletAccountsUseCase,
getSelectedWalletAccount: GetSelectedWalletAccountUseCase, getSelectedWalletAccount: GetSelectedWalletAccountUseCase,
getWalletStateInformation: GetWalletStateInformationUseCase,
private val standardPreferenceProvider: StandardPreferenceProvider, private val standardPreferenceProvider: StandardPreferenceProvider,
private val navigationRouter: NavigationRouter, private val navigationRouter: NavigationRouter,
) : ViewModel() { ) : ViewModel() {
@ -43,24 +40,21 @@ class ZashiTopAppBarViewModel(
combine( combine(
getSelectedWalletAccount.observe().filterNotNull(), getSelectedWalletAccount.observe().filterNotNull(),
isHideBalances, isHideBalances,
getWalletStateInformation.observe() ) { currentAccount, isHideBalances ->
) { currentAccount, isHideBalances, walletState -> createState(currentAccount, isHideBalances)
createState(currentAccount, isHideBalances, walletState)
}.stateIn( }.stateIn(
scope = viewModelScope, scope = viewModelScope,
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT), started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
initialValue = initialValue =
createState( createState(
currentAccount = getWalletAccountUseCase.observe().value?.firstOrNull { it.isSelected }, currentAccount = getWalletAccountUseCase.observe().value?.firstOrNull { it.isSelected },
isHideBalances = isHideBalances.value, isHideBalances = isHideBalances.value
topAppBarSubTitleState = getWalletStateInformation.observe().value
) )
) )
private fun createState( private fun createState(
currentAccount: WalletAccount?, currentAccount: WalletAccount?,
isHideBalances: Boolean?, isHideBalances: Boolean?
topAppBarSubTitleState: TopAppBarSubTitleState
) = ZashiMainTopAppBarState( ) = ZashiMainTopAppBarState(
accountSwitchState = accountSwitchState =
AccountSwitchState( AccountSwitchState(
@ -88,19 +82,7 @@ class ZashiTopAppBarViewModel(
icon = R.drawable.ic_app_bar_settings, icon = R.drawable.ic_app_bar_settings,
onClick = ::onSettingsClicked, onClick = ::onSettingsClicked,
contentDescription = stringRes(co.electriccoin.zcash.ui.R.string.settings_menu_content_description) contentDescription = stringRes(co.electriccoin.zcash.ui.R.string.settings_menu_content_description)
), )
subtitle =
when (topAppBarSubTitleState) {
TopAppBarSubTitleState.Disconnected ->
stringRes(
co.electriccoin.zcash.ui.R.string.disconnected_label_new,
)
TopAppBarSubTitleState.Restoring ->
stringRes(
co.electriccoin.zcash.ui.R.string.restoring_wallet_label_new,
)
TopAppBarSubTitleState.None -> null
}
) )
private fun onAccountTypeClicked() = navigationRouter.forward(AccountList) private fun onAccountTypeClicked() = navigationRouter.forward(AccountList)

View File

@ -15,14 +15,12 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.common.appbar.ZashiMainTopAppBarState.AccountType import co.electriccoin.zcash.ui.common.appbar.ZashiMainTopAppBarState.AccountType
import co.electriccoin.zcash.ui.design.R import co.electriccoin.zcash.ui.design.R
@ -32,10 +30,6 @@ import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
import co.electriccoin.zcash.ui.design.util.StringResource
import co.electriccoin.zcash.ui.design.util.getValue
import co.electriccoin.zcash.ui.design.util.stringRes
@Composable @Composable
fun ZashiTopAppBarWithAccountSelection( fun ZashiTopAppBarWithAccountSelection(
@ -61,16 +55,6 @@ fun ZashiTopAppBarWithAccountSelection(
AccountSwitch(state.accountSwitchState) AccountSwitch(state.accountSwitchState)
}, },
) )
if (state.subtitle != null) {
Text(
modifier = Modifier.align(Alignment.BottomCenter),
text = state.subtitle.getValue().uppercase(),
style = ZashiTypography.textXs,
fontWeight = FontWeight.Normal,
color = ZashiColors.Text.textQuaternary
)
}
} }
} }
@ -128,13 +112,9 @@ private fun AccountSwitch(state: AccountSwitchState) {
data class ZashiMainTopAppBarState( data class ZashiMainTopAppBarState(
val accountSwitchState: AccountSwitchState, val accountSwitchState: AccountSwitchState,
val balanceVisibilityButton: IconButtonState, val balanceVisibilityButton: IconButtonState,
val settingsButton: IconButtonState, val settingsButton: IconButtonState
val subtitle: StringResource?
) { ) {
enum class AccountType { enum class AccountType { ZASHI, KEYSTONE }
ZASHI,
KEYSTONE
}
} }
data class AccountSwitchState( data class AccountSwitchState(
@ -155,8 +135,7 @@ private fun ZashiMainTopAppBarPreview() =
onAccountTypeClick = {} onAccountTypeClick = {}
), ),
balanceVisibilityButton = IconButtonState(R.drawable.ic_app_bar_balances_hide) {}, balanceVisibilityButton = IconButtonState(R.drawable.ic_app_bar_balances_hide) {},
settingsButton = IconButtonState(R.drawable.ic_app_bar_settings) {}, settingsButton = IconButtonState(R.drawable.ic_app_bar_settings) {}
subtitle = null
) )
) )
} }
@ -174,8 +153,7 @@ private fun KeystoneMainTopAppBarPreview() =
onAccountTypeClick = {}, onAccountTypeClick = {},
), ),
balanceVisibilityButton = IconButtonState(R.drawable.ic_app_bar_balances_hide) {}, balanceVisibilityButton = IconButtonState(R.drawable.ic_app_bar_balances_hide) {},
settingsButton = IconButtonState(R.drawable.ic_app_bar_settings) {}, settingsButton = IconButtonState(R.drawable.ic_app_bar_settings) {}
subtitle = null
) )
) )
} }
@ -193,8 +171,7 @@ private fun MainTopAppBarWithSubtitlePreview() =
onAccountTypeClick = {}, onAccountTypeClick = {},
), ),
balanceVisibilityButton = IconButtonState(R.drawable.ic_app_bar_balances_hide) {}, balanceVisibilityButton = IconButtonState(R.drawable.ic_app_bar_balances_hide) {},
settingsButton = IconButtonState(R.drawable.ic_app_bar_settings) {}, settingsButton = IconButtonState(R.drawable.ic_app_bar_settings) {}
subtitle = stringRes("Subtitle")
) )
) )
} }

View File

@ -26,7 +26,6 @@ fun ZashiTopAppbar(
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = title?.getValue(), title = title?.getValue(),
subtitle = state?.subtitle?.getValue(),
navigationAction = { navigationAction = {
ZashiTopAppBarBackNavigation( ZashiTopAppBarBackNavigation(
onBack = onBack, onBack = onBack,

View File

@ -0,0 +1,35 @@
package co.electriccoin.zcash.ui.common.datasource
import cash.z.ecc.android.sdk.model.AccountUuid
import co.electriccoin.zcash.ui.common.provider.ShieldFundsRemindMeCountStorageProvider
import co.electriccoin.zcash.ui.common.provider.ShieldFundsRemindMeTimestampStorageProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
interface ShieldFundsRemindMeDataSource {
suspend fun observe(forAccount: AccountUuid): Flow<ShieldFundsAvailability>
}
class ShieldFundsRemindMeDataSourceImpl(
private val shieldFundsRemindMeCountStorageProvider: ShieldFundsRemindMeCountStorageProvider,
private val shieldFundsRemindMeTimestampStorageProvider: ShieldFundsRemindMeTimestampStorageProvider
): ShieldFundsRemindMeDataSource {
override suspend fun observe(forAccount: AccountUuid): Flow<ShieldFundsAvailability> = combine(
shieldFundsRemindMeCountStorageProvider.observe(forAccount),
shieldFundsRemindMeTimestampStorageProvider.observe(forAccount)
) { count, timestamp ->
when {
timestamp == null -> ShieldFundsAvailability.Available(1.days)
count == 1 -> ShieldFundsAvailability.Available(2.days)
count == 2 -> ShieldFundsAvailability.Available(3.days)
else -> ShieldFundsAvailability.Unavailable
}
}
}
sealed interface ShieldFundsAvailability {
data class Available(val nextLockoutDuration: Duration) : ShieldFundsAvailability
data object Unavailable : ShieldFundsAvailability
}

View File

@ -0,0 +1,100 @@
package co.electriccoin.zcash.ui.common.datasource
import co.electriccoin.zcash.ui.common.provider.WalletBackupFlagStorageProvider
import co.electriccoin.zcash.ui.common.provider.WalletBackupRemindMeCountStorageProvider
import co.electriccoin.zcash.ui.common.provider.WalletBackupRemindMeTimestampStorageProvider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import java.time.Instant
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
interface WalletBackupDataSource {
fun observe(): Flow<WalletBackupAvailability>
suspend fun onUserSavedWalletBackup()
suspend fun remindMeLater()
}
class WalletBackupDataSourceImpl(
private val walletBackupFlagStorageProvider: WalletBackupFlagStorageProvider,
private val walletBackupRemindMeCountStorageProvider: WalletBackupRemindMeCountStorageProvider,
private val walletBackupRemindMeTimestampStorageProvider: WalletBackupRemindMeTimestampStorageProvider
) : WalletBackupDataSource {
@OptIn(ExperimentalCoroutinesApi::class)
override fun observe(): Flow<WalletBackupAvailability> = combine(
walletBackupFlagStorageProvider.observe(),
walletBackupRemindMeCountStorageProvider.observe(),
walletBackupRemindMeTimestampStorageProvider.observe()
) { isBackedUp, count, timestamp ->
Triple(isBackedUp, count, timestamp)
}.flatMapLatest { (isBackedUp, count, timestamp) ->
when {
isBackedUp -> flowOf(WalletBackupAvailability.Unavailable)
timestamp == null -> flowOf(WalletBackupAvailability.Available(WalletBackupLockoutDuration.ONE_DAY))
count == 1 -> calculateNext(
lastTimestamp = timestamp,
lastLockoutDuration = WalletBackupLockoutDuration.ONE_DAY,
nextLockoutDuration = WalletBackupLockoutDuration.TWO_DAYS
)
else -> calculateNext(
lastTimestamp = timestamp,
lastLockoutDuration = if (count == 2) {
WalletBackupLockoutDuration.TWO_DAYS
} else {
WalletBackupLockoutDuration.THREE_DAYS
},
nextLockoutDuration = WalletBackupLockoutDuration.THREE_DAYS
)
}
}
override suspend fun onUserSavedWalletBackup() {
walletBackupFlagStorageProvider.store(true)
}
override suspend fun remindMeLater() {
val count = walletBackupRemindMeCountStorageProvider.get()
val timestamp = Instant.now()
walletBackupRemindMeCountStorageProvider.store(count + 1)
walletBackupRemindMeTimestampStorageProvider.store(timestamp)
}
private fun calculateNext(
lastTimestamp: Instant,
lastLockoutDuration: WalletBackupLockoutDuration,
nextLockoutDuration: WalletBackupLockoutDuration
): Flow<WalletBackupAvailability> {
val nextAvailableTimestamp = lastTimestamp.plusMillis(lastLockoutDuration.duration.inWholeMilliseconds)
val now = Instant.now()
return if (nextAvailableTimestamp > now) {
flow {
val remaining = nextAvailableTimestamp.toEpochMilli() - now.toEpochMilli()
emit(WalletBackupAvailability.Unavailable)
delay(remaining)
emit(WalletBackupAvailability.Available(nextLockoutDuration))
}
} else {
flowOf(WalletBackupAvailability.Available(nextLockoutDuration))
}
}
}
sealed interface WalletBackupAvailability {
data class Available(val lockoutDuration: WalletBackupLockoutDuration) : WalletBackupAvailability
data object Unavailable : WalletBackupAvailability
}
enum class WalletBackupLockoutDuration(val duration: Duration) {
ONE_DAY(10.seconds),
TWO_DAYS(20.seconds),
THREE_DAYS(30.seconds)
}

View File

@ -19,16 +19,3 @@ data class WalletSnapshot(
val progress: PercentDecimal, val progress: PercentDecimal,
val synchronizerError: SynchronizerError? val synchronizerError: SynchronizerError?
) )
// TODO [#1370]: WalletSnapshot.canSpend() calculation limitation
// TODO [#1370]: https://github.com/Electric-Coin-Company/zashi-android/issues/1370
// Note this check is not entirely correct - it does not calculate the resulting fee using the new Proposal API. It's
// fine for now, but it's subject to improvement later once we figure out how to handle it in such cases.
fun WalletSnapshot.canSpend(amount: Zatoshi): Boolean = spendableBalance() >= amount
fun WalletSnapshot.totalBalance() = orchardBalance.total + (saplingBalance?.total ?: Zatoshi(0)) + transparentBalance
// Note that considering both to be spendable is subject to change.
// The user experience could be confusing, and in the future we might prefer to ask users
// to transfer their balance to the latest balance type to make it spendable.
fun WalletSnapshot.spendableBalance() = orchardBalance.available + (saplingBalance?.available ?: Zatoshi(0))

View File

@ -0,0 +1,37 @@
package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.PreferenceHolder
import co.electriccoin.zcash.preference.api.PreferenceProvider
import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
interface BooleanStorageProvider {
suspend fun get(): Boolean
suspend fun store(flag: Boolean)
fun observe(): Flow<Boolean>
suspend fun clear()
}
abstract class BaseBooleanStorageProvider(key: PreferenceKey) : BooleanStorageProvider {
protected abstract val preferenceHolder: PreferenceHolder
private val default = BooleanPreferenceDefault(key = key, defaultValue = DEFAULT)
private suspend fun getPreferenceProvider(): PreferenceProvider = preferenceHolder()
override suspend fun get(): Boolean = default.getValue(getPreferenceProvider())
override suspend fun store(flag: Boolean) = default.putValue(getPreferenceProvider(), flag)
override fun observe(): Flow<Boolean> = flow { emitAll(default.observe(getPreferenceProvider())) }
override suspend fun clear() = default.putValue(getPreferenceProvider(), DEFAULT)
}
private const val DEFAULT = false

View File

@ -0,0 +1,37 @@
package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.PreferenceHolder
import co.electriccoin.zcash.preference.api.PreferenceProvider
import co.electriccoin.zcash.preference.model.entry.IntegerPreferenceDefault
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
interface IntStorageProvider {
suspend fun get(): Int
suspend fun store(amount: Int)
fun observe(): Flow<Int>
suspend fun clear()
}
abstract class BaseIntStorageProvider(key: PreferenceKey) : IntStorageProvider {
protected abstract val preferenceHolder: PreferenceHolder
private val default = IntegerPreferenceDefault(key = key, defaultValue = DEFAULT)
private suspend fun getPreferenceProvider(): PreferenceProvider = preferenceHolder()
override suspend fun get(): Int = default.getValue(getPreferenceProvider())
override suspend fun store(amount: Int) = default.putValue(getPreferenceProvider(), amount)
override fun observe(): Flow<Int> = flow { emitAll(default.observe(getPreferenceProvider())) }
override suspend fun clear() = default.putValue(getPreferenceProvider(), DEFAULT)
}
private const val DEFAULT = 0

View File

@ -1,45 +1,10 @@
package co.electriccoin.zcash.ui.common.provider package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.api.PreferenceProvider
import co.electriccoin.zcash.preference.model.entry.PreferenceDefault
import co.electriccoin.zcash.preference.model.entry.PreferenceKey import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import java.time.Instant
interface RestoreTimestampStorageProvider { interface RestoreTimestampStorageProvider : TimestampStorageProvider
suspend fun get(): Instant?
suspend fun store(key: Instant)
suspend fun clear()
}
class RestoreTimestampStorageProviderImpl( class RestoreTimestampStorageProviderImpl(
private val encryptedPreferenceProvider: EncryptedPreferenceProvider override val preferenceHolder: EncryptedPreferenceProvider
) : RestoreTimestampStorageProvider { ) : BaseTimestampStorageProvider(PreferenceKey("restore_timestamp")), RestoreTimestampStorageProvider
private val default = RestoreTimestampPreferenceDefault()
override suspend fun get(): Instant? = default.getValue(encryptedPreferenceProvider())
override suspend fun store(key: Instant) {
default.putValue(encryptedPreferenceProvider(), key)
}
override suspend fun clear() {
default.putValue(encryptedPreferenceProvider(), null)
}
}
private class RestoreTimestampPreferenceDefault : PreferenceDefault<Instant?> {
override val key: PreferenceKey = PreferenceKey("restore_timestamp")
override suspend fun getValue(preferenceProvider: PreferenceProvider) =
preferenceProvider.getLong(key)?.let {
Instant.ofEpochMilli(it)
}
override suspend fun putValue(
preferenceProvider: PreferenceProvider,
newValue: Instant?
) = preferenceProvider.putLong(key, newValue?.toEpochMilli())
}

View File

@ -0,0 +1,39 @@
package co.electriccoin.zcash.ui.common.provider
import cash.z.ecc.android.sdk.model.AccountUuid
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.api.PreferenceProvider
import co.electriccoin.zcash.preference.model.entry.IntegerPreferenceDefault
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import kotlinx.coroutines.flow.Flow
interface ShieldFundsRemindMeCountStorageProvider {
suspend fun get(forAccount: AccountUuid): Int
suspend fun store(forAccount: AccountUuid, amount: Int)
suspend fun observe(forAccount: AccountUuid): Flow<Int>
}
class ShieldFundsRemindMeCountStorageProviderImpl(
private val encryptedPreferenceProvider: EncryptedPreferenceProvider
) : ShieldFundsRemindMeCountStorageProvider {
@OptIn(ExperimentalStdlibApi::class)
private fun getDefault(forAccount: AccountUuid): IntegerPreferenceDefault {
val key = PreferenceKey("shield_funds_remind_me_count_${forAccount.value.toHexString()}")
return IntegerPreferenceDefault(key = key, defaultValue = 0)
}
override suspend fun get(forAccount: AccountUuid): Int {
return getDefault(forAccount).getValue(encryptedPreferenceProvider())
}
override suspend fun store(forAccount: AccountUuid, amount: Int) {
getDefault(forAccount).putValue(encryptedPreferenceProvider(), amount)
}
override suspend fun observe(forAccount: AccountUuid): Flow<Int> {
return getDefault(forAccount).observe(encryptedPreferenceProvider())
}
}

View File

@ -0,0 +1,38 @@
package co.electriccoin.zcash.ui.common.provider
import cash.z.ecc.android.sdk.model.AccountUuid
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.TimestampPreferenceDefault
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import kotlinx.coroutines.flow.Flow
import java.time.Instant
interface ShieldFundsRemindMeTimestampStorageProvider {
suspend fun get(forAccount: AccountUuid): Instant?
suspend fun store(forAccount: AccountUuid, timestamp: Instant)
suspend fun observe(forAccount: AccountUuid): Flow<Instant?>
}
class ShieldFundsRemindMeTimestampStorageProviderImpl(
private val encryptedPreferenceProvider: EncryptedPreferenceProvider
) : ShieldFundsRemindMeTimestampStorageProvider {
@OptIn(ExperimentalStdlibApi::class)
private fun getDefault(forAccount: AccountUuid): TimestampPreferenceDefault {
val key = PreferenceKey("shield_funds_remind_me_timestamp_${forAccount.value.toHexString()}")
return TimestampPreferenceDefault(key = key)
}
override suspend fun get(forAccount: AccountUuid): Instant? {
return getDefault(forAccount).getValue(encryptedPreferenceProvider())
}
override suspend fun store(forAccount: AccountUuid, timestamp: Instant) {
getDefault(forAccount).putValue(encryptedPreferenceProvider(), timestamp)
}
override suspend fun observe(forAccount: AccountUuid): Flow<Instant?> {
return getDefault(forAccount).observe(encryptedPreferenceProvider())
}
}

View File

@ -53,7 +53,7 @@ class SynchronizerProviderImpl(
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
.stateIn( .stateIn(
scope = scope, scope = scope,
started = SharingStarted.WhileSubscribed(Duration.ZERO, Duration.ZERO), started = SharingStarted.Lazily,
initialValue = null initialValue = null
) )

View File

@ -0,0 +1,36 @@
package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.PreferenceHolder
import co.electriccoin.zcash.preference.api.PreferenceProvider
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
import co.electriccoin.zcash.preference.model.entry.TimestampPreferenceDefault
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import java.time.Instant
interface TimestampStorageProvider {
suspend fun get(): Instant?
suspend fun store(timestamp: Instant)
fun observe(): Flow<Instant?>
suspend fun clear()
}
abstract class BaseTimestampStorageProvider(key: PreferenceKey) : TimestampStorageProvider {
protected abstract val preferenceHolder: PreferenceHolder
private val default = TimestampPreferenceDefault(key)
private suspend fun getPreferenceProvider(): PreferenceProvider = preferenceHolder()
override suspend fun get(): Instant? = default.getValue(getPreferenceProvider())
override suspend fun store(timestamp: Instant) = default.putValue(getPreferenceProvider(), timestamp)
override fun observe(): Flow<Instant?> = flow { emitAll(default.observe(getPreferenceProvider())) }
override suspend fun clear() = default.putValue(getPreferenceProvider(), null)
}

View File

@ -0,0 +1,11 @@
package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
interface WalletBackupFlagStorageProvider : BooleanStorageProvider
class WalletBackupFlagStorageProviderImpl(
override val preferenceHolder: EncryptedPreferenceProvider
) : BaseBooleanStorageProvider(key = PreferenceKey("wallet_backup_flag")),
WalletBackupFlagStorageProvider

View File

@ -0,0 +1,11 @@
package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
interface WalletBackupRemindMeCountStorageProvider : IntStorageProvider
class WalletBackupRemindMeCountStorageProviderImpl(
override val preferenceHolder: EncryptedPreferenceProvider
) : BaseIntStorageProvider(key = PreferenceKey("wallet_backup_remind_me_count")),
WalletBackupRemindMeCountStorageProvider

View File

@ -0,0 +1,11 @@
package co.electriccoin.zcash.ui.common.provider
import co.electriccoin.zcash.preference.EncryptedPreferenceProvider
import co.electriccoin.zcash.preference.model.entry.PreferenceKey
interface WalletBackupRemindMeTimestampStorageProvider : TimestampStorageProvider
class WalletBackupRemindMeTimestampStorageProviderImpl(
override val preferenceHolder: EncryptedPreferenceProvider
) : BaseTimestampStorageProvider(key = PreferenceKey("wallet_backup_remind_me_timestamp")),
WalletBackupRemindMeTimestampStorageProvider

View File

@ -5,13 +5,11 @@ 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.common.provider.SynchronizerProvider import co.electriccoin.zcash.ui.common.provider.SynchronizerProvider
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
import co.electriccoin.zcash.ui.common.wallet.StaleLock import co.electriccoin.zcash.ui.common.wallet.StaleLock
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
import co.electriccoin.zcash.ui.screen.exchangerate.optin.ExchangeRateOptIn
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -37,26 +35,19 @@ import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
interface ExchangeRateRepository { interface ExchangeRateRepository {
val isExchangeRateUsdOptedIn: StateFlow<Boolean?>
val state: StateFlow<ExchangeRateState> val state: StateFlow<ExchangeRateState>
fun optInExchangeRateUsd(optIn: Boolean) fun optInExchangeRateUsd(optIn: Boolean)
fun dismissOptInExchangeRateUsd()
fun refreshExchangeRateUsd()
} }
class ExchangeRateRepositoryImpl( class ExchangeRateRepositoryImpl(
private val synchronizerProvider: SynchronizerProvider, private val synchronizerProvider: SynchronizerProvider,
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())
override val isExchangeRateUsdOptedIn: StateFlow<Boolean?> = private val isExchangeRateUsdOptedIn = nullableBooleanStateFlow(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN)
nullableBooleanStateFlow(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN)
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private val exchangeRateUsdInternal = private val exchangeRateUsdInternal =
@ -167,17 +158,13 @@ class ExchangeRateRepositoryImpl(
} }
false -> ExchangeRateState.OptedOut false -> ExchangeRateState.OptedOut
null -> null -> ExchangeRateState.OptIn
ExchangeRateState.OptIn(
onDismissClick = ::dismissWidgetOptInExchangeRateUsd,
onPrimaryClick = ::showOptInExchangeRateUsd
)
} }
return lastExchangeRateUsdValue return lastExchangeRateUsdValue
} }
override fun refreshExchangeRateUsd() { private fun refreshExchangeRateUsd() {
refreshExchangeRateUsdInternal() refreshExchangeRateUsdInternal()
} }
@ -192,20 +179,8 @@ class ExchangeRateRepositoryImpl(
override fun optInExchangeRateUsd(optIn: Boolean) { override fun optInExchangeRateUsd(optIn: Boolean) {
setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, optIn) setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, optIn)
navigationRouter.back()
} }
override fun dismissOptInExchangeRateUsd() {
setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, false)
navigationRouter.back()
}
private fun dismissWidgetOptInExchangeRateUsd() {
setNullableBooleanPreference(StandardPreferenceKeys.EXCHANGE_RATE_OPTED_IN, false)
}
private fun showOptInExchangeRateUsd() = navigationRouter.forward(ExchangeRateOptIn)
private fun nullableBooleanStateFlow(default: NullableBooleanPreferenceDefault): StateFlow<Boolean?> = private fun nullableBooleanStateFlow(default: NullableBooleanPreferenceDefault): StateFlow<Boolean?> =
flow { flow {
emitAll(default.observe(standardPreferenceProvider())) emitAll(default.observe(standardPreferenceProvider()))
@ -217,7 +192,7 @@ class ExchangeRateRepositoryImpl(
private fun setNullableBooleanPreference( private fun setNullableBooleanPreference(
default: NullableBooleanPreferenceDefault, default: NullableBooleanPreferenceDefault,
newState: Boolean newState: Boolean?
) { ) {
scope.launch { scope.launch {
default.putValue(standardPreferenceProvider(), newState) default.putValue(standardPreferenceProvider(), newState)

View File

@ -20,7 +20,6 @@ import co.electriccoin.zcash.ui.common.datasource.AccountDataSource
import co.electriccoin.zcash.ui.common.datasource.RestoreTimestampDataSource import co.electriccoin.zcash.ui.common.datasource.RestoreTimestampDataSource
import co.electriccoin.zcash.ui.common.model.FastestServersState import co.electriccoin.zcash.ui.common.model.FastestServersState
import co.electriccoin.zcash.ui.common.model.OnboardingState import co.electriccoin.zcash.ui.common.model.OnboardingState
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.model.WalletAccount import co.electriccoin.zcash.ui.common.model.WalletAccount
import co.electriccoin.zcash.ui.common.model.WalletRestoringState import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.model.WalletSnapshot import co.electriccoin.zcash.ui.common.model.WalletSnapshot
@ -81,11 +80,6 @@ interface WalletRepository {
*/ */
val walletRestoringState: StateFlow<WalletRestoringState> val walletRestoringState: StateFlow<WalletRestoringState>
/**
* A flow of the wallet current state information that should be displayed in screens top app bar.
*/
val walletStateInformation: StateFlow<TopAppBarSubTitleState>
fun persistWallet(persistableWallet: PersistableWallet) fun persistWallet(persistableWallet: PersistableWallet)
fun persistOnboardingState(onboardingState: OnboardingState) fun persistOnboardingState(onboardingState: OnboardingState)
@ -228,29 +222,6 @@ class WalletRepositoryImpl(
initialValue = WalletRestoringState.NONE initialValue = WalletRestoringState.NONE
) )
@OptIn(ExperimentalCoroutinesApi::class)
override val walletStateInformation: StateFlow<TopAppBarSubTitleState> =
synchronizer
.filterNotNull()
.flatMapLatest { synchronizer ->
combine(
synchronizer.status,
walletRestoringState
) { status: Synchronizer.Status?, walletRestoringState: WalletRestoringState ->
if (Synchronizer.Status.DISCONNECTED == status) {
TopAppBarSubTitleState.Disconnected
} else if (WalletRestoringState.RESTORING == walletRestoringState) {
TopAppBarSubTitleState.Restoring
} else {
TopAppBarSubTitleState.None
}
}
}.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
initialValue = TopAppBarSubTitleState.None
)
/** /**
* Persists a wallet asynchronously. Clients observe [secretState] to see the side effects. * Persists a wallet asynchronously. Clients observe [secretState] to see the side effects.
*/ */

View File

@ -0,0 +1,87 @@
package co.electriccoin.zcash.ui.common.usecase
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.model.Zatoshi
import co.electriccoin.zcash.ui.common.datasource.WalletBackupAvailability
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
import co.electriccoin.zcash.ui.common.repository.WalletRepository
import co.electriccoin.zcash.ui.common.viewmodel.SynchronizerError
import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState
import co.electriccoin.zcash.ui.util.Quadruple
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlin.time.Duration.Companion.seconds
class GetHomeMessageUseCase(
private val walletRepository: WalletRepository,
private val walletBackupDataSource: WalletBackupDataSource,
private val exchangeRateRepository: ExchangeRateRepository,
) {
@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
fun observe() = combine(
walletRepository.currentWalletSnapshot.filterNotNull(),
walletRepository.walletRestoringState,
walletBackupDataSource.observe(),
exchangeRateRepository.state.map { it == ExchangeRateState.OptIn }.distinctUntilChanged(),
) { walletSnapshot, walletStateInformation, backup, isCCAvailable ->
Quadruple(walletSnapshot, walletStateInformation, backup, isCCAvailable)
}.flatMapLatest { (walletSnapshot, walletStateInformation, backup, isCCAvailable) ->
when {
walletSnapshot.synchronizerError != null -> {
flowOf(HomeMessageData.Error(walletSnapshot.synchronizerError))
}
walletSnapshot.status == Synchronizer.Status.DISCONNECTED -> {
flowOf(HomeMessageData.Disconnected)
}
walletSnapshot.status in listOf(
Synchronizer.Status.INITIALIZING,
Synchronizer.Status.SYNCING,
Synchronizer.Status.STOPPED
) -> {
flow {
val progress = walletSnapshot.progress.decimal * 100f
val result = when {
walletStateInformation == WalletRestoringState.RESTORING -> {
HomeMessageData.Restoring(
progress = progress,
)
}
else -> {
HomeMessageData.Syncing(progress = progress)
}
}
emit(result)
}
}
backup is WalletBackupAvailability.Available -> flowOf(HomeMessageData.Backup)
isCCAvailable -> flowOf(HomeMessageData.EnableCurrencyConversion)
else -> flowOf(null)
}
}.debounce(.5.seconds)
}
sealed interface HomeMessageData {
data object EnableCurrencyConversion : HomeMessageData
data class TransparentBalance(val zatoshi: Zatoshi) : HomeMessageData
data object Backup : HomeMessageData
data object Disconnected : HomeMessageData
data class Error(val synchronizerError: SynchronizerError) : HomeMessageData
data class Restoring(val progress: Float) : HomeMessageData
data class Syncing(val progress: Float) : HomeMessageData
data object Updating : HomeMessageData
}

View File

@ -1,9 +0,0 @@
package co.electriccoin.zcash.ui.common.usecase
import co.electriccoin.zcash.ui.common.repository.WalletRepository
class GetWalletStateInformationUseCase(
private val walletRepository: WalletRepository
) {
fun observe() = walletRepository.walletStateInformation
}

View File

@ -7,13 +7,13 @@ import co.electriccoin.zcash.ui.common.repository.BiometricRequest
import co.electriccoin.zcash.ui.common.repository.BiometricsCancelledException import co.electriccoin.zcash.ui.common.repository.BiometricsCancelledException
import co.electriccoin.zcash.ui.common.repository.BiometricsFailureException import co.electriccoin.zcash.ui.common.repository.BiometricsFailureException
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.seed.SeedRecovery import co.electriccoin.zcash.ui.screen.walletbackup.WalletBackup
class NavigateToSeedRecoveryUseCase( class NavigateToWalletBackupUseCase(
private val navigationRouter: NavigationRouter, private val navigationRouter: NavigationRouter,
private val biometricRepository: BiometricRepository private val biometricRepository: BiometricRepository
) { ) {
suspend operator fun invoke() { suspend operator fun invoke(isOpenedFromSeedBackupInfo: Boolean) {
try { try {
biometricRepository.requestBiometrics( biometricRepository.requestBiometrics(
BiometricRequest( BiometricRequest(
@ -24,7 +24,7 @@ class NavigateToSeedRecoveryUseCase(
) )
) )
) )
navigationRouter.forward(SeedRecovery) navigationRouter.forward(WalletBackup(isOpenedFromSeedBackupInfo = isOpenedFromSeedBackupInfo))
} catch (_: BiometricsFailureException) { } catch (_: BiometricsFailureException) {
// do nothing // do nothing
} catch (_: BiometricsCancelledException) { } catch (_: BiometricsCancelledException) {

View File

@ -0,0 +1,14 @@
package co.electriccoin.zcash.ui.common.usecase
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource
class OnUserSavedWalletBackupUseCase(
private val navigationRouter: NavigationRouter,
private val walletBackupDataSource: WalletBackupDataSource
) {
suspend operator fun invoke() {
walletBackupDataSource.remindMeLater()
navigationRouter.backToRoot()
}
}

View File

@ -0,0 +1,14 @@
package co.electriccoin.zcash.ui.common.usecase
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.common.datasource.WalletBackupDataSource
class RemindWalletBackupLaterUseCase(
private val navigationRouter: NavigationRouter,
private val walletBackupDataSource: WalletBackupDataSource
) {
suspend operator fun invoke() {
walletBackupDataSource.remindMeLater()
navigationRouter.backToRoot()
}
}

View File

@ -3,7 +3,6 @@ package co.electriccoin.zcash.ui.common.viewmodel
import android.app.Application import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.WalletCoordinator import cash.z.ecc.android.sdk.WalletCoordinator
import cash.z.ecc.android.sdk.WalletInitMode import cash.z.ecc.android.sdk.WalletInitMode
import cash.z.ecc.android.sdk.model.BlockHeight import cash.z.ecc.android.sdk.model.BlockHeight
@ -13,12 +12,10 @@ import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.sdk.type.fromResources import cash.z.ecc.sdk.type.fromResources
import co.electriccoin.zcash.preference.StandardPreferenceProvider import co.electriccoin.zcash.preference.StandardPreferenceProvider
import co.electriccoin.zcash.spackle.Twig import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.common.model.OnboardingState import co.electriccoin.zcash.ui.common.model.OnboardingState
import co.electriccoin.zcash.ui.common.model.WalletRestoringState import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.model.WalletSnapshot import co.electriccoin.zcash.ui.common.model.WalletSnapshot
import co.electriccoin.zcash.ui.common.provider.GetDefaultServersProvider import co.electriccoin.zcash.ui.common.provider.GetDefaultServersProvider
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
import co.electriccoin.zcash.ui.common.repository.WalletRepository import co.electriccoin.zcash.ui.common.repository.WalletRepository
import co.electriccoin.zcash.ui.common.usecase.GetSynchronizerUseCase import co.electriccoin.zcash.ui.common.usecase.GetSynchronizerUseCase
import co.electriccoin.zcash.ui.common.usecase.IsFlexaAvailableUseCase import co.electriccoin.zcash.ui.common.usecase.IsFlexaAvailableUseCase
@ -44,39 +41,19 @@ class WalletViewModel(
application: Application, application: Application,
private val walletCoordinator: WalletCoordinator, private val walletCoordinator: WalletCoordinator,
private val walletRepository: WalletRepository, private val walletRepository: WalletRepository,
private val exchangeRateRepository: ExchangeRateRepository,
private val standardPreferenceProvider: StandardPreferenceProvider, private val standardPreferenceProvider: StandardPreferenceProvider,
private val getAvailableServers: GetDefaultServersProvider, private val getAvailableServers: GetDefaultServersProvider,
private val resetInMemoryData: ResetInMemoryDataUseCase, private val resetInMemoryData: ResetInMemoryDataUseCase,
private val resetSharedPrefsData: ResetSharedPrefsDataUseCase, private val resetSharedPrefsData: ResetSharedPrefsDataUseCase,
private val isFlexaAvailable: IsFlexaAvailableUseCase, private val isFlexaAvailable: IsFlexaAvailableUseCase,
private val getSynchronizer: GetSynchronizerUseCase, private val getSynchronizer: GetSynchronizerUseCase,
private val navigationRouter: NavigationRouter,
) : AndroidViewModel(application) { ) : AndroidViewModel(application) {
val synchronizer = walletRepository.synchronizer val synchronizer = walletRepository.synchronizer
val walletStateInformation = walletRepository.walletStateInformation
val secretState: StateFlow<SecretState> = walletRepository.secretState val secretState: StateFlow<SecretState> = walletRepository.secretState
val currentWalletSnapshot: StateFlow<WalletSnapshot?> = walletRepository.currentWalletSnapshot val currentWalletSnapshot: StateFlow<WalletSnapshot?> = walletRepository.currentWalletSnapshot
val isExchangeRateUsdOptedIn = exchangeRateRepository.isExchangeRateUsdOptedIn
val exchangeRateUsd = exchangeRateRepository.state
fun optInExchangeRateUsd(optIn: Boolean) {
exchangeRateRepository.optInExchangeRateUsd(optIn)
}
fun dismissOptInExchangeRateUsd() {
navigationRouter.back()
}
fun onSkipClick() {
navigationRouter.back()
}
fun persistNewWalletAndRestoringState(state: WalletRestoringState) { fun persistNewWalletAndRestoringState(state: WalletRestoringState) {
val application = getApplication<Application>() val application = getApplication<Application>()
@ -259,5 +236,3 @@ sealed class SynchronizerError {
override fun getStackTrace(limit: Int?): String? = null override fun getStackTrace(limit: Int?): String? = null
} }
} }
fun Synchronizer.Status.isSynced() = this == Synchronizer.Status.SYNCED

View File

@ -13,10 +13,7 @@ sealed interface ExchangeRateState {
val onRefresh: () -> Unit, val onRefresh: () -> Unit,
) : ExchangeRateState ) : ExchangeRateState
data class OptIn( data object OptIn : ExchangeRateState
val onDismissClick: () -> Unit = {},
val onPrimaryClick: () -> Unit = {}
) : ExchangeRateState
data object OptedOut : ExchangeRateState data object OptedOut : ExchangeRateState
} }

View File

@ -26,7 +26,6 @@ object ZashiMainTopAppBarStateFixture {
) = ZashiMainTopAppBarState( ) = ZashiMainTopAppBarState(
accountSwitchState = accountSwitchState, accountSwitchState = accountSwitchState,
balanceVisibilityButton = balanceVisibilityButton, balanceVisibilityButton = balanceVisibilityButton,
settingsButton = settingsButton, settingsButton = settingsButton
subtitle = null
) )
} }

View File

@ -16,4 +16,8 @@ data class PersistableWalletPreferenceDefault(
preferenceProvider: PreferenceProvider, preferenceProvider: PreferenceProvider,
newValue: PersistableWallet? newValue: PersistableWallet?
) = preferenceProvider.putString(key, newValue?.toJson()?.toString()) ) = preferenceProvider.putString(key, newValue?.toJson()?.toString())
suspend fun remove(preferenceProvider: PreferenceProvider) {
preferenceProvider.remove(key)
}
} }

View File

@ -9,13 +9,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.configuration.api.ConfigurationProvider import co.electriccoin.zcash.configuration.api.ConfigurationProvider
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.LocalActivity import co.electriccoin.zcash.ui.common.compose.LocalActivity
import co.electriccoin.zcash.ui.common.model.VersionInfo import co.electriccoin.zcash.ui.common.model.VersionInfo
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.about.view.About import co.electriccoin.zcash.ui.screen.about.view.About
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
@ -26,9 +23,6 @@ import org.koin.compose.koinInject
@Composable @Composable
internal fun WrapAbout(goBack: () -> Unit) { internal fun WrapAbout(goBack: () -> Unit) {
val activity = LocalActivity.current val activity = LocalActivity.current
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
BackHandler { BackHandler {
goBack() goBack()
@ -49,7 +43,6 @@ internal fun WrapAbout(goBack: () -> Unit) {
About( About(
onBack = goBack, onBack = goBack,
versionInfo = versionInfo,
configInfo = configInfo, configInfo = configInfo,
onPrivacyPolicy = { onPrivacyPolicy = {
openPrivacyPolicyInWebBrowser( openPrivacyPolicyInWebBrowser(
@ -59,7 +52,7 @@ internal fun WrapAbout(goBack: () -> Unit) {
) )
}, },
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
topAppBarSubTitleState = walletState, versionInfo = versionInfo,
) )
} }

View File

@ -29,7 +29,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.VersionInfo import co.electriccoin.zcash.ui.common.model.VersionInfo
import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
import co.electriccoin.zcash.ui.design.component.ZashiTopAppBarBackNavigation import co.electriccoin.zcash.ui.design.component.ZashiTopAppBarBackNavigation
@ -48,13 +47,11 @@ import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
@Composable @Composable
@Suppress("LongParameterList")
fun About( fun About(
onBack: () -> Unit, onBack: () -> Unit,
configInfo: ConfigInfo, configInfo: ConfigInfo,
onPrivacyPolicy: () -> Unit, onPrivacyPolicy: () -> Unit,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
topAppBarSubTitleState: TopAppBarSubTitleState,
versionInfo: VersionInfo, versionInfo: VersionInfo,
) { ) {
Scaffold( Scaffold(
@ -63,7 +60,6 @@ fun About(
onBack = onBack, onBack = onBack,
versionInfo = versionInfo, versionInfo = versionInfo,
configInfo = configInfo, configInfo = configInfo,
subTitleState = topAppBarSubTitleState,
) )
}, },
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
@ -85,16 +81,9 @@ fun About(
private fun AboutTopAppBar( private fun AboutTopAppBar(
onBack: () -> Unit, onBack: () -> Unit,
versionInfo: VersionInfo, versionInfo: VersionInfo,
configInfo: ConfigInfo, configInfo: ConfigInfo
subTitleState: TopAppBarSubTitleState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
title = stringResource(id = R.string.about_title), title = stringResource(id = R.string.about_title),
navigationAction = { navigationAction = {
ZashiTopAppBarBackNavigation(onBack = onBack) ZashiTopAppBarBackNavigation(onBack = onBack)
@ -198,7 +187,6 @@ private fun AboutPreview() =
configInfo = ConfigInfoFixture.new(), configInfo = ConfigInfoFixture.new(),
onPrivacyPolicy = {}, onPrivacyPolicy = {},
snackbarHostState = SnackbarHostState(), snackbarHostState = SnackbarHostState(),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
versionInfo = VersionInfoFixture.new(), versionInfo = VersionInfoFixture.new(),
) )
} }

View File

@ -6,8 +6,6 @@ import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.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
import co.electriccoin.zcash.ui.screen.addressbook.viewmodel.SelectRecipientViewModel import co.electriccoin.zcash.ui.screen.addressbook.viewmodel.SelectRecipientViewModel
@ -23,9 +21,7 @@ internal fun WrapAddressBook(args: AddressBookArgs) {
@Composable @Composable
private fun WrapAddressBook() { private fun WrapAddressBook() {
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<AddressBookViewModel>() val viewModel = koinViewModel<AddressBookViewModel>()
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { BackHandler {
@ -34,15 +30,12 @@ private fun WrapAddressBook() {
AddressBookView( AddressBookView(
state = state, state = state,
topAppBarSubTitleState = walletState,
) )
} }
@Composable @Composable
private fun WrapSelectRecipient() { private fun WrapSelectRecipient() {
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<SelectRecipientViewModel>() val viewModel = koinViewModel<SelectRecipientViewModel>()
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { BackHandler {
@ -51,7 +44,6 @@ private fun WrapSelectRecipient() {
AddressBookView( AddressBookView(
state = state, state = state,
topAppBarSubTitleState = walletState,
) )
} }

View File

@ -40,7 +40,6 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.design.component.BlankBgScaffold import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
@ -67,14 +66,12 @@ import co.electriccoin.zcash.ui.screen.addressbook.model.AddressBookState
@Composable @Composable
fun AddressBookView( fun AddressBookView(
state: AddressBookState, state: AddressBookState
topAppBarSubTitleState: TopAppBarSubTitleState
) { ) {
BlankBgScaffold( BlankBgScaffold(
topBar = { topBar = {
AddressBookTopAppBar( AddressBookTopAppBar(
onBack = state.onBack, onBack = state.onBack,
subTitleState = topAppBarSubTitleState,
state = state state = state
) )
} }
@ -322,17 +319,10 @@ private fun AddContactButton(
@Composable @Composable
private fun AddressBookTopAppBar( private fun AddressBookTopAppBar(
onBack: () -> Unit, onBack: () -> Unit,
subTitleState: TopAppBarSubTitleState,
state: AddressBookState, state: AddressBookState,
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = state.title.getValue(), title = state.title.getValue(),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
modifier = Modifier.testTag(AddressBookTag.TOP_APP_BAR), modifier = Modifier.testTag(AddressBookTag.TOP_APP_BAR),
showTitleLogo = true, showTitleLogo = true,
navigationAction = { navigationAction = {
@ -382,7 +372,6 @@ private fun AddressBookDataPreview() {
), ),
title = stringRes("Address book") title = stringRes("Address book")
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }
@ -447,7 +436,6 @@ private fun SelectRecipientDataPreview() {
), ),
title = stringRes("Select Recipient") title = stringRes("Select Recipient")
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }
@ -472,7 +460,6 @@ private fun LoadingPreview() {
), ),
title = stringRes("Select Recipient") title = stringRes("Select Recipient")
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }
@ -497,7 +484,6 @@ private fun EmptyAddressBookPreview() {
), ),
title = stringRes("Address Book") title = stringRes("Address Book")
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }
@ -535,7 +521,6 @@ private fun EmptySelectRecipientPreview() {
), ),
title = stringRes("Select Recipient") title = stringRes("Select Recipient")
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }

View File

@ -24,7 +24,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastForEachIndexed import androidx.compose.ui.util.fastForEachIndexed
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.design.component.BlankBgScaffold import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.ZashiButton import co.electriccoin.zcash.ui.design.component.ZashiButton
@ -47,13 +46,11 @@ import kotlinx.collections.immutable.persistentListOf
@Composable @Composable
fun AdvancedSettings( fun AdvancedSettings(
state: AdvancedSettingsState, state: AdvancedSettingsState,
topAppBarSubTitleState: TopAppBarSubTitleState,
) { ) {
BlankBgScaffold( BlankBgScaffold(
topBar = { topBar = {
AdvancedSettingsTopAppBar( AdvancedSettingsTopAppBar(
onBack = state.onBack, onBack = state.onBack,
subTitleState = topAppBarSubTitleState,
) )
} }
) { paddingValues -> ) { paddingValues ->
@ -114,17 +111,10 @@ private fun Info() {
@Composable @Composable
private fun AdvancedSettingsTopAppBar( private fun AdvancedSettingsTopAppBar(
onBack: () -> Unit, onBack: () -> Unit
subTitleState: TopAppBarSubTitleState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = stringResource(id = R.string.advanced_settings_title), title = stringResource(id = R.string.advanced_settings_title),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
modifier = Modifier.testTag(AdvancedSettingsTag.ADVANCED_SETTINGS_TOP_APP_BAR), modifier = Modifier.testTag(AdvancedSettingsTag.ADVANCED_SETTINGS_TOP_APP_BAR),
showTitleLogo = true, showTitleLogo = true,
navigationAction = { navigationAction = {
@ -170,6 +160,5 @@ private fun AdvancedSettingsPreview() =
onClick = {} onClick = {}
) )
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }

View File

@ -8,12 +8,12 @@ import co.electriccoin.zcash.ui.NavigationTargets
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.model.WalletRestoringState import co.electriccoin.zcash.ui.common.model.WalletRestoringState
import co.electriccoin.zcash.ui.common.usecase.GetWalletRestoringStateUseCase import co.electriccoin.zcash.ui.common.usecase.GetWalletRestoringStateUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToSeedRecoveryUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToWalletBackupUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToTaxExportUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToTaxExportUseCase
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.listitem.ZashiListItemState import co.electriccoin.zcash.ui.design.component.listitem.ZashiListItemState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.exchangerate.optin.ExchangeRateOptIn import co.electriccoin.zcash.ui.screen.exchangerate.settings.ExchangeRateSettings
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -26,7 +26,7 @@ class AdvancedSettingsViewModel(
getWalletRestoringState: GetWalletRestoringStateUseCase, getWalletRestoringState: GetWalletRestoringStateUseCase,
private val navigationRouter: NavigationRouter, private val navigationRouter: NavigationRouter,
private val navigateToTaxExport: NavigateToTaxExportUseCase, private val navigateToTaxExport: NavigateToTaxExportUseCase,
private val navigateToSeedRecovery: NavigateToSeedRecoveryUseCase private val navigateToSeedRecovery: NavigateToWalletBackupUseCase
) : ViewModel() { ) : ViewModel() {
val state: StateFlow<AdvancedSettingsState> = val state: StateFlow<AdvancedSettingsState> =
getWalletRestoringState getWalletRestoringState
@ -89,7 +89,7 @@ class AdvancedSettingsViewModel(
private fun onChooseServerClick() = navigationRouter.forward(NavigationTargets.CHOOSE_SERVER) private fun onChooseServerClick() = navigationRouter.forward(NavigationTargets.CHOOSE_SERVER)
private fun onCurrencyConversionClick() = navigationRouter.forward(ExchangeRateOptIn) private fun onCurrencyConversionClick() = navigationRouter.forward(ExchangeRateSettings)
private fun onTaxExportClick() = private fun onTaxExportClick() =
viewModelScope.launch { viewModelScope.launch {
@ -98,6 +98,6 @@ class AdvancedSettingsViewModel(
private fun onSeedRecoveryClick() = private fun onSeedRecoveryClick() =
viewModelScope.launch { viewModelScope.launch {
navigateToSeedRecovery() navigateToSeedRecovery(isOpenedFromSeedBackupInfo = false)
} }
} }

View File

@ -5,8 +5,6 @@ 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.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@ -15,9 +13,7 @@ internal fun WrapAdvancedSettings(
goDeleteWallet: () -> Unit, goDeleteWallet: () -> Unit,
goExportPrivateData: () -> Unit, goExportPrivateData: () -> Unit,
) { ) {
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<AdvancedSettingsViewModel>() val viewModel = koinViewModel<AdvancedSettingsViewModel>()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
val originalState = viewModel.state.collectAsStateWithLifecycle().value val originalState = viewModel.state.collectAsStateWithLifecycle().value
val state = val state =
originalState.copy( originalState.copy(
@ -38,6 +34,5 @@ internal fun WrapAdvancedSettings(
AdvancedSettings( AdvancedSettings(
state = state, state = state,
topAppBarSubTitleState = walletState,
) )
} }

View File

@ -6,17 +6,13 @@ import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.ui.common.compose.LocalNavController import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@Composable @Composable
internal fun WrapChooseServer() { internal fun WrapChooseServer() {
val navController = LocalNavController.current val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<ChooseServerViewModel>() val viewModel = koinViewModel<ChooseServerViewModel>()
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { BackHandler {
@ -32,6 +28,5 @@ internal fun WrapChooseServer() {
navController.popBackStack() navController.popBackStack()
} }
}, },
topAppBarSubTitleState = walletState,
) )
} }

View File

@ -46,7 +46,6 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
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.design.R.drawable import co.electriccoin.zcash.ui.design.R.drawable
import co.electriccoin.zcash.ui.design.component.AlertDialogState import co.electriccoin.zcash.ui.design.component.AlertDialogState
import co.electriccoin.zcash.ui.design.component.AppAlertDialog import co.electriccoin.zcash.ui.design.component.AppAlertDialog
@ -78,7 +77,6 @@ import co.electriccoin.zcash.ui.design.util.stringRes
@Composable @Composable
fun ChooseServerView( fun ChooseServerView(
state: ChooseServerState?, state: ChooseServerState?,
topAppBarSubTitleState: TopAppBarSubTitleState,
onBack: () -> Unit, onBack: () -> Unit,
) { ) {
if (state == null) { if (state == null) {
@ -91,7 +89,6 @@ fun ChooseServerView(
topBar = { topBar = {
ChooseServerTopAppBar( ChooseServerTopAppBar(
onBack = onBack, onBack = onBack,
subTitleState = topAppBarSubTitleState,
) )
}, },
bottomBar = { bottomBar = {
@ -208,17 +205,10 @@ fun ChooseServerBottomBar(saveButtonState: ButtonState) {
@Composable @Composable
private fun ChooseServerTopAppBar( private fun ChooseServerTopAppBar(
onBack: () -> Unit, onBack: () -> Unit
subTitleState: TopAppBarSubTitleState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = stringResource(id = R.string.choose_server_title), title = stringResource(id = R.string.choose_server_title),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
modifier = Modifier.testTag(CHOOSE_SERVER_TOP_APP_BAR), modifier = Modifier.testTag(CHOOSE_SERVER_TOP_APP_BAR),
showTitleLogo = true, showTitleLogo = true,
navigationAction = { navigationAction = {
@ -535,7 +525,6 @@ private fun ChooseServerPreview(
dialogState = dialogState dialogState = dialogState
), ),
onBack = {}, onBack = {},
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }

View File

@ -6,8 +6,6 @@ import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.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
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@ -15,9 +13,7 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapAddContact(address: String?) { internal fun WrapAddContact(address: String?) {
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<AddContactViewModel> { parametersOf(address) } val viewModel = koinViewModel<AddContactViewModel> { parametersOf(address) }
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { BackHandler {
@ -27,7 +23,6 @@ internal fun WrapAddContact(address: String?) {
state?.let { state?.let {
ContactView( ContactView(
state = it, state = it,
topAppBarSubTitleState = walletState,
) )
} }
} }

View File

@ -6,8 +6,6 @@ import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.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
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@ -15,9 +13,7 @@ import org.koin.core.parameter.parametersOf
@Composable @Composable
internal fun WrapUpdateContact(contactAddress: String) { internal fun WrapUpdateContact(contactAddress: String) {
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<UpdateContactViewModel> { parametersOf(contactAddress) } val viewModel = koinViewModel<UpdateContactViewModel> { parametersOf(contactAddress) }
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { BackHandler {
@ -27,7 +23,6 @@ internal fun WrapUpdateContact(contactAddress: String) {
state?.let { state?.let {
ContactView( ContactView(
state = it, state = it,
topAppBarSubTitleState = walletState,
) )
} }
} }

View File

@ -15,7 +15,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.design.component.BlankBgScaffold import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
@ -37,12 +36,11 @@ import co.electriccoin.zcash.ui.screen.contact.model.ContactState
@Composable @Composable
fun ContactView( fun ContactView(
state: ContactState, state: ContactState
topAppBarSubTitleState: TopAppBarSubTitleState
) { ) {
BlankBgScaffold( BlankBgScaffold(
topBar = { topBar = {
ContactTopAppBar(onBack = state.onBack, subTitleState = topAppBarSubTitleState, state = state) ContactTopAppBar(onBack = state.onBack, state = state)
} }
) { paddingValues -> ) { paddingValues ->
if (state.isLoading) { if (state.isLoading) {
@ -129,17 +127,10 @@ private fun ContactViewInternal(
@Composable @Composable
private fun ContactTopAppBar( private fun ContactTopAppBar(
onBack: () -> Unit, onBack: () -> Unit,
subTitleState: TopAppBarSubTitleState,
state: ContactState state: ContactState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = state.title.getValue(), title = state.title.getValue(),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
modifier = Modifier.testTag(ContactTag.TOP_APP_BAR), modifier = Modifier.testTag(ContactTag.TOP_APP_BAR),
showTitleLogo = true, showTitleLogo = true,
navigationAction = { navigationAction = {
@ -169,7 +160,6 @@ private fun DataPreview() {
text = stringRes("Negative"), text = stringRes("Negative"),
) )
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }
@ -195,7 +185,6 @@ private fun LoadingPreview() {
text = stringRes("Add New Contact"), text = stringRes("Add New Contact"),
) )
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }

View File

@ -11,7 +11,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import co.electriccoin.zcash.di.koinActivityViewModel import co.electriccoin.zcash.di.koinActivityViewModel
import co.electriccoin.zcash.ui.MainActivity import co.electriccoin.zcash.ui.MainActivity
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.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.screen.deletewallet.view.DeleteWallet import co.electriccoin.zcash.ui.screen.deletewallet.view.DeleteWallet
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -22,15 +21,11 @@ internal fun MainActivity.WrapDeleteWallet(
onConfirm: () -> Unit, onConfirm: () -> Unit,
) { ) {
val walletViewModel = koinActivityViewModel<WalletViewModel>() val walletViewModel = koinActivityViewModel<WalletViewModel>()
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
WrapDeleteWallet( WrapDeleteWallet(
activity = this, activity = this,
goBack = goBack, goBack = goBack,
topAppBarSubTitleState = walletState, onConfirm = onConfirm,
walletViewModel = walletViewModel, walletViewModel = walletViewModel
onConfirm = onConfirm
) )
} }
@ -39,7 +34,6 @@ internal fun WrapDeleteWallet(
activity: Activity, activity: Activity,
goBack: () -> Unit, goBack: () -> Unit,
onConfirm: () -> Unit, onConfirm: () -> Unit,
topAppBarSubTitleState: TopAppBarSubTitleState,
walletViewModel: WalletViewModel, walletViewModel: WalletViewModel,
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@ -69,6 +63,5 @@ internal fun WrapDeleteWallet(
} }
) )
}, },
topAppBarSubTitleState = topAppBarSubTitleState,
) )
} }

View File

@ -20,7 +20,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
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.design.MINIMAL_WEIGHT import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.ZashiButton import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults
@ -43,7 +42,6 @@ private fun ExportPrivateDataPreview() =
snackbarHostState = SnackbarHostState(), snackbarHostState = SnackbarHostState(),
onBack = {}, onBack = {},
onConfirm = {}, onConfirm = {},
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
@ -52,13 +50,11 @@ fun DeleteWallet(
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
onBack: () -> Unit, onBack: () -> Unit,
onConfirm: () -> Unit, onConfirm: () -> Unit,
topAppBarSubTitleState: TopAppBarSubTitleState,
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
DeleteWalletDataTopAppBar( DeleteWalletDataTopAppBar(
onBack = onBack, onBack = onBack,
subTitleState = topAppBarSubTitleState,
) )
}, },
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
@ -76,17 +72,10 @@ fun DeleteWallet(
@Composable @Composable
private fun DeleteWalletDataTopAppBar( private fun DeleteWalletDataTopAppBar(
onBack: () -> Unit, onBack: () -> Unit
subTitleState: TopAppBarSubTitleState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = stringResource(R.string.delete_wallet_title), title = stringResource(R.string.delete_wallet_title),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
navigationAction = { navigationAction = {
ZashiTopAppBarBackNavigation( ZashiTopAppBarBackNavigation(
onBack = onBack onBack = onBack

View File

@ -1,26 +1,18 @@
package co.electriccoin.zcash.ui.screen.exchangerate.optin package co.electriccoin.zcash.ui.screen.exchangerate.optin
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.viewModels
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import co.electriccoin.zcash.ui.common.compose.LocalActivity import androidx.compose.runtime.getValue
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.koin.androidx.compose.koinViewModel
@Composable @Composable
fun AndroidExchangeRateOptIn() { fun AndroidExchangeRateOptIn() {
val activity = LocalActivity.current val viewModel = koinViewModel<ExchangeRateOptInViewModel>()
val walletViewModel by activity.viewModels<WalletViewModel>() val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { state.onBack() }
BackHandler { ExchangeRateOptInView(state = state)
walletViewModel.dismissOptInExchangeRateUsd()
}
ExchangeRateOptIn(
onEnableClick = { walletViewModel.optInExchangeRateUsd(true) },
onDismiss = { walletViewModel.dismissOptInExchangeRateUsd() },
onSkipClick = { walletViewModel.onSkipClick() }
)
} }
@Serializable @Serializable

View File

@ -0,0 +1,7 @@
package co.electriccoin.zcash.ui.screen.exchangerate.optin
data class ExchangeRateOptInState(
val onEnableClick: () -> Unit,
val onBack: () -> Unit,
val onSkipClick: () -> Unit,
)

View File

@ -29,13 +29,9 @@ import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
import co.electriccoin.zcash.ui.screen.exchangerate.BaseExchangeRateOptIn import co.electriccoin.zcash.ui.screen.exchangerate.BaseExchangeRateOptIn
@Composable @Composable
fun ExchangeRateOptIn( fun ExchangeRateOptInView(state: ExchangeRateOptInState) {
onEnableClick: () -> Unit,
onSkipClick: () -> Unit,
onDismiss: () -> Unit,
) {
BaseExchangeRateOptIn( BaseExchangeRateOptIn(
onDismiss = onDismiss, onDismiss = state.onBack,
content = { content = {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(
@ -61,7 +57,7 @@ fun ExchangeRateOptIn(
footer = { footer = {
ZashiTextButton( ZashiTextButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
onClick = onSkipClick, onClick = state.onSkipClick,
) { ) {
Text( Text(
text = stringResource(R.string.exchange_rate_opt_in_skip), text = stringResource(R.string.exchange_rate_opt_in_skip),
@ -72,7 +68,7 @@ fun ExchangeRateOptIn(
ZashiButton( ZashiButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.exchange_rate_opt_in_enable), text = stringResource(R.string.exchange_rate_opt_in_enable),
onClick = onEnableClick, onClick = state.onEnableClick,
colors = ZashiButtonDefaults.primaryColors() colors = ZashiButtonDefaults.primaryColors()
) )
} }
@ -118,6 +114,12 @@ private fun InfoItem(
private fun CurrencyConversionOptInPreview() = private fun CurrencyConversionOptInPreview() =
ZcashTheme { ZcashTheme {
BlankSurface { BlankSurface {
ExchangeRateOptIn(onEnableClick = {}, onDismiss = {}, onSkipClick = {}) ExchangeRateOptInView(
state = ExchangeRateOptInState(
onEnableClick = {},
onBack = {},
onSkipClick = {},
)
)
} }
} }

View File

@ -0,0 +1,34 @@
package co.electriccoin.zcash.ui.screen.exchangerate.optin
import androidx.lifecycle.ViewModel
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class ExchangeRateOptInViewModel(
private val exchangeRateRepository: ExchangeRateRepository,
private val navigationRouter: NavigationRouter
): ViewModel() {
val state: StateFlow<ExchangeRateOptInState> = MutableStateFlow(
ExchangeRateOptInState(
onBack = ::dismissOptInExchangeRateUsd,
onEnableClick = ::optInExchangeRateUsd,
onSkipClick = ::onSkipClick
)
)
private fun onSkipClick() {
exchangeRateRepository.optInExchangeRateUsd(false)
navigationRouter.back()
}
private fun optInExchangeRateUsd() {
exchangeRateRepository.optInExchangeRateUsd(true)
navigationRouter.back()
}
private fun dismissOptInExchangeRateUsd() {
navigationRouter.back()
}
}

View File

@ -1,30 +1,18 @@
package co.electriccoin.zcash.ui.screen.exchangerate.settings package co.electriccoin.zcash.ui.screen.exchangerate.settings
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.viewModels
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
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 kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.koin.androidx.compose.koinViewModel
@Composable @Composable
fun AndroidExchangeRateSettings() { fun AndroidExchangeRateSettings() {
val activity = LocalActivity.current val viewModel = koinViewModel<ExchangeRateSettingsViewModel>()
val navController = LocalNavController.current val state by viewModel.state.collectAsStateWithLifecycle()
val walletViewModel by activity.viewModels<WalletViewModel>() BackHandler { state.onDismiss() }
val isOptedIn = walletViewModel.isExchangeRateUsdOptedIn.collectAsStateWithLifecycle().value ?: false ExchangeRateSettingsView(state = state)
BackHandler {
navController.popBackStack()
}
ExchangeRateSettings(
isOptedIn = isOptedIn,
onSaveClick = { walletViewModel.optInExchangeRateUsd(it) },
onDismiss = { navController.popBackStack() }
)
} }
@Serializable @Serializable

View File

@ -0,0 +1,10 @@
package co.electriccoin.zcash.ui.screen.exchangerate.settings
import androidx.compose.runtime.Immutable
@Immutable
data class ExchangeRateSettingsState(
val isOptedIn: Boolean,
val onSaveClick: (optIn: Boolean) -> Unit,
val onDismiss: () -> Unit,
)

View File

@ -37,21 +37,17 @@ import co.electriccoin.zcash.ui.screen.exchangerate.BaseExchangeRateOptIn
import co.electriccoin.zcash.ui.screen.exchangerate.SecondaryCard import co.electriccoin.zcash.ui.screen.exchangerate.SecondaryCard
@Composable @Composable
fun ExchangeRateSettings( fun ExchangeRateSettingsView(state: ExchangeRateSettingsState) {
isOptedIn: Boolean, var isOptInSelected by remember(state.isOptedIn) { mutableStateOf(state.isOptedIn) }
onDismiss: () -> Unit,
onSaveClick: (Boolean) -> Unit
) {
var isOptInSelected by remember(isOptedIn) { mutableStateOf(isOptedIn) }
val isButtonDisabled by remember { val isButtonDisabled by remember {
derivedStateOf { derivedStateOf {
(isOptedIn && isOptInSelected) || (!isOptedIn && !isOptInSelected) (state.isOptedIn && isOptInSelected) || (!state.isOptedIn && !isOptInSelected)
} }
} }
BaseExchangeRateOptIn( BaseExchangeRateOptIn(
onDismiss = onDismiss, onDismiss = state.onDismiss,
content = { content = {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(
@ -82,7 +78,7 @@ fun ExchangeRateSettings(
ZashiButton( ZashiButton(
text = stringResource(R.string.exchange_rate_opt_in_save), text = stringResource(R.string.exchange_rate_opt_in_save),
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
onClick = { onSaveClick(isOptInSelected) }, onClick = { state.onSaveClick(isOptInSelected) },
enabled = !isButtonDisabled, enabled = !isButtonDisabled,
colors = ZashiButtonDefaults.primaryColors() colors = ZashiButtonDefaults.primaryColors()
) )
@ -187,6 +183,12 @@ private val Unchecked: Int
private fun SettingsExchangeRateOptInPreview() = private fun SettingsExchangeRateOptInPreview() =
ZcashTheme { ZcashTheme {
BlankSurface { BlankSurface {
ExchangeRateSettings(isOptedIn = true, onDismiss = {}, onSaveClick = {}) ExchangeRateSettingsView(
state = ExchangeRateSettingsState(
isOptedIn = true,
onSaveClick = {},
onDismiss = {}
)
)
} }
} }

View File

@ -0,0 +1,44 @@
package co.electriccoin.zcash.ui.screen.exchangerate.settings
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.common.repository.ExchangeRateRepository
import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
class ExchangeRateSettingsViewModel(
private val exchangeRateRepository: ExchangeRateRepository,
private val navigationRouter: NavigationRouter,
) : ViewModel() {
val state = exchangeRateRepository.state
.map {
createState(it)
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
initialValue = createState(exchangeRateRepository.state.value)
)
private fun createState(it: ExchangeRateState) =
ExchangeRateSettingsState(
isOptedIn = it is ExchangeRateState.OptIn,
onSaveClick = ::onOptInExchangeRateUsdClick,
onDismiss = ::onBack
)
private fun onBack() {
navigationRouter.back()
}
private fun onOptInExchangeRateUsdClick(optInt: Boolean) {
exchangeRateRepository.optInExchangeRateUsd(optIn = optInt)
navigationRouter.back()
}
}

View File

@ -1,126 +0,0 @@
package co.electriccoin.zcash.ui.screen.exchangerate.widget
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.wallet.ExchangeRateState
import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.screen.exchangerate.SecondaryCard
@Suppress("LongMethod")
@Composable
fun StyledExchangeOptIn(
state: ExchangeRateState.OptIn,
modifier: Modifier = Modifier
) {
SecondaryCard(
modifier = modifier,
) {
Column(
modifier = Modifier.padding(start = 20.dp, bottom = 20.dp)
) {
Row {
Image(
modifier = Modifier.padding(top = 20.dp),
painter = painterResource(Icon),
contentDescription = null
)
Spacer(modifier = Modifier.width(12.dp))
Column(
verticalArrangement = Arrangement.Center
) {
Spacer(modifier = Modifier.height(22.dp))
Text(
text = stringResource(R.string.exchange_rate_opt_in_title),
color = ZashiColors.Text.textTertiary,
fontSize = 14.sp,
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = stringResource(R.string.exchange_rate_opt_in_subtitle),
color = ZashiColors.Text.textPrimary,
fontSize = 16.sp,
style = ZcashTheme.extendedTypography.restoringTopAppBarStyle,
)
}
Spacer(modifier = Modifier.weight(1f))
IconButton(
modifier = Modifier.padding(top = 4.dp, end = 8.dp),
onClick = state.onDismissClick,
) {
Icon(
painter = painterResource(R.drawable.ic_exchange_rate_unavailable_dialog_close),
contentDescription = null,
tint = ZashiColors.HintTooltips.defaultFg
)
}
}
Spacer(modifier = Modifier.height(16.dp))
ZashiButton(
modifier =
Modifier
.fillMaxWidth()
.padding(end = 20.dp),
onClick = state.onPrimaryClick,
colors = ZashiButtonDefaults.tertiaryColors(),
text = stringResource(R.string.exchange_rate_opt_in_primary_btn),
) { scope ->
Text(
text = stringResource(R.string.exchange_rate_opt_in_primary_btn),
style =
ZcashTheme.typography.primary.titleSmall
.copy(fontWeight = FontWeight.SemiBold),
fontSize = 14.sp
)
scope.Loading()
}
}
}
}
private val Icon: Int
@DrawableRes
@Composable
get() =
if (isSystemInDarkTheme()) {
R.drawable.ic_exchange_rate_opt_in
} else {
R.drawable.ic_exchange_rate_opt_in_light
}
@Suppress("UnusedPrivateMember")
@Composable
@PreviewScreens
private fun ExchangeRateOptInPreview() =
ZcashTheme {
BlankSurface {
StyledExchangeOptIn(
modifier = Modifier.fillMaxWidth(),
state = ExchangeRateState.OptIn(onDismissClick = {})
)
}
}

View File

@ -14,7 +14,6 @@ import cash.z.ecc.sdk.type.fromResources
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.LocalActivity import co.electriccoin.zcash.ui.common.compose.LocalActivity
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
import co.electriccoin.zcash.ui.common.model.VersionInfo import co.electriccoin.zcash.ui.common.model.VersionInfo
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
@ -34,13 +33,10 @@ internal fun WrapExportPrivateData(
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
WrapExportPrivateData( WrapExportPrivateData(
goBack = goBack, goBack = goBack,
onShare = onConfirm, onShare = onConfirm,
synchronizer = synchronizer, synchronizer = synchronizer,
topAppBarSubTitleState = walletState,
) )
} }
@ -49,7 +45,6 @@ internal fun WrapExportPrivateData(
goBack: () -> Unit, goBack: () -> Unit,
onShare: () -> Unit, onShare: () -> Unit,
synchronizer: Synchronizer?, synchronizer: Synchronizer?,
topAppBarSubTitleState: TopAppBarSubTitleState,
) { ) {
val activity = LocalActivity.current val activity = LocalActivity.current
@ -85,7 +80,6 @@ internal fun WrapExportPrivateData(
} }
} }
}, },
topAppBarSubTitleState = topAppBarSubTitleState,
) )
} }
} }

View File

@ -19,7 +19,6 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
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.design.component.ZashiButton import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.component.ZashiCheckbox import co.electriccoin.zcash.ui.design.component.ZashiCheckbox
import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
@ -38,13 +37,11 @@ fun ExportPrivateData(
onBack: () -> Unit, onBack: () -> Unit,
onAgree: (Boolean) -> Unit, onAgree: (Boolean) -> Unit,
onConfirm: () -> Unit, onConfirm: () -> Unit,
topAppBarSubTitleState: TopAppBarSubTitleState,
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
ExportPrivateDataTopAppBar( ExportPrivateDataTopAppBar(
onBack = onBack, onBack = onBack,
subTitleState = topAppBarSubTitleState,
) )
}, },
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
@ -63,17 +60,10 @@ fun ExportPrivateData(
@Composable @Composable
private fun ExportPrivateDataTopAppBar( private fun ExportPrivateDataTopAppBar(
onBack: () -> Unit, onBack: () -> Unit
subTitleState: TopAppBarSubTitleState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = stringResource(R.string.export_data_title), title = stringResource(R.string.export_data_title),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
navigationAction = { navigationAction = {
ZashiTopAppBarBackNavigation(onBack = onBack) ZashiTopAppBarBackNavigation(onBack = onBack)
}, },
@ -137,6 +127,5 @@ private fun ExportPrivateDataPreview() =
onBack = {}, onBack = {},
onAgree = {}, onAgree = {},
onConfirm = {}, onConfirm = {},
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }

View File

@ -7,9 +7,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect 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.ui.common.compose.LocalNavController import co.electriccoin.zcash.ui.common.compose.LocalNavController
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
import co.electriccoin.zcash.ui.design.component.AppAlertDialog import co.electriccoin.zcash.ui.design.component.AppAlertDialog
import co.electriccoin.zcash.ui.screen.feedback.view.FeedbackView import co.electriccoin.zcash.ui.screen.feedback.view.FeedbackView
import co.electriccoin.zcash.ui.screen.feedback.viewmodel.FeedbackViewModel import co.electriccoin.zcash.ui.screen.feedback.viewmodel.FeedbackViewModel
@ -18,33 +16,15 @@ import org.koin.androidx.compose.koinViewModel
@Composable @Composable
internal fun WrapFeedback() { internal fun WrapFeedback() {
val navController = LocalNavController.current val navController = LocalNavController.current
val walletViewModel = koinActivityViewModel<WalletViewModel>()
val viewModel = koinViewModel<FeedbackViewModel>() val viewModel = koinViewModel<FeedbackViewModel>()
val walletState by walletViewModel.walletStateInformation.collectAsStateWithLifecycle()
val state by viewModel.state.collectAsStateWithLifecycle() val state by viewModel.state.collectAsStateWithLifecycle()
val dialogState by viewModel.dialogState.collectAsStateWithLifecycle() val dialogState by viewModel.dialogState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
viewModel.onBackNavigationCommand.collect { viewModel.onBackNavigationCommand.collect {
navController.popBackStack() navController.popBackStack()
} }
} }
BackHandler(enabled = state != null) { state?.onBack?.invoke() }
BackHandler { state?.let { FeedbackView(state = it) }
state?.onBack?.invoke() dialogState?.let { AppAlertDialog(state = it) }
}
state?.let {
FeedbackView(
state = it,
topAppBarSubTitleState = walletState
)
}
dialogState?.let {
AppAlertDialog(
state = it
)
}
} }

View File

@ -34,7 +34,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.design.component.BlankSurface import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.TextFieldState import co.electriccoin.zcash.ui.design.component.TextFieldState
@ -56,13 +55,11 @@ import co.electriccoin.zcash.ui.screen.feedback.model.FeedbackState
@Composable @Composable
fun FeedbackView( fun FeedbackView(
state: FeedbackState, state: FeedbackState,
topAppBarSubTitleState: TopAppBarSubTitleState,
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
SupportTopAppBar( SupportTopAppBar(
state = state, state = state,
subTitleState = topAppBarSubTitleState,
) )
}, },
) { paddingValues -> ) { paddingValues ->
@ -75,16 +72,9 @@ fun FeedbackView(
@Composable @Composable
private fun SupportTopAppBar( private fun SupportTopAppBar(
state: FeedbackState, state: FeedbackState
subTitleState: TopAppBarSubTitleState
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
title = stringResource(id = R.string.support_header), title = stringResource(id = R.string.support_header),
navigationAction = { navigationAction = {
ZashiTopAppBarBackNavigation(onBack = state.onBack) ZashiTopAppBarBackNavigation(onBack = state.onBack)
@ -258,7 +248,6 @@ private fun Preview() =
onSelected = {} onSelected = {}
) )
), ),
topAppBarSubTitleState = TopAppBarSubTitleState.None,
) )
} }
} }

View File

@ -11,13 +11,14 @@ import co.electriccoin.zcash.ui.screen.balances.BalanceViewModel
import co.electriccoin.zcash.ui.screen.restoresuccess.WrapRestoreSuccess import co.electriccoin.zcash.ui.screen.restoresuccess.WrapRestoreSuccess
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetViewModel import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetViewModel
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.koin.androidx.compose.koinViewModel
@Composable @Composable
internal fun AndroidHome() { internal fun AndroidHome() {
val topAppBarViewModel = koinActivityViewModel<ZashiTopAppBarViewModel>() val topAppBarViewModel = koinActivityViewModel<ZashiTopAppBarViewModel>()
val balanceViewModel = koinActivityViewModel<BalanceViewModel>() val balanceViewModel = koinViewModel<BalanceViewModel>()
val homeViewModel = koinActivityViewModel<HomeViewModel>() val homeViewModel = koinViewModel<HomeViewModel>()
val transactionHistoryWidgetViewModel = koinActivityViewModel<TransactionHistoryWidgetViewModel>() val transactionHistoryWidgetViewModel = koinViewModel<TransactionHistoryWidgetViewModel>()
val restoreDialogState by homeViewModel.restoreDialogState.collectAsStateWithLifecycle() val restoreDialogState by homeViewModel.restoreDialogState.collectAsStateWithLifecycle()
val appBarState by topAppBarViewModel.state.collectAsStateWithLifecycle() val appBarState by topAppBarViewModel.state.collectAsStateWithLifecycle()
val balanceState by balanceViewModel.state.collectAsStateWithLifecycle() val balanceState by balanceViewModel.state.collectAsStateWithLifecycle()

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.CubicBezierEasing import androidx.compose.animation.core.CubicBezierEasing
@ -35,6 +35,22 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupMessage
import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupMessageState
import co.electriccoin.zcash.ui.screen.home.currency.EnableCurrencyConversionMessage
import co.electriccoin.zcash.ui.screen.home.currency.EnableCurrencyConversionMessageState
import co.electriccoin.zcash.ui.screen.home.disconnected.WalletDisconnectedMessage
import co.electriccoin.zcash.ui.screen.home.disconnected.WalletDisconnectedMessageState
import co.electriccoin.zcash.ui.screen.home.error.WalletErrorMessage
import co.electriccoin.zcash.ui.screen.home.error.WalletErrorMessageState
import co.electriccoin.zcash.ui.screen.home.restoring.WalletRestoringMessage
import co.electriccoin.zcash.ui.screen.home.restoring.WalletRestoringMessageState
import co.electriccoin.zcash.ui.screen.home.syncing.WalletSyncingMessage
import co.electriccoin.zcash.ui.screen.home.syncing.WalletSyncingMessageState
import co.electriccoin.zcash.ui.screen.home.transparentbalance.TransparentBalanceMessage
import co.electriccoin.zcash.ui.screen.home.transparentbalance.TransparentBalanceMessageState
import co.electriccoin.zcash.ui.screen.home.updating.WalletUpdatingMessage
import co.electriccoin.zcash.ui.screen.home.updating.WalletUpdatingMessageState
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
@ -112,10 +128,10 @@ fun HomeMessage(
contentPadding = contentPadding contentPadding = contentPadding
) )
is TransparentBalanceDetectedMessageState -> is TransparentBalanceMessageState ->
TransparentBalanceDetectedMessage( TransparentBalanceMessage(
innerModifier = innerModifier, innerModifier = innerModifier,
state = normalizedState as TransparentBalanceDetectedMessageState, state = normalizedState as TransparentBalanceMessageState,
contentPadding = contentPadding contentPadding = contentPadding
) )
@ -203,7 +219,7 @@ fun HomeMessage(
} }
} }
sealed interface HomeMessageState interface HomeMessageState
@Suppress("MagicNumber") @Suppress("MagicNumber")
@Composable @Composable

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -24,8 +24,6 @@ import co.electriccoin.zcash.ui.design.component.LocalZashiCircularProgressIndic
import co.electriccoin.zcash.ui.design.component.VerticalSpacer import co.electriccoin.zcash.ui.design.component.VerticalSpacer
import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults import co.electriccoin.zcash.ui.design.component.ZashiButtonDefaults
import co.electriccoin.zcash.ui.design.component.ZashiCircularProgressIndicatorDefaults import co.electriccoin.zcash.ui.design.component.ZashiCircularProgressIndicatorDefaults
import co.electriccoin.zcash.ui.design.theme.colors.Purple
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.design.theme.colors.ZashiDarkColors import co.electriccoin.zcash.ui.design.theme.colors.ZashiDarkColors
import co.electriccoin.zcash.ui.design.theme.colors.ZashiLightColors import co.electriccoin.zcash.ui.design.theme.colors.ZashiLightColors
import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
@ -47,11 +45,11 @@ fun HomeMessageWrapper(
innerModifier = innerModifier, innerModifier = innerModifier,
) { ) {
CompositionLocalProvider( CompositionLocalProvider(
LocalContentColor provides ZashiColors.Text.textOpposite, LocalContentColor provides ZashiLightColors.Utility.Purple.utilityPurple50,
LocalZashiCircularProgressIndicatorColors provides LocalZashiCircularProgressIndicatorColors provides
ZashiCircularProgressIndicatorDefaults.colors( ZashiCircularProgressIndicatorDefaults.colors(
progressColor = ZashiColors.Text.textOpposite, progressColor = ZashiLightColors.Utility.Purple.utilityPurple50,
trackColor = Purple.`400` trackColor = ZashiLightColors.Utility.Purple.utilityPurple400
) )
) { ) {
start() start()
@ -63,7 +61,7 @@ fun HomeMessageWrapper(
CompositionLocalProvider( CompositionLocalProvider(
LocalTextStyle provides LocalTextStyle provides
ZashiTypography.textSm.copy( ZashiTypography.textSm.copy(
color = ZashiColors.Text.textOpposite, color = ZashiLightColors.Utility.Purple.utilityPurple50,
fontWeight = FontWeight.Medium fontWeight = FontWeight.Medium
), ),
) { ) {
@ -73,7 +71,7 @@ fun HomeMessageWrapper(
CompositionLocalProvider( CompositionLocalProvider(
LocalTextStyle provides LocalTextStyle provides
ZashiTypography.textXs.copy( ZashiTypography.textXs.copy(
color = Purple.`200`, color = ZashiLightColors.Utility.Purple.utilityPurple200,
fontWeight = FontWeight.Medium fontWeight = FontWeight.Medium
), ),
) { ) {
@ -106,10 +104,11 @@ private fun Container(
Modifier Modifier
.background( .background(
Brush.verticalGradient( Brush.verticalGradient(
0f to Purple.`500`, 0f to ZashiLightColors.Utility.Purple.utilityPurple500,
1f to Purple.`900`, 1f to ZashiLightColors.Utility.Purple.utilityPurple900,
) )
).clickable(onClick = onClick) )
.clickable(onClick = onClick)
.padding(contentPadding), .padding(contentPadding),
) { ) {
Row( Row(

View File

@ -1,7 +1,6 @@
package co.electriccoin.zcash.ui.screen.home package co.electriccoin.zcash.ui.screen.home
import co.electriccoin.zcash.ui.design.component.BigIconButtonState import co.electriccoin.zcash.ui.design.component.BigIconButtonState
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessageState
data class HomeState( data class HomeState(
val firstButton: BigIconButtonState, val firstButton: BigIconButtonState,
@ -11,6 +10,6 @@ data class HomeState(
val message: HomeMessageState? val message: HomeMessageState?
) )
data class HomeRestoreDialogState( data class HomeRestoreSuccessDialogState(
val onClick: () -> Unit val onClick: () -> Unit
) )

View File

@ -32,8 +32,7 @@ import co.electriccoin.zcash.ui.fixture.BalanceStateFixture
import co.electriccoin.zcash.ui.fixture.ZashiMainTopAppBarStateFixture import co.electriccoin.zcash.ui.fixture.ZashiMainTopAppBarStateFixture
import co.electriccoin.zcash.ui.screen.balances.BalanceState import co.electriccoin.zcash.ui.screen.balances.BalanceState
import co.electriccoin.zcash.ui.screen.balances.BalanceWidget import co.electriccoin.zcash.ui.screen.balances.BalanceWidget
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessage import co.electriccoin.zcash.ui.screen.home.error.WalletErrorMessageState
import co.electriccoin.zcash.ui.screen.home.messages.WalletErrorMessageState
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetState import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetState
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetStateFixture import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetStateFixture
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.createTransactionHistoryWidgets import co.electriccoin.zcash.ui.screen.transactionhistory.widget.createTransactionHistoryWidgets

View File

@ -2,7 +2,6 @@ package co.electriccoin.zcash.ui.screen.home
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import cash.z.ecc.android.sdk.model.Zatoshi
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.NavigationRouter
import co.electriccoin.zcash.ui.NavigationTargets import co.electriccoin.zcash.ui.NavigationTargets
@ -11,115 +10,61 @@ import co.electriccoin.zcash.ui.common.model.DistributionDimension
import co.electriccoin.zcash.ui.common.model.KeystoneAccount import co.electriccoin.zcash.ui.common.model.KeystoneAccount
import co.electriccoin.zcash.ui.common.model.WalletAccount import co.electriccoin.zcash.ui.common.model.WalletAccount
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
import co.electriccoin.zcash.ui.common.usecase.GetHomeMessageUseCase
import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase
import co.electriccoin.zcash.ui.common.usecase.HomeMessageData
import co.electriccoin.zcash.ui.common.usecase.IsRestoreSuccessDialogVisibleUseCase import co.electriccoin.zcash.ui.common.usecase.IsRestoreSuccessDialogVisibleUseCase
import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase
import co.electriccoin.zcash.ui.design.component.BigIconButtonState import co.electriccoin.zcash.ui.design.component.BigIconButtonState
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.exchangerate.optin.ExchangeRateOptIn import co.electriccoin.zcash.ui.screen.exchangerate.optin.ExchangeRateOptIn
import co.electriccoin.zcash.ui.screen.home.balance.TransparentBalanceInfo import co.electriccoin.zcash.ui.screen.home.backup.SeedBackupInfo
import co.electriccoin.zcash.ui.screen.home.messages.EnableCurrencyConversionMessageState import co.electriccoin.zcash.ui.screen.home.currency.EnableCurrencyConversionMessageState
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessageState import co.electriccoin.zcash.ui.screen.home.transparentbalance.TransparentBalanceMessageState
import co.electriccoin.zcash.ui.screen.home.messages.TransparentBalanceDetectedMessageState import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupMessageState
import co.electriccoin.zcash.ui.screen.home.messages.WalletBackupMessageState import co.electriccoin.zcash.ui.screen.home.disconnected.WalletDisconnectedInfo
import co.electriccoin.zcash.ui.screen.home.messages.WalletDisconnectedMessageState import co.electriccoin.zcash.ui.screen.home.disconnected.WalletDisconnectedMessageState
import co.electriccoin.zcash.ui.screen.home.messages.WalletErrorMessageState import co.electriccoin.zcash.ui.screen.home.error.WalletErrorMessageState
import co.electriccoin.zcash.ui.screen.home.messages.WalletRestoringMessageState import co.electriccoin.zcash.ui.screen.home.restoring.WalletRestoringMessageState
import co.electriccoin.zcash.ui.screen.home.messages.WalletSyncingMessageState import co.electriccoin.zcash.ui.screen.home.syncing.WalletSyncingMessageState
import co.electriccoin.zcash.ui.screen.home.messages.WalletUpdatingMessageState import co.electriccoin.zcash.ui.screen.home.updating.WalletUpdatingMessageState
import co.electriccoin.zcash.ui.screen.home.restoring.WalletRestoringInfo
import co.electriccoin.zcash.ui.screen.home.syncing.WalletSyncingInfo
import co.electriccoin.zcash.ui.screen.home.transparentbalance.TransparentBalanceInfo
import co.electriccoin.zcash.ui.screen.home.updating.WalletUpdatingInfo
import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations
import co.electriccoin.zcash.ui.screen.receive.Receive import co.electriccoin.zcash.ui.screen.receive.Receive
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
import co.electriccoin.zcash.ui.screen.scan.Scan import co.electriccoin.zcash.ui.screen.scan.Scan
import co.electriccoin.zcash.ui.screen.scan.ScanFlow import co.electriccoin.zcash.ui.screen.scan.ScanFlow
import co.electriccoin.zcash.ui.screen.seed.backup.SeedBackup import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupDetail
import co.electriccoin.zcash.ui.screen.send.Send import co.electriccoin.zcash.ui.screen.send.Send
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
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.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.seconds
class HomeViewModel( class HomeViewModel(
getHomeMessage: GetHomeMessageUseCase,
getVersionInfoProvider: GetVersionInfoProvider, getVersionInfoProvider: GetVersionInfoProvider,
getSelectedWalletAccountUseCase: GetSelectedWalletAccountUseCase, getSelectedWalletAccountUseCase: GetSelectedWalletAccountUseCase,
private val navigationRouter: NavigationRouter, private val navigationRouter: NavigationRouter,
private val isRestoreSuccessDialogVisible: IsRestoreSuccessDialogVisibleUseCase, private val isRestoreSuccessDialogVisible: IsRestoreSuccessDialogVisibleUseCase,
private val navigateToCoinbase: NavigateToCoinbaseUseCase private val navigateToCoinbase: NavigateToCoinbaseUseCase,
) : ViewModel() { ) : ViewModel() {
@Suppress("MagicNumber")
private val messageState =
flow {
val states =
listOf(
WalletErrorMessageState(
onClick = {}
),
WalletDisconnectedMessageState(onClick = {
navigationRouter.forward(WalletDisconnectedInfo)
}),
WalletRestoringMessageState(progress = 0, onClick = {
navigationRouter.forward(WalletRestoringInfo)
}),
WalletRestoringMessageState(progress = 100, onClick = {
navigationRouter.forward(WalletRestoringInfo)
}),
WalletSyncingMessageState(progress = 0, onClick = {
navigationRouter.forward(WalletSyncingInfo)
}),
WalletSyncingMessageState(progress = 100, onClick = {
navigationRouter.forward(WalletSyncingInfo)
}),
WalletUpdatingMessageState(onClick = {
navigationRouter.forward(WalletUpdatingInfo)
}),
WalletBackupMessageState(
onClick = {
navigationRouter.forward(SeedBackupInfo)
},
onButtonClick = {
navigationRouter.forward(SeedBackup(false))
}
),
TransparentBalanceDetectedMessageState(
subtitle = stringRes(zatoshi = Zatoshi(1000)),
onClick = {
navigationRouter.forward(TransparentBalanceInfo)
},
onButtonClick = {
// navigationRouter.forward(TransparentBalanceInfo)
},
),
EnableCurrencyConversionMessageState(
onClick = {
navigationRouter.forward(ExchangeRateOptIn)
},
onButtonClick = {
navigationRouter.forward(ExchangeRateOptIn)
},
)
)
var index = 0 private val messageState = getHomeMessage
.observe()
while (true) { .map { createMessageState(it) }
emit(states[index]) .stateIn(
delay(3.seconds) scope = viewModelScope,
if (index == states.lastIndex) { started = SharingStarted.WhileSubscribed(),
emit(null) initialValue = null
delay(10.seconds) )
index = 0
} else {
index += 1
}
}
}
private val isRestoreDialogVisible: Flow<Boolean?> = private val isRestoreDialogVisible: Flow<Boolean?> =
isRestoreSuccessDialogVisible isRestoreSuccessDialogVisible
@ -130,10 +75,10 @@ class HomeViewModel(
initialValue = null initialValue = null
) )
val restoreDialogState: StateFlow<HomeRestoreDialogState?> = val restoreDialogState: StateFlow<HomeRestoreSuccessDialogState?> =
isRestoreDialogVisible isRestoreDialogVisible
.map { isVisible -> .map { isVisible ->
HomeRestoreDialogState( HomeRestoreSuccessDialogState(
onClick = ::onRestoreDialogSeenClick onClick = ::onRestoreDialogSeenClick
).takeIf { isVisible == true } ).takeIf { isVisible == true }
}.stateIn( }.stateIn(
@ -203,6 +148,48 @@ class HomeViewModel(
message = messageState message = messageState
) )
private fun createMessageState(it: HomeMessageData?) = when (it) {
is HomeMessageData.Backup -> WalletBackupMessageState(
onClick = ::onWalletBackupMessageClick,
onButtonClick = ::onWalletBackupMessageButtonClick,
)
HomeMessageData.Disconnected -> WalletDisconnectedMessageState(
onClick = ::onWalletDisconnectedMessageClick
)
HomeMessageData.EnableCurrencyConversion -> EnableCurrencyConversionMessageState(
onClick = ::onEnableCurrencyConversionClick,
onButtonClick = ::onEnableCurrencyConversionClick
)
is HomeMessageData.Error -> WalletErrorMessageState(
onClick = { onWalletErrorMessageClick(it) }
)
is HomeMessageData.Restoring -> WalletRestoringMessageState(
progress = it.progress,
onClick = ::onWalletRestoringMessageClick
)
is HomeMessageData.Syncing -> WalletSyncingMessageState(
progress = it.progress,
onClick = ::onWalletSyncingMessageClick
)
is HomeMessageData.TransparentBalance -> TransparentBalanceMessageState(
subtitle = stringRes(zatoshi = it.zatoshi),
onClick = ::onTransparentBalanceMessageClick,
onButtonClick = ::onTransparentBalanceMessageButtonClick,
)
HomeMessageData.Updating -> WalletUpdatingMessageState(
onClick = ::onWalletUpdatingMessageClick
)
null -> null
}
private fun onRestoreDialogSeenClick() = private fun onRestoreDialogSeenClick() =
viewModelScope.launch { viewModelScope.launch {
isRestoreSuccessDialogVisible.setSeen() isRestoreSuccessDialogVisible.setSeen()
@ -232,4 +219,61 @@ class HomeViewModel(
private fun onRequestClick() { private fun onRequestClick() {
navigationRouter.forward("${NavigationTargets.REQUEST}/${ReceiveAddressType.Unified.ordinal}") navigationRouter.forward("${NavigationTargets.REQUEST}/${ReceiveAddressType.Unified.ordinal}")
} }
private fun onWalletUpdatingMessageClick() {
navigationRouter.forward(WalletUpdatingInfo)
}
private fun onWalletSyncingMessageClick() {
navigationRouter.forward(WalletSyncingInfo)
}
private fun onWalletRestoringMessageClick() {
navigationRouter.forward(WalletRestoringInfo)
}
private fun onEnableCurrencyConversionClick() {
navigationRouter.forward(ExchangeRateOptIn)
}
private fun onWalletDisconnectedMessageClick() {
navigationRouter.forward(WalletDisconnectedInfo)
}
private fun onWalletBackupMessageClick() {
navigationRouter.forward(SeedBackupInfo)
}
private fun onWalletBackupMessageButtonClick() {
navigationRouter.forward(WalletBackupDetail(false))
}
private fun onTransparentBalanceMessageClick() {
navigationRouter.forward(TransparentBalanceInfo)
}
private fun onTransparentBalanceMessageButtonClick(): Nothing {
TODO()
}
private fun onWalletErrorMessageClick(homeMessageData: HomeMessageData.Error): Nothing {
// statusText =
// context.getString(
// R.string.balances_status_error_simple,
// context.getString(R.string.app_name)
// )
// statusAction =
// StatusAction.Error(
// details =
// context.getString(
// R.string.balances_status_error_dialog_cause,
// walletSnapshot.synchronizerError.getCauseMessage()
// ?: context.getString(R.string.balances_status_error_dialog_cause_unknown),
// walletSnapshot.synchronizerError.getStackTrace(limit = STACKTRACE_LIMIT)
// ?: context.getString(R.string.balances_status_error_dialog_stacktrace_unknown)
// ),
// fullStackTrace = walletSnapshot.synchronizerError.getStackTrace(limit = null)
// )
TODO()
}
} }

View File

@ -0,0 +1,22 @@
package co.electriccoin.zcash.ui.screen.home.backup
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.serialization.Serializable
import org.koin.androidx.compose.koinViewModel
import org.koin.core.parameter.parametersOf
@Composable
fun AndroidWalletBackupDetail(args: WalletBackupDetail) {
val viewModel = koinViewModel<WalletBackupDetailViewModel> { parametersOf(args) }
val state by viewModel.state.collectAsStateWithLifecycle()
BackHandler { state.onBack() }
WalletBackupDetailView(state = state)
}
@Serializable
data class WalletBackupDetail(
val isOpenedFromSeedBackupInfo: Boolean
)

View File

@ -0,0 +1,19 @@
package co.electriccoin.zcash.ui.screen.home.backup
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.serialization.Serializable
import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AndroidWalletBackupInfo() {
val viewModel = koinViewModel<WalletBackupInfoViewModel>()
val state by viewModel.state.collectAsStateWithLifecycle()
WalletBackupInfoView(state = state)
}
@Serializable
object SeedBackupInfo

View File

@ -0,0 +1,10 @@
package co.electriccoin.zcash.ui.screen.home.backup
import androidx.compose.runtime.Immutable
@Immutable
data class WalletBackupDetailState(
val onBack: () -> Unit,
val onNextClick: () -> Unit,
val onInfoClick: () -> Unit,
)

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.seed.backup package co.electriccoin.zcash.ui.screen.home.backup
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
@ -20,7 +20,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
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.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.HorizontalSpacer import co.electriccoin.zcash.ui.design.component.HorizontalSpacer
import co.electriccoin.zcash.ui.design.component.IconButtonState import co.electriccoin.zcash.ui.design.component.IconButtonState
@ -38,12 +37,11 @@ import co.electriccoin.zcash.ui.design.util.scaffoldPadding
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
@Composable @Composable
fun SeedBackupView( fun WalletBackupDetailView(
state: SeedBackupState, state: WalletBackupDetailState,
appBarState: TopAppBarSubTitleState,
) { ) {
Scaffold( Scaffold(
topBar = { AppBar(state = state, subTitleState = appBarState) } topBar = { AppBar(state = state) }
) { paddingValues -> ) { paddingValues ->
Content( Content(
modifier = Modifier.scaffoldPadding(paddingValues), modifier = Modifier.scaffoldPadding(paddingValues),
@ -54,18 +52,11 @@ fun SeedBackupView(
@Composable @Composable
private fun AppBar( private fun AppBar(
state: SeedBackupState, state: WalletBackupDetailState,
subTitleState: TopAppBarSubTitleState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
ZashiSmallTopAppBar( ZashiSmallTopAppBar(
title = stringResource(R.string.wallet_backup_title), title = stringResource(R.string.wallet_backup_title),
subtitle =
when (subTitleState) {
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
TopAppBarSubTitleState.None -> null
},
modifier = modifier, modifier = modifier,
navigationAction = { navigationAction = {
ZashiTopAppBarBackNavigation(onBack = state.onBack) ZashiTopAppBarBackNavigation(onBack = state.onBack)
@ -85,7 +76,7 @@ private fun AppBar(
@Composable @Composable
private fun Content( private fun Content(
state: SeedBackupState, state: WalletBackupDetailState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Column( Column(
@ -202,10 +193,9 @@ private fun Item(
@PreviewScreens @PreviewScreens
private fun Preview() = private fun Preview() =
ZcashTheme { ZcashTheme {
SeedBackupView( WalletBackupDetailView(
appBarState = TopAppBarSubTitleState.None,
state = state =
SeedBackupState( WalletBackupDetailState(
onBack = {}, onBack = {},
onNextClick = {}, onNextClick = {},
onInfoClick = {} onInfoClick = {}

View File

@ -0,0 +1,43 @@
package co.electriccoin.zcash.ui.screen.home.backup
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.common.usecase.NavigateToWalletBackupUseCase
import co.electriccoin.zcash.ui.screen.restore.info.SeedInfo
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class WalletBackupDetailViewModel(
private val args: WalletBackupDetail,
private val navigationRouter: NavigationRouter,
private val navigateToWalletBackup: NavigateToWalletBackupUseCase
) : ViewModel() {
val state = MutableStateFlow(
WalletBackupDetailState(
onBack = ::onBack,
onNextClick = ::onNextClick,
onInfoClick = ::onInfoClick
)
).asStateFlow()
private fun onNextClick() =
viewModelScope.launch {
navigateToWalletBackup(true)
}
private fun onInfoClick() {
navigationRouter.forward(SeedInfo)
}
private fun onBack() {
if (args.isOpenedFromSeedBackupInfo) {
navigationRouter.replace(SeedBackupInfo)
} else {
navigationRouter.back()
}
}
}

View File

@ -0,0 +1,10 @@
package co.electriccoin.zcash.ui.screen.home.backup
import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.ModalBottomSheetState
data class WalletBackupInfoState(
override val onBack: () -> Unit,
val primaryButton: ButtonState,
val secondaryButton: ButtonState
) : ModalBottomSheetState

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home package co.electriccoin.zcash.ui.screen.home.backup
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -13,7 +13,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.component.Spacer import co.electriccoin.zcash.ui.design.component.Spacer
@ -27,30 +26,16 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.seed.backup.SeedBackup
import kotlinx.serialization.Serializable
import org.koin.compose.koinInject
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun AndroidSeedBackupInfo() { fun WalletBackupInfoView(
val navigationRouter = koinInject<NavigationRouter>() state: WalletBackupInfoState?,
Content(
onBack = { navigationRouter.back() },
onPositiveClick = { navigationRouter.replace(SeedBackup(true)) }
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Content(
onBack: () -> Unit,
onPositiveClick: () -> Unit,
sheetState: SheetState = rememberScreenModalBottomSheetState(), sheetState: SheetState = rememberScreenModalBottomSheetState(),
) { ) {
ZashiScreenModalBottomSheet( ZashiScreenModalBottomSheet(
sheetState = sheetState, sheetState = sheetState,
onDismissRequest = onBack state = state
) { ) {
Column( Column(
modifier = modifier =
@ -101,21 +86,13 @@ private fun Content(
Spacer(32.dp) Spacer(32.dp)
ZashiButton( ZashiButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
state = state = it.secondaryButton,
ButtonState(
text = stringRes(R.string.general_remind_me_later),
onClick = onBack
),
colors = ZashiButtonDefaults.secondaryColors() colors = ZashiButtonDefaults.secondaryColors()
) )
Spacer(4.dp) Spacer(4.dp)
ZashiButton( ZashiButton(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
state = state = it.primaryButton
ButtonState(
text = stringRes(R.string.general_ok),
onClick = onPositiveClick
)
) )
} }
} }
@ -126,11 +103,17 @@ private fun Content(
@Composable @Composable
private fun Preview() = private fun Preview() =
ZcashTheme { ZcashTheme {
Content( WalletBackupInfoView(
onBack = {}, WalletBackupInfoState(
onPositiveClick = {} onBack = {},
secondaryButton = ButtonState(
text = stringRes(R.string.general_remind_me_later),
onClick = {}
),
primaryButton = ButtonState(
text = stringRes(R.string.general_ok),
onClick = {}
)
)
) )
} }
@Serializable
object SeedBackupInfo

View File

@ -0,0 +1,39 @@
package co.electriccoin.zcash.ui.screen.home.backup
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import co.electriccoin.zcash.ui.NavigationRouter
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.usecase.RemindWalletBackupLaterUseCase
import co.electriccoin.zcash.ui.design.component.ButtonState
import co.electriccoin.zcash.ui.design.util.stringRes
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
class WalletBackupInfoViewModel(
private val navigationRouter: NavigationRouter,
private val remindWalletBackupLater: RemindWalletBackupLaterUseCase
) : ViewModel() {
val state: StateFlow<WalletBackupInfoState?> = MutableStateFlow(
WalletBackupInfoState(
onBack = ::onBack,
secondaryButton = ButtonState(
text = stringRes(R.string.general_remind_me_later),
onClick = ::onRemindMeLaterClick
),
primaryButton = ButtonState(
text = stringRes(R.string.general_ok),
onClick = ::onPrimaryClick
)
)
)
private fun onPrimaryClick() {
navigationRouter.replace(WalletBackupDetail(true))
}
private fun onRemindMeLaterClick() = viewModelScope.launch { remindWalletBackupLater() }
private fun onBack() = navigationRouter.back()
}

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home.backup
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
@ -7,7 +7,6 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -20,6 +19,8 @@ import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.home.HomeMessageState
import co.electriccoin.zcash.ui.screen.home.HomeMessageWrapper
@Suppress("ModifierNaming") @Suppress("ModifierNaming")
@Composable @Composable
@ -34,7 +35,6 @@ fun WalletBackupMessage(
onClick = state.onClick, onClick = state.onClick,
start = { start = {
Image( Image(
modifier = Modifier.align(Alignment.Top),
painter = painterResource(R.drawable.ic_warning_triangle), painter = painterResource(R.drawable.ic_warning_triangle),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(LocalContentColor.current) colorFilter = ColorFilter.tint(LocalContentColor.current)

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home.currency
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -19,6 +18,8 @@ import co.electriccoin.zcash.ui.design.component.ZashiButton
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.util.stringRes import co.electriccoin.zcash.ui.design.util.stringRes
import co.electriccoin.zcash.ui.screen.home.HomeMessageState
import co.electriccoin.zcash.ui.screen.home.HomeMessageWrapper
@Suppress("ModifierNaming") @Suppress("ModifierNaming")
@Composable @Composable
@ -33,7 +34,6 @@ fun EnableCurrencyConversionMessage(
onClick = state.onClick, onClick = state.onClick,
start = { start = {
Image( Image(
modifier = Modifier.align(Alignment.Top),
painter = painterResource(R.drawable.ic_message_currency_conversion), painter = painterResource(R.drawable.ic_message_currency_conversion),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(LocalContentColor.current) colorFilter = ColorFilter.tint(LocalContentColor.current)

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home package co.electriccoin.zcash.ui.screen.home.disconnected
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column

View File

@ -1,11 +1,10 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home.disconnected
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -15,6 +14,8 @@ import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.BlankSurface import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.home.HomeMessageState
import co.electriccoin.zcash.ui.screen.home.HomeMessageWrapper
@Suppress("ModifierNaming") @Suppress("ModifierNaming")
@Composable @Composable
@ -29,7 +30,6 @@ fun WalletDisconnectedMessage(
onClick = state.onClick, onClick = state.onClick,
start = { start = {
Image( Image(
modifier = Modifier.align(Alignment.Top),
painter = painterResource(R.drawable.ic_message_disconnected), painter = painterResource(R.drawable.ic_message_disconnected),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(LocalContentColor.current) colorFilter = ColorFilter.tint(LocalContentColor.current)

View File

@ -1,11 +1,10 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home.error
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@ -15,6 +14,8 @@ import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.BlankSurface import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.home.HomeMessageState
import co.electriccoin.zcash.ui.screen.home.HomeMessageWrapper
@Suppress("ModifierNaming") @Suppress("ModifierNaming")
@Composable @Composable
@ -29,7 +30,6 @@ fun WalletErrorMessage(
onClick = state.onClick, onClick = state.onClick,
start = { start = {
Image( Image(
modifier = Modifier.align(Alignment.Top),
painter = painterResource(R.drawable.ic_warning_triangle), painter = painterResource(R.drawable.ic_warning_triangle),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(LocalContentColor.current) colorFilter = ColorFilter.tint(LocalContentColor.current)

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home package co.electriccoin.zcash.ui.screen.home.restoring
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth

View File

@ -1,7 +1,6 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home.restoring
import androidx.annotation.IntRange import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
@ -13,9 +12,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.BlankSurface import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.component.ZashiCircularProgressIndicator import co.electriccoin.zcash.ui.design.component.ZashiCircularProgressIndicatorByPercent
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.home.HomeMessageState
import co.electriccoin.zcash.ui.screen.home.HomeMessageWrapper
@Suppress("ModifierNaming") @Suppress("ModifierNaming")
@Composable @Composable
@ -29,7 +30,7 @@ fun WalletRestoringMessage(
contentPadding = contentPadding, contentPadding = contentPadding,
onClick = state.onClick, onClick = state.onClick,
start = { start = {
ZashiCircularProgressIndicator( ZashiCircularProgressIndicatorByPercent(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
progressPercent = state.progress, progressPercent = state.progress,
) )
@ -49,7 +50,7 @@ fun WalletRestoringMessage(
} }
class WalletRestoringMessageState( class WalletRestoringMessageState(
@IntRange(from = 0, to = 100) val progress: Int, val progress: Float,
val onClick: () -> Unit val onClick: () -> Unit
) : HomeMessageState ) : HomeMessageState
@ -57,7 +58,7 @@ class WalletRestoringMessageState(
@Composable @Composable
private fun Preview() = private fun Preview() =
ZcashTheme { ZcashTheme {
val progress by animateIntAsState(50, label = "progress", animationSpec = tween(10000)) val progress by animateFloatAsState(50f, label = "progress", animationSpec = tween(10000))
BlankSurface { BlankSurface {
WalletRestoringMessage( WalletRestoringMessage(

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home package co.electriccoin.zcash.ui.screen.home.syncing
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth

View File

@ -1,7 +1,6 @@
package co.electriccoin.zcash.ui.screen.home.messages package co.electriccoin.zcash.ui.screen.home.syncing
import androidx.annotation.IntRange import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
@ -13,9 +12,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.BlankSurface import co.electriccoin.zcash.ui.design.component.BlankSurface
import co.electriccoin.zcash.ui.design.component.ZashiCircularProgressIndicator import co.electriccoin.zcash.ui.design.component.ZashiCircularProgressIndicatorByPercent
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.screen.home.HomeMessageState
import co.electriccoin.zcash.ui.screen.home.HomeMessageWrapper
@Suppress("ModifierNaming") @Suppress("ModifierNaming")
@Composable @Composable
@ -29,7 +30,7 @@ fun WalletSyncingMessage(
contentPadding = contentPadding, contentPadding = contentPadding,
onClick = state.onClick, onClick = state.onClick,
start = { start = {
ZashiCircularProgressIndicator( ZashiCircularProgressIndicatorByPercent(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
progressPercent = state.progress, progressPercent = state.progress,
) )
@ -49,7 +50,7 @@ fun WalletSyncingMessage(
} }
class WalletSyncingMessageState( class WalletSyncingMessageState(
@IntRange(from = 0, to = 100) val progress: Int, val progress: Float,
val onClick: () -> Unit val onClick: () -> Unit
) : HomeMessageState ) : HomeMessageState
@ -57,7 +58,7 @@ class WalletSyncingMessageState(
@Composable @Composable
private fun Preview() = private fun Preview() =
ZcashTheme { ZcashTheme {
val progress by animateIntAsState(50, label = "progress", animationSpec = tween(10000)) val progress by animateFloatAsState(50f, label = "progress", animationSpec = tween(10000))
BlankSurface { BlankSurface {
WalletSyncingMessage( WalletSyncingMessage(

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.balance package co.electriccoin.zcash.ui.screen.home.transparentbalance
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.balance package co.electriccoin.zcash.ui.screen.home.transparentbalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import co.electriccoin.zcash.ui.design.component.ButtonState import co.electriccoin.zcash.ui.design.component.ButtonState

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.screen.home.balance package co.electriccoin.zcash.ui.screen.home.transparentbalance
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column

Some files were not shown because too many files have changed in this diff Show More