From 55216988966b5fd5cf7424f5a9c0918807bbfeb5 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Fri, 19 Jan 2024 17:51:07 +0200 Subject: [PATCH 01/10] show add new link connector screen only when not configured linked connectors in settings --- .../android/data/dapp/LedgerMessenger.kt | 5 +- .../withledger/ChooseLedgerScreen.kt | 6 +-- .../withledger/ChooseLedgerViewModel.kt | 48 ++++++------------- .../ImportLegacyWalletScreen.kt | 2 +- .../ImportLegacyWalletViewModel.kt | 22 +++------ .../AddLedgerDeviceViewModel.kt | 8 ++-- .../LedgerHardwareWalletsScreen.kt | 24 +++++----- .../LedgerHardwareWalletsViewModel.kt | 47 ++++++++---------- .../ui/composables/AddLedgerDeviceScreen.kt | 10 ++-- .../AddLedgerDeviceViewModelTest.kt | 2 +- .../withledger/ChooseLedgerViewModelTest.kt | 2 +- 11 files changed, 70 insertions(+), 106 deletions(-) diff --git a/app/src/main/java/com/babylon/wallet/android/data/dapp/LedgerMessenger.kt b/app/src/main/java/com/babylon/wallet/android/data/dapp/LedgerMessenger.kt index ed10d2099a..a72086ee81 100644 --- a/app/src/main/java/com/babylon/wallet/android/data/dapp/LedgerMessenger.kt +++ b/app/src/main/java/com/babylon/wallet/android/data/dapp/LedgerMessenger.kt @@ -18,7 +18,8 @@ import javax.inject.Inject interface LedgerMessenger { - val isConnected: Flow + val isAnyLinkedConnectorConnected: Flow + suspend fun sendDeviceInfoRequest(interactionId: String): Result suspend fun signTransactionRequest( @@ -55,7 +56,7 @@ class LedgerMessengerImpl @Inject constructor( private val peerdroidClient: PeerdroidClient, ) : LedgerMessenger { - override val isConnected: Flow + override val isAnyLinkedConnectorConnected: Flow get() = peerdroidClient.hasAtLeastOneConnection override suspend fun sendDeviceInfoRequest(interactionId: String): Result { diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerScreen.kt b/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerScreen.kt index db7b978137..c1b24de055 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerScreen.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerScreen.kt @@ -102,7 +102,7 @@ fun ChooseLedgerScreen( context.biometricAuthenticateSuspend() }) }, - linkingToConnector = state.linkingToConnector + linkingToConnector = state.isAddingLinkConnector ) } @@ -126,7 +126,7 @@ fun ChooseLedgerScreen( isNewConnectorContinueButtonEnabled = addLinkConnectorState.isContinueButtonEnabled, onNewConnectorContinueClick = { addLinkConnectorViewModel.onContinueClick() - viewModel.onNewConnectorAdded(showContent.addDeviceAfterLinking) + viewModel.onNewLinkConnectorAdded(showContent.addDeviceAfterLinking) }, onNewConnectorCloseClick = { addLinkConnectorViewModel.onCloseClick() @@ -161,7 +161,7 @@ fun ChooseLedgerScreen( viewModel.onCloseClick() }, onMessageShown = addLedgerDeviceViewModel::onMessageShown, - isLinkConnectionEstablished = addLedgerDeviceState.isLinkConnectionEstablished && state.linkingToConnector.not() + isLinkedConnectorEstablished = addLedgerDeviceState.isAnyLinkedConnectorConnected && state.isAddingLinkConnector.not() ) } } diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerViewModel.kt b/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerViewModel.kt index e64aaf907a..816d460190 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerViewModel.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/account/createaccount/withledger/ChooseLedgerViewModel.kt @@ -53,11 +53,6 @@ class ChooseLedgerViewModel @Inject constructor( override fun initialState(): ChooseLedgerUiState = ChooseLedgerUiState() init { - viewModelScope.launch { - ledgerMessenger.isConnected.collect { connected -> - _state.update { it.copy(isLinkConnectionEstablished = connected) } - } - } viewModelScope.launch { getProfileUseCase.ledgerFactorSources.collect { ledgerDevices -> _state.update { uiState -> @@ -117,23 +112,15 @@ class ChooseLedgerViewModel @Inject constructor( selectableLedgerDevice.selected }?.let { ledgerFactorSource -> viewModelScope.launch { - if (getProfileUseCase.p2pLinks.first().isEmpty()) { + val hasAtLeastOneLinkedConnector = getProfileUseCase.p2pLinks.first().isNotEmpty() + // check if there is not linked connector and show link new connector screen + if (hasAtLeastOneLinkedConnector.not()) { _state.update { it.copy(showContent = ChooseLedgerUiState.ShowContent.LinkNewConnector(false)) } return@launch - } else { - if (!state.value.isLinkConnectionEstablished) { - _state.update { - it.copy( - showLinkConnectorPromptState = ShowLinkConnectorPromptState.Show( - ShowLinkConnectorPromptState.Source.UseLedger - ) - ) - } - return@launch - } } + when (args.ledgerSelectionPurpose) { LedgerSelectionPurpose.CreateAccount -> { // check again if link connector exists @@ -192,19 +179,12 @@ class ChooseLedgerViewModel @Inject constructor( fun onAddLedgerDeviceClick() { viewModelScope.launch { - _state.update { - if (getProfileUseCase.p2pLinks.first().isEmpty()) { - it.copy(showContent = ChooseLedgerUiState.ShowContent.LinkNewConnector()) + _state.update { uiState -> + val hasAtLeastOneLinkedConnector = getProfileUseCase.p2pLinks.first().isNotEmpty() + if (hasAtLeastOneLinkedConnector) { + uiState.copy(showContent = ChooseLedgerUiState.ShowContent.AddLedger) } else { - if (!it.isLinkConnectionEstablished) { - it.copy( - showLinkConnectorPromptState = ShowLinkConnectorPromptState.Show( - ShowLinkConnectorPromptState.Source.AddLedgerDevice - ) - ) - } else { - it.copy(showContent = ChooseLedgerUiState.ShowContent.AddLedger) - } + uiState.copy(showContent = ChooseLedgerUiState.ShowContent.LinkNewConnector()) } } } @@ -222,16 +202,16 @@ class ChooseLedgerViewModel @Inject constructor( } } - fun onNewConnectorAdded(addDeviceAfterLinking: Boolean) { - _state.update { it.copy(linkingToConnector = true) } + fun onNewLinkConnectorAdded(addDeviceAfterLinking: Boolean) { + _state.update { it.copy(isAddingLinkConnector = true) } if (addDeviceAfterLinking) { showAddLedgerDeviceContent() } else { onCloseClick() } viewModelScope.launch { - ledgerMessenger.isConnected.filter { it }.firstOrNull()?.let { - _state.update { state -> state.copy(linkingToConnector = false) } + ledgerMessenger.isAnyLinkedConnectorConnected.filter { it }.firstOrNull()?.let { + _state.update { state -> state.copy(isAddingLinkConnector = false) } } } } @@ -250,7 +230,7 @@ data class ChooseLedgerUiState( val selectedLedgerDeviceId: FactorSource.FactorSourceID.FromHash? = null, val isLinkConnectionEstablished: Boolean = false, val showLinkConnectorPromptState: ShowLinkConnectorPromptState = ShowLinkConnectorPromptState.None, - val linkingToConnector: Boolean = false + val isAddingLinkConnector: Boolean = false ) : UiState { sealed interface ShowContent { diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletScreen.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletScreen.kt index a4e216a7b6..e7408c449e 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletScreen.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletScreen.kt @@ -419,7 +419,7 @@ private fun ImportLegacyWalletContent( onClose = onCloseSettings, waitingForLedgerResponse = waitingForLedgerResponse, onBackClick = onCloseSettings, - isLinkConnectionEstablished = true + isLinkedConnectorEstablished = true ) } diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletViewModel.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletViewModel.kt index b014539c2e..6500c4505a 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletViewModel.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/importlegacywallet/ImportLegacyWalletViewModel.kt @@ -90,11 +90,6 @@ class ImportLegacyWalletViewModel @Inject constructor( ) init { - viewModelScope.launch { - ledgerMessenger.isConnected.collect { connected -> - _state.update { it.copy(isLinkConnectionEstablished = connected) } - } - } viewModelScope.launch { useLedgerDelegate.state.collect { delegateState -> _state.update { uiState -> @@ -446,15 +441,11 @@ class ImportLegacyWalletViewModel @Inject constructor( fun onContinueWithLedgerClick() { viewModelScope.launch { - if (getProfileUseCase.p2pLinks.first().isNotEmpty()) { - if (state.value.isLinkConnectionEstablished.not()) { - _state.update { - it.copy(shouldShowAddLinkConnectorScreen = true) - } - } else { - useLedgerDelegate.onSendAddLedgerRequest() - } - } else if (getProfileUseCase.p2pLinks.first().isEmpty()) { + val hasAtLeastOneLinkedConnector = getProfileUseCase.p2pLinks.first().isNotEmpty() + + if (hasAtLeastOneLinkedConnector) { + useLedgerDelegate.onSendAddLedgerRequest() + } else if (hasAtLeastOneLinkedConnector.not()) { _state.update { it.copy(shouldShowAddLinkConnectorScreen = true) } @@ -522,8 +513,7 @@ data class ImportLegacyWalletUiState( val seedPhraseInputState: SeedPhraseInputDelegate.State = SeedPhraseInputDelegate.State(), val shouldShowAddLinkConnectorScreen: Boolean = false, val shouldShowAddLedgerDeviceScreen: Boolean = false, - var existingOlympiaFactorSourceId: FactorSourceID.FromHash? = null, - val isLinkConnectionEstablished: Boolean = false, + var existingOlympiaFactorSourceId: FactorSourceID.FromHash? = null ) : UiState { fun mnemonicWithPassphrase(): MnemonicWithPassphrase { diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/AddLedgerDeviceViewModel.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/AddLedgerDeviceViewModel.kt index 9742f151d1..2bfdc11bab 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/AddLedgerDeviceViewModel.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/AddLedgerDeviceViewModel.kt @@ -86,8 +86,8 @@ class AddLedgerDeviceViewModel @Inject constructor( private fun observeLinkConnectionStatus() { viewModelScope.launch { - ledgerMessenger.isConnected.collect { connected -> - _state.update { it.copy(isLinkConnectionEstablished = connected) } + ledgerMessenger.isAnyLinkedConnectorConnected.collect { isConnected -> + _state.update { it.copy(isAnyLinkedConnectorConnected = isConnected) } } } } @@ -101,7 +101,7 @@ class AddLedgerDeviceViewModel @Inject constructor( fun initState() { _state.update { current -> - AddLedgerDeviceUiState.init.copy(isLinkConnectionEstablished = current.isLinkConnectionEstablished) + AddLedgerDeviceUiState.init.copy(isAnyLinkedConnectorConnected = current.isAnyLinkedConnectorConnected) } } @@ -136,7 +136,7 @@ data class AddLedgerDeviceUiState( val showContent: ShowContent, val newConnectedLedgerDevice: LedgerDeviceUiModel?, val uiMessage: UiMessage?, - val isLinkConnectionEstablished: Boolean = false + val isAnyLinkedConnectorConnected: Boolean = false ) : UiState { enum class ShowContent { diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsScreen.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsScreen.kt index 95699c51dd..d4db56c70b 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsScreen.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsScreen.kt @@ -95,7 +95,7 @@ fun LedgerHardwareWalletsScreen( ledgerDevices = state.ledgerDevices, onAddLedgerDeviceClick = viewModel::onAddLedgerDeviceClick, onBackClick = onBackClick, - linkingToConnector = state.isAddLedgerButtonEnabled + isNewLinkedConnectorConnected = state.isNewLinkedConnectorConnected ) } @@ -122,7 +122,7 @@ fun LedgerHardwareWalletsScreen( addLedgerDeviceViewModel.initState() viewModel.onCloseClick() }, - isLinkConnectionEstablished = addLedgerDeviceState.isLinkConnectionEstablished + isLinkedConnectorEstablished = addLedgerDeviceState.isAnyLinkedConnectorConnected ) } @@ -163,7 +163,7 @@ private fun LedgerHardwareWalletsContent( ledgerDevices: ImmutableList, onAddLedgerDeviceClick: () -> Unit, onBackClick: () -> Unit, - linkingToConnector: Boolean, + isNewLinkedConnectorConnected: Boolean, ) { BackHandler(onBack = onBackClick) @@ -183,7 +183,7 @@ private fun LedgerHardwareWalletsContent( modifier = Modifier.fillMaxWidth(), ledgerFactorSources = ledgerDevices, onAddLedgerDeviceClick = onAddLedgerDeviceClick, - linkingToConnector = linkingToConnector + isNewLinkedConnectorConnected = isNewLinkedConnectorConnected ) } } @@ -194,7 +194,7 @@ private fun LedgerDeviceDetails( modifier: Modifier = Modifier, ledgerFactorSources: ImmutableList, onAddLedgerDeviceClick: () -> Unit, - linkingToConnector: Boolean + isNewLinkedConnectorConnected: Boolean ) { Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) { Spacer(modifier = Modifier.height(RadixTheme.dimensions.paddingMedium)) @@ -212,7 +212,7 @@ private fun LedgerDeviceDetails( .fillMaxWidth(), ledgerDevices = ledgerFactorSources, onAddLedgerDeviceClick = onAddLedgerDeviceClick, - linkingToConnector = linkingToConnector + isNewLinkedConnectorConnected = isNewLinkedConnectorConnected ) } else { Text( @@ -234,7 +234,8 @@ private fun LedgerDeviceDetails( modifier = Modifier .fillMaxWidth(0.7f) .imePadding(), - enabled = linkingToConnector.not(), + isLoading = isNewLinkedConnectorConnected.not(), + enabled = isNewLinkedConnectorConnected, throttleClicks = true ) } @@ -246,7 +247,7 @@ private fun LedgerDevicesListContent( modifier: Modifier = Modifier, ledgerDevices: ImmutableList, onAddLedgerDeviceClick: () -> Unit, - linkingToConnector: Boolean + isNewLinkedConnectorConnected: Boolean ) { LazyColumn( modifier, @@ -280,7 +281,8 @@ private fun LedgerDevicesListContent( text = stringResource(id = R.string.ledgerHardwareDevices_addNewLedger), onClick = onAddLedgerDeviceClick, throttleClicks = true, - enabled = linkingToConnector.not() + isLoading = isNewLinkedConnectorConnected.not(), + enabled = isNewLinkedConnectorConnected ) } } @@ -294,7 +296,7 @@ fun LedgerHardwareWalletsScreenEmptyPreview() { ledgerDevices = persistentListOf(), onAddLedgerDeviceClick = {}, onBackClick = {}, - linkingToConnector = true + isNewLinkedConnectorConnected = true ) } } @@ -307,7 +309,7 @@ fun LedgerHardwareWalletsScreenPreview() { ledgerDevices = SampleDataProvider().ledgerFactorSourcesSample.toPersistentList(), onAddLedgerDeviceClick = {}, onBackClick = {}, - linkingToConnector = true + isNewLinkedConnectorConnected = true ) } } diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsViewModel.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsViewModel.kt index ea2e561392..1241e49123 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsViewModel.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/accountsecurity/ledgerhardwarewallets/LedgerHardwareWalletsViewModel.kt @@ -8,9 +8,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.dropWhile import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import rdx.works.profile.data.model.factorsources.LedgerHardwareWalletFactorSource @@ -28,11 +28,6 @@ class LedgerHardwareWalletsViewModel @Inject constructor( override fun initialState(): LedgerHardwareWalletsUiState = LedgerHardwareWalletsUiState() init { - viewModelScope.launch { - ledgerMessenger.isConnected.collect { connected -> - _state.update { it.copy(isLinkConnectionEstablished = connected) } - } - } viewModelScope.launch { getProfileUseCase.ledgerFactorSources.collect { ledgerDevices -> _state.update { uiState -> @@ -44,19 +39,18 @@ class LedgerHardwareWalletsViewModel @Inject constructor( fun onAddLedgerDeviceClick() { viewModelScope.launch { - if (getProfileUseCase.p2pLinks.first().isEmpty()) { - _state.update { it.copy(showContent = LedgerHardwareWalletsUiState.ShowContent.LinkNewConnector) } + val hasAtLeastOneLinkedConnector = getProfileUseCase.p2pLinks.first().isNotEmpty() + if (hasAtLeastOneLinkedConnector) { + _state.update { + it.copy(showContent = LedgerHardwareWalletsUiState.ShowContent.AddLedger) + } } else { - if (!state.value.isLinkConnectionEstablished) { - _state.update { - it.copy( - showLinkConnectorPromptState = ShowLinkConnectorPromptState.Show( - ShowLinkConnectorPromptState.Source.UseLedger - ) + _state.update { + it.copy( + showLinkConnectorPromptState = ShowLinkConnectorPromptState.Show( + source = ShowLinkConnectorPromptState.Source.UseLedger ) - } - } else { - _state.update { it.copy(showContent = LedgerHardwareWalletsUiState.ShowContent.AddLedger) } + ) } } } @@ -77,18 +71,16 @@ class LedgerHardwareWalletsViewModel @Inject constructor( fun disableAddLedgerButtonUntilConnectionIsEstablished() { _state.update { - it.copy( - showContent = LedgerHardwareWalletsUiState.ShowContent.Details, - isAddLedgerButtonEnabled = true - ) + it.copy(showContent = LedgerHardwareWalletsUiState.ShowContent.Details) } - viewModelScope.launch { - ledgerMessenger.isConnected.filter { it }.firstOrNull()?.let { + ledgerMessenger.isAnyLinkedConnectorConnected + .dropWhile { isConnected -> _state.update { state -> - state.copy(isAddLedgerButtonEnabled = false) + state.copy(isNewLinkedConnectorConnected = isConnected) } + isConnected.not() // continue while isConnected is not true } - } + .launchIn(viewModelScope) } fun onCloseClick() { @@ -115,8 +107,7 @@ data class LedgerHardwareWalletsUiState( val showContent: ShowContent = ShowContent.Details, val ledgerDevices: ImmutableList = persistentListOf(), val showLinkConnectorPromptState: ShowLinkConnectorPromptState = ShowLinkConnectorPromptState.None, - val isLinkConnectionEstablished: Boolean = false, - val isAddLedgerButtonEnabled: Boolean = false + val isNewLinkedConnectorConnected: Boolean = true ) : UiState { sealed interface ShowContent { diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/AddLedgerDeviceScreen.kt b/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/AddLedgerDeviceScreen.kt index e1f139f02b..1ead1f8f45 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/AddLedgerDeviceScreen.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/AddLedgerDeviceScreen.kt @@ -54,7 +54,7 @@ fun AddLedgerDeviceScreen( onClose: () -> Unit, waitingForLedgerResponse: Boolean, onBackClick: () -> Unit, - isLinkConnectionEstablished: Boolean + isLinkedConnectorEstablished: Boolean ) { BackHandler(onBack = onBackClick) @@ -140,8 +140,8 @@ fun AddLedgerDeviceScreen( modifier = Modifier.fillMaxWidth(), onClick = onSendAddLedgerRequestClick, text = stringResource(id = com.babylon.wallet.android.R.string.addLedgerDevice_addDevice_continue), - enabled = isLinkConnectionEstablished, - isLoading = !isLinkConnectionEstablished + enabled = isLinkedConnectorEstablished, + isLoading = isLinkedConnectorEstablished.not() ) } @@ -230,7 +230,7 @@ fun AddLedgerDeviceScreenPreview() { onClose = {}, waitingForLedgerResponse = false, onBackClick = {}, - isLinkConnectionEstablished = true + isLinkedConnectorEstablished = true ) } } @@ -251,7 +251,7 @@ fun AddLedgerDeviceContentPreview3() { onClose = {}, waitingForLedgerResponse = false, onBackClick = {}, - isLinkConnectionEstablished = true + isLinkedConnectorEstablished = true ) } } diff --git a/app/src/test/java/com/babylon/wallet/android/presentation/createaccount/withledger/AddLedgerDeviceViewModelTest.kt b/app/src/test/java/com/babylon/wallet/android/presentation/createaccount/withledger/AddLedgerDeviceViewModelTest.kt index 8c74a12867..615c15e559 100644 --- a/app/src/test/java/com/babylon/wallet/android/presentation/createaccount/withledger/AddLedgerDeviceViewModelTest.kt +++ b/app/src/test/java/com/babylon/wallet/android/presentation/createaccount/withledger/AddLedgerDeviceViewModelTest.kt @@ -41,7 +41,7 @@ class AddLedgerDeviceViewModelTest : StateViewModelTest(ARG_NETWORK_ID) } returns Radix.Gateway.mainnet.network.id From a4d0df0ac1ef3d8bcf22b40449c16d63013efeef Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Fri, 19 Jan 2024 17:54:07 +0200 Subject: [PATCH 02/10] added PeerConnectionStatus in PeerdroidConnector that informs the client for the status of each available peer connection --- .../peerdroid/data/PeerdroidConnector.kt | 34 +++++++++++++++++++ .../peerdroid/domain/PeerConnectionStatus.kt | 6 ++++ 2 files changed, 40 insertions(+) create mode 100644 peerdroid/src/main/java/rdx/works/peerdroid/domain/PeerConnectionStatus.kt diff --git a/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt b/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt index 53d79fdcaf..11902b461d 100644 --- a/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt +++ b/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt @@ -47,6 +47,7 @@ import rdx.works.peerdroid.domain.ConnectionIdHolder import rdx.works.peerdroid.domain.DataChannelHolder import rdx.works.peerdroid.domain.DataChannelWrapperEvent import rdx.works.peerdroid.domain.PeerConnectionHolder +import rdx.works.peerdroid.domain.PeerConnectionStatus import rdx.works.peerdroid.domain.RemoteClientHolder import rdx.works.peerdroid.domain.WebSocketHolder import timber.log.Timber @@ -56,6 +57,8 @@ interface PeerdroidConnector { val anyChannelConnected: Flow + val peerConnectionStatus: Flow> + suspend fun connectToConnectorExtension(encryptionKey: ByteArray): Result suspend fun deleteConnector(connectionId: ConnectionIdHolder) @@ -92,6 +95,8 @@ internal class PeerdroidConnectorImpl( private val isAnyChannelConnected = MutableStateFlow(false) + private val _peerConnectionStatus = MutableStateFlow(emptyMap()) + init { Timber.d("⚙️ init PeerdroidConnector") } @@ -99,6 +104,9 @@ internal class PeerdroidConnectorImpl( override val anyChannelConnected: Flow get() = isAnyChannelConnected.asSharedFlow() + override val peerConnectionStatus: Flow> + get() = _peerConnectionStatus + override suspend fun connectToConnectorExtension(encryptionKey: ByteArray): Result { val connectionId = encryptionKey.blake2Hash().toHexString() @@ -151,6 +159,7 @@ internal class PeerdroidConnectorImpl( dataChannelHolder.dataChannel.close() } mapOfDataChannels.values.removeAll(dataChannelsForTermination.toSet()) + updateMapOfPeerConnectionState(connectionId = connectionId, isOpen = false, isDeleted = true) Timber.d("⚙️ \uD83D\uDDD1️ link connection with connectionId: ${connectionId.id} deleted ✅") } } @@ -304,6 +313,7 @@ internal class PeerdroidConnectorImpl( .onEach { event -> when (event) { is PeerConnectionEvent.RenegotiationNeeded -> { + updateMapOfPeerConnectionState(connectionId = connectionId, isConnecting = true) Timber.d("⚙️ ⚡ renegotiation needed for remote client: $remoteClientHolder \uD83C\uDD97") renegotiationDeferred.complete(Unit) } @@ -333,6 +343,7 @@ internal class PeerdroidConnectorImpl( dataChannel = dataChannel ) isAnyChannelConnected.tryEmit(mapOfDataChannels.values.isNotEmpty()) + updateMapOfPeerConnectionState(connectionId = connectionId, isConnecting = false, isOpen = true) Timber.d("⚙️ ℹ️ current count of data channels: ${mapOfDataChannels.size}") } @@ -340,6 +351,7 @@ internal class PeerdroidConnectorImpl( Timber.d("⚙️ ⚡ peer connection disconnected for remote client: $remoteClientHolder \uD83D\uDD34") terminatePeerConnectionAndDataChannel(remoteClientHolder, connectionId) isAnyChannelConnected.tryEmit(mapOfDataChannels.values.isNotEmpty()) + updateMapOfPeerConnectionState(connectionId = connectionId, isConnecting = false, isOpen = false) } is PeerConnectionEvent.Failed -> { @@ -476,4 +488,26 @@ internal class PeerdroidConnectorImpl( ) } } + + private fun updateMapOfPeerConnectionState( + connectionId: ConnectionIdHolder, + isConnecting: Boolean = false, + isOpen: Boolean = false, + isDeleted: Boolean = false + ) { + val mapOfPeerConnectionStatus = _peerConnectionStatus.value.toMutableMap() + mapOfPeerConnectionStatus[connectionId.id] = if (isConnecting) { + PeerConnectionStatus.CONNECTING + } else { + if (isOpen) { + PeerConnectionStatus.OPEN + } else { + PeerConnectionStatus.CLOSED + } + } + if (isDeleted) { + mapOfPeerConnectionStatus.remove(connectionId.id) + } + _peerConnectionStatus.tryEmit(mapOfPeerConnectionStatus) + } } diff --git a/peerdroid/src/main/java/rdx/works/peerdroid/domain/PeerConnectionStatus.kt b/peerdroid/src/main/java/rdx/works/peerdroid/domain/PeerConnectionStatus.kt new file mode 100644 index 0000000000..2abd924832 --- /dev/null +++ b/peerdroid/src/main/java/rdx/works/peerdroid/domain/PeerConnectionStatus.kt @@ -0,0 +1,6 @@ +package rdx.works.peerdroid.domain + +// it indicates the PeerConnection state that can be used as a simple indicator in the UI +enum class PeerConnectionStatus { + OPEN, CLOSED, CONNECTING +} From 9aac406ef26f1c2ba1ac665846eecf97bcdc7f31 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Fri, 19 Jan 2024 17:58:21 +0200 Subject: [PATCH 03/10] added a new debug setting item for peer connection status indicator --- .../presentation/settings/SettingsItem.kt | 7 +++- .../settings/debug/DebugSettingsNav.kt | 4 ++ .../settings/debug/DebugSettingsScreen.kt | 39 +++++++++++++++---- .../settings/debug/DebugSettingsViewModel.kt | 37 ++++++++++++++++++ .../core/preferences/PreferencesManager.kt | 12 ++++++ 5 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsViewModel.kt diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/SettingsItem.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/SettingsItem.kt index f9a33d747a..b3bbf1c7c5 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/SettingsItem.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/SettingsItem.kt @@ -108,10 +108,13 @@ sealed interface SettingsItem { sealed interface DebugSettingsItem { data object InspectProfile : DebugSettingsItem + data object LinkConnectionStatusIndicator : DebugSettingsItem + @StringRes fun descriptionRes(): Int { return when (this) { InspectProfile -> R.string.settings_debugSettings_inspectProfile + LinkConnectionStatusIndicator -> R.string.linkedConnectors_title } } @@ -119,12 +122,14 @@ sealed interface SettingsItem { fun getIcon(): Int? { // add rest of icons return when (this) { InspectProfile -> com.babylon.wallet.android.designsystem.R.drawable.ic_personas + LinkConnectionStatusIndicator -> com.babylon.wallet.android.designsystem.R.drawable.ic_desktop_connection } } companion object { fun values() = setOf( - InspectProfile + InspectProfile, + LinkConnectionStatusIndicator ) } } diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsNav.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsNav.kt index f60b8d9fe2..70087b5c11 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsNav.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsNav.kt @@ -2,10 +2,12 @@ package com.babylon.wallet.android.presentation.settings.debug import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.EnterTransition +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import androidx.navigation.navigation +import com.babylon.wallet.android.presentation.settings.SettingsItem import com.babylon.wallet.android.presentation.settings.SettingsItem.DebugSettingsItem.InspectProfile import com.babylon.wallet.android.presentation.settings.debug.profile.inspectProfile @@ -41,12 +43,14 @@ fun NavGraphBuilder.debugSettings( } ) { DebugSettingsScreen( + viewModel = hiltViewModel(), onBackClick = { navController.popBackStack() }, onItemClick = { item -> when (item) { InspectProfile -> navController.inspectProfile() + SettingsItem.DebugSettingsItem.LinkConnectionStatusIndicator -> {} } } ) diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsScreen.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsScreen.kt index a9af0ce877..58fdd602dd 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsScreen.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsScreen.kt @@ -3,27 +3,34 @@ package com.babylon.wallet.android.presentation.settings.debug import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.babylon.wallet.android.R import com.babylon.wallet.android.designsystem.theme.RadixTheme import com.babylon.wallet.android.presentation.settings.SettingsItem import com.babylon.wallet.android.presentation.ui.composables.DefaultSettingsItem import com.babylon.wallet.android.presentation.ui.composables.RadixCenteredTopAppBar +import com.babylon.wallet.android.presentation.ui.composables.SwitchSettingsItem @Composable fun DebugSettingsScreen( modifier: Modifier = Modifier, + viewModel: DebugSettingsViewModel, onBackClick: () -> Unit, onItemClick: (SettingsItem.DebugSettingsItem) -> Unit ) { + val linkConnectionStatusIndicatorState by viewModel.linkConnectionStatusIndicatorState.collectAsStateWithLifecycle() + Scaffold( modifier = modifier, topBar = { @@ -41,16 +48,32 @@ fun DebugSettingsScreen( ) { HorizontalDivider(color = RadixTheme.colors.gray5) LazyColumn(modifier = Modifier.fillMaxSize()) { - SettingsItem.DebugSettingsItem.values().forEachIndexed { index, appSettingsItem -> + SettingsItem.DebugSettingsItem.values().forEach { debugSettingsItem -> item { - DefaultSettingsItem( - title = stringResource(id = appSettingsItem.descriptionRes()), - icon = appSettingsItem.getIcon(), - onClick = { - onItemClick(appSettingsItem) + when (debugSettingsItem) { + SettingsItem.DebugSettingsItem.InspectProfile -> { + DefaultSettingsItem( + title = stringResource(id = debugSettingsItem.descriptionRes()), + icon = debugSettingsItem.getIcon(), + onClick = { + onItemClick(debugSettingsItem) + } + ) + HorizontalDivider(color = RadixTheme.colors.gray5) + } + SettingsItem.DebugSettingsItem.LinkConnectionStatusIndicator -> { + SwitchSettingsItem( + modifier = Modifier + .fillMaxWidth() + .padding(all = RadixTheme.dimensions.paddingDefault), + titleRes = debugSettingsItem.descriptionRes(), + iconResource = debugSettingsItem.getIcon(), + checked = linkConnectionStatusIndicatorState.isEnabled, + onCheckedChange = viewModel::onLinkConnectionStatusIndicatorToggled + ) + HorizontalDivider(color = RadixTheme.colors.gray5) } - ) - HorizontalDivider(color = RadixTheme.colors.gray5) + } } } } diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsViewModel.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsViewModel.kt new file mode 100644 index 0000000000..9f12055132 --- /dev/null +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/debug/DebugSettingsViewModel.kt @@ -0,0 +1,37 @@ +package com.babylon.wallet.android.presentation.settings.debug + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.babylon.wallet.android.utils.Constants +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import rdx.works.core.preferences.PreferencesManager +import javax.inject.Inject + +@HiltViewModel +class DebugSettingsViewModel @Inject constructor( + private val preferencesManager: PreferencesManager +) : ViewModel() { + + @OptIn(ExperimentalCoroutinesApi::class) + val linkConnectionStatusIndicatorState = preferencesManager + .isLinkConnectionStatusIndicatorEnabled + .mapLatest { isEnabled -> + LinkConnectionStatusIndicator(isEnabled = isEnabled) + } + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(Constants.VM_STOP_TIMEOUT_MS), + initialValue = LinkConnectionStatusIndicator(isEnabled = true) + ) + + fun onLinkConnectionStatusIndicatorToggled(isEnabled: Boolean) = viewModelScope.launch { + preferencesManager.setLinkConnectionStatusIndicator(isEnabled = isEnabled) + } + + data class LinkConnectionStatusIndicator(val isEnabled: Boolean) +} diff --git a/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt b/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt index 026676fb9f..1ae6dd6bc0 100644 --- a/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt +++ b/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt @@ -132,6 +132,17 @@ class PreferencesManager @Inject constructor( } } + val isLinkConnectionStatusIndicatorEnabled: Flow = dataStore.data + .map { preferences -> + preferences[KEY_LINK_CONNECTION_STATUS_INDICATOR] ?: true + } + + suspend fun setLinkConnectionStatusIndicator(isEnabled: Boolean) { + dataStore.edit { preferences -> + preferences[KEY_LINK_CONNECTION_STATUS_INDICATOR] = isEnabled + } + } + suspend fun clear() = dataStore.edit { it.clear() } companion object { @@ -144,5 +155,6 @@ class PreferencesManager @Inject constructor( private val KEY_IMPORT_OLYMPIA_WALLET_SETTING_DISMISSED = booleanPreferencesKey("import_olympia_wallet_setting_dismissed") private val KEY_DEVICE_ROOTED_DIALOG_SHOWN = booleanPreferencesKey("device_rooted_dialog_shown") + private val KEY_LINK_CONNECTION_STATUS_INDICATOR = booleanPreferencesKey("link_connection_status_indicator") } } From b7809cc4d15e8d44cbe140fc05bf8314294daa78 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Fri, 19 Jan 2024 17:58:41 +0200 Subject: [PATCH 04/10] added a LinkConnectionStatusObserver --- .../android/LinkConnectionStatusObserver.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt diff --git a/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt b/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt new file mode 100644 index 0000000000..61651a380d --- /dev/null +++ b/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt @@ -0,0 +1,66 @@ +package com.babylon.wallet.android + +import androidx.compose.ui.graphics.Color +import com.babylon.wallet.android.di.coroutines.ApplicationScope +import com.babylon.wallet.android.utils.Constants +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import rdx.works.core.preferences.PreferencesManager +import rdx.works.peerdroid.data.PeerdroidConnector +import rdx.works.peerdroid.domain.PeerConnectionStatus +import javax.inject.Inject + +class LinkConnectionStatusObserver @Inject constructor( + peerdroidConnector: PeerdroidConnector, + preferencesManager: PreferencesManager, + @ApplicationScope private val applicationScope: CoroutineScope +) { + + val isEnabled = preferencesManager + .isLinkConnectionStatusIndicatorEnabled + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(Constants.VM_STOP_TIMEOUT_MS), + initialValue = true + ) + + val currentStatus = peerdroidConnector + .peerConnectionStatus + .map { mapOfPeerConnectionStatus -> + LinkConnectionsStatus( + peerConnectionState = mapOfPeerConnectionStatus.values.toPersistentList() + ) + } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(Constants.VM_STOP_TIMEOUT_MS), + initialValue = LinkConnectionsStatus() + ) + + data class LinkConnectionsStatus( + private val peerConnectionState: ImmutableList = persistentListOf() + ) { + + fun currentStatus() = peerConnectionState + .map { state -> + when (state) { + PeerConnectionStatus.OPEN -> { + Color.Green + } + + PeerConnectionStatus.CLOSED -> { + Color.Red + } + + PeerConnectionStatus.CONNECTING -> { + Color.Yellow + } + } + } + } +} From 65de623cb2b1b49409e79aea75573f22780cfcf1 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Fri, 19 Jan 2024 17:59:05 +0200 Subject: [PATCH 05/10] added link connection status indicator in the top system bar --- .../babylon/wallet/android/MainActivity.kt | 18 +++++- .../composables/DevelopmentPreviewWrapper.kt | 61 ++++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/babylon/wallet/android/MainActivity.kt b/app/src/main/java/com/babylon/wallet/android/MainActivity.kt index 447bfd36d6..bc76536a81 100644 --- a/app/src/main/java/com/babylon/wallet/android/MainActivity.kt +++ b/app/src/main/java/com/babylon/wallet/android/MainActivity.kt @@ -17,12 +17,14 @@ import androidx.core.splashscreen.SplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import androidx.fragment.app.FragmentActivity +import com.babylon.wallet.android.LinkConnectionStatusObserver.LinkConnectionsStatus import com.babylon.wallet.android.designsystem.theme.RadixWalletTheme import com.babylon.wallet.android.presentation.main.AppState import com.babylon.wallet.android.presentation.main.MainViewModel import com.babylon.wallet.android.presentation.ui.composables.DevBannerState import com.babylon.wallet.android.presentation.ui.composables.DevelopmentPreviewWrapper import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject // Extending from FragmentActivity because of Biometric @AndroidEntryPoint @@ -30,6 +32,9 @@ class MainActivity : FragmentActivity() { private val viewModel: MainViewModel by viewModels() + @Inject + lateinit var linkConnectionStatusObserver: LinkConnectionStatusObserver + override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { @@ -46,7 +51,18 @@ class MainActivity : FragmentActivity() { derivedStateOf { DevBannerState(isVisible = isDevBannerVisible) } } - DevelopmentPreviewWrapper(devBannerState = devBannerState) { padding -> + var linkConnectionsStatus: LinkConnectionsStatus? = null + if (BuildConfig.EXPERIMENTAL_FEATURES_ENABLED) { + val isLinkConnectionsStatusEnabled by linkConnectionStatusObserver.isEnabled.collectAsState() + if (isLinkConnectionsStatusEnabled) { + linkConnectionsStatus = linkConnectionStatusObserver.currentStatus.collectAsState().value + } + } + + DevelopmentPreviewWrapper( + devBannerState = devBannerState, + linkConnectionsStatus = linkConnectionsStatus + ) { padding -> WalletApp( modifier = Modifier.padding(padding), mainViewModel = viewModel, diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt b/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt index d702481657..ddfc62ccb6 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt @@ -2,12 +2,18 @@ package com.babylon.wallet.android.presentation.ui.composables +import androidx.compose.foundation.Canvas import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -24,13 +30,18 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.babylon.wallet.android.LinkConnectionStatusObserver.LinkConnectionsStatus import com.babylon.wallet.android.R import com.babylon.wallet.android.designsystem.theme.RadixTheme import com.babylon.wallet.android.designsystem.theme.RadixWalletTheme +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf @Composable fun DevelopmentPreviewWrapper( modifier: Modifier = Modifier, + linkConnectionsStatus: LinkConnectionsStatus? = null, devBannerState: DevBannerState = DevBannerState(false), content: @Composable (PaddingValues) -> Unit ) { @@ -40,7 +51,40 @@ fun DevelopmentPreviewWrapper( content(if (devBannerState.isVisible) PaddingValues(top = bannerHeight) else PaddingValues()) } - if (devBannerState.isVisible) { + if (devBannerState.isVisible && linkConnectionsStatus != null) { + val density = LocalDensity.current + Column( + modifier = Modifier + .fillMaxWidth() + .background(RadixTheme.colors.orange2) + .statusBarsPadding() + .onGloballyPositioned { coordinates -> + bannerHeight = with(density) { coordinates.size.height.toDp() } + } + .padding(RadixTheme.dimensions.paddingXSmall) + ) { + Text( + text = stringResource(R.string.common_developerDisclaimerText), + style = RadixTheme.typography.body2HighImportance, + fontSize = 12.sp, + color = Color.Black, + textAlign = TextAlign.Center, + ) + LazyRow( + modifier = Modifier, + horizontalArrangement = Arrangement.spacedBy(RadixTheme.dimensions.paddingSmall) + ) { + items(items = linkConnectionsStatus.currentStatus()) { color -> + Canvas( + modifier = Modifier.size(12.dp), + onDraw = { + drawCircle(color = color) + } + ) + } + } + } + } else if (devBannerState.isVisible) { val density = LocalDensity.current Text( modifier = Modifier @@ -60,7 +104,10 @@ fun DevelopmentPreviewWrapper( } } -data class DevBannerState(val isVisible: Boolean = false) +data class DevBannerState( + val isVisible: Boolean = false, + val connectionStatus: ImmutableList = persistentListOf() +) val LocalDevBannerState = compositionLocalOf { DevBannerState() } @@ -68,6 +115,14 @@ val LocalDevBannerState = compositionLocalOf { DevBannerState() } @Composable fun DevelopmentBannerPreview() { RadixWalletTheme { - DevelopmentPreviewWrapper(modifier = Modifier, DevBannerState(isVisible = true), content = {}) + DevelopmentPreviewWrapper( + modifier = Modifier, + linkConnectionsStatus = null, + DevBannerState( + isVisible = true, + connectionStatus = persistentListOf() + ), + content = {} + ) } } From c449e593549a31d4d63204ab5443801900755fb8 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Fri, 19 Jan 2024 17:59:11 +0200 Subject: [PATCH 06/10] minor --- .../presentation/settings/appsettings/AppSettingsNav.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/settings/appsettings/AppSettingsNav.kt b/app/src/main/java/com/babylon/wallet/android/presentation/settings/appsettings/AppSettingsNav.kt index 680cb56083..3ffb9d87b4 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/settings/appsettings/AppSettingsNav.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/settings/appsettings/AppSettingsNav.kt @@ -2,7 +2,6 @@ package com.babylon.wallet.android.presentation.settings.appsettings import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExperimentalAnimationApi import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder @@ -43,7 +42,6 @@ fun NavGraphBuilder.appSettingsNavGraph( } } -@OptIn(ExperimentalAnimationApi::class) fun NavGraphBuilder.appSettingsScreen( navController: NavController ) { @@ -87,7 +85,6 @@ fun NavGraphBuilder.appSettingsScreen( } } -@OptIn(ExperimentalAnimationApi::class) private fun NavGraphBuilder.settingsGateway(navController: NavController) { composable( route = Screen.SettingsEditGatewayApiDestination.route, From 196deaca8c798db5f75f2caecd7cf5d05ccc6546 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Wed, 24 Jan 2024 12:23:49 +0200 Subject: [PATCH 07/10] better name for updating peer connection status in PeerdroidConnector --- .../rdx/works/peerdroid/data/PeerdroidConnector.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt b/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt index 11902b461d..ad9b4fe7a8 100644 --- a/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt +++ b/peerdroid/src/main/java/rdx/works/peerdroid/data/PeerdroidConnector.kt @@ -159,7 +159,7 @@ internal class PeerdroidConnectorImpl( dataChannelHolder.dataChannel.close() } mapOfDataChannels.values.removeAll(dataChannelsForTermination.toSet()) - updateMapOfPeerConnectionState(connectionId = connectionId, isOpen = false, isDeleted = true) + updatePeerConnectionStatus(connectionId = connectionId, isOpen = false, isDeleted = true) Timber.d("⚙️ \uD83D\uDDD1️ link connection with connectionId: ${connectionId.id} deleted ✅") } } @@ -313,7 +313,7 @@ internal class PeerdroidConnectorImpl( .onEach { event -> when (event) { is PeerConnectionEvent.RenegotiationNeeded -> { - updateMapOfPeerConnectionState(connectionId = connectionId, isConnecting = true) + updatePeerConnectionStatus(connectionId = connectionId, isConnecting = true) Timber.d("⚙️ ⚡ renegotiation needed for remote client: $remoteClientHolder \uD83C\uDD97") renegotiationDeferred.complete(Unit) } @@ -343,7 +343,7 @@ internal class PeerdroidConnectorImpl( dataChannel = dataChannel ) isAnyChannelConnected.tryEmit(mapOfDataChannels.values.isNotEmpty()) - updateMapOfPeerConnectionState(connectionId = connectionId, isConnecting = false, isOpen = true) + updatePeerConnectionStatus(connectionId = connectionId, isConnecting = false, isOpen = true) Timber.d("⚙️ ℹ️ current count of data channels: ${mapOfDataChannels.size}") } @@ -351,7 +351,7 @@ internal class PeerdroidConnectorImpl( Timber.d("⚙️ ⚡ peer connection disconnected for remote client: $remoteClientHolder \uD83D\uDD34") terminatePeerConnectionAndDataChannel(remoteClientHolder, connectionId) isAnyChannelConnected.tryEmit(mapOfDataChannels.values.isNotEmpty()) - updateMapOfPeerConnectionState(connectionId = connectionId, isConnecting = false, isOpen = false) + updatePeerConnectionStatus(connectionId = connectionId, isConnecting = false, isOpen = false) } is PeerConnectionEvent.Failed -> { @@ -489,7 +489,7 @@ internal class PeerdroidConnectorImpl( } } - private fun updateMapOfPeerConnectionState( + private fun updatePeerConnectionStatus( connectionId: ConnectionIdHolder, isConnecting: Boolean = false, isOpen: Boolean = false, From a08dba1930c24ed0f7bcc510608c785d6d71d174 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Wed, 24 Jan 2024 12:37:44 +0200 Subject: [PATCH 08/10] renaming in LinkConnectionStatusObserver --- .../babylon/wallet/android/LinkConnectionStatusObserver.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt b/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt index 61651a380d..9b6db00cac 100644 --- a/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt +++ b/app/src/main/java/com/babylon/wallet/android/LinkConnectionStatusObserver.kt @@ -33,7 +33,7 @@ class LinkConnectionStatusObserver @Inject constructor( .peerConnectionStatus .map { mapOfPeerConnectionStatus -> LinkConnectionsStatus( - peerConnectionState = mapOfPeerConnectionStatus.values.toPersistentList() + peerConnectionStatus = mapOfPeerConnectionStatus.values.toPersistentList() ) } .stateIn( @@ -43,10 +43,10 @@ class LinkConnectionStatusObserver @Inject constructor( ) data class LinkConnectionsStatus( - private val peerConnectionState: ImmutableList = persistentListOf() + private val peerConnectionStatus: ImmutableList = persistentListOf() ) { - fun currentStatus() = peerConnectionState + fun currentStatus() = peerConnectionStatus .map { state -> when (state) { PeerConnectionStatus.OPEN -> { From c51f66a608a883bea7593876f25b91e6ddce82e9 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Wed, 24 Jan 2024 12:38:01 +0200 Subject: [PATCH 09/10] default to false the linked connector indicator --- .../main/java/rdx/works/core/preferences/PreferencesManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt b/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt index 1ae6dd6bc0..1e2bf6f217 100644 --- a/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt +++ b/core/src/main/java/rdx/works/core/preferences/PreferencesManager.kt @@ -134,7 +134,7 @@ class PreferencesManager @Inject constructor( val isLinkConnectionStatusIndicatorEnabled: Flow = dataStore.data .map { preferences -> - preferences[KEY_LINK_CONNECTION_STATUS_INDICATOR] ?: true + preferences[KEY_LINK_CONNECTION_STATUS_INDICATOR] ?: false } suspend fun setLinkConnectionStatusIndicator(isEnabled: Boolean) { From e80a35150b64fe43c49b0377bf0432338a5e6019 Mon Sep 17 00:00:00 2001 From: "giannis.tsepas" Date: Wed, 24 Jan 2024 12:38:22 +0200 Subject: [PATCH 10/10] fixed dev banner when indicator is visible and also visible in mainnet --- .../composables/DevelopmentPreviewWrapper.kt | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt b/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt index ddfc62ccb6..fc164462b7 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/ui/composables/DevelopmentPreviewWrapper.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.babylon.wallet.android.LinkConnectionStatusObserver.LinkConnectionsStatus import com.babylon.wallet.android.R import com.babylon.wallet.android.designsystem.theme.RadixTheme @@ -48,11 +47,17 @@ fun DevelopmentPreviewWrapper( Box(modifier = modifier) { var bannerHeight by remember { mutableStateOf(0.dp) } CompositionLocalProvider(LocalDevBannerState provides devBannerState) { - content(if (devBannerState.isVisible) PaddingValues(top = bannerHeight) else PaddingValues()) + content( + if (devBannerState.isVisible || linkConnectionsStatus != null) { + PaddingValues(top = bannerHeight) + } else { + PaddingValues() + } + ) } - if (devBannerState.isVisible && linkConnectionsStatus != null) { - val density = LocalDensity.current + val density = LocalDensity.current + if (devBannerState.isVisible) { Column( modifier = Modifier .fillMaxWidth() @@ -64,42 +69,48 @@ fun DevelopmentPreviewWrapper( .padding(RadixTheme.dimensions.paddingXSmall) ) { Text( + modifier = Modifier.fillMaxWidth(), text = stringResource(R.string.common_developerDisclaimerText), style = RadixTheme.typography.body2HighImportance, - fontSize = 12.sp, color = Color.Black, textAlign = TextAlign.Center, ) - LazyRow( - modifier = Modifier, - horizontalArrangement = Arrangement.spacedBy(RadixTheme.dimensions.paddingSmall) - ) { - items(items = linkConnectionsStatus.currentStatus()) { color -> - Canvas( - modifier = Modifier.size(12.dp), - onDraw = { - drawCircle(color = color) - } - ) + + if (linkConnectionsStatus != null) { + LazyRow( + modifier = Modifier, + horizontalArrangement = Arrangement.spacedBy(RadixTheme.dimensions.paddingSmall) + ) { + items(items = linkConnectionsStatus.currentStatus()) { color -> + Canvas( + modifier = Modifier.size(12.dp), + onDraw = { + drawCircle(color = color) + } + ) + } } } } - } else if (devBannerState.isVisible) { - val density = LocalDensity.current - Text( + } else if (linkConnectionsStatus != null) { + LazyRow( modifier = Modifier - .fillMaxWidth() - .background(RadixTheme.colors.orange2) .statusBarsPadding() .onGloballyPositioned { coordinates -> bannerHeight = with(density) { coordinates.size.height.toDp() } } - .padding(RadixTheme.dimensions.paddingSmall), - text = stringResource(R.string.common_developerDisclaimerText), - style = RadixTheme.typography.body2HighImportance, - color = Color.Black, - textAlign = TextAlign.Center, - ) + .padding(RadixTheme.dimensions.paddingXSmall), + horizontalArrangement = Arrangement.spacedBy(RadixTheme.dimensions.paddingSmall) + ) { + items(items = linkConnectionsStatus.currentStatus()) { color -> + Canvas( + modifier = Modifier.size(12.dp), + onDraw = { + drawCircle(color = color) + } + ) + } + } } } }