From 7d34e71aaf78981eba482ada3a3a057284ce1c40 Mon Sep 17 00:00:00 2001 From: synmcj Date: Wed, 2 Mar 2022 21:04:37 +0700 Subject: [PATCH 01/12] feat: sync in progress dialog --- .../ui/entry_point/NewAccountFragment.kt | 4 +-- .../src/main/res/drawable/ic_syncing.xml | 15 +++++++++ .../src/main/res/values/strings-crowdnode.xml | 8 +++-- .../de/schildbach/wallet/di/DatabaseModule.kt | 4 +-- .../wallet/ui/explore/ExploreActivity.kt | 33 ++++++++++++++----- 5 files changed, 48 insertions(+), 16 deletions(-) create mode 100644 integrations/crowdnode/src/main/res/drawable/ic_syncing.xml diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/NewAccountFragment.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/NewAccountFragment.kt index 02f8c093dd..dca19a2898 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/NewAccountFragment.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/NewAccountFragment.kt @@ -128,7 +128,7 @@ class NewAccountFragment : Fragment(R.layout.fragment_new_account) { override fun onClick(widget: View) { safeNavigate(NewAccountFragmentDirections.newAccountToWebview( getString(R.string.terms_of_use), - getString(R.string.terms_of_use_url) + getString(R.string.crowdnode_terms_of_use_url) )) } } @@ -137,7 +137,7 @@ class NewAccountFragment : Fragment(R.layout.fragment_new_account) { override fun onClick(widget: View) { safeNavigate(NewAccountFragmentDirections.newAccountToWebview( getString(R.string.privacy_policy), - getString(R.string.privacy_policy_url) + getString(R.string.crowdnode_privacy_policy_url) )) } } diff --git a/integrations/crowdnode/src/main/res/drawable/ic_syncing.xml b/integrations/crowdnode/src/main/res/drawable/ic_syncing.xml new file mode 100644 index 0000000000..74957c82a2 --- /dev/null +++ b/integrations/crowdnode/src/main/res/drawable/ic_syncing.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml b/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml index 54848f90ba..2b24cbc1a6 100644 --- a/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml +++ b/integrations/crowdnode/src/main/res/values/strings-crowdnode.xml @@ -62,9 +62,13 @@ You can change how / when your reward earnings are paid to you. Balance on CrowdNode Here is the Dash address you used in integration with CrowdNode + The chain is syncing… + Please wait until the chain is fully synced so we can review your transaction history.\n\nYou can visit CrowdNode website and log in/sign up there. + Go to CrowdNode website - https://crowdnode.io/terms/ - https://crowdnode.io/privacy/ + https://crowdnode.io/ + https://crowdnode.io/terms/ + https://crowdnode.io/privacy/ https://app.crowdnode.io/FundsOpen/%s https://test.crowdnode.io/FundsOpen/%s https://knowledge.crowdnode.io/ diff --git a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt index af4861ba77..aafc0f22b1 100644 --- a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt +++ b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt @@ -17,11 +17,9 @@ package de.schildbach.wallet.di -import android.content.Context import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import de.schildbach.wallet.AppDatabase import de.schildbach.wallet.data.BlockchainStateDao @@ -32,7 +30,7 @@ import javax.inject.Singleton object DatabaseModule { @Singleton @Provides - fun provideDatabase(@ApplicationContext context: Context): AppDatabase { + fun provideDatabase(): AppDatabase { return AppDatabase.getAppDatabase() } diff --git a/wallet/src/de/schildbach/wallet/ui/explore/ExploreActivity.kt b/wallet/src/de/schildbach/wallet/ui/explore/ExploreActivity.kt index 3b08516ae4..ca1a17e4b2 100644 --- a/wallet/src/de/schildbach/wallet/ui/explore/ExploreActivity.kt +++ b/wallet/src/de/schildbach/wallet/ui/explore/ExploreActivity.kt @@ -18,6 +18,7 @@ package de.schildbach.wallet.ui.explore import android.content.Intent +import android.net.Uri import android.os.Bundle import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope @@ -26,11 +27,11 @@ import de.schildbach.wallet.data.BlockchainStateDao import de.schildbach.wallet.ui.BaseMenuActivity import de.schildbach.wallet.ui.PaymentsActivity import de.schildbach.wallet.ui.staking.StakingActivity -import de.schildbach.wallet.util.Toast import de.schildbach.wallet_test.R import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.launch +import org.dash.wallet.common.ui.dialogs.AdaptiveDialog import org.dash.wallet.features.exploredash.ui.ExploreViewModel import org.dash.wallet.features.exploredash.ui.NavigationRequest import javax.inject.Inject @@ -61,14 +62,28 @@ class ExploreActivity : BaseMenuActivity() { startActivity(sendCoinsIntent) } NavigationRequest.Staking -> { - lifecycleScope.launch { - // TODO: NMA-1088 - if (isSynced()) { - startActivity(Intent(this@ExploreActivity, StakingActivity::class.java)) - } else { - Toast(this@ExploreActivity).toast("Not synced") - } - } + handleStakingNavigation() + } + } + } + } + + private fun handleStakingNavigation() { + lifecycleScope.launch { + if (isSynced()) { + startActivity(Intent(this@ExploreActivity, StakingActivity::class.java)) + } else { + val openWebsite = AdaptiveDialog.create( + R.drawable.ic_syncing, + getString(R.string.chain_syncing), + getString(R.string.crowdnode_wait_for_sync), + getString(R.string.button_close), + getString(R.string.crowdnode_open_website) + ).showAsync(this@ExploreActivity) + + if (openWebsite == true) { + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.crowdnode_website))) + startActivity(browserIntent) } } } From 464259d8302bded724e21113b690b3074019b9d7 Mon Sep 17 00:00:00 2001 From: synmcj Date: Fri, 4 Mar 2022 21:30:50 +0700 Subject: [PATCH 02/12] feat: module configuration class --- build.gradle | 3 + .../org/dash/wallet/common/Configuration.java | 31 ------- features/exploredash/build.gradle | 7 +- integrations/crowdnode/build.gradle | 7 +- .../crowdnode/api/CrowdNodeApi.kt | 22 ++--- .../crowdnode/api/RemoteDataSource.kt | 2 +- .../crowdnode/di/CrowdNodeModule.kt | 3 - .../ui/entry_point/EntryPointViewModel.kt | 45 +++++++--- .../crowdnode/ui/portal/PortalViewModel.kt | 13 +-- .../crowdnode/utils/ModuleConfiguration.kt | 88 +++++++++++++++++++ 10 files changed, 150 insertions(+), 71 deletions(-) create mode 100644 integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt diff --git a/build.gradle b/build.gradle index b8eae3d7c9..3dc72033ce 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,9 @@ buildscript { recyclerViewVersion = "1.2.1" glideVersion = '4.12.0' slf4jVersion = '1.7.32' + jetpackVersion = '1.6.0' + appCompatVersion = '1.3.1' + materialVersion = "1.4.0" } repositories { diff --git a/common/src/main/java/org/dash/wallet/common/Configuration.java b/common/src/main/java/org/dash/wallet/common/Configuration.java index 6b14a94d6c..7f6c4f19d2 100644 --- a/common/src/main/java/org/dash/wallet/common/Configuration.java +++ b/common/src/main/java/org/dash/wallet/common/Configuration.java @@ -102,11 +102,6 @@ public class Configuration { public static final String PREFS_KEY_HAS_INFO_SCREEN_BEEN_SHOWN_ALREADY = "has_info_screen_been_shown"; public static final String PREFS_KEY_HAS_LOCATION_DIALOG_BEEN_SHOWN = "has_location_dialog_been_shown"; - // CrowdNode - public static final String PREFS_KEY_CROWDNODE_ACCOUNT_ADDRESS = "crowdnode_account_address"; - public static final String PREFS_KEY_CROWDNODE_ERROR = "crowdnode_error"; - public static final String PREFS_KEY_LAST_CROWDNODE_BALANCE = "crowdnode_balance"; - private static final Logger log = LoggerFactory.getLogger(Configuration.class); public Configuration(final SharedPreferences prefs, final Resources res) { @@ -539,30 +534,4 @@ public boolean hasExploreDashLocationDialogBeenShown() { public void setHasExploreDashLocationDialogBeenShown(boolean isShown) { prefs.edit().putBoolean(PREFS_KEY_HAS_LOCATION_DIALOG_BEEN_SHOWN, isShown).apply(); } - - // CrowdNode - public String getCrowdNodeAccountAddress() { - return prefs.getString(PREFS_KEY_CROWDNODE_ACCOUNT_ADDRESS, ""); - } - - public void setCrowdNodeAccountAddress(@NotNull String address) { - prefs.edit().putString(PREFS_KEY_CROWDNODE_ACCOUNT_ADDRESS, address).apply(); - } - - public String getCrowdNodeError() { - return prefs.getString(PREFS_KEY_CROWDNODE_ERROR, ""); - } - - public void setCrowdNodeError(String error) { - prefs.edit().putString(PREFS_KEY_CROWDNODE_ERROR, error).apply(); - } - - public void setLastCrowdNodeBalance(Long balance) { - prefs.edit().putLong(PREFS_KEY_LAST_CROWDNODE_BALANCE, balance).apply(); - } - - @NonNull - public Long getLastCrowdNodeBalance() { - return prefs.getLong(PREFS_KEY_LAST_CROWDNODE_BALANCE, 0); - } } diff --git a/features/exploredash/build.gradle b/features/exploredash/build.gradle index 5b2a84482e..8d920ac222 100644 --- a/features/exploredash/build.gradle +++ b/features/exploredash/build.gradle @@ -51,15 +51,14 @@ dependencies { implementation project(path: ':common') // Core - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' + implementation "androidx.core:core-ktx:$jetpackVersion" + implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_version" // Architecture implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" - implementation 'androidx.preference:preference-ktx:1.1.1' // DI implementation "com.google.dagger:hilt-android:$hiltVersion" @@ -67,7 +66,7 @@ dependencies { kapt 'androidx.hilt:hilt-compiler:1.0.0' // UI - implementation 'com.google.android.material:material:1.4.0' + implementation "com.google.android.material:material:$materialVersion" implementation "androidx.recyclerview:recyclerview:$recyclerViewVersion" implementation "com.github.bumptech.glide:glide:$glideVersion" kapt "com.github.bumptech.glide:compiler:$glideVersion" diff --git a/integrations/crowdnode/build.gradle b/integrations/crowdnode/build.gradle index 1358ca04a5..47754f6135 100644 --- a/integrations/crowdnode/build.gradle +++ b/integrations/crowdnode/build.gradle @@ -49,14 +49,15 @@ dependencies { implementation project(path: ':common') // Core - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' + implementation "androidx.core:core-ktx:$jetpackVersion" + implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation "org.dashj:dashj-core:$dashjVersion" // Architecture implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" + implementation "androidx.datastore:datastore-preferences:1.0.0" // DI implementation "com.google.dagger:hilt-android:$hiltVersion" @@ -66,7 +67,7 @@ dependencies { kapt "androidx.hilt:hilt-compiler:1.0.0" // UI - implementation 'com.google.android.material:material:1.4.0' + implementation "com.google.android.material:material:$materialVersion" implementation "androidx.constraintlayout:constraintlayout:$constrainLayoutVersion" // Tests diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt index cf91d70203..a524a4bd0a 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/CrowdNodeApi.kt @@ -24,13 +24,13 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.workDataOf import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import org.bitcoinj.core.Address import org.bitcoinj.core.Coin import org.bitcoinj.core.Transaction -import org.dash.wallet.common.Configuration import org.dash.wallet.common.WalletDataProvider import org.dash.wallet.common.services.NotificationService import org.dash.wallet.common.services.SendPaymentService @@ -39,6 +39,7 @@ import org.dash.wallet.common.transactions.LockedTransaction import org.dash.wallet.integrations.crowdnode.R import org.dash.wallet.integrations.crowdnode.transactions.* import org.dash.wallet.integrations.crowdnode.utils.CrowdNodeConstants +import org.dash.wallet.integrations.crowdnode.utils.ModuleConfiguration import org.slf4j.LoggerFactory import java.math.BigDecimal import java.math.RoundingMode @@ -64,7 +65,7 @@ interface CrowdNodeApi { suspend fun signUp(accountAddress: Address) suspend fun deposit(accountAddress: Address, amount: Coin) suspend fun loadBalance(): Coin - fun reset() + suspend fun reset() } class CrowdNodeException(message: String): Exception(message) @@ -75,13 +76,14 @@ class CrowdNodeBlockchainApi @Inject constructor( private val walletDataProvider: WalletDataProvider, private val notificationService: NotificationService, private val analyticsService: AnalyticsService, - private val configuration: Configuration, + private val config: ModuleConfiguration, @ApplicationContext private val appContext: Context ): CrowdNodeApi { companion object { private val log = LoggerFactory.getLogger(CrowdNodeBlockchainApi::class.java) } + private val configScope = CoroutineScope(Dispatchers.IO) private val params = walletDataProvider.networkParameters override val signUpStatus = MutableStateFlow(SignUpStatus.NotStarted) @@ -95,7 +97,7 @@ class CrowdNodeBlockchainApi @Inject constructor( init { restoreStatus() walletDataProvider.attachOnWalletWipedListener { - reset() + configScope.launch { reset() } } } @@ -151,7 +153,7 @@ class CrowdNodeBlockchainApi @Inject constructor( apiError = ex signUpStatus.value = SignUpStatus.Error - configuration.crowdNodeError = ex.message + config.setCrowdNodeError(ex.message ?: "") if (showNotificationOnResult) { notificationService.showNotification( @@ -199,23 +201,23 @@ class CrowdNodeBlockchainApi @Inject constructor( } } - override fun reset() { + override suspend fun reset() { log.info("reset is triggered") signUpStatus.value = SignUpStatus.NotStarted accountAddress = null apiError = null - configuration.crowdNodeError = "" + config.setCrowdNodeError("") } private fun restoreStatus() { if (signUpStatus.value == SignUpStatus.NotStarted) { log.info("restoring CrowdNode status") - val savedError = configuration.crowdNodeError + val savedError = runBlocking { config.crowdNodeError.first() } - if (!savedError.isNullOrEmpty()) { + if (savedError.isNotEmpty()) { signUpStatus.value = SignUpStatus.Error apiError = CrowdNodeException(savedError) - configuration.crowdNodeError = "" + configScope.launch { config.setCrowdNodeError("") } log.info("found an error: $savedError") return } diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/RemoteDataSource.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/RemoteDataSource.kt index 5e68e08819..027158e21e 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/RemoteDataSource.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/api/RemoteDataSource.kt @@ -25,7 +25,7 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Inject -class RemoteDataSource { +class RemoteDataSource @Inject constructor() { companion object { private const val BASE_URL = "https://test.crowdnode.io/" } diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/di/CrowdNodeModule.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/di/CrowdNodeModule.kt index 358de1c289..aaa3bb8c09 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/di/CrowdNodeModule.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/di/CrowdNodeModule.kt @@ -29,9 +29,6 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) abstract class CrowdNodeModule { companion object { - @Provides - fun provideRemoteDataSource() = RemoteDataSource() - @Provides fun provideWebApi( remoteDataSource: RemoteDataSource, diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt index adcf63d090..28a24a5c03 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt @@ -21,8 +21,10 @@ import android.content.Intent import androidx.lifecycle.* import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import org.bitcoinj.core.Address import org.bitcoinj.core.Coin import org.dash.wallet.common.Configuration @@ -31,6 +33,7 @@ import org.dash.wallet.common.data.SingleLiveEvent import org.dash.wallet.integrations.crowdnode.api.CrowdNodeApi import org.dash.wallet.integrations.crowdnode.api.SignUpStatus import org.dash.wallet.integrations.crowdnode.utils.CrowdNodeConstants +import org.dash.wallet.integrations.crowdnode.utils.ModuleConfiguration import javax.inject.Inject enum class NavigationRequest { @@ -39,13 +42,14 @@ enum class NavigationRequest { @HiltViewModel class EntryPointViewModel @Inject constructor( - private val config: Configuration, + private val globalConfig: Configuration, private val walletDataProvider: WalletDataProvider, - private val crowdNodeApi: CrowdNodeApi + private val crowdNodeApi: CrowdNodeApi, + private val config: ModuleConfiguration ) : ViewModel() { val navigationCallback = SingleLiveEvent() - private val _accountAddress = MutableLiveData(getOrCreateAccountAddress()) + private val _accountAddress = MutableLiveData
() var accountAddress: LiveData = MediatorLiveData().apply { addSource(_accountAddress) { value = it.toBase58() @@ -53,7 +57,7 @@ class EntryPointViewModel @Inject constructor( } val needPassphraseBackUp - get() = config.remindBackupSeed + get() = globalConfig.remindBackupSeed private val _hasEnoughBalance = MutableLiveData() val hasEnoughBalance: LiveData @@ -81,6 +85,10 @@ class EntryPointViewModel @Inject constructor( _hasEnoughBalance.postValue(it >= CrowdNodeConstants.MINIMUM_REQUIRED_DASH) } .launchIn(viewModelScope) + + viewModelScope.launch { + _accountAddress.value = getOrCreateAccountAddress() + } } fun backupPassphrase() { @@ -104,13 +112,16 @@ class EntryPointViewModel @Inject constructor( } fun reset() { - _accountAddress.value = createNewAccountAddress() - crowdNodeApi.reset() + viewModelScope.launch { + resetAddressAndApi() + } } fun retry() { - reset() - signUp() + viewModelScope.launch { + resetAddressAndApi() + signUp() + } } fun changeNotifyWhenDone(toNotify: Boolean) { @@ -121,26 +132,32 @@ class EntryPointViewModel @Inject constructor( crowdNodeApi.notificationIntent = intent } - private fun getOrCreateAccountAddress(): Address { + private suspend fun getOrCreateAccountAddress(): Address { val existingAddress = crowdNodeApi.accountAddress if (existingAddress != null) { - config.crowdNodeAccountAddress = existingAddress.toBase58() + config.setAccountAddress(existingAddress.toBase58()) return existingAddress } - val savedAddress = config.crowdNodeAccountAddress + val savedAddress = config.accountAddress.first() - return if (savedAddress.isNullOrEmpty()) { + return if (savedAddress.isEmpty()) { return createNewAccountAddress() } else { Address.fromString(walletDataProvider.networkParameters, savedAddress) } } - private fun createNewAccountAddress(): Address { + private suspend fun createNewAccountAddress(): Address { val address = walletDataProvider.freshReceiveAddress() - config.crowdNodeAccountAddress = address.toBase58() + config.setAccountAddress(address.toBase58()) + return address } + + private suspend fun resetAddressAndApi() { + _accountAddress.value = createNewAccountAddress() + crowdNodeApi.reset() + } } \ No newline at end of file diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/PortalViewModel.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/PortalViewModel.kt index 926cf8b573..52247cd3a7 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/PortalViewModel.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/portal/PortalViewModel.kt @@ -21,6 +21,7 @@ import androidx.annotation.MainThread import androidx.lifecycle.* import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -33,11 +34,13 @@ import org.dash.wallet.common.WalletDataProvider import org.dash.wallet.common.data.ExchangeRate import org.dash.wallet.common.services.ExchangeRatesProvider import org.dash.wallet.integrations.crowdnode.api.CrowdNodeApi +import org.dash.wallet.integrations.crowdnode.utils.ModuleConfiguration import javax.inject.Inject @HiltViewModel class PortalViewModel @Inject constructor( - private val config: Configuration, + private val globalConfig: Configuration, + private val config: ModuleConfiguration, private val exchangeRatesProvider: ExchangeRatesProvider, private val crowdNodeApi: CrowdNodeApi, private val walletDataProvider: WalletDataProvider @@ -56,7 +59,7 @@ class PortalViewModel @Inject constructor( get() = _balanceLoading val dashFormat: MonetaryFormat - get() = config.format.noCode() + get() = globalConfig.format.noCode() val networkParameters: NetworkParameters get() = walletDataProvider.networkParameters @@ -65,12 +68,12 @@ class PortalViewModel @Inject constructor( get() = crowdNodeApi.accountAddress!! init { - exchangeRatesProvider.observeExchangeRate(config.exchangeCurrencyCode) + exchangeRatesProvider.observeExchangeRate(globalConfig.exchangeCurrencyCode) .onEach(_exchangeRate::postValue) .launchIn(viewModelScope) viewModelScope.launch { - _balance.value = Coin.valueOf(config.lastCrowdNodeBalance) + _balance.value = Coin.valueOf(config.lastBalance.first()) updateBalance() } } @@ -90,7 +93,7 @@ class PortalViewModel @Inject constructor( withProgress { val balance = crowdNodeApi.loadBalance() _balance.value = balance - config.lastCrowdNodeBalance = balance.value + config.setLastBalance(balance.value) } } } diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt new file mode 100644 index 0000000000..6550fcdca7 --- /dev/null +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2022 Dash Core Group. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.dash.wallet.integrations.crowdnode.utils + +import android.content.Context +import android.util.Log +import androidx.datastore.preferences.core.* +import androidx.datastore.preferences.preferencesDataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.map +import java.io.IOException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ModuleConfiguration @Inject constructor(private val context: Context) { + companion object { + private val ACCOUNT_ADDRESS_KEY = stringPreferencesKey("account_address") + private val CROWDNODE_ERROR_KEY = stringPreferencesKey("error") + private val LAST_BALANCE_KEY = longPreferencesKey("last_balance") + } + + init { + Log.i("CROWDNODE", "ModuleConfiguration init") + } + + private val Context.dataStore by preferencesDataStore("crowdnode") + private val dataStore = context.dataStore.data + .catch { exception -> + if (exception is IOException) { + emit(emptyPreferences()) + } else { + throw exception + } + } + + val accountAddress: Flow = dataStore + .map { preferences -> + preferences[ACCOUNT_ADDRESS_KEY] ?: "" + } + + + suspend fun setAccountAddress(address: String) { + context.dataStore.edit { settings -> + settings[ACCOUNT_ADDRESS_KEY] = address + } + } + + val crowdNodeError: Flow = dataStore + .map { preferences -> + preferences[CROWDNODE_ERROR_KEY] ?: "" + } + + + suspend fun setCrowdNodeError(address: String) { + context.dataStore.edit { settings -> + settings[CROWDNODE_ERROR_KEY] = address + } + } + + val lastBalance: Flow = dataStore + .map { preferences -> + preferences[LAST_BALANCE_KEY] ?: 0L + } + + + suspend fun setLastBalance(balance: Long) { + context.dataStore.edit { settings -> + settings[LAST_BALANCE_KEY] = balance + } + } +} \ No newline at end of file From 4073c44ca591349b7fcbb85ae7e6bf88f6b81026 Mon Sep 17 00:00:00 2001 From: synmcj Date: Sat, 5 Mar 2022 21:18:51 +0700 Subject: [PATCH 03/12] feat: info screen on first staking click --- .../ui/entry_point/EntryPointViewModel.kt | 10 ++ .../ui/entry_point/FirstTimeInfoFragment.kt | 51 +++++++ .../crowdnode/utils/ModuleConfiguration.kt | 18 ++- .../src/main/res/drawable/ic_bolt.xml | 24 +++ .../main/res/drawable/ic_hands_sparkles.xml | 22 +++ .../res/layout/fragment_first_time_info.xml | 139 ++++++++++++++++++ .../src/main/res/navigation/nav_crowdnode.xml | 13 ++ .../src/main/res/values/strings-crowdnode.xml | 5 + settings.gradle | 2 +- .../wallet/ui/staking/StakingActivity.kt | 6 +- 10 files changed, 283 insertions(+), 7 deletions(-) create mode 100644 integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/FirstTimeInfoFragment.kt create mode 100644 integrations/crowdnode/src/main/res/drawable/ic_bolt.xml create mode 100644 integrations/crowdnode/src/main/res/drawable/ic_hands_sparkles.xml create mode 100644 integrations/crowdnode/src/main/res/layout/fragment_first_time_info.xml diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt index 28a24a5c03..8349e3717b 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/EntryPointViewModel.kt @@ -132,6 +132,16 @@ class EntryPointViewModel @Inject constructor( crowdNodeApi.notificationIntent = intent } + suspend fun getIsInfoShown(): Boolean { + return config.isInfoShown.first() + } + + fun setInfoShown(isShown: Boolean) { + viewModelScope.launch { + config.setIsInfoShown(isShown) + } + } + private suspend fun getOrCreateAccountAddress(): Address { val existingAddress = crowdNodeApi.accountAddress diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/FirstTimeInfoFragment.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/FirstTimeInfoFragment.kt new file mode 100644 index 0000000000..8a82bd1116 --- /dev/null +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/ui/entry_point/FirstTimeInfoFragment.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Dash Core Group. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.dash.wallet.integrations.crowdnode.ui.entry_point + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import org.dash.wallet.common.ui.viewBinding +import org.dash.wallet.common.util.safeNavigate +import org.dash.wallet.integrations.crowdnode.R +import org.dash.wallet.integrations.crowdnode.databinding.FragmentFirstTimeInfoBinding + +@AndroidEntryPoint +class FirstTimeInfoFragment : Fragment(R.layout.fragment_first_time_info) { + private val binding by viewBinding(FragmentFirstTimeInfoBinding::bind) + private val viewModel by activityViewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.toolbar.setNavigationOnClickListener { + requireActivity().finish() + } + + binding.continueBtn.setOnClickListener { + safeNavigate(FirstTimeInfoFragmentDirections.infoToPortal()) + } + + viewModel.setInfoShown(true) + } +} \ No newline at end of file diff --git a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt index 6550fcdca7..4fdcdbb664 100644 --- a/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt +++ b/integrations/crowdnode/src/main/java/org/dash/wallet/integrations/crowdnode/utils/ModuleConfiguration.kt @@ -18,7 +18,6 @@ package org.dash.wallet.integrations.crowdnode.utils import android.content.Context -import android.util.Log import androidx.datastore.preferences.core.* import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.Flow @@ -31,15 +30,12 @@ import javax.inject.Singleton @Singleton class ModuleConfiguration @Inject constructor(private val context: Context) { companion object { + private val INFO_SHOWN_KEY = booleanPreferencesKey("info_shown") private val ACCOUNT_ADDRESS_KEY = stringPreferencesKey("account_address") private val CROWDNODE_ERROR_KEY = stringPreferencesKey("error") private val LAST_BALANCE_KEY = longPreferencesKey("last_balance") } - init { - Log.i("CROWDNODE", "ModuleConfiguration init") - } - private val Context.dataStore by preferencesDataStore("crowdnode") private val dataStore = context.dataStore.data .catch { exception -> @@ -85,4 +81,16 @@ class ModuleConfiguration @Inject constructor(private val context: Context) { settings[LAST_BALANCE_KEY] = balance } } + + val isInfoShown: Flow = dataStore + .map { preferences -> + preferences[INFO_SHOWN_KEY] ?: false + } + + + suspend fun setIsInfoShown(isShown: Boolean) { + context.dataStore.edit { settings -> + settings[INFO_SHOWN_KEY] = isShown + } + } } \ No newline at end of file diff --git a/integrations/crowdnode/src/main/res/drawable/ic_bolt.xml b/integrations/crowdnode/src/main/res/drawable/ic_bolt.xml new file mode 100644 index 0000000000..b92f38838a --- /dev/null +++ b/integrations/crowdnode/src/main/res/drawable/ic_bolt.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + diff --git a/integrations/crowdnode/src/main/res/drawable/ic_hands_sparkles.xml b/integrations/crowdnode/src/main/res/drawable/ic_hands_sparkles.xml new file mode 100644 index 0000000000..18bfe15ef6 --- /dev/null +++ b/integrations/crowdnode/src/main/res/drawable/ic_hands_sparkles.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/integrations/crowdnode/src/main/res/layout/fragment_first_time_info.xml b/integrations/crowdnode/src/main/res/layout/fragment_first_time_info.xml new file mode 100644 index 0000000000..7b3a6d642f --- /dev/null +++ b/integrations/crowdnode/src/main/res/layout/fragment_first_time_info.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +