Receive screen account expanded state is now reset on account change
This commit is contained in:
parent
9ae240ce29
commit
1580f7045c
|
@ -30,6 +30,7 @@ import co.electriccoin.zcash.ui.common.usecase.ObserveContactPickedUseCase
|
|||
import co.electriccoin.zcash.ui.common.usecase.ObserveCurrentTransactionsUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveFastestServersUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveIsFlexaAvailableUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveOnAccountChangedUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObservePersistableWalletUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveSelectedEndpointUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveSelectedWalletAccountUseCase
|
||||
|
@ -122,4 +123,5 @@ val useCaseModule =
|
|||
factoryOf(::ObserveTransactionProposalUseCase)
|
||||
factoryOf(::SharePCZTUseCase)
|
||||
factoryOf(::CreateKeystoneProposalPCZTEncoderUseCase)
|
||||
factoryOf(::ObserveOnAccountChangedUseCase)
|
||||
}
|
||||
|
|
|
@ -25,10 +25,12 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
|
@ -37,11 +39,14 @@ import kotlinx.coroutines.flow.flowOn
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.retryWhen
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
interface AccountDataSource {
|
||||
val onAccountChanged: Flow<Unit>
|
||||
|
||||
val allAccounts: StateFlow<List<WalletAccount>?>
|
||||
|
||||
val selectedAccount: Flow<WalletAccount?>
|
||||
|
@ -72,6 +77,8 @@ class AccountDataSourceImpl(
|
|||
) : AccountDataSource {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
override val onAccountChanged = MutableSharedFlow<Unit>()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private val internalAccounts: Flow<List<InternalAccountWithBalances>?> =
|
||||
synchronizerProvider
|
||||
|
@ -199,12 +206,14 @@ class AccountDataSourceImpl(
|
|||
.map { account ->
|
||||
account?.firstOrNull { it.isSelected }
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
override val zashiAccount: Flow<ZashiAccount?> =
|
||||
allAccounts
|
||||
.map { account ->
|
||||
account?.filterIsInstance<ZashiAccount>()?.firstOrNull()
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
override suspend fun getAllAccounts() =
|
||||
withContext(Dispatchers.IO) {
|
||||
|
@ -221,15 +230,21 @@ class AccountDataSourceImpl(
|
|||
zashiAccount.filterNotNull().first()
|
||||
}
|
||||
|
||||
override suspend fun selectAccount(account: Account) =
|
||||
override suspend fun selectAccount(account: Account) {
|
||||
withContext(Dispatchers.IO) {
|
||||
selectedAccountUUIDProvider.setUUID(account.accountUuid)
|
||||
}
|
||||
val current = selectedAccountUUIDProvider.getUUID()
|
||||
|
||||
override suspend fun selectAccount(account: WalletAccount) =
|
||||
withContext(Dispatchers.IO) {
|
||||
selectedAccountUUIDProvider.setUUID(account.sdkAccount.accountUuid)
|
||||
selectedAccountUUIDProvider.setUUID(account.accountUuid)
|
||||
|
||||
scope.launch {
|
||||
if (current != account.accountUuid) {
|
||||
onAccountChanged.emit(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun selectAccount(account: WalletAccount) = selectAccount(account.sdkAccount)
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override suspend fun importKeystoneAccount(
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package co.electriccoin.zcash.ui.common.usecase
|
||||
|
||||
import co.electriccoin.zcash.ui.common.datasource.AccountDataSource
|
||||
|
||||
class ObserveOnAccountChangedUseCase(private val accountDataSource: AccountDataSource) {
|
||||
operator fun invoke() = accountDataSource.onAccountChanged
|
||||
}
|
|
@ -11,6 +11,8 @@ data class ReceiveAddressState(
|
|||
val icon: Int,
|
||||
val title: StringResource,
|
||||
val subtitle: StringResource,
|
||||
val isExpanded: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
val isShielded: Boolean,
|
||||
val onCopyClicked: () -> Unit,
|
||||
val onQrClicked: () -> Unit,
|
||||
|
|
|
@ -21,10 +21,6 @@ import androidx.compose.foundation.verticalScroll
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
@ -85,8 +81,6 @@ private fun ReceiveContents(
|
|||
items: List<ReceiveAddressState>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var expandedIndex by rememberSaveable { mutableIntStateOf(0) }
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
modifier
|
||||
|
@ -122,8 +116,6 @@ private fun ReceiveContents(
|
|||
|
||||
AddressPanel(
|
||||
state = state,
|
||||
expanded = index == expandedIndex,
|
||||
onExpand = { expandedIndex = index },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
@ -133,8 +125,6 @@ private fun ReceiveContents(
|
|||
@Composable
|
||||
private fun AddressPanel(
|
||||
state: ReceiveAddressState,
|
||||
expanded: Boolean,
|
||||
onExpand: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
|
@ -151,7 +141,7 @@ private fun AddressPanel(
|
|||
RoundedCornerShape(ZashiDimensions.Radius.radius3xl)
|
||||
)
|
||||
.clip(RoundedCornerShape(ZashiDimensions.Radius.radius3xl))
|
||||
.clickable { onExpand() }
|
||||
.clickable(onClick = state.onClick)
|
||||
.padding(all = ZcashTheme.dimens.spacingLarge)
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
|
@ -192,7 +182,7 @@ private fun AddressPanel(
|
|||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = expanded) {
|
||||
AnimatedVisibility(visible = state.isExpanded) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier =
|
||||
|
@ -298,6 +288,8 @@ private fun ZashiPreview() =
|
|||
onCopyClicked = {},
|
||||
onQrClicked = { },
|
||||
onRequestClicked = {},
|
||||
isExpanded = true,
|
||||
onClick = {}
|
||||
),
|
||||
ReceiveAddressState(
|
||||
icon = R.drawable.ic_zec_round_stroke,
|
||||
|
@ -307,6 +299,8 @@ private fun ZashiPreview() =
|
|||
onCopyClicked = {},
|
||||
onQrClicked = { },
|
||||
onRequestClicked = { },
|
||||
isExpanded = false,
|
||||
onClick = {}
|
||||
)
|
||||
),
|
||||
isLoading = false
|
||||
|
@ -314,28 +308,3 @@ private fun ZashiPreview() =
|
|||
zashiMainTopAppBarState = ZashiMainTopAppBarStateFixture.new()
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun KeystonePreview() =
|
||||
ZcashTheme {
|
||||
ReceiveView(
|
||||
state =
|
||||
ReceiveState(
|
||||
items =
|
||||
listOf(
|
||||
ReceiveAddressState(
|
||||
icon = co.electriccoin.zcash.ui.design.R.drawable.ic_item_keystone,
|
||||
title = stringRes("Keystone Address"),
|
||||
subtitle = stringRes("subtitle"),
|
||||
isShielded = true,
|
||||
onCopyClicked = {},
|
||||
onQrClicked = {},
|
||||
onRequestClicked = {},
|
||||
),
|
||||
),
|
||||
isLoading = false
|
||||
),
|
||||
zashiMainTopAppBarState = ZashiMainTopAppBarStateFixture.new()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,39 +11,48 @@ import co.electriccoin.zcash.ui.common.model.KeystoneAccount
|
|||
import co.electriccoin.zcash.ui.common.model.WalletAccount
|
||||
import co.electriccoin.zcash.ui.common.model.ZashiAccount
|
||||
import co.electriccoin.zcash.ui.common.usecase.CopyToClipboardUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveOnAccountChangedUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveSelectedWalletAccountUseCase
|
||||
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||
import co.electriccoin.zcash.ui.screen.addressbook.viewmodel.ADDRESS_MAX_LENGTH
|
||||
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressState
|
||||
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
|
||||
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveState
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ReceiveViewModel(
|
||||
observeSelectedWalletAccount: ObserveSelectedWalletAccountUseCase,
|
||||
observeOnAccountChanged: ObserveOnAccountChangedUseCase,
|
||||
private val application: Application,
|
||||
private val copyToClipboard: CopyToClipboardUseCase,
|
||||
private val navigationRouter: NavigationRouter,
|
||||
) : ViewModel() {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private val expandedIndex = MutableStateFlow(0)
|
||||
|
||||
internal val state =
|
||||
observeSelectedWalletAccount.require().mapLatest { account ->
|
||||
combine(expandedIndex, observeSelectedWalletAccount.require()) { expandedIndex, account ->
|
||||
ReceiveState(
|
||||
items =
|
||||
listOfNotNull(
|
||||
createAddressState(
|
||||
account = account,
|
||||
address = account.unified.address.address,
|
||||
type = ReceiveAddressType.Unified
|
||||
type = ReceiveAddressType.Unified,
|
||||
isExpanded = expandedIndex == 0,
|
||||
onClick = { onAddressClick(0) }
|
||||
),
|
||||
createAddressState(
|
||||
account = account,
|
||||
address = account.transparent.address.address,
|
||||
type = ReceiveAddressType.Transparent
|
||||
type = ReceiveAddressType.Transparent,
|
||||
isExpanded = expandedIndex == 1,
|
||||
onClick = { onAddressClick(1) }
|
||||
),
|
||||
),
|
||||
isLoading = false
|
||||
|
@ -54,10 +63,20 @@ class ReceiveViewModel(
|
|||
initialValue = ReceiveState(items = null, isLoading = true)
|
||||
)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
observeOnAccountChanged().collect {
|
||||
expandedIndex.update { 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAddressState(
|
||||
account: WalletAccount,
|
||||
address: String,
|
||||
type: ReceiveAddressType
|
||||
type: ReceiveAddressType,
|
||||
isExpanded: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) = ReceiveAddressState(
|
||||
icon =
|
||||
when (account) {
|
||||
|
@ -94,6 +113,8 @@ class ReceiveViewModel(
|
|||
},
|
||||
onQrClicked = { onQrCodeClick(type) },
|
||||
onRequestClicked = { onRequestClick(type) },
|
||||
onClick = onClick,
|
||||
isExpanded = isExpanded
|
||||
)
|
||||
|
||||
private fun onRequestClick(addressType: ReceiveAddressType) =
|
||||
|
@ -101,4 +122,8 @@ class ReceiveViewModel(
|
|||
|
||||
private fun onQrCodeClick(addressType: ReceiveAddressType) =
|
||||
navigationRouter.forward("${NavigationTargets.QR_CODE}/${addressType.ordinal}")
|
||||
|
||||
private fun onAddressClick(index: Int) {
|
||||
expandedIndex.update { index }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue