diff --git a/.bundle/config b/.bundle/config
new file mode 100644
index 0000000000..2369228816
--- /dev/null
+++ b/.bundle/config
@@ -0,0 +1,2 @@
+---
+BUNDLE_PATH: "vendor/bundle"
diff --git a/.editorconfig b/.editorconfig
index 25a2f7c928..0ab5ea61ec 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,5 +1,4 @@
[*.{kt,kts}]
-ktlint_ignore_back_ticked_identifier = true
indent_size = 4
indent_style = space
diff --git a/.gitignore b/.gitignore
index dd33a7dab3..dcdbe5fc57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,9 @@ local.properties
# LayoutInspector files
/captures
+# bundler
+/vendor
+
# OS-specific files
.DS_Store
.DS_Store?
diff --git a/Gemfile.lock b/Gemfile.lock
index 9dd60618bd..b4221a320d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,80 +1,102 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.4)
+ CFPropertyList (3.0.6)
rexml
- addressable (2.8.0)
- public_suffix (>= 2.0.2, < 5.0)
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
+ artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
- aws-partitions (1.519.0)
- aws-sdk-core (3.121.3)
+ aws-partitions (1.702.0)
+ aws-sdk-core (3.170.0)
aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.239.0)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.5)
+ jmespath (~> 1, >= 1.6.1)
+ aws-sdk-kms (1.62.0)
+ aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
- jmespath (~> 1.0)
- aws-sdk-kms (1.50.0)
- aws-sdk-core (~> 3, >= 3.121.2)
- aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.104.0)
- aws-sdk-core (~> 3, >= 3.121.2)
+ aws-sdk-s3 (1.119.0)
+ aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
- aws-sigv4 (1.4.0)
+ aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
- claide (1.0.3)
+ claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
- commander-fastlane (4.4.6)
- highline (~> 1.7.2)
+ commander (4.6.0)
+ highline (~> 2.0.0)
declarative (0.0.20)
- declarative-option (0.1.0)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
- dotenv (2.7.6)
- emoji_regex (1.0.1)
- excon (0.87.0)
- faraday (0.17.4)
- multipart-post (>= 1.2, < 3)
+ dotenv (2.8.1)
+ emoji_regex (3.2.3)
+ excon (0.98.0)
+ faraday (1.10.3)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
- faraday_middleware (0.13.1)
- faraday (>= 0.7.4, < 1.0)
- fastimage (2.2.5)
- fastlane (2.146.1)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ faraday_middleware (1.2.0)
+ faraday (~> 1.0)
+ fastimage (2.2.6)
+ fastlane (2.211.0)
CFPropertyList (>= 2.3, < 4.0.0)
- addressable (>= 2.3, < 3.0.0)
+ addressable (>= 2.8, < 3.0.0)
+ artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
- babosa (>= 1.0.2, < 2.0.0)
+ babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
- commander-fastlane (>= 4.4.6, < 5.0.0)
+ commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
- emoji_regex (>= 0.1, < 2.0)
+ emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
- faraday (~> 0.17)
+ faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
- faraday_middleware (~> 0.13.1)
+ faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
- google-api-client (>= 0.29.2, < 0.37.0)
- google-cloud-storage (>= 1.15.0, < 2.0.0)
- highline (>= 1.7.2, < 2.0.0)
+ google-apis-androidpublisher_v3 (~> 0.3)
+ google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-storage (~> 1.31)
+ highline (~> 2.0)
json (< 3.0.0)
- jwt (~> 2.1.0)
+ jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
- multi_xml (~> 0.5)
multipart-post (~> 2.0.0)
+ naturally (~> 2.2)
+ optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
- public_suffix (~> 2.0.0)
- rubyzip (>= 1.3.0, < 2.0.0)
+ rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
- slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
@@ -83,74 +105,87 @@ GEM
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
- fastlane-plugin-firebase_app_distribution (0.3.1)
+ fastlane-plugin-firebase_app_distribution (0.4.2)
gh_inspector (1.1.3)
- google-api-client (0.32.1)
+ google-apis-androidpublisher_v3 (0.33.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-core (0.10.0)
addressable (~> 2.5, >= 2.5.1)
- googleauth (>= 0.5, < 0.10.0)
- httpclient (>= 2.8.1, < 3.0)
+ googleauth (>= 0.16.2, < 2.a)
+ httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
- retriable (>= 2.0, < 4.0)
- signet (~> 0.10)
- google-cloud-core (1.3.2)
+ retriable (>= 2.0, < 4.a)
+ rexml
+ webrick
+ google-apis-iamcredentials_v1 (0.16.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-playcustomapp_v1 (0.12.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-storage_v1 (0.19.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
- google-cloud-env (1.2.1)
- faraday (~> 0.11)
- google-cloud-storage (1.21.1)
- addressable (~> 2.5)
+ google-cloud-errors (~> 1.0)
+ google-cloud-env (1.6.0)
+ faraday (>= 0.17.3, < 3.0)
+ google-cloud-errors (1.3.0)
+ google-cloud-storage (1.44.0)
+ addressable (~> 2.8)
digest-crc (~> 0.4)
- google-api-client (~> 0.26)
- google-cloud-core (~> 1.2)
- googleauth (>= 0.6.2, < 0.10.0)
+ google-apis-iamcredentials_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.19.0)
+ google-cloud-core (~> 1.6)
+ googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- googleauth (0.9.0)
- faraday (~> 0.12)
+ googleauth (1.3.0)
+ faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
- signet (~> 0.7)
- highline (1.7.10)
- http-cookie (1.0.4)
+ signet (>= 0.16, < 2.a)
+ highline (2.0.3)
+ http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
- jmespath (1.4.0)
- json (2.6.1)
- jwt (2.1.0)
+ jmespath (1.6.2)
+ json (2.6.3)
+ jwt (2.6.0)
memoist (0.16.2)
- mini_magick (4.11.0)
+ mini_magick (4.12.0)
mini_mime (1.1.2)
multi_json (1.15.0)
- multi_xml (0.6.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
naturally (2.2.1)
- os (1.1.1)
+ optparse (0.1.1)
+ os (1.1.4)
plist (3.6.0)
- public_suffix (2.0.5)
+ public_suffix (5.0.1)
rake (13.0.6)
- representable (3.0.4)
+ representable (3.2.0)
declarative (< 0.1.0)
- declarative-option (< 0.2.0)
+ trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rouge (2.0.7)
- rubyzip (1.3.0)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
security (0.1.3)
- signet (0.11.0)
- addressable (~> 2.3)
- faraday (~> 0.9)
+ signet (0.17.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
- simctl (1.6.8)
+ simctl (1.6.10)
CFPropertyList
naturally
- slack-notifier (2.4.0)
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
+ trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
@@ -158,10 +193,11 @@ GEM
uber (0.1.0)
unf (0.1.4)
unf_ext
- unf_ext (0.0.8)
+ unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
+ webrick (1.8.1)
word_wrap (1.0.0)
- xcodeproj (1.21.0)
+ xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@@ -174,11 +210,11 @@ GEM
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
- universal-darwin-18
+ ruby
DEPENDENCIES
fastlane
fastlane-plugin-firebase_app_distribution
BUNDLED WITH
- 2.2.16
+ 1.17.2
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 34d26a35ae..1c44bd0851 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -2,6 +2,7 @@ plugins {
id("com.android.application")
kotlin("android")
kotlin("kapt")
+ kotlin("plugin.serialization")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
id("com.google.dagger.hilt.android")
@@ -102,6 +103,7 @@ android {
}
repositories {
+ mavenCentral()
maven(url = "https://jitpack.io")
}
@@ -200,6 +202,7 @@ dependencies {
implementation(Library.googlePlayServicesWallet)
implementation(Library.composeShimmer)
implementation(Library.mviCoreWatcher)
+ implementation(Library.kotlinSerialization)
/** Testing libraries */
testImplementation(Test.junit)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f09883d42e..5fa1e04d9d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,10 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.tangem.wallet">
-
-
@@ -19,6 +15,9 @@
+
@@ -51,47 +50,49 @@
android:windowSoftInputMode="adjustResize">
-
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt
index 61762924a3..6b5d0bd175 100644
--- a/app/src/main/java/com/tangem/tap/MainActivity.kt
+++ b/app/src/main/java/com/tangem/tap/MainActivity.kt
@@ -12,6 +12,7 @@ import com.google.android.material.snackbar.Snackbar
import com.tangem.TangemSdk
import com.tangem.operations.backup.BackupService
import com.tangem.tangem_sdk_new.extensions.init
+import com.tangem.tangem_sdk_new.extensions.initWithBiometrics
import com.tangem.tap.common.ActivityResultCallbackHolder
import com.tangem.tap.common.DialogManager
import com.tangem.tap.common.OnActivityResultCallback
@@ -20,8 +21,8 @@ import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.redux.NotificationsHandler
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
-import com.tangem.tap.common.shop.GooglePayService
-import com.tangem.tap.common.shop.GooglePayService.Companion.LOAD_PAYMENT_DATA_REQUEST_CODE
+import com.tangem.tap.common.shop.googlepay.GooglePayService
+import com.tangem.tap.common.shop.googlepay.GooglePayService.Companion.LOAD_PAYMENT_DATA_REQUEST_CODE
import com.tangem.tap.common.shop.googlepay.GooglePayUtil.createPaymentsClient
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.userWalletList.UserWalletsListManager
@@ -77,9 +78,10 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
systemActions()
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
- tangemSdk = TangemSdk.init(this, TangemSdkManager.config)
+ tangemSdk = TangemSdk.initWithBiometrics(this, TangemSdkManager.config)
tangemSdkManager = TangemSdkManager(tangemSdk, this)
appStateHolder.tangemSdkManager = tangemSdkManager
+ appStateHolder.tangemSdk = tangemSdk
backupService = BackupService.init(tangemSdk, this)
userWalletsListManager = UserWalletsListManager.provideBiometricImplementation(
context = applicationContext,
@@ -115,29 +117,12 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
super.onResume()
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
- val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
- val isScannedBefore = store.state.globalState.scanResponse != null
- val isOnboardingServiceActive = store.state.globalState.onboardingState.onboardingStarted
- val shopOpened = store.state.shopState.total != null
- if (backStackIsEmpty || (!isOnboardingServiceActive && !isScannedBefore && !shopOpened)) {
- if (userWalletsListManager.hasSavedUserWallets) {
- store.dispatchOnMain(WelcomeAction.HandleDeepLink(intent))
- store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Welcome))
- } else {
- store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home))
- intentHandler.handleWalletConnectLink(intent)
- }
- store.dispatch(BackupAction.CheckForUnfinishedBackup)
- }
- intentHandler.handleBackgroundScan(intent)
- intentHandler.handleSellCurrencyCallback(intent)
+ navigateToInitialScreenIfNeeded(intent)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
- intentHandler.handleBackgroundScan(intent)
- intentHandler.handleSellCurrencyCallback(intent)
- intentHandler.handleWalletConnectLink(intent)
+ intentHandler.handleIntent(intent, userWalletsListManager.hasSavedUserWallets)
}
override fun onStart() {
@@ -160,7 +145,9 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
if (snackbar != null) return
snackbar = Snackbar.make(
- binding.fragmentContainer, getString(text), Snackbar.LENGTH_INDEFINITE,
+ binding.fragmentContainer,
+ getString(text),
+ Snackbar.LENGTH_INDEFINITE,
)
if (buttonTitle != null && action != null) {
snackbar?.setAction(getString(buttonTitle), action)
@@ -200,4 +187,30 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
lockUserWalletsTimer?.restart()
}
+
+ private fun navigateToInitialScreenIfNeeded(intent: Intent?) {
+ val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
+ val isNotScannedBefore = store.state.globalState.scanResponse == null
+ val isOnboardingServiceNotActive = store.state.globalState.onboardingState.onboardingStarted
+ val isShopNotOpened = store.state.shopState.total != null
+ when {
+ !backStackIsEmpty && isNotScannedBefore && isOnboardingServiceNotActive && isShopNotOpened -> {
+ navigateToInitialScreen(intent)
+ }
+ backStackIsEmpty -> {
+ navigateToInitialScreen(intent)
+ }
+ }
+ }
+
+ private fun navigateToInitialScreen(intent: Intent?) {
+ if (userWalletsListManager.hasSavedUserWallets) {
+ store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Welcome))
+ store.dispatchOnMain(WelcomeAction.HandleIntentIfNeeded(intent))
+ } else {
+ store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home))
+ intentHandler.handleIntent(intent, hasSavedUserWallets = false)
+ }
+ store.dispatch(BackupAction.CheckForUnfinishedBackup)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt b/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt
index 2239eacd70..6e620bd0bc 100644
--- a/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt
+++ b/app/src/main/java/com/tangem/tap/NavBarInsetsFragmentLifecycleCallback.kt
@@ -36,4 +36,4 @@ class NavBarInsetsFragmentLifecycleCallback : FragmentLifecycleCallbacks() {
windowInsets
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt
index d77a6e9c1b..274048b425 100644
--- a/app/src/main/java/com/tangem/tap/TapApplication.kt
+++ b/app/src/main/java/com/tangem/tap/TapApplication.kt
@@ -10,13 +10,15 @@ import com.tangem.LogFormat
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
-import com.tangem.common.json.MoshiJsonConverter
import com.tangem.core.analytics.Analytics
import com.tangem.datasource.api.common.MoshiConverter
+import com.tangem.datasource.config.models.Config
+import com.tangem.datasource.config.ConfigManager
+import com.tangem.datasource.config.FeaturesLocalLoader
+import com.tangem.datasource.utils.AndroidAssetReader
+import com.tangem.datasource.utils.AssetReader
import com.tangem.domain.DomainLayer
import com.tangem.domain.common.LogConfig
-import com.tangem.tap.common.AndroidAssetReader
-import com.tangem.tap.common.AssetReader
import com.tangem.tap.common.IntentHandler
import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
@@ -29,14 +31,10 @@ import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
import com.tangem.tap.common.feedback.FeedbackManager
import com.tangem.tap.common.images.createCoilImageLoader
import com.tangem.tap.common.log.TangemLogCollector
-import com.tangem.tap.common.moshi.BigDecimalAdapter
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.appReducer
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.shop.TangemShopService
-import com.tangem.tap.domain.configurable.config.Config
-import com.tangem.tap.domain.configurable.config.ConfigManager
-import com.tangem.tap.domain.configurable.config.FeaturesLocalLoader
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.totalBalance.TotalFiatBalanceCalculator
@@ -51,7 +49,6 @@ import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
import com.tangem.tap.domain.walletStores.repository.di.provideDefaultImplementation
import com.tangem.tap.domain.walletconnect.WalletConnectRepository
import com.tangem.tap.network.NetworkConnectivity
-import com.tangem.tap.persistence.CardBalanceStateAdapter
import com.tangem.tap.persistence.PreferencesStorage
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.wallet.BuildConfig
@@ -117,6 +114,9 @@ class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var appStateHolder: AppStateHolder
+ @Inject
+ lateinit var configManager: ConfigManager
+
override fun onCreate() {
super.onCreate()
@@ -136,14 +136,13 @@ class TapApplication : Application(), ImageLoaderFactory {
activityResultCaller = foregroundActivityObserver
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
- initMoshiConverter()
DomainLayer.init()
NetworkConnectivity.createInstance(store, this)
preferencesStorage = PreferencesStorage(this)
walletConnectRepository = WalletConnectRepository(this)
assetReader = AndroidAssetReader(this)
- val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.INSTANCE.moshi)
+ val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.sdkMoshi, BuildConfig.ENVIRONMENT)
initConfigManager(configLoader, ::initWithConfigDependency)
initWarningMessagesManager()
@@ -158,18 +157,6 @@ class TapApplication : Application(), ImageLoaderFactory {
appStateHolder.walletStoresManager = walletStoresManager
}
- //todo refactor: move to datasource and provide via DI
- private fun initMoshiConverter() {
- fun appAdapters(): List = listOf(
- BigDecimalAdapter(),
- CardBalanceStateAdapter(),
- )
- MoshiConverter.reInitInstance(
- adapters = appAdapters() + MoshiJsonConverter.getTangemSdkAdapters(),
- typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters(),
- )
- }
-
override fun newImageLoader(): ImageLoader {
return createCoilImageLoader(
context = this,
@@ -178,7 +165,6 @@ class TapApplication : Application(), ImageLoaderFactory {
}
private fun initConfigManager(loader: FeaturesLocalLoader, onComplete: (Config) -> Unit) {
- val configManager = ConfigManager()
configManager.load(loader) { config ->
store.dispatch(GlobalAction.SetConfigManager(configManager))
onComplete(config)
@@ -188,7 +174,7 @@ class TapApplication : Application(), ImageLoaderFactory {
private fun initWithConfigDependency(config: Config) {
shopService = TangemShopService(this, config.shopify!!)
initAnalytics(this, config)
- initFeedbackManager(this, preferencesStorage, config)
+ initFeedbackManager(this, preferencesStorage)
}
private fun initAnalytics(application: Application, config: Config) {
@@ -205,12 +191,12 @@ class TapApplication : Application(), ImageLoaderFactory {
config = config,
isDebug = BuildConfig.DEBUG,
logConfig = LogConfig.analyticsHandlers,
- jsonConverter = MoshiConverter.INSTANCE,
+ jsonConverter = MoshiConverter.sdkMoshiConverter,
)
factory.build(Analytics, buildData)
}
- private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) {
+ private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage) {
fun initAdditionalFeedbackInfo(context: Context): AdditionalFeedbackInfo = AdditionalFeedbackInfo().apply {
appVersion = try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
diff --git a/app/src/main/java/com/tangem/tap/WaitForMigration.kt b/app/src/main/java/com/tangem/tap/WaitForMigration.kt
index 536b9711eb..59c14fb064 100644
--- a/app/src/main/java/com/tangem/tap/WaitForMigration.kt
+++ b/app/src/main/java/com/tangem/tap/WaitForMigration.kt
@@ -4,4 +4,4 @@ package com.tangem.tap
[REDACTED_AUTHOR]
*/
-val DELAY_SDK_DIALOG_CLOSE = 1400L
\ No newline at end of file
+const val DELAY_SDK_DIALOG_CLOSE = 1400L
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt
index 2ae1553d38..2f3e688532 100644
--- a/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt
+++ b/app/src/main/java/com/tangem/tap/common/CurrencyConverter.kt
@@ -9,8 +9,8 @@ import java.math.RoundingMode
[REDACTED_AUTHOR]
*/
class CurrencyConverter(
- private val rateValue: BigDecimal,
- private val decimals: Int
+ private val rateValue: BigDecimal,
+ private val decimals: Int
) {
private val roundingMode = RoundingMode.HALF_UP
diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt
index f36d0656e8..93c54eeefa 100644
--- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt
@@ -14,10 +14,9 @@ import com.tangem.tap.features.details.ui.walletconnect.dialogs.ClipboardOrScanQ
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PersonalSignDialog
import com.tangem.tap.features.details.ui.walletconnect.dialogs.TransactionDialog
import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog
-import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
-import com.tangem.tap.features.onboarding.products.twins.ui.dialog.CreateWalletInterruptDialog
+import com.tangem.tap.features.onboarding.OnboardingDialog
+import com.tangem.tap.features.onboarding.products.twins.ui.dialog.TwinningProcessNotCompletedDialog
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog
-import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.InterruptOnboardingDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.NoFundsForActivationDialog
import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.PutVisaCardDialog
@@ -57,6 +56,7 @@ class DialogManager : StoreSubscriber {
store.unsubscribe(this)
}
+ @Suppress("LongMethod", "ComplexMethod")
override fun newState(state: GlobalState) {
if (state.dialog == null) {
dialog?.dismiss()
@@ -74,7 +74,7 @@ class DialogManager : StoreSubscriber {
is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context)
is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context)
is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context)
- is TwinCardsAction.Wallet.ShowInterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context)
+ is OnboardingDialog.TwinningProcessNotCompleted -> TwinningProcessNotCompletedDialog.create(context)
is OnboardingDialog.InterruptOnboarding -> InterruptOnboardingDialog.create(context, state.dialog)
is WalletConnectDialog.UnsupportedCard ->
SimpleAlertDialog.create(
@@ -135,13 +135,15 @@ class DialogManager : StoreSubscriber {
is SaltPayDialog.Activation.PutVisaCard -> PutVisaCardDialog.create(context)
is SaltPayDialog.Activation.OnError -> RegistrationErrorDialog.create(context, state.dialog)
is WalletDialog.CurrencySelectionDialog -> CurrencySelectionDialog.create(state.dialog, context)
- is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context)
+ is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context, state.dialog)
is WalletDialog.SelectAmountToSendDialog -> AmountToSendBottomSheetDialog(context, state.dialog)
is WalletDialog.SignedHashesMultiWalletDialog -> SignedHashesWarningDialog.create(context)
is WalletDialog.TokensAreLinkedDialog -> SimpleAlertDialog.create(
title = context.getString(state.dialog.titleRes, state.dialog.currencySymbol),
message = context.getString(
- state.dialog.messageRes, state.dialog.currencySymbol, state.dialog.currencyTitle,
+ state.dialog.messageRes,
+ state.dialog.currencySymbol,
+ state.dialog.currencyTitle,
),
context = context,
)
diff --git a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt
index af4645f141..a716d772fe 100644
--- a/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt
+++ b/app/src/main/java/com/tangem/tap/common/GlobalLayoutStateHandler.kt
@@ -7,9 +7,9 @@ import timber.log.Timber
/**
[REDACTED_AUTHOR]
*/
-class GlobalLayoutStateHandler(
- private val view: T,
- attachImmediately: Boolean = true
+class GlobalLayoutStateHandler(
+ private val view: T,
+ attachImmediately: Boolean = true
) : ViewTreeObserver.OnGlobalLayoutListener {
var onStateChanged: ((T) -> Unit)? = null
diff --git a/app/src/main/java/com/tangem/tap/common/IntentHandler.kt b/app/src/main/java/com/tangem/tap/common/IntentHandler.kt
index 6783e3762e..f1cd3b1027 100644
--- a/app/src/main/java/com/tangem/tap/common/IntentHandler.kt
+++ b/app/src/main/java/com/tangem/tap/common/IntentHandler.kt
@@ -3,18 +3,33 @@ package com.tangem.tap.common
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.Tag
+import android.os.Build
import com.tangem.tap.common.extensions.removePrefixOrNull
-import com.tangem.tap.common.redux.navigation.AppScreen
-import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.walletconnect.WalletConnectManager
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.home.redux.HomeAction
import com.tangem.tap.features.wallet.redux.WalletAction
+import com.tangem.tap.features.welcome.redux.WelcomeAction
+import com.tangem.tap.scope
import com.tangem.tap.store
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import timber.log.Timber
class IntentHandler {
+ private val nfcActions = arrayOf(
+ NfcAdapter.ACTION_NDEF_DISCOVERED,
+ NfcAdapter.ACTION_TECH_DISCOVERED,
+ NfcAdapter.ACTION_TAG_DISCOVERED,
+ )
+
+ fun handleIntent(intent: Intent?, hasSavedUserWallets: Boolean) {
+ handleBackgroundScan(intent, hasSavedUserWallets)
+ handleWalletConnectLink(intent)
+ handleSellCurrencyCallback(intent)
+ }
+
fun handleWalletConnectLink(intent: Intent?) {
val wcUri = when (intent?.scheme) {
WalletConnectManager.WC_SCHEME -> {
@@ -32,19 +47,29 @@ class IntentHandler {
}
}
- fun handleBackgroundScan(intent: Intent?) {
- if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED == intent.action ||
- NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action
- )
- ) {
- val tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
- if (tag != null) {
- intent.action = null
- store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
- store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
- store.dispatch(HomeAction.ReadCard())
- }
+ fun handleBackgroundScan(intent: Intent?, hasSavedUserWallets: Boolean): Boolean {
+ if (intent == null || intent.action !in nfcActions) return false
+
+ val tag: Tag? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ intent.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
}
+ if (tag == null) return false
+
+ intent.action = null
+ if (hasSavedUserWallets) {
+ // TODO: Remove delay after [REDACTED_JIRA]
+ scope.launch {
+ delay(timeMillis = 200)
+ store.dispatch(WelcomeAction.ProceedWithCard)
+ }
+ } else {
+ store.dispatch(HomeAction.ReadCard())
+ }
+
+ return true
}
fun handleSellCurrencyCallback(intent: Intent?) {
diff --git a/app/src/main/java/com/tangem/tap/common/KeyboardObserver.kt b/app/src/main/java/com/tangem/tap/common/KeyboardObserver.kt
index 69581a7a34..47f579ca1b 100644
--- a/app/src/main/java/com/tangem/tap/common/KeyboardObserver.kt
+++ b/app/src/main/java/com/tangem/tap/common/KeyboardObserver.kt
@@ -44,7 +44,7 @@ class KeyboardObserver(activity: Activity) {
onKeyboardListener?.invoke(isShow)
}
- private fun isSoftKeyChanged() = ((lastWindowHeight - getWindowHeight()).absoluteValue) == getSoftKeyButtonHeight()
+ private fun isSoftKeyChanged() = (lastWindowHeight - getWindowHeight()).absoluteValue == getSoftKeyButtonHeight()
private fun getSoftKeyButtonHeight(): Int {
val applicationDisplayHeight = DisplayMetrics().apply {
@@ -57,5 +57,4 @@ class KeyboardObserver(activity: Activity) {
return realDisplayHeight - applicationDisplayHeight
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/TestActions.kt b/app/src/main/java/com/tangem/tap/common/TestActions.kt
index 5eb1021886..b787e7a1b3 100644
--- a/app/src/main/java/com/tangem/tap/common/TestActions.kt
+++ b/app/src/main/java/com/tangem/tap/common/TestActions.kt
@@ -40,9 +40,10 @@ typealias TestAction = Pair Unit>
class TestActionsBottomSheetDialog(
private val appDialog: AppDialog.TestActionsDialog,
- context: Context
+ context: Context,
) : BottomSheetDialog(context) {
+ @Suppress("MagicNumber")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventsLogger.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventsLogger.kt
index 6b5a1fc3a2..39291d12f6 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventsLogger.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventsLogger.kt
@@ -1,8 +1,8 @@
package com.tangem.tap.common.analytics
import com.tangem.common.json.MoshiJsonConverter
-import com.tangem.analytics.api.ErrorEventLogger
-import com.tangem.analytics.api.EventLogger
+import com.tangem.core.analytics.api.ErrorEventLogger
+import com.tangem.core.analytics.api.EventLogger
import timber.log.Timber
class AnalyticsEventsLogger(
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkError.kt b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt
similarity index 96%
rename from app/src/main/java/com/tangem/tap/common/analytics/TangemSdkError.kt
rename to app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt
index 491ef8f683..2f9552c1ae 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkError.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/TangemSdkErrorMapper.kt
@@ -2,10 +2,11 @@ package com.tangem.tap.common.analytics
import com.tangem.common.core.TangemSdkError
-object TangemSdk {
+object TangemSdkErrorMapper {
// This mapping is performed to group errors in FirebaseCrashlytics.
// At the moment, the errors in Crashlytics can only be grouped by their place of creation (class and line).
+ @Suppress("LongMethod", "ComplexMethod")
fun map(error: TangemSdkError): TangemSdkError {
return when (error) {
is TangemSdkError.TagLost -> TangemSdkError.TagLost()
@@ -13,12 +14,15 @@ object TangemSdk {
is TangemSdkError.SerializeCommandError -> TangemSdkError.SerializeCommandError()
is TangemSdkError.DeserializeApduFailed -> TangemSdkError.DeserializeApduFailed()
is TangemSdkError.EncodingFailedTypeMismatch -> TangemSdkError.EncodingFailedTypeMismatch(
- error.customMessage)
+ error.customMessage
+ )
is TangemSdkError.EncodingFailed -> TangemSdkError.EncodingFailed(error.customMessage)
is TangemSdkError.DecodingFailedMissingTag -> TangemSdkError.DecodingFailedMissingTag(
- error.customMessage)
+ error.customMessage
+ )
is TangemSdkError.DecodingFailedTypeMismatch -> TangemSdkError.DecodingFailedTypeMismatch(
- error.customMessage)
+ error.customMessage
+ )
is TangemSdkError.DecodingFailed -> TangemSdkError.DecodingFailed(error.customMessage)
is TangemSdkError.InvalidResponse -> TangemSdkError.InvalidResponse()
is TangemSdkError.UnknownStatus -> TangemSdkError.UnknownStatus(error.statusWord)
@@ -90,7 +94,8 @@ object TangemSdk {
is TangemSdkError.BackupFailedEmptyWallets -> TangemSdkError.BackupFailedEmptyWallets()
is TangemSdkError.BackupFailedNotEmptyWallets -> TangemSdkError.BackupFailedNotEmptyWallets()
is TangemSdkError.NoActiveBackup -> TangemSdkError.NoActiveBackup()
- is TangemSdkError.ResetBackupFailedHasBackupedWallets -> TangemSdkError.ResetBackupFailedHasBackupedWallets()
+ is TangemSdkError.ResetBackupFailedHasBackupedWallets ->
+ TangemSdkError.ResetBackupFailedHasBackupedWallets()
is TangemSdkError.BackupServiceInvalidState -> TangemSdkError.BackupServiceInvalidState()
is TangemSdkError.NoBackupCardForIndex -> TangemSdkError.NoBackupCardForIndex()
is TangemSdkError.EmptyBackupCards -> TangemSdkError.EmptyBackupCards()
@@ -111,5 +116,4 @@ object TangemSdk {
is TangemSdkError.BiometricsAuthenticationFailed -> error
}
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/AnalyticsHandlerBuilder.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/AnalyticsHandlerBuilder.kt
index 6d23925143..4727772b38 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/api/AnalyticsHandlerBuilder.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/api/AnalyticsHandlerBuilder.kt
@@ -4,7 +4,7 @@ import android.app.Application
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.core.analytics.api.AnalyticsHandler
import com.tangem.domain.common.AnalyticsHandlersLogConfig
-import com.tangem.tap.domain.configurable.config.Config
+import com.tangem.datasource.config.models.Config
interface AnalyticsHandlerBuilder {
fun build(data: Data): AnalyticsHandler?
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt
index 1eeda46c6f..1f227fc391 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt
@@ -7,7 +7,6 @@ import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.analytics.filters.BasicTopUpFilter
-import com.tangem.tap.domain.extensions.isMultiwalletAllowed
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
import com.tangem.tap.features.wallet.redux.ProgressState
@@ -28,13 +27,14 @@ class BasicEventsPreChecker {
BasicTopUpEventConverter().convert(converterData)?.let { Analytics.send(it) }
}
+ @Suppress("ComplexMethod")
private fun isReadyToSend(data: BasicEventsSourceData): Boolean {
val (scanResponse, walletState, biometricsWalletDataModels) = data
if (walletState.derivationsCheckIsScheduled) {
Timber.d("FAILED: derivationsCheckIsScheduled")
return false
}
- if (scanResponse.card.isMultiwalletAllowed && walletState.missingDerivations.isNotEmpty()) {
+ if (scanResponse.cardTypesResolver.isMultiwalletAllowed() && walletState.missingDerivations.isNotEmpty()) {
Timber.d("FAILED: isMultiwalletAllowed || missingDerivations.isNotEmpty")
return false
}
@@ -70,13 +70,14 @@ class BasicEventsPreChecker {
return false
}
- if (biometricsWalletDataModels.any {
- it.status is WalletDataModel.Loading ||
- it.status is WalletDataModel.NoAccount ||
- it.status is WalletDataModel.Unreachable ||
- it.status is WalletDataModel.MissedDerivation ||
- it.status.isErrorStatus
- }) {
+ val isCorrectStatus = biometricsWalletDataModels.any {
+ it.status is WalletDataModel.Loading ||
+ it.status is WalletDataModel.NoAccount ||
+ it.status is WalletDataModel.Unreachable ||
+ it.status is WalletDataModel.MissedDerivation ||
+ it.status.isErrorStatus
+ }
+ if (isCorrectStatus) {
Timber.d("FAILED: by status")
return false
}
@@ -106,7 +107,9 @@ data class BasicEventsSourceData(
?.stringValue
}
- val paramCardCurrency: AnalyticsParam.CardCurrency? by lazy { ParamCardCurrencyConverter().convert(scanResponse) }
+ val paramCardCurrency: AnalyticsParam.CardCurrency? by lazy {
+ ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver)
+ }
val paramCardBalanceState: AnalyticsParam.CardBalanceState by lazy { calculateAmount().toCardBalanceState() }
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt
index e359de8e5a..61d71c5a14 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt
@@ -2,24 +2,20 @@ package com.tangem.tap.common.analytics.converters
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.Converter
+import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.SaltPayWorkaround
-import com.tangem.domain.common.ScanResponse
-import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.tap.common.analytics.events.AnalyticsParam
-import com.tangem.tap.domain.extensions.isMultiwalletAllowed
/**
[REDACTED_AUTHOR]
*/
-class ParamCardCurrencyConverter : Converter {
+class ParamCardCurrencyConverter : Converter {
- override fun convert(value: ScanResponse): AnalyticsParam.CardCurrency? {
- if (value.card.isMultiwalletAllowed) return AnalyticsParam.CardCurrency.MultiCurrency
+ override fun convert(value: CardTypesResolver): AnalyticsParam.CardCurrency? {
+ if (value.isMultiwalletAllowed()) return AnalyticsParam.CardCurrency.MultiCurrency
val type = when {
- value.isTangemNote() -> {
- value.card.getTangemNoteBlockchain()?.let { AnalyticsParam.CurrencyType.Blockchain(it) }
- }
+ value.isTangemNote() -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain())
value.isTangemTwins() -> AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin)
value.isSaltPay() -> AnalyticsParam.CurrencyType.Token(SaltPayWorkaround.tokenFrom(Blockchain.SaltPay))
value.getBlockchain() != Blockchain.Unknown -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain())
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt
index 49f6762db9..5d779e661f 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt
@@ -20,7 +20,8 @@ class ShopOrderToEventConverter : Converter "3"
}
val amount = "${checkout.totalPriceV2.amount} ${checkout.totalPriceV2.currencyCode.name}"
- val code = (checkout.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
+ val code = (checkout.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)
+ ?.code
return Shop.Purchased(sku, count, amount, code)
}
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt
index bad36d3f0d..2e5a925560 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt
@@ -8,7 +8,10 @@ sealed class AnalyticsParam {
class Currency(currency: com.tangem.tap.features.wallet.models.Currency) : CurrencyType(currency.currencySymbol)
class Blockchain(blockchain: com.tangem.blockchain.common.Blockchain) : CurrencyType(blockchain.currency)
class Token(token: com.tangem.blockchain.common.Token) : CurrencyType(token.symbol)
- class FiatCurrency(fiatCurrency: com.tangem.tap.common.entities.FiatCurrency) : CurrencyType(fiatCurrency.symbol)
+ class FiatCurrency(
+ fiatCurrency: com.tangem.tap.common.entities.FiatCurrency,
+ ) : CurrencyType(fiatCurrency.symbol)
+
class Amount(amount: com.tangem.blockchain.common.Amount) : CurrencyType(amount.currencySymbol)
}
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt
index ecdedd9761..0d9a529469 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt
@@ -33,4 +33,4 @@ sealed class Basic(
event = "Scan",
error = error,
)
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt
index 8eb0f6490d..4ec37c4806 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt
@@ -75,7 +75,7 @@ sealed class Onboarding(
class ClaimScreenOpened : Onboarding("Onboarding", "Claim screen opened")
class ButtonClaim : Onboarding("Onboarding", "Button - Claim")
class ClaimWasSuccessfully : Onboarding("Onboarding", "Claim was successfully")
- class ButtonChat: Onboarding("Onboarding", "Button - Chat")
+ class ButtonChat : Onboarding("Onboarding", "Button - Chat")
class EnableBiometrics(state: AnalyticsParam.OnOffState) : Onboarding(
category = "Onboarding / Biometric",
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeClient.kt
index 80f8359025..ddb27d18ff 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeClient.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeClient.kt
@@ -4,7 +4,7 @@ import android.app.Application
import com.amplitude.api.Amplitude
import com.amplitude.api.AmplitudeClient
import com.tangem.common.Converter
-import com.tangem.analytics.api.EventLogger
+import com.tangem.core.analytics.api.EventLogger
import org.json.JSONObject
/**
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerClient.kt
index b8271cc6af..40cee4e698 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerClient.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerClient.kt
@@ -2,7 +2,7 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer
import android.content.Context
import com.appsflyer.AppsFlyerLib
-import com.tangem.analytics.api.EventLogger
+import com.tangem.core.analytics.api.EventLogger
/**
[REDACTED_AUTHOR]
diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt
index 3db2ed90bc..33751b5e0a 100644
--- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt
+++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseClient.kt
@@ -6,8 +6,8 @@ import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
-import com.tangem.analytics.api.ErrorEventLogger
-import com.tangem.analytics.api.EventLogger
+import com.tangem.core.analytics.api.ErrorEventLogger
+import com.tangem.core.analytics.api.EventLogger
/**
[REDACTED_AUTHOR]
diff --git a/app/src/main/java/com/tangem/tap/common/compose/AutoSizeText.kt b/app/src/main/java/com/tangem/tap/common/compose/AutoSizeText.kt
index 324fd3877e..63d98b6269 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/AutoSizeText.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/AutoSizeText.kt
@@ -11,12 +11,13 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
+@Suppress("MagicNumber")
@Composable
fun TextAutoSize(
- modifier: Modifier = Modifier,
text: String,
- textStyle: TextStyle = LocalTextStyle.current,
fontSizeRange: FontSizeRange,
+ modifier: Modifier = Modifier,
+ textStyle: TextStyle = LocalTextStyle.current,
) {
val fontSizeValue = remember { mutableStateOf(fontSizeRange.max.value) }
val readyToDraw = remember { mutableStateOf(false) }
@@ -46,7 +47,7 @@ fun TextAutoSize(
} else {
readyToDraw.value = true
}
- }
+ },
)
}
diff --git a/app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt b/app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt
index 3df228a032..215fb7b312 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/BlockchainSpinner.kt
@@ -17,7 +17,7 @@ fun BlockchainSpinner(
textFieldConverter: (Blockchain) -> String,
dropdownItemView: @Composable ((Blockchain) -> Unit)? = null,
closePopupTrigger: ClosePopupTrigger = ClosePopupTrigger(),
- onItemSelected: (Blockchain) -> Unit,
+ onItemSelect: (Blockchain) -> Unit,
) {
OutlinedSpinner(
modifier = Modifier.fillMaxWidth(),
@@ -27,7 +27,7 @@ fun BlockchainSpinner(
textFieldConverter = textFieldConverter,
dropdownItemView = dropdownItemView,
isEnabled = isEnabled,
- onItemSelected = onItemSelected,
+ onItemSelected = onItemSelect,
closePopupTrigger = closePopupTrigger,
)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/Button.kt b/app/src/main/java/com/tangem/tap/common/compose/Button.kt
index b20f7470b8..c536af17bd 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/Button.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/Button.kt
@@ -1,137 +1,8 @@
package com.tangem.tap.common.compose
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.material.Button
-import androidx.compose.material.ButtonDefaults
-import androidx.compose.material.Icon
-import androidx.compose.material.IconButton
-import androidx.compose.material.Scaffold
-import androidx.compose.material.Text
import androidx.compose.material.ripple.LocalRippleTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.colorResource
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.DpSize
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.tangem.core.ui.components.SpacerH8
-import com.tangem.tap.common.compose.extensions.stringResourceDefault
-import com.tangem.wallet.R
-
-/**
-[REDACTED_AUTHOR]
- */
-@Composable
-fun RectangleButton(
- modifier: Modifier = Modifier,
- text: String = "",
- textId: Int? = null,
- isEnabled: Boolean = true,
- contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
- leadingView: @Composable RowScope.() -> Unit = {},
- middleView: @Composable RowScope.() -> Unit = { TextInButton(text = text, textId = textId) },
- trailingView: @Composable RowScope.() -> Unit = {},
- onClick: () -> Unit,
-) {
- Button(
- modifier = modifier,
- contentPadding = contentPadding,
- enabled = isEnabled,
- onClick = onClick,
- ) {
- leadingView()
- middleView()
- trailingView()
- }
-}
-
-@Composable
-private fun TextInButton(
- modifier: Modifier = Modifier,
- text: String = "",
- textId: Int? = null,
-) {
- Text(
- modifier = modifier,
- text = stringResourceDefault(textId, text),
- maxLines = 1,
- style = TextStyle(
- fontSize = 16.sp,
- lineHeight = 20.sp,
- fontWeight = FontWeight.Medium,
- )
- )
-}
-
-@Composable
-fun PasteButton(
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- dpSize: DpSize = DpSize(40.dp, 40.dp),
- onClick: () -> Unit,
- tint: Color? = null,
- content: @Composable (() -> Unit)? = null
-) {
- IconButton(
- modifier = modifier.size(dpSize),
- enabled = enabled,
- onClick = onClick,
- ) {
- when (content) {
- null -> {
- val tintColor = tint
- ?: colorResource(id = if (enabled) R.color.accent else R.color.accent_disabled)
- Icon(
- painterResource(id = R.drawable.ic_paste),
- contentDescription = "Paste",
- tint = tintColor,
- )
- }
- else -> content()
- }
- }
-}
-
-@Composable
-fun ClearButton(
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- dpSize: DpSize = DpSize(40.dp, 40.dp),
- onClick: () -> Unit,
- tint: Color? = null,
- content: @Composable (() -> Unit)? = null
-) {
- IconButton(
- modifier = modifier.size(dpSize),
- enabled = enabled,
- onClick = onClick,
- ) {
- when (content) {
- null -> {
- val tintColor = tint
- ?: colorResource(id = if (enabled) R.color.accent else R.color.accent_disabled)
- Icon(
- painterResource(id = R.drawable.ic_clear),
- contentDescription = "Clear",
- tint = tintColor,
- )
- }
- else -> content()
- }
- }
-}
/**
* Used for disable ripple if button is enable = false
@@ -143,34 +14,4 @@ fun ToggledRippleTheme(
) {
val theme = LocalRippleTheme provides if (isEnabled) LocalRippleTheme.current else NoRippleTheme()
CompositionLocalProvider(theme) { content() }
-}
-
-@Preview
-@Composable
-fun ButtonTest() {
- Scaffold {
- Column(modifier = Modifier.padding(16.dp)) {
- PreviewItem("Button") {
- RectangleButton(text = "Some button") {}
- }
- PreviewItem("PasteButton") {
- PasteButton(onClick = {})
- }
- }
- }
-}
-
-@Composable
-fun PreviewItem(
- name: String,
- content: @Composable RowScope.() -> Unit,
-) {
- Row(verticalAlignment = Alignment.CenterVertically) {
- Text(
- modifier = Modifier.weight(1f),
- text = name,
- )
- content()
- }
- SpacerH8()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/ComposableValueDebouncer.kt b/app/src/main/java/com/tangem/tap/common/compose/ComposableValueDebouncer.kt
index b3251f3cac..44395f9279 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/ComposableValueDebouncer.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/ComposableValueDebouncer.kt
@@ -11,19 +11,19 @@ import com.tangem.domain.common.util.ValueDebouncer
@Composable
fun valueDebouncerAsState(
initialValue: T,
+ onValueChange: (T) -> Unit,
debounce: Long = 600,
- onEmitValueReceived: (T) -> Unit = {},
- onValueChanged: (T) -> Unit,
+ onEmitValueReceive: (T) -> Unit = {},
): ValueDebouncer {
return remember {
- ValueDebouncer(
+ ValueDebouncer(
initialValue = initialValue,
debounceDuration = debounce,
onEmitValueReceived = { emitValue ->
- emitValue?.let { onEmitValueReceived(it) }
+ emitValue?.let { onEmitValueReceive(it) }
},
onValueChanged = { changedValue ->
- changedValue?.let { onValueChanged(it) }
+ changedValue?.let { onValueChange(it) }
},
)
}
@@ -32,16 +32,16 @@ fun valueDebouncerAsState(
@Composable
fun valueDebouncerNullableAsState(
initialValue: T?,
+ onValueChange: (T?) -> Unit,
debounce: Long = 400,
- onEmitValueReceived: (T?) -> Unit = {},
- onValueChanged: (T?) -> Unit,
+ onEmitValueReceive: (T?) -> Unit = {},
): ValueDebouncer {
return remember {
ValueDebouncer(
initialValue = initialValue,
debounceDuration = debounce,
- onEmitValueReceived = onEmitValueReceived,
- onValueChanged = onValueChanged,
+ onEmitValueReceived = onEmitValueReceive,
+ onValueChanged = onValueChange,
)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt
index 99042c3391..8d0de7df69 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/ComposeDialogManager.kt
@@ -80,6 +80,7 @@ private fun ShowTheDialog(dialogState: MutableState) {
onDismissRequest
)
is DomainDialog.SelectTokenDialog -> SelectTokenNetworkDialog(dialog, onDismissRequest)
+ else -> {}
}
}
diff --git a/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt b/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt
index 49b6625474..c8d0701b2e 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/ErrorViews.kt
@@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -19,23 +18,20 @@ import androidx.compose.ui.unit.dp
fun ErrorView(
text: String,
modifier: Modifier = Modifier,
- style: TextStyle = LocalTextStyle.current
+ style: TextStyle = LocalTextStyle.current,
) {
Text(
text,
color = MaterialTheme.colors.error,
modifier = modifier,
- style = style
+ style = style,
)
}
@Preview
@Composable
-fun ErrorViewTest() {
- Scaffold(
- ) {
- Box(Modifier.padding(16.dp)) {
- ErrorView(text = "Some error description")
- }
+private fun ErrorViewTest() {
+ Box(Modifier.padding(16.dp)) {
+ ErrorView(text = "Some error description")
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/Theme.kt b/app/src/main/java/com/tangem/tap/common/compose/NoRippleTheme.kt
similarity index 100%
rename from app/src/main/java/com/tangem/tap/common/compose/Theme.kt
rename to app/src/main/java/com/tangem/tap/common/compose/NoRippleTheme.kt
diff --git a/app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt b/app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt
index 3792119da9..981e5e00e6 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/OutlinedSpinner.kt
@@ -17,14 +17,15 @@ import com.tangem.tap.common.extensions.ValueCallback
/**
[REDACTED_AUTHOR]
*/
+@Suppress("MagicNumber")
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun OutlinedSpinner(
- modifier: Modifier = Modifier,
label: String,
itemList: List,
selectedItem: Field.Data,
onItemSelected: ValueCallback,
+ modifier: Modifier = Modifier,
textFieldConverter: (T) -> String = { it.toString() },
dropdownItemView: @Composable ((T) -> Unit)? = null,
isEnabled: Boolean = true,
@@ -66,6 +67,7 @@ fun OutlinedSpinner(
onValueChange = {},
label = { Text(label) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = rIsExpanded.value) },
+ colors = TangemTextFieldsDefault.defaultTextFieldColors,
)
if (isEnabled) {
@@ -94,13 +96,11 @@ class ClosePopupTrigger {
@Preview
@Composable
-fun TestSpinnerPreview() {
- Scaffold() {
- OutlinedSpinner(
- label = "Blockchain name",
- itemList = listOf(Blockchain.values()),
- selectedItem = Field.Data(Blockchain.Avalanche, false),
- onItemSelected = {},
- )
- }
-}
+private fun TestSpinnerPreview() {
+ OutlinedSpinner(
+ label = "Blockchain name",
+ itemList = listOf(Blockchain.values()),
+ selectedItem = Field.Data(Blockchain.Avalanche, false),
+ onItemSelected = {},
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt b/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt
index deacbaf05f..113dbfb809 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/OutlinedTextFieldWidget.kt
@@ -6,6 +6,7 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
+import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@@ -13,8 +14,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.OutlinedTextField
-import androidx.compose.material.Scaffold
import androidx.compose.material.Text
+import androidx.compose.material.TextFieldColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -28,6 +29,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.tangem.common.module.ModuleError
+import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.common.form.Field
import com.tangem.tap.common.CompositionLogger
import com.tangem.tap.common.compose.extensions.stringResourceDefault
@@ -38,7 +40,6 @@ import com.tangem.tap.domain.moduleMessage.ModuleMessageConverter
*/
@Composable
fun OutlinedTextFieldWidget(
- modifier: Modifier = Modifier,
fieldData: Field.Data,
labelId: Int? = null,
label: String = "",
@@ -53,15 +54,12 @@ fun OutlinedTextFieldWidget(
debounceTextChanges: Long = 400,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
- onTextChanged: (String) -> Unit,
+ onTextChange: (String) -> Unit,
) {
if (!isVisible) return
- Column(
- modifier = modifier.animateContentSize(),
- ) {
+ Column(modifier = Modifier.animateContentSize()) {
OutlinedProgressTextField(
- modifier = modifier,
fieldData = fieldData,
label = stringResourceDefault(labelId, label),
placeholder = stringResourceDefault(placeholderId, placeholder),
@@ -72,15 +70,15 @@ fun OutlinedTextFieldWidget(
debounce = debounceTextChanges,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
- onTextChanged = onTextChanged,
+ onTextChange = onTextChange,
)
- errorConverter?.let { AnimatedErrorView(error, it) }
+ errorConverter?.let { AnimatedErrorView(errorConverter = it, error = error) }
}
}
+@Suppress("LongMethod", "NestedBlockDepth", "MagicNumber", "MaxLineLength")
@Composable
private fun OutlinedProgressTextField(
- modifier: Modifier = Modifier,
fieldData: Field.Data,
label: String = "",
placeholder: String = "",
@@ -90,8 +88,10 @@ private fun OutlinedProgressTextField(
debounce: Long = 400,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+ colors: TextFieldColors = TangemTextFieldsDefault.defaultTextFieldColors,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
trailingIcon: @Composable (() -> Unit)? = null,
- onTextChanged: (String) -> Unit,
+ onTextChange: (String) -> Unit,
) {
val logger = remember {
CompositionLogger(label, "OutlinedProgressTextField", listOf("Символ токена"))
@@ -102,19 +102,19 @@ private fun OutlinedProgressTextField(
val textDebouncer = valueDebouncerAsState(
initialValue = fieldData.value,
debounce = debounce,
- onEmitValueReceived = {
+ onEmitValueReceive = {
logger.log("DEBOUNCER: onEmitValueReceived: [$it]")
logger.log("DEBOUNCER: start RECOMPOSE by new value for textValueState.value = [$it]")
textValueState.value = it
},
- onValueChanged = {
+ onValueChange = {
logger.log("DEBOUNCER: onValueChanged: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> dispatch.toStore([$it])")
- onTextChanged(it)
+ onTextChange(it)
},
)
logger.log("RECOMPOSE ---------------------------------------------------------------START [${logger.count}]")
- logger.log("RECOMPOSE --data: fieldData.value: [${fieldData}]")
+ logger.log("RECOMPOSE --data: fieldData.value: [$fieldData]")
logger.log("RECOMPOSE --data: textValueState.value: [${textValueState.value}]")
logger.log("RECOMPOSE --data: textDebouncer.emittedValue = [${textDebouncer.emittedValue}]")
logger.log("RECOMPOSE --data: textDebouncer.debounced = [${textDebouncer.debounced}]")
@@ -127,21 +127,32 @@ private fun OutlinedProgressTextField(
logger.log("$isNotUserInput: внешние данные ОДИНАКОВЫ с данными в поле")
} else {
logger.log("$isNotUserInput: внешние данные РАЗЛИЧАЮТСЯ с данными в поле")
- if ((textDebouncer.emittedValue != textDebouncer.debounced) || textDebouncer.emitsCountBeforeDebounce > 0) {
+ if (textDebouncer.emittedValue != textDebouncer.debounced || textDebouncer.emitsCountBeforeDebounce > 0) {
logger.log("$isNotUserInput: пользователь ВВОДИТ данные -> внешние данные игнорируем, ждем RECOMPOSE")
} else {
logger.log("$isNotUserInput: пользователь НЕ вводит данные -> пытаемся обработать внешние данные")
- if (textValueState.value != textDebouncer.emittedValue || textValueState.value != textDebouncer.debounced) {
+ if (textValueState.value != textDebouncer.emittedValue ||
+ textValueState.value != textDebouncer.debounced
+ ) {
logger.log("$isNotUserInput: даннные в поле не соответствуют данным из textDebouncer")
if (textDebouncer.emittedValue.isEmpty() && textDebouncer.debounced.isEmpty()) {
- logger.log("$isNotUserInput: даннные в textDebouncer ПУСТЫ -> start RECOMPOSE новые данные для textValueState.value = [${fieldData.value}]")
+ logger.log(
+ "$isNotUserInput: даннные в textDebouncer ПУСТЫ -> start RECOMPOSE новые данные для " +
+ "textValueState.value = [${fieldData.value}]",
+ )
textValueState.value = fieldData.value
} else {
- logger.log("$isNotUserInput: даннные в textDebouncer НЕ ПУСТЫ -> start RECOMPOSE новые данные для textValueState.value = [${fieldData.value}]")
+ logger.log(
+ "$isNotUserInput: даннные в textDebouncer НЕ ПУСТЫ -> start RECOMPOSE новые данные для " +
+ "textValueState.value = [${fieldData.value}]",
+ )
textValueState.value = fieldData.value
}
} else {
- logger.log("$isNotUserInput: в пустое поле вставляются данные -> start RECOMPOSE новые данные для textValueState.value = [${fieldData.value}]")
+ logger.log(
+ "$isNotUserInput: в пустое поле вставляются данные -> start RECOMPOSE новые данные для " +
+ "textValueState.value = [${fieldData.value}]",
+ )
textValueState.value = fieldData.value
}
}
@@ -159,10 +170,22 @@ private fun OutlinedProgressTextField(
textDebouncer.emmit(it)
},
keyboardOptions = keyboardOptions,
- label = { Text(label) },
+ label = {
+ Text(
+ text = label,
+ style = TangemTheme.typography.caption,
+ color = colors.labelColor(
+ enabled = isEnabled,
+ error = error != null,
+ interactionSource = interactionSource,
+ ).value,
+ )
+ },
placeholder = {
Text(
text = placeholder,
+ style = TangemTheme.typography.body1,
+ color = colors.placeholderColor(enabled = isEnabled).value,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
@@ -172,21 +195,27 @@ private fun OutlinedProgressTextField(
enabled = isEnabled,
isError = error != null,
visualTransformation = visualTransformation,
+ colors = colors,
+ interactionSource = interactionSource,
)
AnimatedVisibility(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(start = 6.dp, top = 0.dp, end = 6.dp, bottom = 6.dp),
visible = isLoading,
- ) { LinearProgressIndicator() }
+ ) {
+ LinearProgressIndicator(
+ color = TangemTheme.colors.icon.primary1,
+ )
+ }
}
}
@Composable
private fun AnimatedErrorView(
- error: ModuleError? = null,
errorConverter: ModuleMessageConverter,
+ error: ModuleError? = null,
) {
AnimatedVisibility(
visible = error != null,
@@ -204,7 +233,7 @@ private fun AnimatedErrorView(
@Preview
@Composable
-fun OutlinedTextFieldWithErrorTest() {
+private fun OutlinedTextFieldWithErrorTest() {
val context = LocalContext.current
val converter = remember { ModuleMessageConverter(context) }
@@ -217,41 +246,35 @@ fun OutlinedTextFieldWithErrorTest() {
val modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
- Scaffold {
- Column {
- OutlinedTextFieldWidget(
- modifier = modifier,
- fieldData = Field.Data("", false),
- label = "First label",
- placeholder = "1 placeholder",
- error = null,
- errorConverter = converter,
- ) {}
- OutlinedTextFieldWidget(
- modifier = modifier,
- fieldData = Field.Data("First", false),
- label = "First label",
- placeholder = "1 placeholder",
- error = null,
- errorConverter = converter,
- ) {}
- OutlinedTextFieldWidget(
- modifier = modifier,
- fieldData = Field.Data("First", false),
- label = "First label",
- placeholder = "1 placeholder",
- isLoading = true,
- error = null,
- errorConverter = converter,
- ) {}
- OutlinedTextFieldWidget(
- modifier = modifier,
- fieldData = Field.Data("First", false),
- label = "First label",
- placeholder = "1 placeholder",
- error = SimpleError(),
- errorConverter = converter,
- ) {}
- }
+ Column {
+ OutlinedTextFieldWidget(
+ fieldData = Field.Data("", false),
+ label = "First label",
+ placeholder = "1 placeholder",
+ error = null,
+ errorConverter = converter,
+ ) {}
+ OutlinedTextFieldWidget(
+ fieldData = Field.Data("First", false),
+ label = "First label",
+ placeholder = "1 placeholder",
+ error = null,
+ errorConverter = converter,
+ ) {}
+ OutlinedTextFieldWidget(
+ fieldData = Field.Data("First", false),
+ label = "First label",
+ placeholder = "1 placeholder",
+ isLoading = true,
+ error = null,
+ errorConverter = converter,
+ ) {}
+ OutlinedTextFieldWidget(
+ fieldData = Field.Data("First", false),
+ label = "First label",
+ placeholder = "1 placeholder",
+ error = SimpleError(),
+ errorConverter = converter,
+ ) {}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt b/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt
index ad7bbe794b..f742bb5731 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/PinCodeWidget.kt
@@ -50,7 +50,7 @@ import androidx.core.text.isDigitsOnly
@Composable
fun PinCodeWidget(
config: PinViewConfig = tangemPinConfig,
- onPinChanged: (String, Boolean) -> Unit = { pin, isLastSymbolEntered -> },
+ onPinChange: (String, Boolean) -> Unit = { pin, isLastSymbolEntered -> },
) {
val focusRequester = remember { FocusRequester() }
val keyboardController = LocalSoftwareKeyboardController.current
@@ -65,7 +65,7 @@ fun PinCodeWidget(
if (value.text.length <= config.pinsCount) {
rTextFieldValue.value = value
- onPinChanged(value.text, isLastSymbolEntered())
+ onPinChange(value.text, isLastSymbolEntered())
}
}
@@ -125,10 +125,6 @@ private fun PinElement(
}
}
-@Composable
-private fun HiddenInputField() {
-}
-
private fun createPinSymbolsList(size: Int, text: String): List = List(size) {
try {
text[it].toString()
@@ -165,7 +161,7 @@ private val tangemPinConfig = PinViewConfig(
@Preview
@Composable
-fun PinCodeWidgetPreview() {
+private fun PinCodeWidgetPreview() {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
PinCodeWidget(tangemPinConfig)
}
diff --git a/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt b/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt
new file mode 100644
index 0000000000..694fd8c376
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/common/compose/TangemTextFieldsDefault.kt
@@ -0,0 +1,156 @@
+package com.tangem.tap.common.compose
+
+import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
+import androidx.compose.material.TextFieldColors
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.graphics.Color
+import com.tangem.core.ui.res.TangemTheme
+
+// Copy from com.tangem.core.ui.components
+// TODO: Delete this after fields has been moved to core-ui module
+internal object TangemTextFieldsDefault {
+ val defaultTextFieldColors: TangemTextFieldColors
+ @Composable @Stable get() = TangemTextFieldColors(
+ textColor = TangemTheme.colors.text.primary1,
+ disabledTextColor = TangemTheme.colors.text.disabled,
+ backgroundColor = Color.Transparent,
+ cursorColor = TangemTheme.colors.icon.primary1,
+ errorCursorColor = TangemTheme.colors.icon.warning,
+ focusedIndicatorColor = TangemTheme.colors.icon.primary1,
+ unfocusedIndicatorColor = TangemTheme.colors.stroke.primary,
+ disabledIndicatorColor = TangemTheme.colors.stroke.primary,
+ errorIndicatorColor = TangemTheme.colors.icon.warning,
+ leadingIconColor = TangemTheme.colors.icon.informative,
+ disabledLeadingIconColor = Color.Transparent,
+ errorLeadingIconColor = TangemTheme.colors.icon.warning,
+ trailingIconColor = TangemTheme.colors.icon.informative,
+ disabledTrailingIconColor = Color.Transparent,
+ errorTrailingIconColor = TangemTheme.colors.icon.warning,
+ focusedLabelColor = TangemTheme.colors.text.primary1,
+ unfocusedLabelColor = TangemTheme.colors.text.secondary,
+ disabledLabelColor = TangemTheme.colors.text.disabled,
+ errorLabelColor = TangemTheme.colors.icon.warning,
+ placeholderColor = TangemTheme.colors.text.secondary,
+ disabledPlaceholderColor = TangemTheme.colors.text.disabled,
+ captionColor = TangemTheme.colors.text.tertiary,
+ disabledCaptionColor = TangemTheme.colors.text.disabled,
+ errorCaptionColor = TangemTheme.colors.icon.warning,
+ )
+}
+
+@Immutable
+internal data class TangemTextFieldColors(
+ private val textColor: Color,
+ private val disabledTextColor: Color,
+ private val cursorColor: Color,
+ private val errorCursorColor: Color,
+ private val focusedIndicatorColor: Color,
+ private val unfocusedIndicatorColor: Color,
+ private val errorIndicatorColor: Color,
+ private val disabledIndicatorColor: Color,
+ private val leadingIconColor: Color,
+ private val disabledLeadingIconColor: Color,
+ private val errorLeadingIconColor: Color,
+ private val trailingIconColor: Color,
+ private val disabledTrailingIconColor: Color,
+ private val errorTrailingIconColor: Color,
+ private val backgroundColor: Color,
+ private val focusedLabelColor: Color,
+ private val unfocusedLabelColor: Color,
+ private val disabledLabelColor: Color,
+ private val errorLabelColor: Color,
+ private val placeholderColor: Color,
+ private val disabledPlaceholderColor: Color,
+ private val captionColor: Color,
+ private val disabledCaptionColor: Color,
+ private val errorCaptionColor: Color,
+) : TextFieldColors {
+
+ @Composable
+ override fun leadingIconColor(enabled: Boolean, isError: Boolean): State {
+ return rememberUpdatedState(
+ when {
+ !enabled -> disabledLeadingIconColor
+ isError -> errorLeadingIconColor
+ else -> leadingIconColor
+ },
+ )
+ }
+
+ @Composable
+ override fun trailingIconColor(enabled: Boolean, isError: Boolean): State {
+ return rememberUpdatedState(
+ when {
+ !enabled -> disabledTrailingIconColor
+ isError -> errorTrailingIconColor
+ else -> trailingIconColor
+ },
+ )
+ }
+
+ @Composable
+ override fun indicatorColor(
+ enabled: Boolean,
+ isError: Boolean,
+ interactionSource: InteractionSource,
+ ): State {
+ val focused by interactionSource.collectIsFocusedAsState()
+
+ val targetValue = when {
+ !enabled -> disabledIndicatorColor
+ isError -> errorIndicatorColor
+ focused -> focusedIndicatorColor
+ else -> unfocusedIndicatorColor
+ }
+ return if (enabled) {
+ animateColorAsState(targetValue, tween(durationMillis = 120))
+ } else {
+ rememberUpdatedState(targetValue)
+ }
+ }
+
+ @Composable
+ override fun backgroundColor(enabled: Boolean): State {
+ return rememberUpdatedState(backgroundColor)
+ }
+
+ @Composable
+ override fun placeholderColor(enabled: Boolean): State {
+ return rememberUpdatedState(if (enabled) placeholderColor else disabledPlaceholderColor)
+ }
+
+ @Composable
+ override fun labelColor(
+ enabled: Boolean,
+ error: Boolean,
+ interactionSource: InteractionSource,
+ ): State {
+ val focused by interactionSource.collectIsFocusedAsState()
+
+ val targetValue = when {
+ !enabled -> disabledLabelColor
+ error -> errorLabelColor
+ focused -> focusedLabelColor
+ else -> unfocusedLabelColor
+ }
+ return rememberUpdatedState(targetValue)
+ }
+
+ @Composable
+ override fun textColor(enabled: Boolean): State {
+ return rememberUpdatedState(if (enabled) textColor else disabledTextColor)
+ }
+
+ @Composable
+ override fun cursorColor(isError: Boolean): State {
+ return rememberUpdatedState(if (isError) errorCursorColor else cursorColor)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt b/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt
index 6cd0b70d72..10e2ec9956 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/Undefined.kt
@@ -16,7 +16,7 @@ fun TitleSubtitle(
title: String,
subtitle: String
) {
- Column() {
+ Column {
Text(text = title)
Text(
text = subtitle,
diff --git a/app/src/main/java/com/tangem/tap/common/compose/Warning.kt b/app/src/main/java/com/tangem/tap/common/compose/Warning.kt
index 0d19a8e2ea..ea4d150e51 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/Warning.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/Warning.kt
@@ -22,9 +22,9 @@ import com.tangem.wallet.R
*/
@Composable
fun AddCustomTokenWarning(
- modifier: Modifier = Modifier,
warning: ModuleMessage,
- converter: ModuleMessageConverter
+ converter: ModuleMessageConverter,
+ modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier,
@@ -49,6 +49,5 @@ fun AddCustomTokenWarning(
lineHeight = 18.sp
)
}
-
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/Color.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/Color.kt
deleted file mode 100644
index d25bc9e26b..0000000000
--- a/app/src/main/java/com/tangem/tap/common/compose/extensions/Color.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.tangem.tap.common.compose.extensions
-
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.toArgb
-import androidx.core.graphics.alpha
-import androidx.core.graphics.blue
-import androidx.core.graphics.green
-import androidx.core.graphics.red
-
-/**
-[REDACTED_AUTHOR]
- */
-fun Color.toAndroidGraphicsColor(): Int {
- val argb = this.toArgb()
- return android.graphics.Color.argb(argb.alpha, argb.red, argb.green, argb.blue)
-}
-
-fun Color.parse(hexColor: String): Color {
- return Color(hexColor.removePrefix("#").toInt(16))
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/Context.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/Context.kt
index 25ae94623c..719c80d0d4 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/extensions/Context.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/extensions/Context.kt
@@ -8,11 +8,13 @@ import com.tangem.tap.common.extensions.getFromClipboard
/**
[REDACTED_AUTHOR]
*/
+@Suppress("ComposableFunctionName")
@Composable
fun copyToClipboard(value: Any, label: String = "") {
LocalContext.current.copyToClipboard(value, label)
}
+@Suppress("ComposableFunctionName")
@Composable
fun getFromClipboard(default: CharSequence? = null): CharSequence? {
return LocalContext.current.getFromClipboard(default)
diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt
index 1692b4c51f..99911d9e6f 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/extensions/ImageBitmap.kt
@@ -13,7 +13,8 @@ import androidx.core.graphics.drawable.toBitmap
*/
@Composable
fun asImageBitmap(@DrawableRes drawableId: Int): ImageBitmap {
- val drawable = AppCompatResources.getDrawable(LocalContext.current, drawableId)
- ?: throw NullPointerException()
+ val drawable = requireNotNull(AppCompatResources.getDrawable(LocalContext.current, drawableId)) {
+ "drawable is null"
+ }
return drawable.toBitmap().asImageBitmap()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/compose/extensions/LazyListState.kt b/app/src/main/java/com/tangem/tap/common/compose/extensions/LazyListState.kt
index f05044368f..dab9b8f654 100644
--- a/app/src/main/java/com/tangem/tap/common/compose/extensions/LazyListState.kt
+++ b/app/src/main/java/com/tangem/tap/common/compose/extensions/LazyListState.kt
@@ -1,12 +1,16 @@
package com.tangem.tap.common.compose.extensions
import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalView
import com.tangem.tap.common.extensions.hideKeyboard
@Composable
-fun LazyListState.OnBottomReached(loadMoreThreshold: Int, loadMore: () -> Unit) {
+fun LazyListState.OnBottomReached(loadMoreThreshold: Int, onLoadMore: () -> Unit) {
require(loadMoreThreshold >= 0)
val shouldLoadMore by remember {
derivedStateOf {
@@ -17,7 +21,7 @@ fun LazyListState.OnBottomReached(loadMoreThreshold: Int, loadMore: () -> Unit)
}
LaunchedEffect(shouldLoadMore) {
- if (shouldLoadMore) loadMore()
+ if (shouldLoadMore) onLoadMore()
}
}
diff --git a/app/src/main/java/com/tangem/tap/common/entities/Button.kt b/app/src/main/java/com/tangem/tap/common/entities/Button.kt
index a2d4127c8f..d9ff2b27f8 100644
--- a/app/src/main/java/com/tangem/tap/common/entities/Button.kt
+++ b/app/src/main/java/com/tangem/tap/common/entities/Button.kt
@@ -6,7 +6,7 @@ import com.tangem.tap.features.wallet.redux.ProgressState
open class Button(val enabled: Boolean)
open class IndeterminateProgressButton(
- val state: ButtonState
+ val state: ButtonState
) : Button(state != ButtonState.DISABLED) {
val progressState: ProgressState
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt b/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt
index 8ed146440b..5f531a9bc8 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Activity.kt
@@ -26,11 +26,11 @@ fun Activity.sendEmail(
) {
fun createEmailShareIntent(recipient: String, subject: String, text: String, file: File? = null): Intent {
val builder = ShareCompat.IntentBuilder.from(this)
- .setType("message/rfc822")
- .setEmailTo(arrayOf(recipient))
- .setSubject(subject)
- .setText(text)
- file?.let { builder.setStream(FileProvider.getUriForFile(this, "${packageName}.provider", it)) }
+ .setType("message/rfc822")
+ .setEmailTo(arrayOf(recipient))
+ .setSubject(subject)
+ .setText(text)
+ file?.let { builder.setStream(FileProvider.getUriForFile(this, "$packageName.provider", it)) }
return builder.intent
}
@@ -41,17 +41,17 @@ fun Activity.sendEmail(
val emailFilterIntentResults = packageManager.queryIntentActivities(emailFilterIntent, 0)
val targetedIntents = originalIntentResults
- .filter { originalResult ->
- emailFilterIntentResults.any {
- originalResult.activityInfo.packageName == it.activityInfo.packageName
- }
+ .filter { originalResult ->
+ emailFilterIntentResults.any {
+ originalResult.activityInfo.packageName == it.activityInfo.packageName
}
- .map {
- createEmailShareIntent(email, subject, message, file).apply {
- setPackage(it.activityInfo.packageName)
- }
+ }
+ .map {
+ createEmailShareIntent(email, subject, message, file).apply {
+ setPackage(it.activityInfo.packageName)
}
- .toMutableList()
+ }
+ .toMutableList()
try {
val chooserIntent = Intent.createChooser(targetedIntents.removeAt(0), "Send mail...")
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toTypedArray())
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/AssetManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/AssetManager.kt
index b2905ec473..9130b6c91d 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/AssetManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/AssetManager.kt
@@ -3,4 +3,4 @@ package com.tangem.tap.common.extensions
import android.content.res.AssetManager
fun AssetManager.readJsonFileToString(fileName: String): String =
- this.open("$fileName.json").bufferedReader().readText()
\ No newline at end of file
+ this.open("$fileName.json").bufferedReader().readText()
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt b/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt
index abe1863c6d..140f0946b4 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/BackupService.kt
@@ -6,8 +6,7 @@ import com.tangem.operations.backup.BackupService
/**
[REDACTED_AUTHOR]
*/
+@Suppress("MagicNumber")
fun BackupService.primaryCardIsSaltPayVisa(): Boolean {
- return primaryCardId?.slice(0..3)?.let {
- SaltPayWorkaround.isVisaBatchId(it)
- } ?: false
+ return primaryCardId?.slice(0..3)?.let(SaltPayWorkaround::isVisaBatchId) ?: false
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt b/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt
index e8b3891ce9..80e756c21c 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Bitmap.kt
@@ -4,12 +4,14 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.ByteArrayOutputStream
+@Suppress("MagicNumber")
fun Bitmap.toByteArray(): ByteArray {
val stream = ByteArrayOutputStream()
this.compress(Bitmap.CompressFormat.JPEG, 20, stream)
return stream.toByteArray()
}
+@Suppress("MagicNumber")
fun ByteArray.toBitmap(): Bitmap {
return BitmapFactory.decodeByteArray(this, 0, this.size)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
index e53e1effbe..133869ee22 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt
@@ -5,49 +5,17 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.remove
import com.tangem.wallet.R
-@DrawableRes
-fun Blockchain.getRoundIconRes(): Int {
- return when (this) {
- Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> R.drawable.ic_arbitrum_round
- Blockchain.Ducatus -> R.drawable.ic_ducatus
- Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_round
- Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_round
- Blockchain.Litecoin -> R.drawable.ic_litecoin_round
- Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_round
- Blockchain.EthereumClassic, Blockchain.EthereumClassicTestnet -> R.drawable.ic_eth_round
- Blockchain.RSK -> R.drawable.ic_rsk_round
- Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_round
- Blockchain.Tezos -> R.drawable.ic_tezos_round
- Blockchain.XRP -> R.drawable.ic_xrp_round
- Blockchain.Stellar -> R.drawable.ic_stellar_round
- Blockchain.Avalanche, Blockchain.AvalancheTestnet -> R.drawable.ic_avalanche_round
- Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_round
- Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_round
- Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_round
- Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_round
- Blockchain.Dogecoin -> R.drawable.ic_dogecoin_round
- Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_round
- Blockchain.Gnosis -> R.drawable.ic_gnosis_round
- Blockchain.EthereumPow, Blockchain.EthereumPowTestnet -> R.drawable.ic_ethereumpow_round
- Blockchain.EthereumFair -> R.drawable.ic_ethereumfair_round
- Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.drawable.ic_polkadot_round
- Blockchain.Kusama -> R.drawable.ic_kusama_round
- Blockchain.Optimism, Blockchain.OptimismTestnet -> R.drawable.ic_optimism
- Blockchain.Dash -> R.drawable.ic_dash
- else -> R.drawable.ic_tangem_logo
- }
-}
-
+@Suppress("ComplexMethod")
@DrawableRes
fun Blockchain.getGreyedOutIconRes(): Int {
return when (this) {
Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> R.drawable.ic_arbitrum_no_color
// Blockchain.Ducatus -> R.drawable.ic_ducatus
- Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_no_color
+ Blockchain.Bitcoin, Blockchain.BitcoinTestnet -> R.drawable.ic_bitcoin_no_color
Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_no_color
Blockchain.Litecoin -> R.drawable.ic_litecoin_no_color
- Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_no_color
- Blockchain.EthereumClassic, Blockchain.EthereumClassicTestnet, -> R.drawable.ic_eth_no_color
+ Blockchain.Ethereum, Blockchain.EthereumTestnet -> R.drawable.ic_eth_no_color
+ Blockchain.EthereumClassic, Blockchain.EthereumClassicTestnet -> R.drawable.ic_eth_no_color
Blockchain.RSK -> R.drawable.ic_rsk_no_color
Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_no_color
Blockchain.Tezos -> R.drawable.ic_tezos_no_color
@@ -57,7 +25,8 @@ fun Blockchain.getGreyedOutIconRes(): Int {
Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_no_color
Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_no_color
Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_no_color
- Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_no_color
+ Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet ->
+ R.drawable.ic_bsc_no_color
Blockchain.Dogecoin -> R.drawable.ic_dogecoin_no_color
Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_no_color
Blockchain.Gnosis -> R.drawable.ic_gnosis_no_color
@@ -82,4 +51,4 @@ fun Blockchain.getNetworkName(): String {
}
val Blockchain.fullNameWithoutTestnet
-get() = this.fullName.remove(" Testnet")
\ No newline at end of file
+ get() = this.fullName.remove(" Testnet")
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Context.kt b/app/src/main/java/com/tangem/tap/common/extensions/Context.kt
index cba31fe77c..556f261f46 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Context.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Context.kt
@@ -1,7 +1,11 @@
package com.tangem.tap.common.extensions
+import android.content.ContentResolver
import android.content.Context
import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.net.Uri
+import androidx.annotation.AnyRes
import androidx.core.content.ContextCompat
fun Context.readFile(fileName: String): String =
@@ -13,10 +17,22 @@ fun Context.rewriteFile(content: String, fileName: String) {
}
}
-fun Context.readAssetAsString(fileName: String): String {
- return this.assets.open("$fileName.json").bufferedReader().readText()
-}
-
fun Context.isPermissionGranted(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
+}
+
+/**
+ * Get uri to any resource type via given Resource Instance
+ * @param resId - resource id
+ * @throws Resources.NotFoundException if the given ID does not exist.
+ * @return - Uri to resource by the given ID
+ */
+@Throws(Resources.NotFoundException::class)
+fun Context.resourceUri(@AnyRes resId: Int): Uri {
+ return Uri.parse(
+ ContentResolver.SCHEME_ANDROID_RESOURCE +
+ "://" + resources.getResourcePackageName(resId) +
+ '/' + resources.getResourceTypeName(resId) +
+ '/' + resources.getResourceEntryName(resId),
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
index 711e7ed172..6cb707b071 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Navigation.kt
@@ -1,12 +1,12 @@
package com.tangem.tap.common.extensions
-import androidx.activity.OnBackPressedCallback
+import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
-import com.tangem.common.extensions.VoidCallback
import com.tangem.feature.referral.ReferralFragment
+import com.tangem.feature.swap.presentation.SwapFragment
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
@@ -37,10 +37,12 @@ import timber.log.Timber
fun FragmentActivity.openFragment(
screen: AppScreen,
addToBackstack: Boolean,
+ bundle: Bundle? = null,
fgShareTransition: FragmentShareTransition? = null,
) {
val transaction = this.supportFragmentManager.beginTransaction()
val fragment = fragmentFactory(screen)
+ fragment.arguments = bundle
fgShareTransition?.apply {
fragment.sharedElementEnterTransition = enterTransitionSet
fragment.sharedElementReturnTransition = exitTransitionSet
@@ -80,21 +82,15 @@ fun FragmentActivity.getPreviousScreen(): AppScreen? {
} else {
0
}
- val tag = if (indexOfLastFragment < this.supportFragmentManager.backStackEntryCount)
+ val tag = if (indexOfLastFragment < this.supportFragmentManager.backStackEntryCount) {
this.supportFragmentManager.getBackStackEntryAt(indexOfLastFragment).name
- else null
+ } else {
+ null
+ }
return tag?.let { AppScreen.valueOf(tag) }
}
-fun FragmentActivity.addOnBackPressedDispatcher(
- isEnabled: Boolean = true,
- onBackPressed: VoidCallback
-): OnBackPressedCallback = (object : OnBackPressedCallback(isEnabled) {
- override fun handleOnBackPressed() {
- onBackPressed()
- }
-}).also { this.onBackPressedDispatcher.addCallback(it) }
-
+@Suppress("ComplexMethod")
private fun fragmentFactory(screen: AppScreen): Fragment {
return when (screen) {
AppScreen.Home -> HomeFragment()
@@ -117,6 +113,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
AppScreen.WalletConnectSessions -> WalletConnectFragment()
AppScreen.QrScan -> QrScanFragment()
AppScreen.ReferralProgram -> ReferralFragment()
+ AppScreen.Swap -> SwapFragment()
AppScreen.Welcome -> WelcomeFragment()
AppScreen.SaveWallet -> SaveWalletBottomSheetFragment()
AppScreen.WalletSelector -> WalletSelectorBottomSheetFragment()
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt
index 8ff6116155..ff4f898d8d 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt
@@ -11,8 +11,11 @@ import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.*
+// TODO: move extensions to utils
fun BigDecimal.toFormattedString(
- decimals: Int, roundingMode: RoundingMode = RoundingMode.DOWN, locale: Locale = Locale.US
+ decimals: Int,
+ roundingMode: RoundingMode = RoundingMode.DOWN,
+ locale: Locale = Locale.US,
): String {
val symbols = DecimalFormatSymbols(locale)
val df = DecimalFormat()
@@ -24,9 +27,12 @@ fun BigDecimal.toFormattedString(
return df.format(this)
}
+@Suppress("MagicNumber")
fun BigDecimal.toFormattedCurrencyString(
- decimals: Int, currency: String, roundingMode: RoundingMode = RoundingMode.DOWN,
- limitNumberOfDecimals: Boolean = true
+ decimals: Int,
+ currency: String,
+ roundingMode: RoundingMode = RoundingMode.DOWN,
+ limitNumberOfDecimals: Boolean = true,
): String {
val decimalsForRounding = if (limitNumberOfDecimals) {
if (decimals > 8) 8 else decimals
@@ -34,13 +40,14 @@ fun BigDecimal.toFormattedCurrencyString(
decimals
}
val formattedAmount = this.toFormattedString(
- decimals = decimalsForRounding, roundingMode = roundingMode
+ decimals = decimalsForRounding,
+ roundingMode = roundingMode,
)
return "$formattedAmount $currency"
}
fun BigDecimal.toFiatRateString(
- fiatCurrencyName: String
+ fiatCurrencyName: String,
): String {
val value = this
.setScale(2, RoundingMode.HALF_UP)
@@ -51,7 +58,7 @@ fun BigDecimal.toFiatRateString(
fun BigDecimal.toFiatString(
rateValue: BigDecimal,
fiatCurrencyName: String,
- formatWithSpaces: Boolean = false
+ formatWithSpaces: Boolean = false,
): String {
val fiatValue = rateValue.multiply(this)
return fiatValue.toFormattedFiatValue(fiatCurrencyName, formatWithSpaces)
@@ -64,7 +71,7 @@ fun BigDecimal.toFiatValue(rateValue: BigDecimal): BigDecimal {
fun BigDecimal.toFormattedFiatValue(
fiatCurrencyName: String,
- formatWithSpaces: Boolean = false
+ formatWithSpaces: Boolean = false,
): String {
val fiatValue = this.setScale(2, RoundingMode.HALF_UP)
.let { if (formatWithSpaces) it.formatWithSpaces() else it }
@@ -81,9 +88,7 @@ fun BigDecimal.scaleToFiat(applyPrecision: Boolean = false): BigDecimal {
if (this.isZero()) return this
val scaledFiat = this.setScale(2, RoundingMode.DOWN)
- return if (scaledFiat.isZero() && applyPrecision) this.setPrecision(1)
- else scaledFiat
-
+ return if (scaledFiat.isZero() && applyPrecision) this.setPrecision(1) else scaledFiat
}
fun BigDecimal.setPrecision(precision: Int, roundingMode: RoundingMode = RoundingMode.DOWN): BigDecimal {
@@ -108,7 +113,7 @@ fun BigDecimal.isLessThanOrEqual(value: BigDecimal): Boolean {
fun BigDecimal.formatAmountAsSpannedString(
currencySymbol: String,
- reminderPartSizeProportion: Float = 0.7f
+ reminderPartSizeProportion: Float = 0.7f,
): SpannedString {
val amount = this
.setScale(2, RoundingMode.HALF_UP)
@@ -124,11 +129,12 @@ fun BigDecimal.formatAmountAsSpannedString(
append(
"$reminder $currencySymbol",
RelativeSizeSpan(reminderPartSizeProportion),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
)
}
}
+@Suppress("MagicNumber")
fun BigDecimal.formatWithSpaces(): String {
val str = this.toString()
var integerStr = str.substringBefore('.')
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/String.kt b/app/src/main/java/com/tangem/tap/common/extensions/String.kt
index 021cc3a7f2..3c4125d422 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/String.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/String.kt
@@ -29,7 +29,7 @@ fun String.colorSegment(
context: Context,
color: Int,
startIndex: Int = 0,
- endIndex: Int = this.length
+ endIndex: Int = this.length,
): Spannable {
return this.toSpannable()
.also { spannable ->
@@ -37,11 +37,12 @@ fun String.colorSegment(
ForegroundColorSpan(ContextCompat.getColor(context, color)),
startIndex,
endIndex,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
)
}
}
+@Suppress("MagicNumber")
fun String.toQrCode(): Bitmap {
val hintMap = Hashtable()
hintMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M // H = 30% damage
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt b/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt
index 48ee67afc7..aef0701282 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/TextView.kt
@@ -18,13 +18,12 @@ fun EditText.update(text: String?) {
val textLength = text?.length ?: 0
- //prevent cursor jumping while editing a text
+ // prevent cursor jumping while editing a text
val cursorPosition = if (selectionEnd > textLength) textLength else selectionEnd
this.setText(text)
if (!isFocused || textLength == 0) return
- if (cursorPosition == 0) setSelection(textLength)
- else setSelection(cursorPosition)
+ if (cursorPosition == 0) setSelection(textLength) else setSelection(cursorPosition)
}
fun EditText.setOnImeActionListener(action: Int, handler: (EditText) -> Unit) {
@@ -56,13 +55,4 @@ fun TextInputLayout.enableError(enable: Boolean, errorMessage: String? = null) {
error = null
isErrorEnabled = false
}
-}
-
-fun TextView.isEllipsized(): Boolean {
- val layout = this.layout
- if (layout != null) {
- val lines: Int = layout.lineCount
- return (lines > 0) && (layout.getEllipsisCount(lines - 1) > 0)
- }
- return false
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Token.kt b/app/src/main/java/com/tangem/tap/common/extensions/Token.kt
index 59c918d736..7acbdfd9fb 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/Token.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/Token.kt
@@ -6,19 +6,23 @@ import androidx.core.graphics.luminance
import androidx.core.graphics.toColorInt
import com.tangem.blockchain.common.Token
+@Suppress("MagicNumber")
@ColorInt
fun Token.getColor(isTestnet: Boolean = false): Int {
val defaultColor = "#C7C7CC".toColorInt() // equivalent to R.color.lightGray4
- return if (isTestnet)
- defaultColor
- else try {
- ("#" + this.contractAddress.subSequence(2..7).toString()).toColorInt()
- } catch (exception: Exception) {
+ return if (isTestnet) {
defaultColor
+ } else {
+ try {
+ ("#" + this.contractAddress.subSequence(2..7).toString()).toColorInt()
+ } catch (exception: Exception) {
+ defaultColor
+ }
}
}
+@Suppress("MagicNumber")
@ColorInt
fun Token.getTextColor(isTestnet: Boolean = false): Int = when {
isTestnet -> Color.WHITE
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt
index 885fd337e3..9a1dceb21f 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt
@@ -1,16 +1,14 @@
+@file:Suppress("TooManyFunctions")
+
package com.tangem.tap.common.extensions
import android.app.Activity
-import android.content.ActivityNotFoundException
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
-import android.content.res.Resources
import android.graphics.drawable.Drawable
-import android.os.Build
-import android.os.Bundle
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.View
@@ -25,11 +23,6 @@ import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import com.google.android.material.card.MaterialCardView
-import com.tangem.common.extensions.VoidCallback
-
-fun Fragment.getDrawable(@DrawableRes drawableResId: Int): Drawable? {
- return ContextCompat.getDrawable(requireContext(), drawableResId)
-}
fun Context.getDrawableCompat(@DrawableRes drawableResId: Int): Drawable? {
return ContextCompat.getDrawable(this, drawableResId)
@@ -62,17 +55,8 @@ fun View.getQuantityString(@PluralsRes id: Int, quantity: Int): String {
return context.resources.getQuantityString(id, quantity, quantity)
}
-fun View.getResourceName(): String {
- return try {
- resources.getResourceEntryName(id)
- } catch (ex: Resources.NotFoundException) {
- "Not found"
- }
-}
-
fun View.show(show: Boolean, invokeBeforeStateChanged: (() -> Unit)? = null) {
- return if (show) this.show(invokeBeforeStateChanged)
- else this.hide(invokeBeforeStateChanged)
+ return if (show) this.show(invokeBeforeStateChanged) else this.hide(invokeBeforeStateChanged)
}
fun View.show(invokeBeforeStateChanged: (() -> Unit)? = null) {
@@ -102,7 +86,9 @@ fun View.invisible(invisible: Boolean = true, invokeBeforeStateChanged: (() -> U
fun Context.dpToPixels(dp: Int): Int =
TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), this.resources.displayMetrics,
+ TypedValue.COMPLEX_UNIT_DIP,
+ dp.toFloat(),
+ this.resources.displayMetrics,
).toInt()
fun Context.pixelsToDp(pixels: Int): Int {
@@ -111,12 +97,6 @@ fun Context.pixelsToDp(pixels: Int): Int {
.toInt()
}
-fun Context.dpToPixels(dp: Float): Float =
- TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, this.resources.displayMetrics)
-
-fun Context.pixelsToDp(pixels: Float): Float =
- (pixels / (resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT))
-
tailrec fun Context?.getActivity(): Activity? = this as? Activity
?: (this as? ContextWrapper)?.baseContext?.getActivity()
@@ -136,19 +116,6 @@ fun MaterialCardView.setMargins(
this.layoutParams = params
}
-fun Activity.setSystemBarTextColor(setTextDark: Boolean) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- val flags = this.window.decorView.systemUiVisibility
- // Update the SystemUiVisibility dependening on whether we want a Light or Dark theme.
- this.window.decorView.systemUiVisibility =
- if (setTextDark) {
- flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
- } else {
- flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
- }
- }
-}
-
fun View.hideKeyboard() {
val inputMethodManager =
context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager
@@ -185,21 +152,6 @@ fun Fragment.shareText(text: String) {
requireContext().shareText(text)
}
-fun Context.safeStartActivity(
- intent: Intent,
- options: Bundle? = null,
- fallback: ((ActivityNotFoundException) -> Unit)? = null,
- finally: VoidCallback? = null,
-) {
- try {
- this.startActivity(intent, options)
- } catch (ex: ActivityNotFoundException) {
- fallback?.invoke(ex)
- } finally {
- finally?.invoke()
- }
-}
-
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
return context.getString(resId, *formatArgs)
}
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Any.kt b/app/src/main/java/com/tangem/tap/common/extensions/ValueCallback.kt
similarity index 100%
rename from app/src/main/java/com/tangem/tap/common/extensions/Any.kt
rename to app/src/main/java/com/tangem/tap/common/extensions/ValueCallback.kt
diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt
index cda489f536..97997ba97f 100644
--- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt
@@ -21,6 +21,7 @@ import timber.log.Timber
/**
[REDACTED_AUTHOR]
*/
+@Suppress("MagicNumber")
suspend fun WalletManager.safeUpdate(): Result = try {
val scanResponse = store.state.globalState.scanResponse
@@ -72,8 +73,7 @@ fun WalletManager?.getAddressData(): AddressData? {
val wallet = this?.wallet ?: return null
val addressDataList = wallet.createAddressesData()
- return if (addressDataList.isEmpty()) null
- else addressDataList[0]
+ return if (addressDataList.isEmpty()) null else addressDataList[0]
}
fun WalletManager.Companion.stub(): T {
diff --git a/app/src/main/java/com/tangem/tap/common/feature/Feature.kt b/app/src/main/java/com/tangem/tap/common/feature/Feature.kt
index ce1313c772..1eb07546b4 100644
--- a/app/src/main/java/com/tangem/tap/common/feature/Feature.kt
+++ b/app/src/main/java/com/tangem/tap/common/feature/Feature.kt
@@ -4,5 +4,5 @@ package com.tangem.tap.common.feature
[REDACTED_AUTHOR]
*/
interface Feature {
- fun featureIsSwitchedOn():Boolean
+ fun featureIsSwitchedOn(): Boolean
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt
index 589597238f..c6f5bafd0a 100644
--- a/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt
+++ b/app/src/main/java/com/tangem/tap/common/feedback/AdditionalFeedbackInfo.kt
@@ -48,6 +48,9 @@ class AdditionalFeedbackInfo {
var fee: String = ""
var token: String = ""
+ private val Address.name: String
+ get() = type.javaClass.simpleName
+
fun setCardInfo(data: ScanResponse) {
cardId = data.card.cardId
cardBlockchain = data.walletData?.blockchain ?: ""
@@ -108,6 +111,7 @@ class AdditionalFeedbackInfo {
}
}
+ @Suppress("MagicNumber")
private fun Wallet.formatAddressWith(with: String, mapAddress: (Address) -> String): String {
return if (addresses.size == 1) {
getExploreUrl(address)
@@ -117,7 +121,4 @@ class AdditionalFeedbackInfo {
.joinToString("\n")
}
}
-
- private val Address.name: String
- get() = type.javaClass.simpleName
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt
index 8a426cccfc..452eb173aa 100644
--- a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt
+++ b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackData.kt
@@ -15,6 +15,7 @@ interface FeedbackData {
fun createOptionalMessage(infoHolder: AdditionalFeedbackInfo): String
+ @Suppress("MagicNumber")
fun joinTogether(context: Context, infoHolder: AdditionalFeedbackInfo): String {
return StringBuilder().apply {
append(context.getString(mainMessageResId))
@@ -42,6 +43,7 @@ class ScanFailsEmail : FeedbackData {
override val subjectResId: Int = R.string.feedback_subject_scan_failed
override val mainMessageResId: Int = R.string.feedback_preface_scan_failed
+ @Suppress("MagicNumber")
override fun joinTogether(context: Context, infoHolder: AdditionalFeedbackInfo): String = StringBuilder().apply {
append(context.getString(mainMessageResId))
breakLine(4)
diff --git a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt
index b44db4004b..c6513c9188 100644
--- a/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt
+++ b/app/src/main/java/com/tangem/tap/common/feedback/FeedbackManager.kt
@@ -6,7 +6,7 @@ import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds
import com.tangem.tap.common.extensions.sendEmail
import com.tangem.tap.common.log.TangemLogCollector
-import com.tangem.tap.common.zendesk.ZendeskConfig
+import com.tangem.datasource.config.models.ZendeskConfig
import com.tangem.tap.foregroundActivityObserver
import com.tangem.tap.persistence.PreferencesStorage
import com.tangem.tap.withForegroundActivity
diff --git a/app/src/main/java/com/tangem/tap/common/images/Coil.kt b/app/src/main/java/com/tangem/tap/common/images/Coil.kt
index 5224c40df0..4e5a88d6e0 100644
--- a/app/src/main/java/com/tangem/tap/common/images/Coil.kt
+++ b/app/src/main/java/com/tangem/tap/common/images/Coil.kt
@@ -30,13 +30,11 @@ fun createCoilImageLoader(
}
)
.build()
-
}
}
.build()
}
-
private class CoilTimberLogger : Logger {
override var level: Int = Log.DEBUG
diff --git a/app/src/main/java/com/tangem/tap/common/leapfrogWidget/TestLeapfrogFragment.kt b/app/src/main/java/com/tangem/tap/common/leapfrogWidget/TestLeapfrogFragment.kt
index 1999c35855..98a06327bb 100644
--- a/app/src/main/java/com/tangem/tap/common/leapfrogWidget/TestLeapfrogFragment.kt
+++ b/app/src/main/java/com/tangem/tap/common/leapfrogWidget/TestLeapfrogFragment.kt
@@ -17,13 +17,13 @@ class TestLeapfrogFragment : Fragment(R.layout.test_leapfrog_fragment) {
private lateinit var twinsCardWidget: TwinsCardWidget
private val binding: TestLeapfrogFragmentBinding by viewBinding(TestLeapfrogFragmentBinding::bind)
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = TransitionInflater.from(requireContext())
exitTransition = inflater.inflateTransition(R.transition.fade)
}
+ @Suppress("MagicNumber")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
diff --git a/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt b/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt
index da69eed9ae..4a86caa20d 100644
--- a/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt
+++ b/app/src/main/java/com/tangem/tap/common/qrCodeScan/ScanQrCodeActivity.kt
@@ -16,11 +16,6 @@ import me.dm7.barcodescanner.zxing.ZXingScannerView
[REDACTED_AUTHOR]
*/
class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
- companion object {
- val SCAN_QR_REQUEST_CODE = 1001
- val SCAN_RESULT = "scanResult"
- }
-
private lateinit var mScannerView: ZXingScannerView
override fun onCreate(state: Bundle?) {
@@ -29,7 +24,6 @@ class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
setContentView(mScannerView)
if (!permissionIsGranted()) requestPermission()
-
}
override fun onResume() {
@@ -66,4 +60,9 @@ class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
private fun requestPermission() {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), PERMISSION_REQUEST_CODE)
}
+
+ companion object {
+ const val SCAN_QR_REQUEST_CODE = 1001
+ const val SCAN_RESULT = "scanResult"
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt
index 9f7c34b90f..820f5b3d3f 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/AppState.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/AppState.kt
@@ -39,6 +39,7 @@ import com.tangem.tap.features.walletSelector.redux.WalletSelectorMiddleware
import com.tangem.tap.features.walletSelector.redux.WalletSelectorState
import com.tangem.tap.features.welcome.redux.WelcomeMiddleware
import com.tangem.tap.features.welcome.redux.WelcomeState
+import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import org.rekotlin.Middleware
import org.rekotlin.StateType
@@ -68,6 +69,12 @@ data class AppState(
val domainNetworks: NetworkServices
get() = domainState.globalState.networkServices
+ val featureRepositoryProvider: FeatureRepositoryProvider
+ get() = FeatureRepositoryProvider(
+ tangemTechApi = domainNetworks.tangemTechService.api,
+ dispatchers = AppCoroutineDispatcherProvider(),
+ )
+
companion object {
fun getMiddleware(): List> {
return listOf(
diff --git a/app/src/main/java/com/tangem/tap/common/redux/FeatureRepositoryProvider.kt b/app/src/main/java/com/tangem/tap/common/redux/FeatureRepositoryProvider.kt
new file mode 100644
index 0000000000..5794edffb9
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/common/redux/FeatureRepositoryProvider.kt
@@ -0,0 +1,15 @@
+package com.tangem.tap.common.redux
+
+import com.tangem.datasource.api.tangemTech.TangemTechApi
+import com.tangem.tap.features.home.data.HomeRepositoryImpl
+import com.tangem.tap.features.home.domain.HomeRepository
+import com.tangem.tap.features.wallet.data.WalletRepositoryImpl
+import com.tangem.tap.features.wallet.domain.WalletRepository
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+
+class FeatureRepositoryProvider(tangemTechApi: TangemTechApi, dispatchers: CoroutineDispatcherProvider) {
+
+ val walletRepository: WalletRepository = WalletRepositoryImpl(tangemTechApi, dispatchers)
+
+ val homeRepository: HomeRepository = HomeRepositoryImpl(tangemTechApi, dispatchers)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt
index a32545d675..4a7cb7b8f8 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/NotificationsMiddleware.kt
@@ -88,6 +88,7 @@ val notificationsMiddleware: Middleware = { dispatch, state ->
}
}
+@Suppress("ComplexMethod")
private fun handleNotificationAction(action: Action) {
if (action is Debug && !BuildConfig.DEBUG) return
diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt
index 1f51374cae..4017f9b32f 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt
@@ -13,9 +13,9 @@ import com.tangem.tap.common.redux.ErrorAction
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.common.redux.ToastNotificationAction
-import com.tangem.tap.common.zendesk.ZendeskConfig
+import com.tangem.datasource.config.models.ZendeskConfig
import com.tangem.tap.domain.TapError
-import com.tangem.tap.domain.configurable.config.ConfigManager
+import com.tangem.datasource.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.details.redux.SecurityOption
@@ -47,7 +47,7 @@ sealed class GlobalAction : Action {
* For SaltPay cards unfinished backup resumed after scanning the card on HomeScreen through Onboarding.Start.
* See more Onboarding.Start, CheckForUnfinishedBackup
*/
- object StartForUnfinishedBackup : Onboarding()
+ data class StartForUnfinishedBackup(val addedBackupCardsCount: Int) : Onboarding()
object Stop : Onboarding()
}
diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt
similarity index 92%
rename from app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt
rename to app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt
index dfcdf942bf..b880c71872 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt
@@ -4,7 +4,6 @@ import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.ifNotNull
-import com.tangem.common.services.Result
import com.tangem.domain.common.LogConfig
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
@@ -31,10 +30,8 @@ import org.rekotlin.DispatchFunction
import org.rekotlin.Middleware
import java.util.*
-class GlobalMiddleware {
- companion object {
- val handler = globalMiddlewareHandler
- }
+object GlobalMiddleware {
+ val handler = globalMiddlewareHandler
}
private val globalMiddlewareHandler: Middleware = { dispatch, appState ->
@@ -46,6 +43,7 @@ private val globalMiddlewareHandler: Middleware = { dispatch, appState
}
}
+@Suppress("LongMethod", "ComplexMethod")
private fun handleAction(action: Action, appState: () -> AppState?, dispatch: DispatchFunction) {
when (action) {
is GlobalAction.ScanFailsCounter.ChooseBehavior -> {
@@ -74,7 +72,7 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
store.state.globalState.warningManager?.let {
if (it.hideWarning(action.warning)) {
if (WarningMessagesManager.isAlreadySignedHashesWarning(action.warning)) {
- //TODO: No appropriate warningMessage identification. Make it better later
+ // TODO: No appropriate warningMessage identification. Make it better later
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
}
@@ -101,7 +99,7 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
// if config not set -> try to get it based on a scanResponse.productType
val unsafeZendeskConfig = action.zendeskConfig ?: when {
- scanResponse?.isSaltPay() == true -> config.saltPayConfig?.zendesk
+ scanResponse?.cardTypesResolver?.isSaltPay() == true -> config.saltPayConfig?.zendesk
else -> config.zendesk
}
@@ -187,23 +185,20 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
}
is GlobalAction.FetchUserCountry -> {
scope.launch {
- val techService = store.state.domainNetworks.tangemTechService
- when (val result = techService.userCountry()) {
- is Result.Success -> {
+ // TODO("After adding DI") get dependencies by DI
+ runCatching { store.state.featureRepositoryProvider.homeRepository.getUserCountryCode() }
+ .onSuccess {
store.dispatchOnMain(
- GlobalAction.FetchUserCountry.Success(
- countryCode = result.data.code.lowercase(),
- ),
+ GlobalAction.FetchUserCountry.Success(countryCode = it.code.lowercase()),
)
}
- is Result.Failure -> {
+ .onFailure {
store.dispatchOnMain(
GlobalAction.FetchUserCountry.Success(
countryCode = Locale.getDefault().country.lowercase(),
),
)
}
- }
}
}
}
diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt
index 543e734f8f..7934a195f6 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt
@@ -9,8 +9,8 @@ import com.tangem.tap.preferencesStorage
import com.tangem.tap.proxy.AppStateHolder
import org.rekotlin.Action
+@Suppress("LongMethod", "ComplexMethod")
fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolder): GlobalState {
-
if (action !is GlobalAction) return state.globalState
val globalState = state.globalState
@@ -39,6 +39,7 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde
globalState.copy(scanResponse = action.scanResponse)
}
is GlobalAction.ChangeAppCurrency -> {
+ appStateHolder.appFiatCurrency = action.appCurrency
globalState.copy(appCurrency = action.appCurrency)
}
is GlobalAction.RestoreAppCurrency.Success -> {
diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt
index b897f1b5dc..845715809d 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt
@@ -6,7 +6,7 @@ import com.tangem.tap.common.feedback.FeedbackManager
import com.tangem.tap.common.redux.StateDialog
import com.tangem.tap.domain.PayIdManager
import com.tangem.tap.domain.TapWalletManager
-import com.tangem.tap.domain.configurable.config.ConfigManager
+import com.tangem.datasource.config.ConfigManager
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.features.onboarding.OnboardingManager
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt
index 69547d020f..ab7aa07259 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/FragmentShareTransition.kt
@@ -10,7 +10,7 @@ import java.lang.ref.WeakReference
data class FragmentShareTransition(
val shareElements: List,
val enterTransitionSet: TransitionSet,
- val exitTransitionSet: TransitionSet
+ val exitTransitionSet: TransitionSet,
)
/**
@@ -24,12 +24,12 @@ class ShareElement(view: View, name: String? = null) {
init {
name?.let { view.transitionName = it }
elementName = view.transitionName
- ?: throw UnsupportedOperationException("ShareElement require the name")
+ ?: throw UnsupportedOperationException("ShareElement require the name")
wView = WeakReference(view)
}
companion object {
- val imvFrontCard = "imv_front_card"
- val imvBackCard = "imv_back_card"
+ const val imvFrontCard = "imv_front_card"
+ const val imvBackCard = "imv_back_card"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt
index 3e4f3a9702..71f3274e4c 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationAction.kt
@@ -1,6 +1,7 @@
package com.tangem.tap.common.redux.navigation
import android.net.Uri
+import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.rekotlin.Action
import java.lang.ref.WeakReference
@@ -10,6 +11,7 @@ sealed class NavigationAction : Action {
val screen: AppScreen,
val fragmentShareTransition: FragmentShareTransition? = null,
val addToBackstack: Boolean = true,
+ val bundle: Bundle? = null,
) : NavigationAction()
data class PopBackTo(
diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt
index 28357c1efd..bf5df6a9a9 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationMiddleware.kt
@@ -25,6 +25,7 @@ val navigationMiddleware: Middleware = { _, state ->
screen = action.screen,
addToBackstack = action.addToBackstack,
fgShareTransition = action.fragmentShareTransition,
+ bundle = action.bundle,
)
}
is NavigationAction.PopBackTo -> {
@@ -33,8 +34,13 @@ val navigationMiddleware: Middleware = { _, state ->
AppScreen.Home,
AppScreen.Welcome,
-> {
- navState?.activity?.get()?.popBackTo(screen, inclusive = true)
- store.dispatchOnMain(NavigationAction.NavigateTo(screen))
+ if (navState?.backStack?.contains(screen) == false) {
+ // Pop back to activity
+ navState.activity?.get()?.popBackTo(screen = null, inclusive = true)
+ store.dispatchOnMain(NavigationAction.NavigateTo(screen))
+ } else {
+ navState?.activity?.get()?.popBackTo(screen, action.inclusive)
+ }
}
else -> {
navState?.activity?.get()?.popBackTo(screen, action.inclusive)
diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt
index b6f7522586..7febcfa59c 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationReducer.kt
@@ -4,14 +4,11 @@ import com.tangem.tap.common.extensions.getPreviousScreen
import com.tangem.tap.common.redux.AppState
import org.rekotlin.Action
-class NavigationReducer {
- companion object {
- fun reduce(action: Action, state: AppState): NavigationState = internalReduce(action, state)
- }
+object NavigationReducer {
+ fun reduce(action: Action, state: AppState): NavigationState = internalReduce(action, state)
}
private fun internalReduce(action: Action, state: AppState): NavigationState {
-
val navigationAction = action as? NavigationAction ?: return state.navigationState
val navState = state.navigationState
diff --git a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt
index cf60dc79f6..0b40b7bd8e 100644
--- a/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt
+++ b/app/src/main/java/com/tangem/tap/common/redux/navigation/NavigationState.kt
@@ -23,6 +23,7 @@ enum class AppScreen(
WalletConnectSessions,
QrScan,
ReferralProgram,
+ Swap,
Welcome,
SaveWallet(isDialogFragment = true),
WalletSelector(isDialogFragment = true),
diff --git a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt
index 95b6a0e7db..9685dd54b7 100644
--- a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt
+++ b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt
@@ -10,8 +10,9 @@ import com.tangem.tap.common.extensions.filterNotNull
import com.tangem.tap.common.shop.data.ProductType
import com.tangem.tap.common.shop.data.TangemProduct
import com.tangem.tap.common.shop.data.TotalSum
+import com.tangem.tap.common.shop.googlepay.GooglePayService
import com.tangem.tap.common.shop.shopify.ShopifyService
-import com.tangem.tap.common.shop.shopify.ShopifyShop
+import com.tangem.datasource.config.models.ShopifyShop
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@@ -87,7 +88,8 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
fun buyWithGooglePay(productType: ProductType) {
val totalPrice = checkouts[productType]!!.totalPriceV2.amount
googlePayService.payWithGooglePay(
- totalPriceCents = totalPrice, currencyCode = checkouts[productType]!!.currencyCode.name,
+ totalPriceCents = totalPrice,
+ currencyCode = checkouts[productType]!!.currencyCode.name,
merchantID = shopifyService.shop.merchantID,
)
}
@@ -188,7 +190,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
appliedDiscount = it.getAppliedDiscount(),
),
- )
+ )
}
return Result.failure(result.exceptionOrNull()!!)
}
diff --git a/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayService.kt b/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayService.kt
index 13c3913ebe..757b207741 100644
--- a/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayService.kt
+++ b/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayService.kt
@@ -1,4 +1,4 @@
-package com.tangem.tap.common.shop
+package com.tangem.tap.common.shop.googlepay
import android.app.Activity
import android.app.Activity.RESULT_CANCELED
@@ -6,9 +6,12 @@ import android.app.Activity.RESULT_OK
import android.content.Intent
import android.util.Log
import com.google.android.gms.common.api.ApiException
-import com.google.android.gms.wallet.*
+import com.google.android.gms.wallet.AutoResolveHelper
+import com.google.android.gms.wallet.IsReadyToPayRequest
+import com.google.android.gms.wallet.PaymentData
+import com.google.android.gms.wallet.PaymentDataRequest
+import com.google.android.gms.wallet.PaymentsClient
import com.tangem.common.core.TangemSdkError
-import com.tangem.tap.common.shop.googlepay.GooglePayUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.json.JSONException
@@ -22,7 +25,6 @@ class GooglePayService(private val paymentsClient: PaymentsClient, private val a
// var responseCallback: ((Result) -> Unit)? = null
suspend fun checkIfGooglePayAvailable(): Result {
-
val isReadyToPayJson = GooglePayUtil.isReadyToPayRequest() ?: return Result.success(false)
val request = IsReadyToPayRequest.fromJson(isReadyToPayJson.toString())
@@ -48,7 +50,7 @@ class GooglePayService(private val paymentsClient: PaymentsClient, private val a
totalPriceCents,
currencyCode = currencyCode,
countryCode = "RU",
- merchantID = merchantID
+ merchantID = merchantID,
)
if (paymentDataRequestJson == null) {
Timber.e("RequestPayment: can't fetch payment data request")
@@ -57,7 +59,9 @@ class GooglePayService(private val paymentsClient: PaymentsClient, private val a
val request = PaymentDataRequest.fromJson(paymentDataRequestJson.toString())
AutoResolveHelper.resolveTask(
- paymentsClient.loadPaymentData(request), activity, LOAD_PAYMENT_DATA_REQUEST_CODE
+ paymentsClient.loadPaymentData(request),
+ activity,
+ LOAD_PAYMENT_DATA_REQUEST_CODE,
)
}
@@ -81,7 +85,6 @@ class GooglePayService(private val paymentsClient: PaymentsClient, private val a
} else {
Result.failure(Exception("$statusCode"))
}
-
}
else -> Result.failure(Exception("Unknown Status"))
}
@@ -117,7 +120,6 @@ class GooglePayService(private val paymentsClient: PaymentsClient, private val a
.getString("token")
return GooglePayResponse(address, token)
-
} catch (e: JSONException) {
Log.e("handlePaymentSuccess", "Error: " + e.toString())
}
@@ -144,5 +146,5 @@ data class Address(
val address3: String,
val locality: String,
val administrativeArea: String,
- val sortingCode: String
+ val sortingCode: String,
)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt b/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt
index 610ab10c9d..82509e1180 100644
--- a/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt
+++ b/app/src/main/java/com/tangem/tap/common/shop/googlepay/GooglePayUtil.kt
@@ -14,20 +14,7 @@ object GooglePayUtil {
put("apiVersionMinor", 0)
}
- private fun gatewayTokenizationSpecification(merchantID: String): JSONObject {
- return JSONObject().apply {
- put("type", "PAYMENT_GATEWAY")
- put(
- "parameters", JSONObject(
- mapOf(
- "gateway" to "shopify",
- "gatewayMerchantId" to merchantID
- )
- )
- )
- }
- }
-
+ @Suppress("MagicNumber")
private val allowedCardNetworks = JSONArray(
listOf(
"AMEX",
@@ -35,27 +22,46 @@ object GooglePayUtil {
"INTERAC",
"JCB",
"MASTERCARD",
- "VISA"
- )
+ "VISA",
+ ),
)
private val allowedCardAuthMethods = JSONArray(
listOf(
"PAN_ONLY",
- "CRYPTOGRAM_3DS"
- )
+ "CRYPTOGRAM_3DS",
+ ),
)
+ private val merchantInfo: JSONObject = JSONObject().put("merchantName", "Example Merchant")
+
+ private fun gatewayTokenizationSpecification(merchantID: String): JSONObject {
+ return JSONObject().apply {
+ put("type", "PAYMENT_GATEWAY")
+ put(
+ "parameters",
+ JSONObject(
+ mapOf(
+ "gateway" to "shopify",
+ "gatewayMerchantId" to merchantID,
+ ),
+ ),
+ )
+ }
+ }
+
private fun baseCardPaymentMethod(): JSONObject {
return JSONObject().apply {
-
val parameters = JSONObject().apply {
put("allowedAuthMethods", allowedCardAuthMethods)
put("allowedCardNetworks", allowedCardNetworks)
put("billingAddressRequired", true)
- put("billingAddressParameters", JSONObject().apply {
- put("format", "FULL")
- })
+ put(
+ "billingAddressParameters",
+ JSONObject().apply {
+ put("format", "FULL")
+ },
+ )
}
put("type", "CARD")
@@ -83,7 +89,6 @@ object GooglePayUtil {
baseRequest.apply {
put("allowedPaymentMethods", JSONArray().put(baseCardPaymentMethod()))
}
-
} catch (e: JSONException) {
null
}
@@ -92,7 +97,7 @@ object GooglePayUtil {
private fun getTransactionInfo(
price: String,
countryCode: String,
- currencyCode: String
+ currencyCode: String,
): JSONObject {
return JSONObject().apply {
put("totalPrice", price)
@@ -102,15 +107,11 @@ object GooglePayUtil {
}
}
- private val merchantInfo: JSONObject =
- JSONObject().put("merchantName", "Example Merchant")
-
-
fun getPaymentDataRequest(
price: String,
countryCode: String,
currencyCode: String,
- merchantID: String
+ merchantID: String,
): JSONObject? {
try {
return baseRequest.apply {
@@ -133,5 +134,4 @@ object GooglePayUtil {
}
}
-
const val PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_TEST
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt b/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt
index a33fb82b84..71081fc7b1 100644
--- a/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt
+++ b/app/src/main/java/com/tangem/tap/common/shop/shopify/ShopifyService.kt
@@ -7,6 +7,7 @@ import com.shopify.buy3.RetryHandler
import com.shopify.buy3.Storefront.*
import com.shopify.graphql.support.ID
import com.shopify.graphql.support.Input
+import com.tangem.datasource.config.models.ShopifyShop
import com.tangem.tap.common.shop.shopify.data.CheckoutItem
import com.tangem.tap.common.shop.shopify.data.checkoutFieldsFragment
import com.tangem.tap.common.shop.shopify.data.collectionFieldsFragment
@@ -16,11 +17,10 @@ import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
-
+@Suppress("LargeClass")
class ShopifyService(private val application: Application, val shop: ShopifyShop) {
val client: GraphClient by lazy { initClient() }
-
suspend fun getShopName(): Result {
val query = query { rootQuery: QueryRootQuery ->
rootQuery
@@ -40,16 +40,15 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
}
}
+ @Suppress("MagicNumber")
suspend fun getProducts(collectionTitleFilter: String? = null): Result> {
val filter = collectionTitleFilter?.let { "title:\"$it\"" }
val query = query { rootQuery: QueryRootQuery ->
- rootQuery
- .collections(
- { arg -> arg.first(250).query(filter) },
- ) { collectionConnectionQuery ->
- collectionConnectionQuery.collectionFieldsFragment()
- }
+ rootQuery.collections(
+ { arg -> arg.first(250).query(filter) },
+ CollectionConnectionQuery::collectionFieldsFragment,
+ )
}
return when (val result = queryAsync(query)) {
is GraphCallResult.Success -> {
@@ -66,7 +65,6 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
}
suspend fun checkout(pollUntilOrder: Boolean, checkoutID: ID): Result {
-
val query = query { rootQuery: QueryRootQuery ->
rootQuery
.node(checkoutID) { query ->
@@ -78,7 +76,8 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
}
}
val retryHandler = RetryHandler.build(
- 1, TimeUnit.SECONDS
+ delay = 1,
+ timeUnit = TimeUnit.SECONDS,
) {
this.retryWhen { result ->
when (result) {
@@ -100,7 +99,6 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
} else {
Result.failure(ShopifyError.Unknown)
}
-
}
is GraphCallResult.Failure -> {
Result.failure(result.error)
@@ -110,10 +108,8 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
suspend fun createCheckout(
checkoutItems: List,
- checkoutID: ID? = null
+ checkoutID: ID? = null,
): Result {
-
-
val storefrontLineItems: MutableList = checkoutItems
.map { CheckoutLineItemInput(it.quantity, it.id) }.toMutableList()
@@ -121,13 +117,14 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
mutation { mutationQuery: MutationQuery ->
mutationQuery
.checkoutLineItemsReplace(
- storefrontLineItems, checkoutID
+ storefrontLineItems,
+ checkoutID,
) { payloadQuery: CheckoutLineItemsReplacePayloadQuery ->
payloadQuery
.checkout { checkoutQuery: CheckoutQuery ->
checkoutQuery.checkoutFieldsFragment()
}
- .userErrors() { userErrorQuery: CheckoutUserErrorQuery ->
+ .userErrors { userErrorQuery: CheckoutUserErrorQuery ->
userErrorQuery
.field()
.message()
@@ -137,18 +134,18 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
} else {
val input = CheckoutCreateInput()
.setLineItemsInput(
- Input.value(storefrontLineItems)
+ Input.value(storefrontLineItems),
)
mutation { mutationQuery: MutationQuery ->
mutationQuery
.checkoutCreate(
- input
+ input,
) { payloadQuery: CheckoutCreatePayloadQuery ->
payloadQuery
.checkout { checkoutQuery: CheckoutQuery ->
checkoutQuery.checkoutFieldsFragment()
}
- .checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
+ .checkoutUserErrors { userErrorQuery: CheckoutUserErrorQuery ->
userErrorQuery
.field()
.message()
@@ -163,13 +160,14 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
val query = mutation { mutationQuery: MutationQuery ->
mutationQuery
.checkoutDiscountCodeApplyV2(
- discountCode, checkoutID
+ discountCode,
+ checkoutID,
) { payloadQuery: CheckoutDiscountCodeApplyV2PayloadQuery ->
payloadQuery
.checkout { checkoutQuery: CheckoutQuery ->
checkoutQuery.checkoutFieldsFragment()
}
- .checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
+ .checkoutUserErrors { userErrorQuery: CheckoutUserErrorQuery ->
userErrorQuery
.field()
.message()
@@ -183,44 +181,9 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
val query = mutation { mutationQuery: MutationQuery ->
mutationQuery
.checkoutDiscountCodeRemove(
- checkoutID
+ checkoutID,
) { payloadQuery: CheckoutDiscountCodeRemovePayloadQuery ->
payloadQuery
- .checkout { checkoutQuery: CheckoutQuery ->
- checkoutQuery.checkoutFieldsFragment()
- }
- .checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
- userErrorQuery
- .field()
- .message()
- }
- }
- }
- return runCheckoutMutation(query)
- }
-
- suspend fun updateAddress(
- address: MailingAddress,
- checkoutID: ID,
- waitForShippingRates: Boolean
- ): Result {
- val input = MailingAddressInput()
- .setAddress1(address.address1)
- .setAddress2(address.address2)
- .setCity(address.city)
- .setCountry(address.country)
- .setFirstName(address.firstName)
- .setLastName(address.lastName)
- .setPhone(address.phone)
- .setProvince(address.province)
- .setZip(address.zip)
-
- val query = mutation { mutationQuery: MutationQuery ->
- mutationQuery
- .checkoutShippingAddressUpdateV2(
- input, checkoutID
- ) { shippingAddressUpdatePayloadQuery: CheckoutShippingAddressUpdateV2PayloadQuery ->
- shippingAddressUpdatePayloadQuery
.checkout { checkoutQuery: CheckoutQuery ->
checkoutQuery.checkoutFieldsFragment()
}
@@ -231,59 +194,18 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
}
}
}
-
- return runCheckoutMutation(query)
- }
-
- suspend fun updateEmail(email: String?, checkoutID: ID): Result {
- val query = mutation { mutationQuery: MutationQuery ->
- mutationQuery
- .checkoutEmailUpdateV2(
- checkoutID, email
- ) { emailUpdatePayloadQuery: CheckoutEmailUpdateV2PayloadQuery ->
- emailUpdatePayloadQuery
- .checkout { checkoutQuery: CheckoutQuery ->
- checkoutQuery.checkoutFieldsFragment()
- }
- .checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
- userErrorQuery
- .field()
- .message()
- }
- }
- }
- return runCheckoutMutation(query)
- }
-
- suspend fun updateShippingRate(handle: String?, checkoutID: ID): Result {
- val query = mutation { mutationQuery: MutationQuery ->
- mutationQuery
- .checkoutShippingLineUpdate(
- checkoutID, handle
- ) { shippingLineUpdatePayloadQuery: CheckoutShippingLineUpdatePayloadQuery ->
- shippingLineUpdatePayloadQuery
- .checkout { checkoutQuery: CheckoutQuery ->
- checkoutQuery.checkoutFieldsFragment()
- }
- .checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
- userErrorQuery
- .field()
- .message()
- }
- }
- }
return runCheckoutMutation(query)
}
suspend fun completeWithTokenizedPayment(
payment: TokenizedPaymentInputV3,
- checkoutID: ID
+ checkoutID: ID,
): Result {
-
val query = mutation { mutationQuery: MutationQuery ->
mutationQuery
.checkoutCompleteWithTokenizedPaymentV3(
- checkoutID, payment
+ checkoutID,
+ payment,
) { payloadQuery: CheckoutCompleteWithTokenizedPaymentV3PayloadQuery ->
payloadQuery
.payment { paymentQuery: PaymentQuery ->
@@ -295,7 +217,7 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
checkoutQuery
.ready()
}
- .checkoutUserErrors() { userErrorQuery: CheckoutUserErrorQuery ->
+ .checkoutUserErrors { userErrorQuery: CheckoutUserErrorQuery ->
userErrorQuery
.field()
.message()
@@ -305,10 +227,6 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
return runCheckoutMutation(query)
}
- fun startGooglePaySession() {
-// PaySession()
- }
-
private suspend fun runCheckoutMutation(mutation: MutationQuery): Result {
return when (val result = mutationQueryAsync(mutation)) {
is GraphCallResult.Success -> {
@@ -322,13 +240,13 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
Result.success(checkout)
}
- is GraphCallResult.Failure -> Result.failure(result.error)
+ is GraphCallResult.Failure -> Result.failure(result.error)
}
}
private suspend fun queryAsync(
query: QueryRootQuery,
- retryHandler: RetryHandler
+ retryHandler: RetryHandler,
): GraphCallResult =
withContext(Dispatchers.IO) {
suspendCoroutine { continuation ->
@@ -358,12 +276,11 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
}
}
-
private fun initClient(): GraphClient {
return GraphClient.build(
application,
shop.domain,
- shop.storefrontApiKey
+ shop.storefrontApiKey,
) {
// httpCache(application.filesDir) {
// cacheMaxSizeBytes = (1024 * 1024 * 10)
@@ -371,13 +288,9 @@ class ShopifyService(private val application: Application, val shop: ShopifyShop
// HttpCachePolicy.Default.CACHE_FIRST.expireAfter(20, TimeUnit.MINUTES)
// }
}
-
}
}
-
sealed class ShopifyError : Throwable() {
object Unknown : ShopifyError()
- object GooglePayFailed : ShopifyError()
- class UserError(val errorMessage: String)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Checkout.kt b/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Checkout.kt
index 849c1f33c3..7565db2447 100644
--- a/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Checkout.kt
+++ b/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Checkout.kt
@@ -2,23 +2,24 @@ package com.tangem.tap.common.shop.shopify.data
import com.shopify.buy3.Storefront
+@Suppress("LongMethod", "MagicNumber")
fun Storefront.CheckoutQuery.checkoutFieldsFragment() {
- // id()
ready()
webUrl()
currencyCode()
lineItemsSubtotalPrice { it.amount() }
totalPriceV2 {
it.currencyCode()
- it.amount() }
+ it.amount()
+ }
lineItems({ arg -> arg.first(250) }) {
it.edges {
it.node {
// it.id()
it.title()
it.quantity()
- it.variant() {
- it.priceV2() { it.amount() }
+ it.variant {
+ it.priceV2 { it.amount() }
}
}
}
diff --git a/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Collection.kt b/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Collection.kt
index 572a7b68c7..1527fc9558 100644
--- a/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Collection.kt
+++ b/app/src/main/java/com/tangem/tap/common/shop/shopify/data/Collection.kt
@@ -2,13 +2,15 @@ package com.tangem.tap.common.shop.shopify.data
import com.shopify.buy3.Storefront
+@Suppress("MagicNumber")
fun Storefront.CollectionConnectionQuery.collectionFieldsFragment() {
edges { collectionEdgeQuery ->
collectionEdgeQuery
.node { collectionQuery ->
collectionQuery
.title()
- .products({ arg -> arg.first(250) }
+ .products(
+ { arg -> arg.first(250) },
) { productConnectionQuery ->
productConnectionQuery
.edges { productEdgeQuery ->
diff --git a/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt b/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt
index 69f2114528..d224143c98 100644
--- a/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt
+++ b/app/src/main/java/com/tangem/tap/common/snackBar/MaxAmountSnackbar.kt
@@ -17,15 +17,15 @@ import com.tangem.wallet.R
[REDACTED_AUTHOR]
*/
class MaxAmountSnackbar(
- parent: ViewGroup,
- content: MaxAmountSnackbarView
+ parent: ViewGroup,
+ content: MaxAmountSnackbarView
) : BaseTransientBottomBar(parent, content, content) {
companion object {
fun make(view: View, onClick: () -> Unit): MaxAmountSnackbar {
val parent = view.findSuitableParent() ?: throw IllegalArgumentException(
- "No suitable parent found from the given view. Please provide a valid view."
+ "No suitable parent found from the given view. Please provide a valid view."
)
val inflater = LayoutInflater.from(view.context)
val customView = inflater.inflate(R.layout.view_snackbar_max_amount, parent, false) as MaxAmountSnackbarView
@@ -57,14 +57,13 @@ class MaxAmountSnackbar(
} while (view != null)
return fallback
}
-
}
}
class MaxAmountSnackbarView @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), ContentViewCallback {
init {
@@ -72,10 +71,9 @@ class MaxAmountSnackbarView @JvmOverloads constructor(
clipToPadding = false
}
-
override fun animateContentIn(delay: Int, duration: Int) {
}
override fun animateContentOut(delay: Int, duration: Int) {
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/text/DecimalDigitsInputFilter.kt b/app/src/main/java/com/tangem/tap/common/text/DecimalDigitsInputFilter.kt
index 689095c534..2201e794cc 100644
--- a/app/src/main/java/com/tangem/tap/common/text/DecimalDigitsInputFilter.kt
+++ b/app/src/main/java/com/tangem/tap/common/text/DecimalDigitsInputFilter.kt
@@ -8,13 +8,23 @@ import java.util.regex.Pattern
[REDACTED_AUTHOR]
*/
class DecimalDigitsInputFilter(
- digitsBeforeDecimal: Int,
- digitsAfterDecimal: Int,
- private val decimalSeparator: String
+ digitsBeforeDecimal: Int,
+ digitsAfterDecimal: Int,
+ private val decimalSeparator: String,
) : InputFilter {
- private val pattern: Pattern = Pattern.compile("(([1-9]{1}[0-9]{0,${digitsBeforeDecimal - 1}})?||[0]{1})((\\$decimalSeparator[0-9]{0,$digitsAfterDecimal})?)||(\\$decimalSeparator)?")
+ private val pattern: Pattern = Pattern.compile(
+ "(([1-9]{1}[0-9]{0,${digitsBeforeDecimal - 1}})?||[0]{1})" +
+ "((\\$decimalSeparator[0-9]{0,$digitsAfterDecimal})?)||(\\$decimalSeparator)?",
+ )
- override fun filter(source: CharSequence, sourceStart: Int, sourceEnd: Int, destination: Spanned, destinationStart: Int, destinationEnd: Int): CharSequence? {
+ override fun filter(
+ source: CharSequence,
+ sourceStart: Int,
+ sourceEnd: Int,
+ destination: Spanned,
+ destinationStart: Int,
+ destinationEnd: Int,
+ ): CharSequence? {
val destString = destination.toString()
val prefix = destString.substring(0, destinationStart)
val suffix = destString.substring(destinationEnd, destString.length)
@@ -47,4 +57,4 @@ class DecimalDigitsInputFilter(
}
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/text/Truncate.kt b/app/src/main/java/com/tangem/tap/common/text/Truncate.kt
index 3ed50ca1d2..0aeb17d6d2 100644
--- a/app/src/main/java/com/tangem/tap/common/text/Truncate.kt
+++ b/app/src/main/java/com/tangem/tap/common/text/Truncate.kt
@@ -16,9 +16,9 @@ interface Truncate {
companion object {
fun create(type: TruncateType): Truncate {
return when (type) {
- TruncateType.START -> TruncateStart()
- TruncateType.MIDDLE -> TruncateMiddle()
- TruncateType.END -> TruncateEnd()
+ TruncateType.START -> TruncateStart()
+ TruncateType.MIDDLE -> TruncateMiddle()
+ TruncateType.END -> TruncateEnd()
}
}
}
@@ -127,10 +127,10 @@ fun TextView.truncateWith(text: String, type: TruncateType, with: String = "..."
}
fun TextView.truncateStartWith(text: String, with: String = "..."): String =
- this.truncateWith(text, TruncateType.START, with)
+ this.truncateWith(text, TruncateType.START, with)
fun TextView.truncateMiddleWith(text: String, with: String = "..."): String =
- this.truncateWith(text, TruncateType.MIDDLE, with)
+ this.truncateWith(text, TruncateType.MIDDLE, with)
fun TextView.truncateEndWith(text: String, with: String = "..."): String =
- this.truncateWith(text, TruncateType.END, with)
\ No newline at end of file
+ this.truncateWith(text, TruncateType.END, with)
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/common/toggleWidget/IndeterminateProgressButtonWidget.kt b/app/src/main/java/com/tangem/tap/common/toggleWidget/IndeterminateProgressButtonWidget.kt
index 4b15ee3cb5..56f80d5d78 100644
--- a/app/src/main/java/com/tangem/tap/common/toggleWidget/IndeterminateProgressButtonWidget.kt
+++ b/app/src/main/java/com/tangem/tap/common/toggleWidget/IndeterminateProgressButtonWidget.kt
@@ -38,6 +38,7 @@ open class IndeterminateProgressButtonWidget(
when (progressState) {
ProgressState.Done, ProgressState.Error -> switchToNone()
ProgressState.Loading -> switchToProgress()
+ else -> {}
}
}
diff --git a/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt b/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt
index 7bccdffc08..6a5bd17f60 100644
--- a/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt
+++ b/app/src/main/java/com/tangem/tap/common/toggleWidget/RefreshBalanceWidget.kt
@@ -17,6 +17,7 @@ import com.tangem.wallet.R
/**
[REDACTED_AUTHOR]
*/
+@Suppress("MagicNumber")
class RefreshBalanceWidget(
private val root: ViewGroup,
) : ViewStateWidget {
@@ -57,6 +58,7 @@ class RefreshBalanceWidget(
viewSwitcher.showNext()
}
+ @Suppress("MagicNumber")
private fun animateState(state: ProgressState) {
when (state) {
ProgressState.Done, ProgressState.Error -> {
@@ -65,15 +67,25 @@ class RefreshBalanceWidget(
}
ProgressState.Loading -> {
progressViewAnimation = RotateAnimation(
- 0f, 360f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f,
+ /* fromDegrees = */
+ 0f,
+ /* toDegrees = */
+ 360f,
+ /* pivotXType = */
+ Animation.RELATIVE_TO_SELF,
+ /* pivotXValue = */
+ 0.5f,
+ /* pivotYType = */
+ Animation.RELATIVE_TO_SELF,
+ /* pivotYValue = */
+ 0.5f,
)
progressViewAnimation?.duration = 700
progressViewAnimation?.interpolator = AccelerateInterpolator()
progressViewAnimation?.repeatCount = -1
progressViewAnimation?.let { arrowView.startAnimation(it) }
}
+ else -> {}
}
}
@@ -93,14 +105,19 @@ class RefreshBalanceWidget(
private fun getState(): ProgressState = if (isArrowRefreshActive()) ProgressState.Done else ProgressState.Loading
}
+@Suppress("MagicNumber")
class ShowAnimation : AnimationSet(true) {
init {
addAnimation(
ScaleAnimation(
- 0f, 1f,
- 0f, 1f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f,
+ 0f,
+ 1f,
+ 0f,
+ 1f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f,
),
)
addAnimation(AlphaAnimation(0f, 1f))
diff --git a/app/src/main/java/com/tangem/tap/common/toggleWidget/ViewStateWidget.kt b/app/src/main/java/com/tangem/tap/common/toggleWidget/ViewStateWidget.kt
index 48ba0a7291..10b6a1f7a6 100644
--- a/app/src/main/java/com/tangem/tap/common/toggleWidget/ViewStateWidget.kt
+++ b/app/src/main/java/com/tangem/tap/common/toggleWidget/ViewStateWidget.kt
@@ -2,7 +2,6 @@ package com.tangem.tap.common.toggleWidget
import android.view.View
-
/**
[REDACTED_AUTHOR]
*/
diff --git a/app/src/main/java/com/tangem/tap/common/transitions/OnboardingTransitions.kt b/app/src/main/java/com/tangem/tap/common/transitions/OnboardingTransitions.kt
index 32785f0147..e250846a42 100644
--- a/app/src/main/java/com/tangem/tap/common/transitions/OnboardingTransitions.kt
+++ b/app/src/main/java/com/tangem/tap/common/transitions/OnboardingTransitions.kt
@@ -1,33 +1,13 @@
package com.tangem.tap.common.transitions
-import androidx.transition.*
-
-/**
-[REDACTED_AUTHOR]
- */
-class FrontCardEnterTransition : TransitionSet() {
- init {
- ordering = ORDERING_TOGETHER;
- addTransition(Fade())
- addTransition(ChangeImageTransform()) // изменения внутри ImageView
- addTransition(ChangeTransform()) // изменение размеров, углов накона
- addTransition(ChangeBounds()) // изменение положения
- }
-}
-
-class FrontCardExitTransition : TransitionSet() {
- init {
- ordering = ORDERING_TOGETHER;
- addTransition(Fade())
- addTransition(ChangeImageTransform())
- addTransition(ChangeTransform())
- addTransition(ChangeBounds())
- }
-}
+import androidx.transition.ChangeBounds
+import androidx.transition.ChangeTransform
+import androidx.transition.Fade
+import androidx.transition.TransitionSet
class HomeToOnboardingTransition : TransitionSet() {
init {
- ordering = ORDERING_TOGETHER;
+ ordering = ORDERING_TOGETHER
addTransition(Fade())
addTransition(ChangeTransform())
addTransition(ChangeBounds())
@@ -36,7 +16,7 @@ class HomeToOnboardingTransition : TransitionSet() {
class InternalNoteLayoutTransition : TransitionSet() {
init {
- ordering = ORDERING_TOGETHER;
+ ordering = ORDERING_TOGETHER
addTransition(ChangeTransform())
addTransition(ChangeBounds())
addTransition(Fade())
diff --git a/app/src/main/java/com/tangem/tap/common/ui/SimpleAlertDialog.kt b/app/src/main/java/com/tangem/tap/common/ui/SimpleAlertDialog.kt
index 8cd6e7e5ba..365f235f11 100644
--- a/app/src/main/java/com/tangem/tap/common/ui/SimpleAlertDialog.kt
+++ b/app/src/main/java/com/tangem/tap/common/ui/SimpleAlertDialog.kt
@@ -6,54 +6,49 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.store
import com.tangem.wallet.R
-class SimpleAlertDialog {
- companion object {
- fun create(
- titleRes: Int? = null,
- messageRes: Int? = null,
- title: String? = null,
- message: String? = null,
- primaryButtonRes: Int = R.string.common_ok,
- context: Context,
- ): AlertDialog {
- return SimpleCancelableAlertDialog.create(
- titleRes = titleRes,
- messageRes = messageRes,
- title = title,
- message = message,
- primaryButtonRes = primaryButtonRes,
- secondaryButtonRes = null,
- context = context
- )
- }
+object SimpleAlertDialog {
+ fun create(
+ titleRes: Int? = null,
+ messageRes: Int? = null,
+ title: String? = null,
+ message: String? = null,
+ primaryButtonRes: Int = R.string.common_ok,
+ context: Context,
+ ): AlertDialog {
+ return SimpleCancelableAlertDialog.create(
+ titleRes = titleRes,
+ messageRes = messageRes,
+ title = title,
+ message = message,
+ primaryButtonRes = primaryButtonRes,
+ secondaryButtonRes = null,
+ context = context,
+ )
}
}
-class SimpleCancelableAlertDialog {
- companion object {
- fun create(
- titleRes: Int? = null,
- messageRes: Int? = null,
- title: String? = null,
- message: String? = null,
- primaryButtonRes: Int = R.string.common_ok,
- secondaryButtonRes: Int? = R.string.common_cancel,
- primaryButtonAction: () -> Unit = {},
- secondaryButtonAction: () -> Unit = {},
- context: Context,
- ): AlertDialog {
-
- return AlertDialog.Builder(context).apply {
- setTitle(titleRes?.let { context.getString(it) } ?: title )
- setMessage(messageRes?.let { context.getString(it) } ?: message)
- setPositiveButton(context.getText(primaryButtonRes)) { _, _ -> primaryButtonAction() }
- if (secondaryButtonRes != null) {
- setNegativeButton(context.getText(secondaryButtonRes)) { _, _ -> secondaryButtonAction()}
- }
- setOnDismissListener {
- store.dispatch(GlobalAction.HideDialog)
- }
- }.create()
- }
+object SimpleCancelableAlertDialog {
+ fun create(
+ titleRes: Int? = null,
+ messageRes: Int? = null,
+ title: String? = null,
+ message: String? = null,
+ primaryButtonRes: Int = R.string.common_ok,
+ secondaryButtonRes: Int? = R.string.common_cancel,
+ primaryButtonAction: () -> Unit = {},
+ secondaryButtonAction: () -> Unit = {},
+ context: Context,
+ ): AlertDialog {
+ return AlertDialog.Builder(context).apply {
+ setTitle(titleRes?.let { context.getString(it) } ?: title)
+ setMessage(messageRes?.let { context.getString(it) } ?: message)
+ setPositiveButton(context.getText(primaryButtonRes)) { _, _ -> primaryButtonAction() }
+ if (secondaryButtonRes != null) {
+ setNegativeButton(context.getText(secondaryButtonRes)) { _, _ -> secondaryButtonAction() }
+ }
+ setOnDismissListener {
+ store.dispatch(GlobalAction.HideDialog)
+ }
+ }.create()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt b/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt
index cfd5c2b5c2..d66ac2ed73 100644
--- a/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/PayIdManager.kt
@@ -10,7 +10,11 @@ import java.util.*
class PayIdManager {
- suspend fun verifyPayId(payId: String, blockchain: Blockchain): Result = withContext(Dispatchers.IO) {
+ @Suppress("MagicNumber")
+ suspend fun verifyPayId(
+ payId: String,
+ blockchain: Blockchain,
+ ): Result = withContext(Dispatchers.IO) {
val splitPayId = payId.split("\$")
val user = splitPayId[0]
val baseUrl = "https://${splitPayId[1]}/"
@@ -22,25 +26,26 @@ class PayIdManager {
Blockchain.XRP -> "XRPL"
Blockchain.RSK -> "RSK"
else -> this.currency
- }.toLowerCase()
+ }.lowercase(Locale.getDefault())
}
companion object {
- val payIdRegExp = "^[a-z0-9!#@%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#@%&*+/=?^_`{|}~-]+)*\\\$(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z-]*[a-z0-9])?|(?:[0-9]{1,3}\\.){3}[0-9]{1,3})\$".toRegex()
+ private val payIdRegExp = ("^[a-z0-9!#@%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#@%&*+/=?^_`{|}~-]+)*\\\$(?:(?:[a-z0-9]" +
+ "(?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z-]*[a-z0-9])?|(?:[0-9]{1,3}\\.){3}[0-9]{1,3})\$").toRegex()
val payIdSupported: EnumSet = EnumSet.of(
- Blockchain.XRP,
- Blockchain.Ethereum,
- Blockchain.Bitcoin,
- Blockchain.Litecoin,
- Blockchain.Stellar,
- Blockchain.Cardano,
- Blockchain.CardanoShelley,
- Blockchain.Ducatus,
- Blockchain.BitcoinCash,
- Blockchain.Binance,
- Blockchain.RSK,
- Blockchain.Tezos
+ Blockchain.XRP,
+ Blockchain.Ethereum,
+ Blockchain.Bitcoin,
+ Blockchain.Litecoin,
+ Blockchain.Stellar,
+ Blockchain.Cardano,
+ Blockchain.CardanoShelley,
+ Blockchain.Ducatus,
+ Blockchain.BitcoinCash,
+ Blockchain.Binance,
+ Blockchain.RSK,
+ Blockchain.Tezos,
)
fun isPayId(value: String?): Boolean = value?.contains(payIdRegExp) ?: false
diff --git a/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt b/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt
index 7cee3bcfd9..3d2a5764e2 100644
--- a/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt
+++ b/app/src/main/java/com/tangem/tap/domain/RatesRepository.kt
@@ -1,48 +1,49 @@
package com.tangem.tap.domain
import com.tangem.common.services.Result
+import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.ThrottlerWithValues
-import com.tangem.datasource.api.tangemTech.TangemTechService
import com.tangem.tap.features.wallet.models.Currency
-import com.tangem.tap.store
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.withContext
import java.math.BigDecimal
-//TODO: refactoring: move to domain
-class RatesRepository {
-
- private val tangemTechService: TangemTechService
- get() = store.state.domainNetworks.tangemTechService
-
+class RatesRepository(
+ private val tangemTechApi: TangemTechApi,
+ private val dispatchers: CoroutineDispatcherProvider,
+) {
private val throttler = ThrottlerWithValues?>(60000)
- suspend fun loadFiatRate(currencyId: String, coinsList: List): Result {
-// get and submit previous result of equivalents.
- val throttledResult = coinsList.filter { throttler.isStillThrottled(it) }.map {
- Pair(it, throttler.geValue(it))
- }
-
- val currenciesToUpdate = coinsList.filter { !throttler.isStillThrottled(it) }
- val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct()
- if (coinIds.isEmpty()) return handleFiatRatesResult(throttledResult.toMap())
-
- return when (val result = tangemTechService.rates(currencyId, coinIds)) {
- is Result.Success -> {
- val ratesResultList: Map> = result.data.rates.mapValues {
- Result.Success(it.value.toBigDecimal())
- }
- val updatedCurrencies = throttledResult.toMap().toMutableMap()
- coinsList.forEach { currency ->
- ratesResultList[currency.coinId]?.let {
- updatedCurrencies[currency] = it
- throttler.updateThrottlingTo(currency)
- throttler.setValue(currency, it)
- }
- }
- handleFiatRatesResult(updatedCurrencies)
+ suspend fun loadFiatRate(currencyId: String, coinsList: List): Result =
+ withContext(dispatchers.io) {
+ // get and submit previous result of equivalents.
+ val throttledResult = coinsList.filter { throttler.isStillThrottled(it) }.map {
+ Pair(it, throttler.geValue(it))
}
- is Result.Failure -> Result.Failure(result.error)
+
+ val currenciesToUpdate = coinsList.filter { !throttler.isStillThrottled(it) }
+ val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct()
+ if (coinIds.isEmpty()) return@withContext handleFiatRatesResult(throttledResult.toMap())
+
+ runCatching { tangemTechApi.getRates(currencyId.lowercase(), coinIds.joinToString(",")) }
+ .onSuccess { response ->
+ val ratesResultList: Map> = response.rates.mapValues {
+ Result.Success(it.value.toBigDecimal())
+ }
+ val updatedCurrencies = throttledResult.toMap().toMutableMap()
+ coinsList.forEach { currency ->
+ ratesResultList[currency.coinId]?.let {
+ updatedCurrencies[currency] = it
+ throttler.updateThrottlingTo(currency)
+ throttler.setValue(currency, it)
+ }
+ }
+ return@withContext handleFiatRatesResult(updatedCurrencies)
+ }
+ .onFailure { Result.Failure(it) }
+
+ error("Unreachable code because runCatching must return result")
}
- }
private fun handleFiatRatesResult(rates: Map?>): Result.Success {
val success = mutableMapOf()
diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt
index cf8a13681c..288d399817 100644
--- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt
@@ -21,6 +21,7 @@ import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.common.map
import com.tangem.common.usersCode.UserCodeRepository
+import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.operations.CommandResponse
@@ -30,7 +31,6 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.pins.CheckUserCodesCommand
import com.tangem.operations.pins.CheckUserCodesResponse
import com.tangem.operations.pins.SetUserCodeCommand
-import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
import com.tangem.tap.domain.tasks.product.CreateProductWalletTask
@@ -85,7 +85,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
scanResponse: ScanResponse,
): CompletionResult {
return runTaskAsync(
- CreateProductWalletTask(scanResponse.productType),
+ CreateProductWalletTask(scanResponse.cardTypesResolver),
scanResponse.card.cardId,
Message(context.getString(R.string.initial_message_create_wallet_body)),
)
@@ -211,11 +211,12 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
return withContext(Dispatchers.Main) { result }
}
+ @Suppress("MagicNumber")
fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) {
tangemSdk.config.cardIdDisplayFormat = when {
scanResponse == null -> CardIdDisplayFormat.Full
- scanResponse.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4)
- scanResponse.isSaltPay() -> CardIdDisplayFormat.None
+ scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4)
+ scanResponse.cardTypesResolver.isSaltPay() -> CardIdDisplayFormat.None
else -> CardIdDisplayFormat.Full
}
}
diff --git a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt
index aae3cf8e9a..b0ee231286 100644
--- a/app/src/main/java/com/tangem/tap/domain/TapErrors.kt
+++ b/app/src/main/java/com/tangem/tap/domain/TapErrors.kt
@@ -2,7 +2,6 @@ package com.tangem.tap.domain
import androidx.annotation.StringRes
import com.tangem.common.core.TangemError
-import com.tangem.datasource.api.tangemTech.TangemTechError
import com.tangem.wallet.R
interface TapErrors
@@ -18,21 +17,20 @@ interface MultiMessageError : TapErrors {
sealed class TapError(
@StringRes val messageResource: Int,
- override val args: List? = null
+ override val args: List? = null,
) : Throwable(), TapErrors, ArgError {
object UnknownError : TapError(R.string.send_error_unknown)
open class CustomError(val customMessage: String) : TapError(R.string.common_custom_string, listOf(customMessage))
object ScanCardError : TapError(R.string.scan_card_error)
- object PayIdAlreadyCreated : TapError(R.string.wallet_create_payid_error_already_created)
- object PayIdCreatingError : TapError(R.string.wallet_create_payid_error_message)
- object PayIdEmptyField : TapError(R.string.wallet_create_payid_empty)
object UnknownBlockchain : TapError(R.string.wallet_error_unsupported_blockchain_subtitle)
object NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
- object InsufficientBalance : TapError(R.string.send_error_insufficient_balance)
object BlockchainInternalError : TapError(R.string.send_error_blockchain_internal)
object AmountExceedsBalance : TapError(R.string.send_validation_amount_exceeds_balance)
- data class AmountLowerExistentialDeposit(override val args: List) : TapError(R.string.send_error_minimum_balance_format)
+ data class AmountLowerExistentialDeposit(
+ override val args: List,
+ ) : TapError(R.string.send_error_minimum_balance_format)
+
object FeeExceedsBalance : TapError(R.string.send_validation_invalid_fee)
object TotalExceedsBalance : TapError(R.string.send_validation_invalid_total)
object InvalidAmountValue : TapError(R.string.send_validation_invalid_amount)
@@ -49,7 +47,6 @@ sealed class TapError(
object CreationError : CustomError("Can't create wallet manager")
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
class InternalError(message: String) : CustomError(message)
- object BlockchainIsUnreachable : TapError(R.string.wallet_balance_blockchain_unreachable)
object BlockchainIsUnreachableTryLater : TapError(R.string.wallet_balance_blockchain_unreachable_try_later)
}
@@ -78,13 +75,4 @@ fun TapErrors.assembleErrors(): MutableList?>> {
is TapError -> idList.add(Pair(this.messageResource, this.args))
}
return idList
-}
-
-fun TangemTechError.toTapError(): TapError {
- return when (this.code) {
- 404 -> NoDataError(this.description)
- else -> TapError.CustomError(customMessage = this.description)
- }
-}
-
-class NoDataError(message: String) : TapError.CustomError(customMessage = message)
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt
index df19afc1c4..7bbfdc4f1d 100644
--- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt
@@ -12,7 +12,6 @@ import com.tangem.common.doOnSuccess
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
-import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.ThrottlerWithValues
import com.tangem.domain.common.extensions.withMainContext
@@ -20,8 +19,7 @@ import com.tangem.operations.attestation.Attestation
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.common.redux.global.GlobalAction
-import com.tangem.tap.domain.configurable.config.ConfigManager
-import com.tangem.tap.domain.extensions.isMultiwalletAllowed
+import com.tangem.datasource.config.ConfigManager
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.domain.extensions.makeWalletManagersForApp
import com.tangem.tap.domain.model.UserWallet
@@ -38,6 +36,7 @@ import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userTokensRepository
import com.tangem.tap.walletStoresManager
+import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.rekotlin.Action
@@ -46,7 +45,14 @@ import timber.log.Timber
class TapWalletManager {
val walletManagerFactory: WalletManagerFactory
by lazy { WalletManagerFactory(blockchainSdkConfig) }
- val rates: RatesRepository = RatesRepository()
+
+ // TODO("After adding DI") get dependencies by DI
+ val rates: RatesRepository by lazy {
+ RatesRepository(
+ tangemTechApi = store.state.domainNetworks.tangemTechService.api,
+ dispatchers = AppCoroutineDispatcherProvider(),
+ )
+ }
private val blockchainSdkConfig by lazy {
store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig()
@@ -157,12 +163,16 @@ class TapWalletManager {
store.dispatch(WalletConnectAction.ResetState)
store.dispatch(GlobalAction.SaveScanResponse(data))
store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard))
- store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed))
+ store.dispatch(
+ WalletAction.MultiWallet.SetIsMultiwalletAllowed(
+ data.cardTypesResolver.isMultiwalletAllowed(),
+ ),
+ )
store.dispatch(WalletConnectAction.RestoreSessions(data))
store.dispatch(
WalletAction.MultiWallet.ShowWalletBackupWarning(
- show = data.card.settings.isBackupAllowed
- && data.card.backupStatus == CardDTO.BackupStatus.NoBackup,
+ show = data.card.settings.isBackupAllowed &&
+ data.card.backupStatus == CardDTO.BackupStatus.NoBackup,
),
)
loadData(data)
@@ -171,18 +181,18 @@ class TapWalletManager {
fun updateConfigManager(data: ScanResponse) {
val configManager = store.state.globalState.configManager
- val blockchain = data.getBlockchain()
- if (data.card.isStart2Coin) {
- configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled)
- configManager?.turnOff(ConfigManager.isTopUpEnabled)
- } else if (blockchain == Blockchain.Bitcoin
- || data.walletData?.blockchain == Blockchain.Bitcoin.id
+ val blockchain = data.cardTypesResolver.getBlockchain()
+ if (data.cardTypesResolver.isStart2Coin()) {
+ configManager?.turnOff(ConfigManager.IS_SENDING_TO_PAY_ID_ENABLED)
+ configManager?.turnOff(ConfigManager.IS_TOP_UP_ENABLED)
+ } else if (blockchain == Blockchain.Bitcoin ||
+ data.walletData?.blockchain == Blockchain.Bitcoin.id
) {
- configManager?.resetToDefault(ConfigManager.isSendingToPayIdEnabled)
- configManager?.resetToDefault(ConfigManager.isTopUpEnabled)
+ configManager?.resetToDefault(ConfigManager.IS_SENDING_TO_PAY_ID_ENABLED)
+ configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED)
} else {
- configManager?.resetToDefault(ConfigManager.isSendingToPayIdEnabled)
- configManager?.resetToDefault(ConfigManager.isTopUpEnabled)
+ configManager?.resetToDefault(ConfigManager.IS_SENDING_TO_PAY_ID_ENABLED)
+ configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED)
}
}
@@ -193,7 +203,7 @@ class TapWalletManager {
return
}
- if (data.card.isMultiwalletAllowed) {
+ if (data.cardTypesResolver.isMultiwalletAllowed()) {
dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation)
loadMultiWalletData(data)
} else {
@@ -221,7 +231,7 @@ class TapWalletManager {
}
private suspend fun loadSingleWalletData(data: ScanResponse) {
- val blockchain = data.getBlockchain()
+ val blockchain = data.cardTypesResolver.getBlockchain()
val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data)
if (blockchain != Blockchain.Unknown && primaryWalletManager != null) {
@@ -231,7 +241,7 @@ class TapWalletManager {
blockchains = listOf(BlockchainNetwork.fromWalletManager(primaryWalletManager)),
walletManagers = listOf(primaryWalletManager),
),
- data.getPrimaryToken()?.let {
+ data.cardTypesResolver.getPrimaryToken()?.let {
primaryWalletManager.addToken(it)
primaryWalletManager.wallet.setAmount(Amount(it))
WalletAction.MultiWallet.AddToken(it, blockchainNetwork, false)
@@ -269,7 +279,7 @@ class TapWalletManager {
}
suspend fun reloadData(data: ScanResponse) {
- if (data.card.isMultiwalletAllowed) {
+ if (data.cardTypesResolver.isMultiwalletAllowed()) {
loadUserCurrencies(data, walletManagerFactory)
}
withContext(Dispatchers.Main) {
@@ -289,10 +299,11 @@ class TapWalletManager {
private fun getActionIfUnknownBlockchainOrEmptyWallet(data: ScanResponse): WalletAction? {
return when {
// check order is important
- data.isTangemTwins() && !data.twinsIsTwinned() -> {
+ data.cardTypesResolver.isTangemTwins() && !data.twinsIsTwinned() -> {
WalletAction.EmptyWallet
}
- data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> {
+ data.cardTypesResolver.getBlockchain() == Blockchain.Unknown &&
+ !data.cardTypesResolver.isMultiwalletAllowed() -> {
WalletAction.LoadData.Failure(TapError.UnknownBlockchain)
}
data.isDemoCard() -> {
diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt b/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt
deleted file mode 100644
index 5354d0b219..0000000000
--- a/app/src/main/java/com/tangem/tap/domain/configurable/Loader.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.tangem.tap.domain.configurable
-
-import com.tangem.wallet.BuildConfig
-
-/**
-[REDACTED_AUTHOR]
- */
-interface Loader {
- fun load(onComplete: (T) -> Unit)
-
- companion object {
- const val featuresName = "features_${BuildConfig.ENVIRONMENT}"
- const val configValuesName = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
- const val warnings = "warnings_${BuildConfig.ENVIRONMENT}"
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt
deleted file mode 100644
index 8a2a6032cc..0000000000
--- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.tangem.tap.domain.configurable.config
-
-import com.tangem.blockchain.common.BlockchainSdkConfig
-import com.tangem.blockchain.common.BlockchairCredentials
-import com.tangem.blockchain.common.GetBlockCredentials
-import com.tangem.blockchain.common.NowNodeCredentials
-import com.tangem.blockchain.common.QuickNodeCredentials
-import com.tangem.tap.common.shop.shopify.ShopifyShop
-import com.tangem.tap.common.zendesk.ZendeskConfig
-import com.tangem.tap.domain.configurable.Loader
-import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayConfig
-
-/**
-[REDACTED_AUTHOR]
- */
-data class Config(
- val coinMarketCapKey: String = "f6622117-c043-47a0-8975-9d673ce484de",
- val moonPayApiKey: String = "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE",
- val moonPayApiSecretKey: String = "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C",
- val mercuryoWidgetId: String = "",
- val mercuryoSecret: String = "",
- val appsFlyerDevKey: String = "",
- val amplitudeApiKey: String = "",
- val blockchainSdkConfig: BlockchainSdkConfig = BlockchainSdkConfig(),
- val isSendingToPayIdEnabled: Boolean = true,
- val isTopUpEnabled: Boolean = false,
- @Deprecated("Not relevant since version 3.23")
- val isCreatingTwinCardsAllowed: Boolean = false,
- val shopify: ShopifyShop? = null,
- val zendesk: ZendeskConfig? = null,
- val saltPayConfig: SaltPayConfig? = null,
-)
-
-class ConfigManager {
-
- var config: Config = Config()
- private set
-
- private var defaultConfig = Config()
-
- fun load(configLoader: Loader, onComplete: ((config: Config) -> Unit)? = null) {
- configLoader.load { configModel ->
- setupFeature(configModel.features)
- setupKey(configModel.configValues)
- onComplete?.invoke(config)
- }
- }
-
- fun turnOff(name: String) {
- when (name) {
- isSendingToPayIdEnabled -> config = config.copy(isSendingToPayIdEnabled = false)
- isTopUpEnabled -> config = config.copy(isTopUpEnabled = false)
- isCreatingTwinCardsAllowed -> config = config.copy(isCreatingTwinCardsAllowed = false)
- }
- }
-
- fun resetToDefault(name: String) {
- when (name) {
- isSendingToPayIdEnabled -> config =
- config.copy(isSendingToPayIdEnabled = defaultConfig.isSendingToPayIdEnabled)
- isTopUpEnabled -> config = config.copy(isTopUpEnabled = defaultConfig.isTopUpEnabled)
- isCreatingTwinCardsAllowed -> config =
- config.copy(isCreatingTwinCardsAllowed = defaultConfig.isCreatingTwinCardsAllowed)
- }
- }
-
- private fun setupFeature(featureModel: FeatureModel?) {
- val model = featureModel ?: return
-
- config = config.copy(
- isTopUpEnabled = model.isTopUpEnabled,
- isSendingToPayIdEnabled = model.isSendingToPayIdEnabled,
- isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed,
- )
- defaultConfig = defaultConfig.copy(
- isTopUpEnabled = model.isTopUpEnabled,
- isSendingToPayIdEnabled = model.isSendingToPayIdEnabled,
- isCreatingTwinCardsAllowed = model.isCreatingTwinCardsAllowed,
- )
- }
-
- private fun setupKey(configValues: ConfigValueModel?) {
- val values = configValues ?: return
- config = config.copy(
- coinMarketCapKey = values.coinMarketCapKey,
- moonPayApiKey = values.moonPayApiKey,
- moonPayApiSecretKey = values.moonPayApiSecretKey,
- mercuryoWidgetId = values.mercuryoWidgetId,
- mercuryoSecret = values.mercuryoSecret,
- blockchainSdkConfig = BlockchainSdkConfig(
- blockchairCredentials = BlockchairCredentials(
- apiKey = values.blockchairApiKeys,
- authToken = values.blockchairAuthorizationToken,
- ),
- blockcypherTokens = values.blockcypherTokens,
- quickNodeSolanaCredentials = QuickNodeCredentials(
- apiKey = values.quiknodeApiKey,
- subdomain = values.quiknodeSubdomain,
- ),
- quickNodeBscCredentials = QuickNodeCredentials(
- apiKey = values.bscQuiknodeApiKey,
- subdomain = values.bscQuiknodeSubdomain,
- ),
- nowNodeCredentials = NowNodeCredentials(values.nowNodesApiKey),
- getBlockCredentials = GetBlockCredentials(values.getBlockApiKey),
- infuraProjectId = values.infuraProjectId,
- tronGridApiKey = values.tronGridApiKey,
- saltPayAuthToken = values.saltPay.credentials.token,
- ),
- appsFlyerDevKey = values.appsFlyer.appsFlyerDevKey,
- amplitudeApiKey = values.amplitudeApiKey,
- shopify = values.shopifyShop,
- zendesk = values.zendesk,
- saltPayConfig = values.saltPay,
- )
- defaultConfig = defaultConfig.copy(
- coinMarketCapKey = values.coinMarketCapKey,
- moonPayApiKey = values.moonPayApiKey,
- moonPayApiSecretKey = values.moonPayApiSecretKey,
- mercuryoWidgetId = values.mercuryoWidgetId,
- mercuryoSecret = values.mercuryoSecret,
- blockchainSdkConfig = BlockchainSdkConfig(
- blockchairCredentials = BlockchairCredentials(
- apiKey = values.blockchairApiKeys,
- authToken = values.blockchairAuthorizationToken,
- ),
- blockcypherTokens = values.blockcypherTokens,
- quickNodeSolanaCredentials = QuickNodeCredentials(
- apiKey = values.quiknodeApiKey,
- subdomain = values.quiknodeSubdomain,
- ),
- quickNodeBscCredentials = QuickNodeCredentials(
- apiKey = values.bscQuiknodeApiKey,
- subdomain = values.bscQuiknodeSubdomain,
- ),
- nowNodeCredentials = NowNodeCredentials(values.nowNodesApiKey),
- getBlockCredentials = GetBlockCredentials(values.getBlockApiKey),
- infuraProjectId = values.infuraProjectId,
- saltPayAuthToken = values.saltPay.credentials.token,
- ),
- appsFlyerDevKey = values.appsFlyer.appsFlyerDevKey,
- amplitudeApiKey = values.amplitudeApiKey,
- shopify = values.shopifyShop,
- zendesk = values.zendesk,
- saltPayConfig = values.saltPay,
- )
- }
-
- companion object {
- const val isSendingToPayIdEnabled = "isSendingToPayIdEnabled"
- const val isCreatingTwinCardsAllowed = "isCreatingTwinCardsAllowed"
- const val isTopUpEnabled = "isTopUpEnabled"
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt
index 03c10daf6f..ddadfcfc70 100644
--- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt
+++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessage.kt
@@ -24,7 +24,6 @@ data class WarningMessage(
blockchains?.map { Blockchain.fromId(it.uppercase()) }
}
-
var isHidden = false
enum class Priority {
@@ -40,15 +39,14 @@ data class WarningMessage(
enum class Type {
@Json(name = "permanent")
- Permanent, // нельзя скрыть
+ Permanent, // нельзя скрыть
@Json(name = "temporary")
- Temporary, // можно скрыть (кнопка ОК)
+ Temporary, // можно скрыть (кнопка ОК)
AppRating,
TestCard
-
}
enum class Location {
diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt
index f75a4922ce..a0e382136a 100644
--- a/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/configurable/warningMessage/WarningMessagesManager.kt
@@ -39,8 +39,8 @@ class WarningMessagesManager {
val foundWarning = findWarning(warning)
return when {
foundWarning == null -> false
- foundWarning.type == WarningMessage.Type.Temporary
- || foundWarning.type == WarningMessage.Type.AppRating -> {
+ foundWarning.type == WarningMessage.Type.Temporary ||
+ foundWarning.type == WarningMessage.Type.AppRating -> {
if (foundWarning.isHidden) {
false
} else {
@@ -70,6 +70,8 @@ class WarningMessagesManager {
}
companion object {
+ const val REMAINING_SIGNATURES_WARNING = 10
+
fun devCardWarning(): WarningMessage = WarningMessage(
"",
"",
@@ -171,7 +173,5 @@ class WarningMessagesManager {
R.string.alert_demo_message,
WarningMessage.Origin.Local,
)
-
- const val REMAINING_SIGNATURES_WARNING = 10
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt
index 673ef1787b..9adb6b24aa 100644
--- a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt
+++ b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt
@@ -5,7 +5,7 @@ import com.tangem.blockchain.common.Token
import com.tangem.common.card.EllipticCurve
import java.math.BigDecimal
-
+@Suppress("MagicNumber")
fun Blockchain.amountToCreateAccount(token: Token? = null): BigDecimal? {
return when (this) {
Blockchain.Stellar -> if (token?.symbol == NODL) BigDecimal(1.5) else BigDecimal.ONE
diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt
index 486a9f6b89..005f05500c 100644
--- a/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt
+++ b/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt
@@ -1,16 +1,12 @@
package com.tangem.tap.domain.extensions
-import com.tangem.common.card.EllipticCurve
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.extensions.toHexString
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.isSaltPay
-import com.tangem.domain.common.TapWorkarounds.isStart2Coin
-import com.tangem.domain.common.TapWorkarounds.isTangemNote
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.common.getTwinCardNumber
-import com.tangem.domain.common.isTangemTwin
import com.tangem.operations.attestation.CardVerifyAndGetInfo
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.features.wallet.redux.Artwork
@@ -21,22 +17,13 @@ val CardDTO.remainingSignatures: Int?
val CardDTO.isWalletDataSupported: Boolean
get() = this.firmwareVersion.major >= 4
-val CardDTO.isMultiwalletAllowed: Boolean
- get() {
- return !isTangemTwin() && !isStart2Coin && !isTangemNote && !isSaltPay &&
- (firmwareVersion >= FirmwareVersion.MultiWalletAvailable ||
- wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1)
- }
+val CardDTO.isFirmwareMultiwalletAllowed: Boolean
+ get() = firmwareVersion >= FirmwareVersion.MultiWalletAvailable && settings.maxWalletsCount > 1
val CardDTO.isHdWalletAllowedByApp: Boolean
get() = settings.isHDWalletAllowed && !isSaltPay
-val CardDTO.isTangemWallet: Boolean
- get() = settings.isBackupAllowed
- && settings.isHDWalletAllowed
- && firmwareVersion >= FirmwareVersion.MultiWalletAvailable
- && !isSaltPay
-
+@Suppress("UnnecessaryParentheses")
fun CardDTO.hasSignedHashes(): Boolean {
return wallets.any { (it.totalSignedHashes ?: 0) > 0 }
}
diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt
index 989793e59a..07e92a313f 100644
--- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt
+++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt
@@ -37,7 +37,7 @@ fun WalletManagerFactory.makeWalletManagerForApp(
val seedKey = wallet.extendedPublicKey
return when {
- scanResponse.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> {
+ scanResponse.cardTypesResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> {
makeTwinWalletManager(
walletPublicKey = wallet.publicKey,
pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(),
@@ -45,7 +45,7 @@ fun WalletManagerFactory.makeWalletManagerForApp(
curve = wallet.curve,
)
}
- scanResponse.card.isHdWalletAllowedByApp && (seedKey != null && derivationParams != null) -> {
+ scanResponse.card.isHdWalletAllowedByApp && seedKey != null && derivationParams != null -> {
val derivedKeys = scanResponse.derivedKeys[wallet.publicKey.toMapKey()]
val derivationPath = when (derivationParams) {
is DerivationParams.Default -> blockchain.derivationPath(derivationParams.style)
@@ -72,7 +72,8 @@ fun WalletManagerFactory.makeWalletManagerForApp(
}
fun WalletManagerFactory.makeWalletManagerForApp(
- scanResponse: ScanResponse, blockchainNetwork: BlockchainNetwork,
+ scanResponse: ScanResponse,
+ blockchainNetwork: BlockchainNetwork,
): WalletManager? {
return makeWalletManagerForApp(
scanResponse,
@@ -119,9 +120,9 @@ fun WalletManagerFactory.makePrimaryWalletManager(
scanResponse: ScanResponse,
): WalletManager? {
val blockchain = if (scanResponse.card.isTestCard) {
- scanResponse.getBlockchain().getTestnetVersion() ?: return null
+ scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null
} else {
- scanResponse.getBlockchain()
+ scanResponse.cardTypesResolver.getBlockchain()
}
val derivationParams = getDerivationParams(null, scanResponse.card)
return makeWalletManagerForApp(
@@ -142,13 +143,14 @@ private fun selectWallet(wallets: List): CardDTO.Wallet? {
fun WalletManagerFactory.makeSaltPayWalletManager(
scanResponse: ScanResponse,
): EthereumWalletManager {
- val blockchain = scanResponse.getBlockchain()
- if (blockchain != Blockchain.SaltPay)
- throw IllegalArgumentException()
+ val blockchain = scanResponse.cardTypesResolver.getBlockchain()
+ if (blockchain != Blockchain.SaltPay) {
+ error("WalletManager for the SaltPay can be created based only on Blockchain.SaltPay")
+ }
val token = SaltPayWorkaround.tokenFrom(blockchain)
val cardWallet = scanResponse.card.wallets.firstOrNull().guard {
- throw NullPointerException("SaltPay card must have one wallet at least")
+ error("SaltPay card must have one wallet at least")
}
return makeWalletManager(
diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt
index 22cc834b2a..a2c699667a 100644
--- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt
+++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt
@@ -1,7 +1,5 @@
package com.tangem.tap.domain.model.builders
-import com.tangem.common.card.EllipticCurve
-import com.tangem.common.card.FirmwareVersion
import com.tangem.common.extensions.toHexString
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
@@ -32,28 +30,11 @@ class UserWalletBuilder(
ProductType.Start2Coin -> "Start2Coin"
ProductType.Wallet -> when {
card.isBackupNotAllowed -> "Tangem card"
+ card.isStart2Coin -> "Start2Coin"
else -> "Wallet"
}
}
- private val ScanResponse.isMultiCurrency: Boolean
- get() = when (productType) {
- ProductType.Note -> false
- ProductType.Twins -> false
- ProductType.SaltPay -> false
- ProductType.Start2Coin -> false
- ProductType.Wallet -> when {
- card.isStart2Coin -> false
- card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable -> true
- else -> {
- val cardWallets = card.wallets
- require(cardWallets.isNotEmpty()) { "Card wallets must not be empty" }
-
- cardWallets.first().curve == EllipticCurve.Secp256k1
- }
- }
- }
-
fun backupCardsIds(backupCardsIds: Set?) = this.apply {
if (backupCardsIds != null) {
this.backupCardsIds = backupCardsIds
@@ -71,7 +52,7 @@ class UserWalletBuilder(
artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey),
cardsInWallet = backupCardsIds.plus(card.cardId),
scanResponse = this,
- isMultiCurrency = isMultiCurrency,
+ isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(),
)
}
}
@@ -106,6 +87,6 @@ class UserWalletBuilder(
private fun getUrlForArtwork(cardId: String, cardPublicKeyHex: String, artworkId: String): String {
return TangemApi.Companion.BaseUrl.VERIFY.url + TangemApi.ARTWORK +
- "?artworkId=${artworkId}&CID=${cardId}&publicKey=$cardPublicKeyHex"
+ "?artworkId=$artworkId&CID=$cardId&publicKey=$cardPublicKeyHex"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt
index 651ab25018..b48ae715a2 100644
--- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt
+++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt
@@ -57,7 +57,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl(
userWalletId = userWalletId,
blockchain = blockchainNetwork.blockchain,
derivationPath = blockchainNetwork.derivationPath?.let { DerivationPath(it) },
- walletsData = (listOf(blockchainWalletData) + tokensWalletsData),
+ walletsData = listOf(blockchainWalletData) + tokensWalletsData,
walletRent = null,
walletManager = walletManager,
blockchainNetwork = blockchainNetwork,
@@ -73,13 +73,13 @@ private class WalletMangerWalletStoreBuilderImpl(
override fun build(): WalletStoreModel {
val wallet = walletManager.wallet
val blockchainWalletData = wallet.blockchain.toBlockchainWalletData(walletManager)
- val tokenWalletsData = walletManager.cardTokens.map { it.toTokenWalletData(walletManager) }
+ val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData(walletManager)
return WalletStoreModel(
userWalletId = userWalletId,
blockchain = wallet.blockchain,
derivationPath = wallet.publicKey.derivationPath,
- walletsData = (listOf(blockchainWalletData) + tokenWalletsData),
+ walletsData = listOf(blockchainWalletData) + listOfNotNull(tokenWalletsData),
walletRent = null,
walletManager = walletManager,
blockchainNetwork = BlockchainNetwork.fromWalletManager(walletManager),
diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt
index 66e41dc48e..daa0901b14 100644
--- a/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt
+++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/domain/converter/AddCustomTokenErrorConverter.kt
@@ -15,8 +15,9 @@ internal class AddCustomTokenErrorConverter(
private val context: Context,
) : ModuleMessageConverter {
+ @Suppress("MagicNumber")
override fun convert(message: DomainModuleError): ConvertedMessage? {
- val customTokenError = (message as? AddCustomTokenError) ?: throw UnsupportedOperationException()
+ val customTokenError = message as? AddCustomTokenError ?: throw UnsupportedOperationException()
val rawMessage = when (customTokenError) {
AddCustomTokenError.Warning.PotentialScamToken -> R.string.custom_token_validation_error_not_found
diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt
index ac8c8cd359..9db1c78996 100644
--- a/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt
+++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/SaltPayMessageConverter.kt
@@ -31,4 +31,4 @@ class SaltPayErrorConverter(
is SaltPayActivationError -> SaltPayActivationErrorConverter(context).convert(message)
else -> null
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayActivationErrorConverter.kt b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayActivationErrorConverter.kt
index 65de384d44..1771a2db47 100644
--- a/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayActivationErrorConverter.kt
+++ b/app/src/main/java/com/tangem/tap/domain/moduleMessage/saltPay/converter/SaltPayActivationErrorConverter.kt
@@ -14,7 +14,7 @@ internal class SaltPayActivationErrorConverter(
) : ModuleMessageConverter {
override fun convert(message: SaltPayActivationError): ConvertedDialogMessage? {
- val saltPayError = (message as? SaltPayActivationError) ?: throw UnsupportedOperationException()
+ val saltPayError = message as? SaltPayActivationError ?: throw UnsupportedOperationException()
val dialogMessage = when (saltPayError) {
SaltPayActivationError.NoGas -> {
diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt
index 6caafef969..36f4635c4a 100644
--- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt
+++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt
@@ -129,7 +129,7 @@ object ScanCardProcessor {
?.let { it == scanResponse.card.cardId }
?: false
- if (scanResponse.isSaltPayWallet() || !isTheSamePrimaryCard) {
+ if (scanResponse.cardTypesResolver.isSaltPayWallet() || !isTheSamePrimaryCard) {
val error = SaltPayActivationError.PutVisaCard
SaltPayExceptionHandler.handle(error)
onFailure(TangemSdkError.ExceptionError(error))
@@ -148,30 +148,33 @@ object ScanCardProcessor {
store.dispatchOnMain(DisclaimerAction.SetDisclaimer(disclaimer))
if (disclaimer.isAccepted()) {
- nextHandler((scanResponse))
- } else scope.launch {
- delay(DELAY_SDK_DIALOG_CLOSE)
- disclaimerWillShow()
- dispatchOnMain(
- DisclaimerAction.Show(
- fromScreen = AppScreen.Home,
- callback = DisclaimerCallback(
- onAccept = {
- scope.launch(Dispatchers.Main) {
- nextHandler(scanResponse)
- }
- },
- onDismiss = {
- scope.launch(Dispatchers.Main) {
- onFailure(TangemSdkError.UserCancelled())
- }
- },
+ nextHandler(scanResponse)
+ } else {
+ scope.launch {
+ delay(DELAY_SDK_DIALOG_CLOSE)
+ disclaimerWillShow()
+ dispatchOnMain(
+ DisclaimerAction.Show(
+ fromScreen = AppScreen.Home,
+ callback = DisclaimerCallback(
+ onAccept = {
+ scope.launch(Dispatchers.Main) {
+ nextHandler(scanResponse)
+ }
+ },
+ onDismiss = {
+ scope.launch(Dispatchers.Main) {
+ onFailure(TangemSdkError.UserCancelled())
+ }
+ },
+ ),
),
- ),
- )
+ )
+ }
}
}
+ @Suppress("LongMethod", "MagicNumber")
private suspend inline fun onScanSuccess(
scanResponse: ScanResponse,
crossinline onProgressStateChange: suspend (showProgress: Boolean) -> Unit,
@@ -185,8 +188,8 @@ object ScanCardProcessor {
store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse))
- if (scanResponse.isSaltPay()) {
- if (scanResponse.isSaltPayVisa()) {
+ if (scanResponse.cardTypesResolver.isSaltPay()) {
+ if (scanResponse.cardTypesResolver.isSaltPayVisa()) {
val (manager, config) = OnboardingSaltPayState.initDependency(scanResponse)
val result = OnboardingSaltPayHelper.isOnboardingCase(scanResponse, manager)
delay(500)
diff --git a/app/src/main/java/com/tangem/tap/domain/statePrinter/OnboardingWalletStateConverter.kt b/app/src/main/java/com/tangem/tap/domain/statePrinter/OnboardingWalletStateConverter.kt
index 858dc8b5d1..3e98a50996 100644
--- a/app/src/main/java/com/tangem/tap/domain/statePrinter/OnboardingWalletStateConverter.kt
+++ b/app/src/main/java/com/tangem/tap/domain/statePrinter/OnboardingWalletStateConverter.kt
@@ -24,7 +24,7 @@ class OnboardingWalletStateConverter : StringStateConverter {
BackupStepAdapter(),
BigIntegerAdapter(),
- )
+ )
}
override fun convert(stateHolder: AppState): String {
@@ -56,6 +56,7 @@ class BackupStepAdapter {
}
}
+ @Suppress("MagicNumber")
@FromJson
fun fromJson(json: String): BackupStep {
return when (json) {
diff --git a/app/src/main/java/com/tangem/tap/domain/statePrinter/ScanResponseConverter.kt b/app/src/main/java/com/tangem/tap/domain/statePrinter/ScanResponseConverter.kt
index f8597dc48b..e59536ab1e 100644
--- a/app/src/main/java/com/tangem/tap/domain/statePrinter/ScanResponseConverter.kt
+++ b/app/src/main/java/com/tangem/tap/domain/statePrinter/ScanResponseConverter.kt
@@ -29,14 +29,12 @@ class ScanResponseConverter : StringStateConverter {
)
}
derivedKeysMap[keyWalletPubKey.bytes.toHexString()] = exPubKeysMap
-
}
scanResponseMap["derivedKeys"] = derivedKeysMap
val json = converter.prettyPrint(scanResponseMap)
return json
-
}
}
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt
index 140a0ef72d..5c39928f88 100644
--- a/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tasks/CreateWalletsTask.kt
@@ -13,9 +13,9 @@ import com.tangem.operations.wallet.CreateWalletTask
class CreateWalletsTask(curves: List? = null) : CardSessionRunnable {
private val curves = curves ?: listOf(
- EllipticCurve.Secp256k1,
- EllipticCurve.Ed25519,
- EllipticCurve.Secp256r1,
+ EllipticCurve.Secp256k1,
+ EllipticCurve.Ed25519,
+ EllipticCurve.Secp256r1,
)
private var index = 0
@@ -26,10 +26,10 @@ class CreateWalletsTask(curves: List? = null) : CardSessionRunnab
}
private fun createWallet(
- curve: EllipticCurve, session: CardSession,
+ curve: EllipticCurve,
+ session: CardSession,
callback: (result: CompletionResult) -> Unit
) {
-
CreateWalletTask(curve).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/DerivationTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/DerivationTask.kt
deleted file mode 100644
index 3c471f4bc4..0000000000
--- a/app/src/main/java/com/tangem/tap/domain/tasks/DerivationTask.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-//package com.tangem.tap.domain.tasks
-//
-//import com.tangem.common.CompletionResult
-//import com.tangem.common.core.CardSession
-//import com.tangem.common.core.CardSessionRunnable
-//import com.tangem.common.core.CompletionCallback
-//import com.tangem.common.hdWallet.DerivationPath
-//import com.tangem.common.hdWallet.ExtendedPublicKey
-//import com.tangem.operations.CommandResponse
-//import com.tangem.operations.derivation.DeriveWalletPublicKeysTask
-//import com.tangem.tap.common.extensions.ByteArrayKey
-//
-//class ExtendedPublicKeyList(
-// items: Collection
-//): ArrayList(items), CommandResponse
-//
-//
-//class DerivationTaskResponse(
-// val entries: Map
-//): CommandResponse
-//
-//class DerivationTask(
-// private val derivations: Map>
-//) : CardSessionRunnable {
-//
-// val response: MutableMap = mutableMapOf()
-//
-// override fun run(session: CardSession, callback: CompletionCallback) {
-// derive(keys = derivations.keys.toList(), index = 0, session = session, callback = callback)
-// }
-//
-// private fun derive(
-// keys: List,
-// index: Int,
-// session: CardSession,
-// callback: CompletionCallback
-// ) {
-// if (index == keys.count()) {
-// callback(CompletionResult.Success(DerivationTaskResponse(response.toMap())))
-// return
-// }
-//
-// val key = keys[index]
-// val paths = derivations[key]!!
-// DeriveWalletPublicKeysTask(key.bytes, paths).run(session) { result ->
-// when (result) {
-// is CompletionResult.Success -> {
-// response[key] = result.data[key]
-// derive(keys = keys, index = index + 1, session = session, callback = callback)
-// }
-// is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
-// }
-// }
-// }
-//}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt
index 58520125ce..3e5d37ac4b 100644
--- a/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tasks/SignHashTask.kt
@@ -34,4 +34,4 @@ class SignHashTask(
}
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt
index 98ce39259e..7bbd4d1811 100644
--- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt
@@ -13,10 +13,9 @@ import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.common.map
import com.tangem.domain.common.CardDTO
+import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.KeyWalletPublicKey
-import com.tangem.domain.common.ProductType
import com.tangem.domain.common.TapWorkarounds.derivationStyle
-import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.operations.CommandResponse
import com.tangem.operations.backup.PrimaryCard
@@ -56,7 +55,7 @@ private data class CreateWalletResponse(
}
class CreateProductWalletTask(
- private val type: ProductType,
+ private val cardTypesResolver: CardTypesResolver,
) : CardSessionRunnable {
override val allowsRequestAccessCodeFromRepository: Boolean = false
@@ -71,9 +70,10 @@ class CreateProductWalletTask(
}
val cardDto = CardDTO(card)
- val commandProcessor = when (type) {
- ProductType.Note -> CreateWalletTangemNote()
- ProductType.Twins -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
+ val commandProcessor = when {
+ cardTypesResolver.isTangemNote() -> CreateWalletTangemNote(cardTypesResolver)
+ cardTypesResolver.isTangemTwins() ->
+ throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
else -> CreateWalletTangemWallet()
}
commandProcessor.proceed(cardDto, session) {
@@ -95,7 +95,8 @@ class CreateProductWalletTask(
}
}
-private class CreateWalletTangemNote : ProductCommandProcessor {
+private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesResolver) :
+ ProductCommandProcessor {
override fun proceed(
card: CardDTO,
session: CardSession,
@@ -106,8 +107,8 @@ private class CreateWalletTangemNote : ProductCommandProcessor {
callback(
CompletionResult.Success(
- CreateProductWalletTaskResponse(card = session.environment.card!!)
- )
+ CreateProductWalletTaskResponse(card = session.environment.card!!),
+ ),
)
}
}
@@ -209,9 +210,10 @@ private class CreateWalletTangemWallet : ProductCommandProcessor()
override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
- if (curves.isEmpty()){
+ if (curves.isEmpty()) {
callback(CompletionResult.Failure(TangemSdkError.WalletIsNotCreated()))
return
}
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt
index 444a7b3971..398f369a54 100644
--- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ResetToFactorySettingsTask.kt
@@ -8,7 +8,7 @@ import com.tangem.common.extensions.guard
import com.tangem.operations.backup.ResetBackupCommand
import com.tangem.operations.wallet.PurgeWalletCommand
-class ResetToFactorySettingsTask() : CardSessionRunnable {
+class ResetToFactorySettingsTask : CardSessionRunnable {
override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) {
deleteWallets(session, callback)
@@ -18,7 +18,6 @@ class ResetToFactorySettingsTask() : CardSessionRunnable {
session: CardSession,
callback: (result: CompletionResult) -> Unit,
) {
-
val wallet = session.environment.card?.wallets?.lastOrNull().guard {
resetBackup(session, callback)
return
@@ -38,7 +37,6 @@ class ResetToFactorySettingsTask() : CardSessionRunnable {
session: CardSession,
callback: (result: CompletionResult) -> Unit,
) {
-
val backupStatus = session.environment.card?.backupStatus
if (backupStatus == null || backupStatus == Card.BackupStatus.NoBackup) {
callback(CompletionResult.Success(session.environment.card!!))
diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt
index b04226d1d6..6cbd5923e6 100644
--- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt
@@ -8,19 +8,23 @@ import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
+import com.tangem.common.deserialization.WalletDataDeserializer
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.guard
+import com.tangem.common.extensions.hexToBytes
+import com.tangem.common.extensions.toByteArray
import com.tangem.common.extensions.toHexString
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
+import com.tangem.common.tlv.Tlv
+import com.tangem.common.tlv.TlvDecoder
+import com.tangem.crypto.CryptoUtils
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ProductType
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isExcluded
import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease
import com.tangem.domain.common.TapWorkarounds.isSaltPay
-import com.tangem.domain.common.TapWorkarounds.isStart2Coin
-import com.tangem.domain.common.TapWorkarounds.isTangemNote
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.TwinsHelper
@@ -30,10 +34,11 @@ import com.tangem.operations.ScanTask
import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.backup.StartPrimaryCardLinkingTask
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
+import com.tangem.operations.files.ReadFilesTask
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.extensions.getPrimaryCurve
-import com.tangem.tap.domain.extensions.isMultiwalletAllowed
+import com.tangem.tap.domain.extensions.isFirmwareMultiwalletAllowed
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.preferencesStorage
@@ -66,7 +71,6 @@ class ScanProductTask(
}
val commandProcessor = when {
- cardDto.isTangemNote -> ScanNoteProcessor()
cardDto.isTangemTwins -> ScanTwinProcessor()
else -> ScanWalletProcessor(userTokensRepository, additionalBlockchainsToDerive)
}
@@ -97,24 +101,6 @@ class ScanProductTask(
}
}
-private class ScanNoteProcessor : ProductCommandProcessor {
- override fun proceed(
- card: CardDTO,
- session: CardSession,
- callback: (result: CompletionResult) -> Unit,
- ) {
- callback(
- CompletionResult.Success(
- ScanResponse(
- card = card,
- productType = ProductType.Note,
- walletData = session.environment.walletData,
- ),
- ),
- )
- }
-}
-
private class ScanWalletProcessor(
private val userTokensRepository: UserTokensRepository?,
private val additionalBlockchainsToDerive: Collection? = null,
@@ -126,15 +112,81 @@ private class ScanWalletProcessor(
session: CardSession,
callback: (result: CompletionResult) -> Unit,
) {
+ @Suppress("MagicNumber")
+ if (card.firmwareVersion.doubleValue >= 4.39 && card.settings.maxWalletsCount == 1) {
+ readFile(card, session, callback)
+ return
+ }
+
createMissingWalletsIfNeeded(card, session, callback)
}
+ private fun readFile(
+ card: CardDTO,
+ session: CardSession,
+ callback: (result: CompletionResult) -> Unit,
+ ) {
+ val funToContinue = { createMissingWalletsIfNeeded(card, session, callback) }
+
+ ReadFilesTask(fileName = "blockchainInfo", walletPublicKey = null).run(session) { result ->
+
+ when (result) {
+ is CompletionResult.Success -> {
+ val file = result.data.firstOrNull()
+ val counter = file?.counter
+ val signature = file?.signature
+
+ val tlv = file?.data?.let { Tlv.deserialize(it) }
+ val walletData = tlv?.let { WalletDataDeserializer.deserialize(TlvDecoder(tlv)) }
+
+ if (walletData == null || counter == null || signature == null) {
+ funToContinue()
+ return@run
+ }
+
+ val dataToVerify = card.cardId.hexToBytes() + file.data + counter.toByteArray()
+ val isVerified = CryptoUtils.verify(
+ publicKey = card.issuer.publicKey,
+ message = dataToVerify,
+ signature = signature,
+ )
+ if (!isVerified) {
+ funToContinue()
+ return@run
+ }
+
+ if (walletData.blockchain != "ANY") {
+ callback(
+ CompletionResult.Success(
+ ScanResponse(
+ card = card,
+ productType = ProductType.Note,
+ walletData = walletData,
+ ),
+ ),
+ )
+ } else {
+ funToContinue()
+ }
+ }
+ is CompletionResult.Failure -> {
+ when (result.error) {
+ is TangemSdkError.FileNotFound, is TangemSdkError.InsNotSupported -> {
+ funToContinue()
+ }
+ else -> callback(CompletionResult.Failure(result.error))
+ }
+ }
+ }
+ }
+ }
+
private fun createMissingWalletsIfNeeded(
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult) -> Unit,
) {
- if (card.wallets.isEmpty() || !card.isMultiwalletAllowed) {
+ if (card.wallets.isEmpty() || !card.isFirmwareMultiwalletAllowed) {
startLinkingForBackupIfNeeded(card, session, callback)
return
}
@@ -170,8 +222,9 @@ private class ScanWalletProcessor(
) {
val activationInProgress = preferencesStorage.usedCardsPrefStorage.isActivationInProgress(card.cardId)
- if ((card.backupStatus == CardDTO.BackupStatus.NoBackup && card.wallets.isNotEmpty())
- && (activationInProgress || card.isSaltPay)
+ @Suppress("ComplexCondition")
+ if (card.backupStatus == CardDTO.BackupStatus.NoBackup && card.wallets.isNotEmpty() &&
+ (activationInProgress || card.isSaltPay)
) {
StartPrimaryCardLinkingTask().run(session) { linkingResult ->
when (linkingResult) {
@@ -194,9 +247,8 @@ private class ScanWalletProcessor(
session: CardSession,
callback: (result: CompletionResult) -> Unit,
) {
- val productType = when {
- card.isSaltPay -> ProductType.SaltPay
- card.isStart2Coin -> ProductType.Start2Coin
+ val productType = when (card.isSaltPay) {
+ true -> ProductType.SaltPay
else -> ProductType.Wallet
}
scope.launch {
@@ -266,7 +318,12 @@ private class ScanWalletProcessor(
}
if (additionalBlockchainsToDerive != null) {
blockchainsToDerive.addAll(
- additionalBlockchainsToDerive.map { BlockchainNetwork(it, card) }
+ additionalBlockchainsToDerive.map {
+ BlockchainNetwork(
+ blockchain = it,
+ card = card,
+ )
+ },
)
}
if (!card.useOldStyleDerivation) {
@@ -277,7 +334,12 @@ private class ScanWalletProcessor(
Blockchain.RSK,
Blockchain.Fantom, Blockchain.FantomTestnet,
Blockchain.Avalanche, Blockchain.AvalancheTestnet,
- ).map { BlockchainNetwork(it, card) },
+ ).map {
+ BlockchainNetwork(
+ blockchain = it,
+ card = card,
+ )
+ },
)
}
return blockchainsToDerive.distinct()
@@ -307,6 +369,7 @@ private class ScanWalletProcessor(
}
}
+@Suppress("MagicNumber")
private class ScanTwinProcessor : ProductCommandProcessor {
override fun proceed(
card: CardDTO,
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt
index 0e18c4018d..c70127f7e2 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/Currency.kt
@@ -2,8 +2,8 @@ package com.tangem.tap.domain.tokens
import com.squareup.moshi.JsonClass
import com.tangem.blockchain.common.Blockchain
+import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.domain.common.extensions.fromNetworkId
-import com.tangem.datasource.api.tangemTech.CoinsResponse
@JsonClass(generateAdapter = true)
data class CurrencyFromJson(
@@ -26,7 +26,6 @@ data class CurrenciesFromJson(
val coins: List
)
-
fun List.toContracts(): List {
return mapNotNull { Contract.fromJsonObject(it) }
}
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt
index fbbaad9022..bc1f1dccc5 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/LoadAvailableCoinsService.kt
@@ -1,23 +1,23 @@
package com.tangem.tap.domain.tokens
import com.squareup.moshi.JsonAdapter
-import com.squareup.moshi.Moshi
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.services.Result
-import com.tangem.domain.common.extensions.getListOfCoins
-import com.tangem.domain.common.extensions.toNetworkId
-import com.tangem.datasource.api.tangemTech.CoinsResponse
-import com.tangem.datasource.api.tangemTech.TangemTechService
import com.tangem.datasource.api.common.MoshiConverter
-import com.tangem.tap.common.AssetReader
+import com.tangem.datasource.api.tangemTech.TangemTechApi
+import com.tangem.datasource.api.tangemTech.models.CoinsResponse
+import com.tangem.domain.common.extensions.toNetworkId
+import com.tangem.datasource.utils.AssetReader
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.withContext
class LoadAvailableCoinsService(
- private val networkService: TangemTechService,
+ private val tangemTechApi: TangemTechApi,
+ private val dispatchers: CoroutineDispatcherProvider,
private val assetReader: AssetReader,
) {
- private val moshi: Moshi by lazy { MoshiConverter.defaultMoshi() }
private val currenciesAdapter: JsonAdapter =
- moshi.adapter(CurrenciesFromJson::class.java)
+ MoshiConverter.networkMoshi.adapter(CurrenciesFromJson::class.java)
suspend fun getSupportedTokens(
isTestNet: Boolean = false,
@@ -43,7 +43,7 @@ class LoadAvailableCoinsService(
LoadedCoins(
currencies = data.coins.map { Currency.fromCoinResponse(it, data.imageHost) },
moreAvailable = data.total > offset + LOAD_PER_PAGE,
- )
+ ),
)
}
is Result.Failure -> {
@@ -55,16 +55,23 @@ class LoadAvailableCoinsService(
private suspend fun loadCoins(
supportedBlockchains: List,
offset: Int,
- searchInput: String? = null
+ searchInput: String? = null,
): Result {
- val networkIds = supportedBlockchains.toSet().map { it.toNetworkId() }
- return networkService.getListOfCoins(
- networkIds = networkIds,
- active = true,
- offset = offset,
- limit = LOAD_PER_PAGE,
- searchText = searchInput,
- )
+ return withContext(dispatchers.io) {
+ runCatching {
+ tangemTechApi.getCoins(
+ networkIds = supportedBlockchains.toSet().map(Blockchain::toNetworkId).joinToString(","),
+ active = true,
+ searchText = searchInput,
+ offset = offset,
+ limit = LOAD_PER_PAGE,
+ )
+ }
+ .onSuccess { return@withContext Result.Success(it) }
+ .onFailure { return@withContext Result.Failure(it) }
+
+ error("Unreachable code because runCatching must return result")
+ }
}
fun getTestnetCoins(): List {
@@ -88,7 +95,6 @@ class LoadAvailableCoinsService(
}
}
-
data class LoadedCoins(
val currencies: List,
val moreAvailable: Boolean,
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt
index 2aa1dce1a7..b9338e42a3 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/OldUserTokensRepository.kt
@@ -4,23 +4,23 @@ import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Types
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
-import com.tangem.common.services.Result
-import com.tangem.domain.common.extensions.getTokens
-import com.tangem.domain.common.extensions.toNetworkId
-import com.tangem.datasource.api.tangemTech.TangemTechService
import com.tangem.datasource.api.common.MoshiConverter
+import com.tangem.datasource.api.tangemTech.TangemTechApi
+import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.tap.common.FileReader
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.domain.tokens.models.TokenDao
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.async
-import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.withContext
@Deprecated("Use this only for migration")
class OldUserTokensRepository(
private val fileReader: FileReader,
- private val tangemNetworkService: TangemTechService,
+ private val tangemTechApi: TangemTechApi,
+ private val dispatchers: CoroutineDispatcherProvider,
) {
- private val moshi = MoshiConverter.defaultMoshi()
+ private val moshi = MoshiConverter.networkMoshi
private val blockchainsAdapter: JsonAdapter> = moshi.adapter(
Types.newParameterizedType(List::class.java, Blockchain::class.java),
)
@@ -83,7 +83,8 @@ class OldUserTokensRepository(
}
private suspend fun loadSavedCurrenciesOldWay(
- cardId: String, isHdWalletSupported: Boolean = false,
+ cardId: String,
+ isHdWalletSupported: Boolean = false,
): List {
val blockchains = loadSavedBlockchains(cardId)
val tokens = loadSavedTokens(cardId)
@@ -104,20 +105,27 @@ class OldUserTokensRepository(
return blockchainNetworks
}
- private suspend fun getTokensIds(tokens: List): Map = coroutineScope {
+ private suspend fun getTokensIds(tokens: List): Map = withContext(dispatchers.io) {
tokens.map {
async {
- tangemNetworkService.getTokens(
+ tangemTechApi.getCoins(
contractAddress = it.contractAddress,
- networkId = it.blockchainDao.toBlockchain().toNetworkId(),
+ networkIds = it.blockchainDao.toBlockchain().toNetworkId(),
active = true,
)
}
- }.map { it.await() }
- .map { (it as? Result.Success)?.data?.coins?.firstOrNull()?.id }
+ }
+ .map {
+ runCatching { it.await() }
+ .onSuccess { return@map it.coins.firstOrNull()?.id }
+ .onFailure { return@map null }
+
+ error("Unreachable code because runCatching must return result")
+ }
.mapIndexedNotNull { index, id ->
if (id == null) null else tokens[index].contractAddress to id
- }.toMap()
+ }
+ .toMap()
}
companion object {
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt
deleted file mode 100644
index 821a8046ac..0000000000
--- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensNetworkService.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.tangem.tap.domain.tokens
-
-import com.tangem.common.core.TangemSdkError
-import com.tangem.common.services.Result
-import com.tangem.datasource.api.tangemTech.TangemTechService
-import com.tangem.datasource.api.tangemTech.UserTokensResponse
-import com.tangem.tap.domain.NoDataError
-
-class UserTokensNetworkService(private val tangemTechService: TangemTechService) {
- suspend fun getUserTokens(userId: String): Result {
- return when (val result = tangemTechService.getUserTokens(userId)) {
- is Result.Success -> result
- is Result.Failure -> {
- val error = result.error
- if (error is TangemSdkError.NetworkError && error.customMessage.contains("404")) {
- return Result.Failure(NoDataError(error.customMessage))
- } else {
- return result
- }
- }
- }
- }
-
- suspend fun saveUserTokens(userId: String, tokens: UserTokensResponse): Result {
- return tangemTechService.putUserTokens(userId, tokens)
- }
-}
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt
index b3efb6ce5b..7d01846702 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt
@@ -2,108 +2,103 @@ package com.tangem.tap.domain.tokens
import android.content.Context
import com.tangem.blockchain.common.DerivationStyle
-import com.tangem.common.services.Result
+import com.tangem.common.core.TangemSdkError
+import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.TangemTechService
-import com.tangem.datasource.api.tangemTech.UserTokensResponse
+import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.domain.common.CardDTO
import com.tangem.tap.common.AndroidFileReader
-import com.tangem.tap.domain.NoDataError
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
+import com.tangem.tap.domain.tokens.converters.CurrencyConverter
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.models.toBlockchainNetworks
import com.tangem.tap.features.wallet.models.toCurrencies
import com.tangem.tap.network.NetworkConnectivity
-import com.tangem.tap.store
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
+import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.withContext
class UserTokensRepository(
private val storageService: UserTokensStorageService,
- private val networkService: UserTokensNetworkService,
+ private val tangemTechApi: TangemTechApi,
+ private val dispatchers: CoroutineDispatcherProvider,
) {
- suspend fun getUserTokens(card: CardDTO): List {
- val userId = getUserWalletId(card) ?: return emptyList()
+
+ // TODO("After adding DI") replace with CoroutineDispatcherProvider
+ suspend fun getUserTokens(card: CardDTO): List = withContext(dispatchers.io) {
+ val userId = getUserWalletId(card) ?: return@withContext emptyList()
if (DemoHelper.isDemoCardId(card.cardId)) {
- return loadTokensOffline(card, userId).ifEmpty { loadDemoCurrencies() }
+ return@withContext loadTokensOffline(card, userId).ifEmpty(::loadDemoCurrencies)
}
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
- return loadTokensOffline(card, userId)
+ return@withContext loadTokensOffline(card, userId)
}
- return when (val networkResult = networkService.getUserTokens(userId)) {
- is Result.Success -> {
- val tokens = networkResult.data.tokens.mapNotNull { Currency.fromTokenResponse(it) }
- storageService.saveUserTokens(userId, tokens.toUserTokensResponse())
- tokens.distinct()
+ runCatching { tangemTechApi.getUserTokens(userId) }
+ .onSuccess { response ->
+ return@withContext response.tokens
+ .mapNotNull(Currency.Companion::fromTokenResponse).also {
+ storageService.saveUserTokens(userId, it.toUserTokensResponse())
+ }
+ .distinct()
+ }
+ .onFailure {
+ return@withContext handleGetUserTokensFailure(card = card, userId = userId, error = it)
}
- is Result.Failure -> {
- handleGetUserTokensFailure(card = card, userId = userId, error = networkResult.error)
- }
- }
+ error("Unreachable code because runCatching must return result")
}
- suspend fun saveUserTokens(card: CardDTO, tokens: List) {
- val userId = getUserWalletId(card) ?: return
+ // TODO("After adding DI") replace with CoroutineDispatcherProvider
+ suspend fun saveUserTokens(card: CardDTO, tokens: List) = withContext(dispatchers.io) {
+ val userId = getUserWalletId(card) ?: return@withContext
val userTokens = tokens.toUserTokensResponse()
- networkService.saveUserTokens(userId, userTokens)
+ tangemTechApi.saveUserTokens(userId, userTokens)
storageService.saveUserTokens(userId, userTokens)
}
- suspend fun removeUserTokens(card: CardDTO) {
- val userId = getUserWalletId(card) ?: return
- val userTokens = emptyList().toUserTokensResponse()
- networkService.saveUserTokens(userId, userTokens)
- storageService.saveUserTokens(userId, userTokens)
- }
-
- private fun List.toUserTokensResponse(): UserTokensResponse {
- val tokensResponse = this.map { it.toTokenResponse() }
- return UserTokensResponse(
- tokens = tokensResponse,
- group = GROUP_DEFAULT_VALUE,
- sort = SORT_DEFAULT_VALUE,
- )
- }
-
- suspend fun loadBlockchainsToDerive(card: CardDTO): List {
- val userId = getUserWalletId(card) ?: return emptyList()
- val blockchainNetworks = loadTokensOffline(card, userId).toBlockchainNetworks()
+ suspend fun loadBlockchainsToDerive(card: CardDTO): List = withContext(dispatchers.io) {
+ val userId = getUserWalletId(card) ?: return@withContext emptyList()
+ val blockchainNetworks = loadTokensOffline(card = card, userId = userId).toBlockchainNetworks()
if (DemoHelper.isDemoCardId(card.cardId)) {
- return blockchainNetworks
- .ifEmpty { loadDemoCurrencies().toBlockchainNetworks() }
+ return@withContext blockchainNetworks.ifEmpty(loadDemoCurrencies()::toBlockchainNetworks)
}
- return blockchainNetworks
+ return@withContext blockchainNetworks
+ }
+
+ private suspend fun loadTokensOffline(card: CardDTO, userId: String): List {
+ return storageService.getUserTokens(userId) ?: storageService.getUserTokens(card)
}
private fun loadDemoCurrencies(): List {
- return DemoHelper.config.demoBlockchains.map {
- BlockchainNetwork(
- blockchain = it,
- derivationPath = it.derivationPath(DerivationStyle.LEGACY)?.rawPath,
- tokens = emptyList(),
- )
- }.flatMap { it.toCurrencies() }
+ return DemoHelper.config.demoBlockchains
+ .map { blockchain ->
+ BlockchainNetwork(
+ blockchain = blockchain,
+ derivationPath = blockchain.derivationPath(DerivationStyle.LEGACY)?.rawPath,
+ tokens = emptyList(),
+ )
+ }
+ .flatMap(BlockchainNetwork::toCurrencies)
}
- private suspend fun handleGetUserTokensFailure(
- card: CardDTO,
- userId: String,
- error: Throwable,
- ): List {
- return when (error) {
- is NoDataError -> {
- val tokens = storageService.getUserTokens(card)
- val userTokens = tokens.toUserTokensResponse()
- coroutineScope { launch { networkService.saveUserTokens(userId = userId, tokens = userTokens) } }
- tokens
- }
+ private fun List.toUserTokensResponse() = UserTokensResponse(
+ tokens = CurrencyConverter.convertList(this),
+ group = GROUP_DEFAULT_VALUE,
+ sort = SORT_DEFAULT_VALUE,
+ )
+ private suspend fun handleGetUserTokensFailure(card: CardDTO, userId: String, error: Throwable): List {
+ return when {
+ error is TangemSdkError.NetworkError && error.customMessage.contains(NOT_FOUND_HTTP_CODE) ->
+ storageService.getUserTokens(card).also {
+ tangemTechApi.saveUserTokens(userId = userId, userTokens = it.toUserTokensResponse())
+ }
else -> {
val tokens = storageService.getUserTokens(userId) ?: storageService.getUserTokens(card)
tokens.distinct()
@@ -111,26 +106,36 @@ class UserTokensRepository(
}
}
- private suspend fun loadTokensOffline(card: CardDTO, userId: String): List {
- return storageService.getUserTokens(userId) ?: storageService.getUserTokens(card)
- }
-
private fun getUserWalletId(card: CardDTO): String? {
return UserWalletIdBuilder.card(card).build()
?.stringValue
}
companion object {
- const val SORT_DEFAULT_VALUE = "manual"
- const val GROUP_DEFAULT_VALUE = "none"
+ private const val GROUP_DEFAULT_VALUE = "none"
+ private const val SORT_DEFAULT_VALUE = "manual"
+ private const val NOT_FOUND_HTTP_CODE = "404"
+
+ // TODO("After adding DI") get dependencies by DI
fun init(context: Context, tangemTechService: TangemTechService): UserTokensRepository {
val fileReader = AndroidFileReader(context)
+ val dispatchers = AppCoroutineDispatcherProvider()
+
val oldUserTokensRepository = OldUserTokensRepository(
- fileReader, store.state.domainNetworks.tangemTechService,
+ fileReader = fileReader,
+ tangemTechApi = tangemTechService.api,
+ dispatchers = dispatchers,
+ )
+ val storageService = UserTokensStorageService(
+ oldUserTokensRepository = oldUserTokensRepository,
+ fileReader = fileReader,
+ )
+
+ return UserTokensRepository(
+ storageService = storageService,
+ tangemTechApi = tangemTechService.api,
+ dispatchers = dispatchers,
)
- val storageService = UserTokensStorageService(oldUserTokensRepository, fileReader)
- val networkService = UserTokensNetworkService(tangemTechService)
- return UserTokensRepository(storageService, networkService)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt
index 9e5dac0b68..9df51fb6f4 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt
@@ -2,8 +2,8 @@ package com.tangem.tap.domain.tokens
import com.squareup.moshi.JsonAdapter
import com.tangem.Log
-import com.tangem.datasource.api.tangemTech.UserTokensResponse
import com.tangem.datasource.api.common.MoshiConverter
+import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.domain.common.CardDTO
import com.tangem.tap.common.FileReader
import com.tangem.tap.features.wallet.models.Currency
@@ -13,9 +13,8 @@ class UserTokensStorageService(
private val oldUserTokensRepository: OldUserTokensRepository,
private val fileReader: FileReader,
) {
- private val moshi = MoshiConverter.defaultMoshi()
private val userTokensAdapter: JsonAdapter =
- moshi.adapter(UserTokensResponse::class.java)
+ MoshiConverter.networkMoshi.adapter(UserTokensResponse::class.java)
fun getUserTokens(userId: String): List? {
return try {
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt b/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt
new file mode 100644
index 0000000000..3ac6babc72
--- /dev/null
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/converters/CurrencyConverter.kt
@@ -0,0 +1,20 @@
+package com.tangem.tap.domain.tokens.converters
+
+import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
+import com.tangem.domain.common.extensions.toNetworkId
+import com.tangem.tap.features.wallet.models.Currency
+import com.tangem.utils.converter.Converter
+
+/** Converter from domain model [Currency] to data model [UserTokensResponse.Token] */
+object CurrencyConverter : Converter {
+
+ override fun convert(value: Currency) = UserTokensResponse.Token(
+ id = value.coinId,
+ networkId = value.blockchain.toNetworkId(),
+ derivationPath = value.derivationPath,
+ name = value.currencyName,
+ symbol = value.currencySymbol,
+ decimals = value.decimals,
+ contractAddress = if (value is Currency.Token) value.token.contractAddress else null
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainDao.kt b/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainDao.kt
index 73eef228ad..4417004531 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainDao.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainDao.kt
@@ -10,14 +10,13 @@ data class BlockchainDao(
@Json(name = "key")
val name: String,
@Json(name = "testnet")
- val isTestNet: Boolean
+ val isTestNet: Boolean,
) {
@Deprecated("The method is used only for migration from older versions of the app")
fun toBlockchain(): Blockchain {
val blockchain = Blockchain.values().find { it.name.lowercase() == name.lowercase() }
- ?: throw Exception("Invalid BlockchainDao")
- return if (!isTestNet) blockchain else blockchain.getTestnetVersion()
- ?: throw Exception("Invalid BlockchainDao")
+ ?: error("Blockchain is null")
+ return if (!isTestNet) blockchain else blockchain.getTestnetVersion() ?: error("Invalid BlockchainDao")
}
companion object {
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainNetwork.kt b/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainNetwork.kt
index 3b9558c303..8abb99b14d 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainNetwork.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/models/BlockchainNetwork.kt
@@ -12,15 +12,16 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle
data class BlockchainNetwork(
val blockchain: Blockchain,
val derivationPath: String?,
- val tokens: List
+ val tokens: List,
) {
- constructor(
- blockchain: Blockchain,
- card: CardDTO,
- ) : this(
+ constructor(blockchain: Blockchain, card: CardDTO) : this(
blockchain = blockchain,
- derivationPath = if (card.settings.isHDWalletAllowed) blockchain.derivationPath(card.derivationStyle)?.rawPath else null,
+ derivationPath = if (card.settings.isHDWalletAllowed) {
+ blockchain.derivationPath(card.derivationStyle)?.rawPath
+ } else {
+ null
+ },
tokens = emptyList(),
)
@@ -43,7 +44,8 @@ data class BlockchainNetwork(
}
override fun hashCode(): Int = calculateHashCode(
- blockchain.hashCode(), derivationPath?.hashCode() ?: 0
+ blockchain.hashCode(),
+ derivationPath?.hashCode() ?: 0,
)
companion object {
@@ -51,7 +53,7 @@ data class BlockchainNetwork(
return BlockchainNetwork(
walletManager.wallet.blockchain,
walletManager.wallet.publicKey.derivationPath?.rawPath,
- walletManager.cardTokens.toList()
+ walletManager.cardTokens.toList(),
)
}
}
diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt b/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt
index a8a717b1ce..ef6f541f6e 100644
--- a/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt
+++ b/app/src/main/java/com/tangem/tap/domain/tokens/models/TokenDao.kt
@@ -26,5 +26,4 @@ data class TokenDao(
customIconUrl?.let { this.setCustomIconUrl(it) }
}
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt
index faa4628b9b..b0224afdac 100644
--- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt
+++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt
@@ -47,10 +47,10 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator {
is WalletDataModel.VerifiedOnline,
is WalletDataModel.SameCurrencyTransactionInProgress,
is WalletDataModel.TransactionInProgress,
- is WalletDataModel.NoAccount,
- -> {
- if (walletData.fiatRate == null) TotalFiatBalanceStatus.Error
- else TotalFiatBalanceStatus.Loaded
+ is WalletDataModel.NoAccount -> if (walletData.fiatRate == null) {
+ TotalFiatBalanceStatus.Error
+ } else {
+ TotalFiatBalanceStatus.Loaded
}
is WalletDataModel.Unreachable,
is WalletDataModel.MissedDerivation,
diff --git a/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt
index d4e00cb3fe..b173602e3d 100644
--- a/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt
@@ -10,7 +10,8 @@ import com.tangem.operations.PreflightReadTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
class FinalizeTwinTask(
- private val twinPublicKey: ByteArray, private val issuerKeys: KeyPair,
+ private val twinPublicKey: ByteArray,
+ private val issuerKeys: KeyPair,
) : CardSessionRunnable {
override val allowsRequestAccessCodeFromRepository: Boolean = false
diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt
index b910fcb589..8e2cea35fa 100644
--- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt
@@ -12,7 +12,7 @@ import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.operations.wallet.CreateWalletResponse
-import com.tangem.tap.common.AssetReader
+import com.tangem.datasource.utils.AssetReader
import com.tangem.tap.tangemSdkManager
class TwinCardsManager(
@@ -83,7 +83,7 @@ class TwinCardsManager(
}
private fun getAdapter(): JsonAdapter> {
- return MoshiConverter.defaultMoshi().adapter(
+ return MoshiConverter.sdkMoshi.adapter(
Types.newParameterizedType(List::class.java, Issuer::class.java),
)
}
diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt
index 36d3b037ff..95d1d76fdd 100644
--- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt
+++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsWidget.kt
@@ -11,14 +11,13 @@ import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapView
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapViewState
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
-
/**
[REDACTED_AUTHOR]
*/
class TwinsCardWidget(
val leapfrogWidget: LeapfrogWidget,
private val deviceScaleFactor: Float = 1f,
- val getTopOfAnchorViewForActivateState: () -> Float
+ val getTopOfAnchorViewForActivateState: () -> Float,
) {
var state: TwinCardsWidgetState? = null
@@ -37,7 +36,7 @@ class TwinsCardWidget(
val animator = createAnimator(animate)
animator.playTogether(
createAnimator(TwinCardNumber.First, createWelcomeProperties(TwinCardNumber.First)),
- createAnimator(TwinCardNumber.Second, createWelcomeProperties(TwinCardNumber.Second))
+ createAnimator(TwinCardNumber.Second, createWelcomeProperties(TwinCardNumber.Second)),
)
animator.doOnEnd { onEnd() }
leapfrogWidget.fold(animate) { animator.start() }
@@ -50,7 +49,7 @@ class TwinsCardWidget(
val animator = createAnimator(animate)
animator.playTogether(
createAnimator(TwinCardNumber.First, createLeapfrogProperties(TwinCardNumber.First)),
- createAnimator(TwinCardNumber.Second, createLeapfrogProperties(TwinCardNumber.Second))
+ createAnimator(TwinCardNumber.Second, createLeapfrogProperties(TwinCardNumber.Second)),
)
animator.doOnEnd {
leapfrogWidget.initViews()
@@ -66,7 +65,7 @@ class TwinsCardWidget(
val animator = createAnimator(animate)
animator.playTogether(
createAnimator(TwinCardNumber.First, createActivateProperties(TwinCardNumber.First)),
- createAnimator(TwinCardNumber.Second, createActivateProperties(TwinCardNumber.Second))
+ createAnimator(TwinCardNumber.Second, createActivateProperties(TwinCardNumber.Second)),
)
animator.doOnEnd { onEnd() }
animator.start()
@@ -85,6 +84,7 @@ class TwinsCardWidget(
return animator
}
+ @Suppress("MagicNumber")
private fun createWelcomeProperties(cardNumber: TwinCardNumber): TwinsCardProperties {
return when (cardNumber) {
TwinCardNumber.First -> {
@@ -118,6 +118,7 @@ class TwinsCardWidget(
)
}
+ @Suppress("MagicNumber")
private fun createActivateProperties(cardNumber: TwinCardNumber): TwinsCardProperties {
val topOfAnchorView = getTopOfAnchorViewForActivateState()
val twinProperties = TwinsCardProperties.from(getLeapViewByCardNumber(cardNumber).state)
diff --git a/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt
index 31d35c4a06..2a415c6eda 100644
--- a/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt
+++ b/app/src/main/java/com/tangem/tap/domain/twins/WriteProtectedIssuerDataTask.kt
@@ -15,7 +15,8 @@ import com.tangem.operations.issuerAndUserData.WriteIssuerDataCommand
import com.tangem.operations.sign.SignHashCommand
class WriteProtectedIssuerDataTask(
- private val twinPublicKey: ByteArray, private val issuerKeys: KeyPair,
+ private val twinPublicKey: ByteArray,
+ private val issuerKeys: KeyPair,
) : CardSessionRunnable {
override fun run(
@@ -33,12 +34,19 @@ class WriteProtectedIssuerDataTask(
when (readResult) {
is CompletionResult.Success -> {
writeIssuerData(
- twinPublicKey, issuerKeys, signResult.data.signature,
- readResult.data, session, callback
+ twinPublicKey,
+ issuerKeys,
+ signResult.data.signature,
+ readResult.data,
+ session,
+ callback,
)
}
- is CompletionResult.Failure -> callback(CompletionResult.Failure(
- readResult.error))
+ is CompletionResult.Failure -> callback(
+ CompletionResult.Failure(
+ readResult.error,
+ ),
+ )
}
}
}
@@ -47,8 +55,11 @@ class WriteProtectedIssuerDataTask(
}
}
+ @Suppress("LongParameterList")
private fun writeIssuerData(
- twinPublicKey: ByteArray, issuerKeys: KeyPair, cardSignature: ByteArray,
+ twinPublicKey: ByteArray,
+ issuerKeys: KeyPair,
+ cardSignature: ByteArray,
readResponse: ReadIssuerDataResponse,
session: CardSession,
callback: (
diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt
index 9e7619e7c5..91d3b8dd91 100644
--- a/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/UserWalletsListManager.kt
@@ -6,25 +6,71 @@ import com.tangem.tap.domain.model.UserWallet
import kotlinx.coroutines.flow.Flow
interface UserWalletsListManager {
+ /**
+ * [Flow] with all saved [UserWallet]s updates
+ * */
val userWallets: Flow>
+
+ /**
+ * [Flow] with selected [UserWallet] updates
+ * */
val selectedUserWallet: Flow
+
+ /**
+ * Selected [UserWallet]
+ * */
val selectedUserWalletSync: UserWallet?
+
+ /**
+ * Indicates that all [UserWallet]s is unlocked
+ *
+ * @see [isLockedSync]
+ * @see [UserWallet.isLocked]
+ * */
val isLocked: Flow
+
+ /**
+ * Indicates that all [UserWallet]s is unlocked
+ *
+ * Sync version
+ *
+ * @see [isLocked]
+ * @see [UserWallet.isLocked]
+ * */
val isLockedSync: Boolean
+
val hasSavedUserWallets: Boolean
+ /**
+ * Receive saved [UserWallet]s, populate [userWallets] flow with it and set [isLocked] as false.
+ * Require biometric user authorization
+ *
+ * @return [CompletionResult] of operation, with selected [UserWallet]
+ * or null if there is no selected [UserWallet]
+ * */
suspend fun unlockWithBiometry(): CompletionResult
+
+ /**
+ * Remove [UserWallet]s from [userWallets] and set [isLocked] as true
+ * */
fun lock()
+ /**
+ * Set [UserWallet] with provided [UserWalletId] as selected
+ *
+ * @param userWalletId [UserWalletId] of [UserWallet] which must be selected
+ *
+ * @return [CompletionResult] of operation with selected [UserWallet]
+ * */
suspend fun selectWallet(userWalletId: UserWalletId): CompletionResult
/**
* Save provided user wallet and set it as selected
* @param userWallet [UserWallet] to save
- * @param canOverride If false, then terminate with [UserWalletListError.WalletAlreadySaved] when user tries to save an
- * already saved card
+ * @param canOverride If false, then terminate with [UserWalletListError.WalletAlreadySaved] when user tries
+ * to save an already saved card
* @return [CompletionResult] of operation
- * */
+ */
suspend fun save(userWallet: UserWallet, canOverride: Boolean = false): CompletionResult
/**
@@ -38,10 +84,30 @@ interface UserWalletsListManager {
* */
suspend fun update(userWalletId: UserWalletId, update: (UserWallet) -> UserWallet): CompletionResult
+ /**
+ * Delete saved [UserWallet]s with provided [UserWalletId]s
+ *
+ * @param userWalletIds [UserWalletId]s of [UserWallet]s which must be deleted
+ *
+ * @return [CompletionResult] of operation
+ * */
suspend fun delete(userWalletIds: List): CompletionResult
+
+ /**
+ * Clear all saved [UserWallet]s and set [isLocked] as true
+ *
+ * @return [CompletionResult] of operation
+ * */
suspend fun clear(): CompletionResult
+ /**
+ * Get [UserWallet] with provided [UserWalletId]
+ * May terminate with [NoSuchElementException] if [UserWallet] is not found
+ *
+ * @return [CompletionResult] of operation with found [UserWallet]
+ * */
suspend fun get(userWalletId: UserWalletId): CompletionResult
+ // For provider
companion object
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt
index db1db2ebbd..748665ccea 100644
--- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt
@@ -59,12 +59,7 @@ internal class BiometricUserWalletsListManager(
}
override fun lock() {
- state.update { prevState ->
- prevState.copy(
- encryptionKeys = emptyList(),
- isLocked = true,
- )
- }
+ state.update { State() }
}
override suspend fun selectWallet(userWalletId: UserWalletId): CompletionResult = catching {
@@ -143,7 +138,7 @@ internal class BiometricUserWalletsListManager(
.flatMap { keysRepository.clear() }
.map {
selectedUserWalletRepository.set(null)
- state.update { State() }
+ lock()
}
}
@@ -219,13 +214,18 @@ internal class BiometricUserWalletsListManager(
private suspend fun loadModels(): CompletionResult {
return getSavedUserWallets()
.map { userWallets ->
- if (userWallets.isNotEmpty()) state.update { prevState ->
- val wallets = (userWallets + prevState.userWallets).distinctBy { it.walletId }
+ if (userWallets.isNotEmpty()) {
+ state.update { prevState ->
+ val wallets = (userWallets + prevState.userWallets).distinctBy { it.walletId }
- prevState.copy(
- userWallets = wallets,
- selectedUserWalletId = findOrSetSelectedUserWalletId(prevState.selectedUserWalletId, wallets),
- )
+ prevState.copy(
+ userWallets = wallets,
+ selectedUserWalletId = findOrSetSelectedUserWalletId(
+ prevSelectedWalletId = prevState.selectedUserWalletId,
+ userWallets = wallets,
+ ),
+ )
+ }
}
}
.doOnFailure { error ->
diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt
index 11e558535d..5f72d40ab7 100644
--- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt
+++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/BiometricUserWalletsKeysRepository.kt
@@ -134,7 +134,7 @@ internal class BiometricUserWalletsKeysRepository(
}
private suspend fun deleteUserWalletsIds(userWalletsIds: List) {
- val remainingIds = (getUserWalletsIds() - userWalletsIds.toSet())
+ val remainingIds = getUserWalletsIds() - userWalletsIds.toSet()
withContext(Dispatchers.IO) {
secureStorage.store(remainingIds.encode(), StorageKey.UserWalletIds.name)
diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt
index 673ec51a10..8d1fdddb9f 100644
--- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt
+++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/implementation/DefaultUserWalletsSensitiveInformationRepository.kt
@@ -15,7 +15,6 @@ import com.tangem.tap.domain.userWalletList.UserWalletListError
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
import com.tangem.tap.domain.userWalletList.repository.UserWalletsSensitiveInformationRepository
-import com.tangem.tap.domain.userWalletList.utils.encryptionKey
import com.tangem.tap.domain.userWalletList.utils.sensitiveInformation
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -180,7 +179,7 @@ internal class DefaultUserWalletsSensitiveInformationRepository(
}
class SensitiveInformationIv(userWalletId: String) : StorageKey {
- override val name: String = "user_wallet_sensitive_information_iv_${userWalletId}"
+ override val name: String = "user_wallet_sensitive_information_iv_$userWalletId"
}
}
diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt
index fb77a29584..2738438ac1 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/WalletCurrenciesManager.kt
@@ -5,25 +5,70 @@ import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.features.wallet.models.Currency
interface WalletCurrenciesManager {
+ /**
+ * Update [UserWallet] currencies with same blockchain as provided [Currency] blockchain
+ * [UserWallet] currencies updates can be observed
+ * with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
+ * or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
+ *
+ * @param userWallet [UserWallet] which currencies will be updated
+ * @param currency [Currency] to find other currencies to update
+ *
+ * @return [CompletionResult] of operation
+ * */
suspend fun update(
userWallet: UserWallet,
currency: Currency,
): CompletionResult
+ /**
+ * Add list of [Currency] to [UserWallet].
+ * [UserWallet] currencies updates can be observed
+ * with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
+ * or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
+ *
+ * @param userWallet [UserWallet] to add currencies
+ * @param currenciesToAdd list of [Currency] to add [UserWallet]
+ *
+ * @return [CompletionResult] of operation
+ * */
suspend fun addCurrencies(
userWallet: UserWallet,
currenciesToAdd: List,
): CompletionResult
+ /**
+ * Remove [Currency] from [UserWallet]
+ * [UserWallet] currencies updates can be observed
+ * with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
+ * or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
+ *
+ * @param userWallet [UserWallet] which currency will be removed
+ * @param currencyToRemove [Currency] to remove from [UserWallet]
+ *
+ * @return [CompletionResult] of operation
+ * */
suspend fun removeCurrency(
userWallet: UserWallet,
currencyToRemove: Currency,
): CompletionResult
+ /**
+ * Remove list of [Currency] from [UserWallet]
+ * [UserWallet] currencies updates can be observed
+ * with [com.tangem.tap.domain.walletStores.WalletStoresManager.getAll]
+ * or [com.tangem.tap.domain.walletStores.WalletStoresManager.get]
+ *
+ * @param userWallet [UserWallet] which currency will be removed
+ * @param currenciesToRemove list of [Currency] to remove from [UserWallet]
+ *
+ * @return [CompletionResult] of operation
+ * */
suspend fun removeCurrencies(
userWallet: UserWallet,
currenciesToRemove: List,
): CompletionResult
+ // For provider
companion object
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt
index 2b5a565f7e..25e54b765d 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt
@@ -37,8 +37,8 @@ internal class DefaultWalletCurrenciesManager(
): CompletionResult = withContext(Dispatchers.Default) {
val walletStore = walletStoresRepository.getSync(userWallet.walletId)
.find {
- it.blockchain == currency.blockchain
- && it.derivationPath?.rawPath == currency.derivationPath
+ it.blockchain == currency.blockchain &&
+ it.derivationPath?.rawPath == currency.derivationPath
}
if (walletStore != null) {
diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt
index de8c07b6d2..826c158a8b 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresError.kt
@@ -11,6 +11,7 @@ sealed class WalletStoresError(code: Int) : TangemError(code) {
override val message: String?
get() = customMessage
+ @Suppress("MagicNumber")
class FetchFiatRatesError(
currencies: List,
override val cause: Throwable?,
@@ -18,18 +19,22 @@ sealed class WalletStoresError(code: Int) : TangemError(code) {
override var customMessage: String = "Failed to fetch fiat rates for currencies $currencies"
}
+ @Suppress("MagicNumber")
class UnknownBlockchain : WalletStoresError(60012) {
override var customMessage: String = "Unknown blockchain"
}
+ @Suppress("MagicNumber")
object NoInternetConnection : WalletStoresError(60013) {
override var customMessage: String = "No internet connection"
}
+ @Suppress("MagicNumber")
class WalletManagerNotCreated(blockchain: Blockchain) : WalletStoresError(60014) {
override var customMessage: String = "Wallet manager can not be created for $blockchain"
}
+ @Suppress("MagicNumber")
class UpdateWalletManagerError(
blockchain: Blockchain,
override val cause: Throwable,
diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt
index f1fdaff7aa..e4bebc2c07 100644
--- a/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt
+++ b/app/src/main/java/com/tangem/tap/domain/walletStores/WalletStoresManager.kt
@@ -7,26 +7,78 @@ import com.tangem.tap.domain.model.WalletStoreModel
import kotlinx.coroutines.flow.Flow
interface WalletStoresManager {
+ /**
+ * Get all [WalletStoreModel]s updates
+ *
+ * @return [Flow] with map of [WalletStoreModel] list assigned by [UserWalletId]
+ * */
fun getAll(): Flow