diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5e5e70656a..570f9e96e3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -35,6 +35,8 @@ dependencies { implementation(projects.domain.txhistory) implementation(projects.domain.appCurrency) implementation(projects.domain.appCurrency.models) + implementation(projects.domain.appTheme) + implementation(projects.domain.appTheme.models) implementation(project(":common")) implementation(project(":core:analytics")) @@ -48,13 +50,15 @@ dependencies { implementation(project(":libs:crypto")) implementation(project(":libs:auth")) - implementation(project(":data:source:preferences")) + implementation(projects.data.appCurrency) + implementation(projects.data.appTheme) implementation(projects.data.card) implementation(projects.data.common) implementation(projects.data.settings) + implementation(projects.data.source.preferences) implementation(projects.data.tokens) implementation(projects.data.txhistory) - implementation(projects.data.appCurrency) + implementation(projects.data.wallets) /** Features */ implementation(project(":features:onboarding")) @@ -86,6 +90,7 @@ dependencies { implementation(deps.lifecycle.runtime.ktx) implementation(deps.lifecycle.common.java8) implementation(deps.lifecycle.viewModel.ktx) + implementation(deps.lifecycle.compose) /** Compose libraries */ implementation(deps.compose.constraintLayout) diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 28cd0f57de..65bbb228d0 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -26,6 +26,7 @@ import com.tangem.domain.DomainLayer import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.common.LogConfig +import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.WalletManagersRepository import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles @@ -42,6 +43,7 @@ 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.log.TimberFormatStrategy import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction @@ -165,6 +167,9 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var appCurrencyRepository: AppCurrencyRepository + @Inject + lateinit var walletManagersFacade: WalletManagersFacade + override fun onCreate() { super.onCreate() @@ -184,12 +189,13 @@ class TapApplication : Application(), ImageLoaderFactory { tokenDetailsFeatureToggles = tokenDetailsFeatureToggles, scanCardProcessor = scanCardProcessor, appCurrencyRepository = appCurrencyRepository, + walletManagersFacade = walletManagersFacade, ), ), ) if (BuildConfig.DEBUG) { - Logger.addLogAdapter(AndroidLogAdapter()) + Logger.addLogAdapter(AndroidLogAdapter(TimberFormatStrategy())) Timber.plant( object : Timber.DebugTree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { diff --git a/app/src/main/java/com/tangem/tap/common/apptheme/MutableAppThemeModeHolder.kt b/app/src/main/java/com/tangem/tap/common/apptheme/MutableAppThemeModeHolder.kt new file mode 100644 index 0000000000..c1b0f942c5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/apptheme/MutableAppThemeModeHolder.kt @@ -0,0 +1,17 @@ +package com.tangem.tap.common.apptheme + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import com.tangem.core.ui.theme.AppThemeModeHolder +import com.tangem.domain.apptheme.model.AppThemeMode + +internal object MutableAppThemeModeHolder : AppThemeModeHolder { + + override val appThemeMode: MutableState = mutableStateOf(AppThemeMode.DEFAULT) + + var value: AppThemeMode + set(value) { + appThemeMode.value = value + } + get() = appThemeMode.value +} \ No newline at end of file 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 6665cab485..1533313216 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 @@ -82,7 +82,7 @@ fun WalletManager?.getAddressData(): WalletDataModel.AddressData? { } fun WalletManager.Companion.stub(): T { - val wallet = Wallet(Blockchain.Unknown, setOf(), Wallet.PublicKey(byteArrayOf(), null, null), setOf()) + val wallet = Wallet(Blockchain.Unknown, setOf(), Wallet.PublicKey(byteArrayOf(), null), setOf()) return object : WalletManager(wallet) { override val currentHost: String = "" override suspend fun update() {} diff --git a/app/src/main/java/com/tangem/tap/common/log/TimberFormatStrategy.kt b/app/src/main/java/com/tangem/tap/common/log/TimberFormatStrategy.kt new file mode 100644 index 0000000000..0a43f525d4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/log/TimberFormatStrategy.kt @@ -0,0 +1,63 @@ +package com.tangem.tap.common.log + +import com.orhanobut.logger.FormatStrategy +import com.orhanobut.logger.LogStrategy +import com.orhanobut.logger.LogcatLogStrategy + +class TimberFormatStrategy : FormatStrategy { + + private val logStrategy: LogStrategy = LogcatLogStrategy() + + override fun log(priority: Int, tag: String?, message: String) { + logTopBorder(priority, tag) + val bytes = message.toByteArray() + val length = bytes.size + if (length <= CHUNK_SIZE) { + logContent(priority, tag, message) + logBottomBorder(priority, tag) + return + } + var i = 0 + while (i < length) { + val count = (length - i).coerceAtMost(CHUNK_SIZE) + // create a new String with system's default charset (which is UTF-8 for Android) + logContent(priority, tag, String(bytes, i, count)) + i += CHUNK_SIZE + } + logBottomBorder(priority, tag) + } + + private fun logTopBorder(logType: Int, tag: String?) { + logChunk(logType, tag, TOP_BORDER) + } + + private fun logBottomBorder(logType: Int, tag: String?) { + logChunk(logType, tag, BOTTOM_BORDER) + } + + private fun logContent(logType: Int, tag: String?, chunk: String) { + chunk.split(System.lineSeparator()).forEach { line -> + logChunk(logType, tag, "$HORIZONTAL_LINE $line") + } + } + + private fun logChunk(priority: Int, tag: String?, chunk: String) { + logStrategy.log(priority, tag, chunk) + } + + private companion object { + /** + * Android's max limit for a log entry is ~4076 bytes, + * so 4000 bytes is used as chunk size since default charset + * is UTF-8 + */ + private const val CHUNK_SIZE = 4000 + + const val TOP_LEFT_CORNER = "┌" + const val BOTTOM_LEFT_CORNER = "└" + const val HORIZONTAL_LINE = "│" + const val DOUBLE_DIVIDER = "────────────────────────────────────────────────────────" + const val TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER + const val BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/AppStateHolderModule.kt b/app/src/main/java/com/tangem/tap/di/AppStateHolderModule.kt index 05cc610f95..5016fe7d2e 100644 --- a/app/src/main/java/com/tangem/tap/di/AppStateHolderModule.kt +++ b/app/src/main/java/com/tangem/tap/di/AppStateHolderModule.kt @@ -1,6 +1,7 @@ package com.tangem.tap.di import com.tangem.core.navigation.NavigationStateHolder +import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.wallets.legacy.WalletsStateHolder import com.tangem.tap.proxy.AppStateHolder import dagger.Binds @@ -20,4 +21,8 @@ internal interface AppStateHolderModule { @Binds @Singleton fun bindsNavigationStateHolder(appStateHolder: AppStateHolder): NavigationStateHolder + + @Binds + @Singleton + fun bindsReduxStateHolder(appStateHolder: AppStateHolder): ReduxStateHolder } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/ThemeModule.kt b/app/src/main/java/com/tangem/tap/di/ThemeModule.kt new file mode 100644 index 0000000000..af2732b2d9 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/di/ThemeModule.kt @@ -0,0 +1,18 @@ +package com.tangem.tap.di + +import com.tangem.core.ui.theme.AppThemeModeHolder +import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent + +@Module +@InstallIn(ActivityComponent::class) +internal object ThemeModule { + + @Provides + fun provideAppThemeModeHolder(): AppThemeModeHolder { + return MutableAppThemeModeHolder + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/domain/AppThemeDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/AppThemeDomainModule.kt new file mode 100644 index 0000000000..b4378101b0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/di/domain/AppThemeDomainModule.kt @@ -0,0 +1,24 @@ +package com.tangem.tap.di.domain + +import com.tangem.domain.apptheme.ChangeAppThemeModeUseCase +import com.tangem.domain.apptheme.GetAppThemeModeUseCase +import com.tangem.domain.apptheme.repository.AppThemeModeRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ViewModelComponent + +@Module +@InstallIn(ViewModelComponent::class) +internal object AppThemeDomainModule { + + @Provides + fun provideGetAppThemeModeUpdatesUseCase(appThemeModeRepository: AppThemeModeRepository): GetAppThemeModeUseCase { + return GetAppThemeModeUseCase(appThemeModeRepository) + } + + @Provides + fun provideChangeAppThemeModeUseCase(appThemeModeRepository: AppThemeModeRepository): ChangeAppThemeModeUseCase { + return ChangeAppThemeModeUseCase(appThemeModeRepository) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index d5ab303555..3dd86e4e03 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -51,10 +51,9 @@ internal object TokensDomainModule { @Provides @ViewModelScoped fun provideToggleTokenListGroupingUseCase( - networksRepository: NetworksRepository, dispatchers: CoroutineDispatcherProvider, ): ToggleTokenListGroupingUseCase { - return ToggleTokenListGroupingUseCase(networksRepository, dispatchers) + return ToggleTokenListGroupingUseCase(dispatchers) } @Provides @@ -71,4 +70,12 @@ internal object TokensDomainModule { ): ApplyTokenListSortingUseCase { return ApplyTokenListSortingUseCase(currenciesRepository, dispatchers) } + + @Provides + @ViewModelScoped + fun provideGetCryptoCurrencyActionsUseCase( + dispatchers: CoroutineDispatcherProvider, + ): GetCryptoCurrencyActionsUseCase { + return GetCryptoCurrencyActionsUseCase(dispatchers) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt index 92f1340058..8e3d763c56 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/WalletsDomainModule.kt @@ -2,6 +2,7 @@ package com.tangem.tap.di.domain import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.WalletsStateHolder +import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.* import dagger.Module import dagger.Provides @@ -48,4 +49,22 @@ internal object WalletsDomainModule { fun providesSelectWalletUseCase(walletsStateHolder: WalletsStateHolder): SelectWalletUseCase { return SelectWalletUseCase(walletsStateHolder = walletsStateHolder) } + + @Provides + @ViewModelScoped + fun providesUpdateWalletUseCase(walletsStateHolder: WalletsStateHolder): UpdateWalletUseCase { + return UpdateWalletUseCase(walletsStateHolder = walletsStateHolder) + } + + @Provides + @ViewModelScoped + fun providesDeleteWalletUseCase(walletsStateHolder: WalletsStateHolder): DeleteWalletUseCase { + return DeleteWalletUseCase(walletsStateHolder = walletsStateHolder) + } + + @Provides + @ViewModelScoped + fun providesShouldSaveUserWalletsUseCase(walletsRepository: WalletsRepository): ShouldSaveUserWalletsUseCase { + return ShouldSaveUserWalletsUseCase(walletsRepository = walletsRepository) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt b/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt new file mode 100644 index 0000000000..681d4ffabd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/settings/DefaultLegacySettingsRepository.kt @@ -0,0 +1,11 @@ +package com.tangem.tap.domain.settings + +import com.tangem.domain.settings.repositories.LegacySettingsRepository +import com.tangem.tap.domain.TangemSdkManager + +internal class DefaultLegacySettingsRepository( + private val tangemSdkManager: TangemSdkManager, +) : LegacySettingsRepository { + + override fun canUseBiometry(): Boolean = tangemSdkManager.canUseBiometry +} \ No newline at end of file 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 2717354cc4..7008747005 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 @@ -1,5 +1,6 @@ package com.tangem.tap.domain.tasks.product +import com.tangem.blockchain.blockchains.cardano.CardanoUtils import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.common.card.Card @@ -224,7 +225,8 @@ private class ScanWalletProcessor( walletData = session.environment.walletData, primaryCard = primaryCard, ) - val derivations = collectDerivations(card, config, scanResponse.derivationStyleProvider) + val derivations = + collectDerivations(card, config, scanResponse.derivationStyleProvider) if (derivations.isEmpty() || !card.settings.isHDWalletAllowed) { callback(CompletionResult.Success(scanResponse)) return@launch @@ -249,60 +251,101 @@ private class ScanWalletProcessor( val userTokensRepository = userTokensRepository ?: return emptyList() val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card) .toMutableList() - .ifEmpty { - mutableListOf( - BlockchainNetwork( - blockchain = Blockchain.Bitcoin, - derivationStyleProvider = derivationStyleProvider, - ), - BlockchainNetwork( - blockchain = Blockchain.Ethereum, - derivationStyleProvider = derivationStyleProvider, - ), - ) - } + .ifEmpty { getDefaultBlockchains(derivationStyleProvider) } if (card.settings.isHDWalletAllowed) { - blockchainsToDerive.addAll( - listOf( - BlockchainNetwork( - blockchain = Blockchain.Ethereum, - derivationStyleProvider = derivationStyleProvider, - ), - BlockchainNetwork( - blockchain = Blockchain.EthereumTestnet, - derivationStyleProvider = derivationStyleProvider, - ), - ), - ) + blockchainsToDerive += getEthereumBlockchains(derivationStyleProvider) } - if (additionalBlockchainsToDerive != null) { - blockchainsToDerive.addAll( - additionalBlockchainsToDerive.map { - BlockchainNetwork( - blockchain = it, - derivationStyleProvider = derivationStyleProvider, - ) - }, - ) + + additionalBlockchainsToDerive?.let { + blockchainsToDerive += getAdditionalBlockchainToDerive(derivationStyleProvider, it) } + + // we should generate second key for cardano + // because cardano address generation for wallet2 requires keys from 2 derivations + // https://developers.cardano.org/docs/get-started/cardano-serialization-lib/generating-keys/ + val secondCardanoNetwork = blockchainsToDerive + .find { it.blockchain == Blockchain.Cardano } + ?.let { getCardanoSecondNetwork(it) } + secondCardanoNetwork?.let { blockchainsToDerive.add(it) } + + // pay attention to this if (!card.useOldStyleDerivation) { - blockchainsToDerive.removeAll( - listOf( - Blockchain.BSC, Blockchain.BSCTestnet, - Blockchain.Polygon, Blockchain.PolygonTestnet, - Blockchain.RSK, - Blockchain.Fantom, Blockchain.FantomTestnet, - Blockchain.Avalanche, Blockchain.AvalancheTestnet, - ).map { - BlockchainNetwork( - blockchain = it, - derivationStyleProvider = derivationStyleProvider, - ) - }, + removeUnnecessaryBlockchains(blockchainsToDerive, derivationStyleProvider) + } + + return blockchainsToDerive.distinct() + } + + private fun getDefaultBlockchains( + derivationStyleProvider: DerivationStyleProvider, + ): MutableList { + return mutableListOf( + BlockchainNetwork( + blockchain = Blockchain.Bitcoin, + derivationStyleProvider = derivationStyleProvider, + ), + BlockchainNetwork( + blockchain = Blockchain.Ethereum, + derivationStyleProvider = derivationStyleProvider, + ), + ) + } + + private fun getEthereumBlockchains(derivationStyleProvider: DerivationStyleProvider): List { + return listOf( + BlockchainNetwork( + blockchain = Blockchain.Ethereum, + derivationStyleProvider = derivationStyleProvider, + ), + BlockchainNetwork( + blockchain = Blockchain.EthereumTestnet, + derivationStyleProvider = derivationStyleProvider, + ), + ) + } + + private fun getAdditionalBlockchainToDerive( + derivationStyleProvider: DerivationStyleProvider, + collection: Collection, + ): List { + return collection.map { + BlockchainNetwork( + blockchain = it, + derivationStyleProvider = derivationStyleProvider, ) } - return blockchainsToDerive.distinct() + } + + private fun getCardanoSecondNetwork(cardanoBlockchainNetwork: BlockchainNetwork): BlockchainNetwork? { + val cardanoStandardDerivation = cardanoBlockchainNetwork.derivationPath?.let { DerivationPath(it) } + ?: return null + val cardanoPatchedDerivation = CardanoUtils.extendedDerivationPath(cardanoStandardDerivation) + return BlockchainNetwork( + blockchain = Blockchain.Cardano, + derivationPath = cardanoPatchedDerivation.rawPath, + tokens = emptyList(), + ) + } + + private fun removeUnnecessaryBlockchains( + blockchainsToDerive: MutableList, + derivationStyleProvider: DerivationStyleProvider, + ) { + blockchainsToDerive.removeAll( + listOf( + Blockchain.BSC, Blockchain.BSCTestnet, + Blockchain.Polygon, Blockchain.PolygonTestnet, + Blockchain.RSK, + Blockchain.Fantom, Blockchain.FantomTestnet, + Blockchain.Avalanche, Blockchain.AvalancheTestnet, + ).map { + BlockchainNetwork( + blockchain = it, + derivationStyleProvider = derivationStyleProvider, + ) + }, + ) } private suspend fun collectDerivations( diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt index fcf584cf31..1de357e9df 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoHelper.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.demo import com.tangem.domain.demo.DemoConfig import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.details.redux.DetailsAction @@ -21,8 +22,8 @@ object DemoHelper { private val disabledActionFeatures = listOf( WalletConnectAction.StartWalletConnect::class.java, - WalletAction.TradeCryptoAction.Buy::class.java, - WalletAction.TradeCryptoAction.Sell::class.java, + TradeCryptoAction.Buy::class.java, + TradeCryptoAction.Sell::class.java, BackupAction.StartBackup::class.java, WalletAction.ExploreAddress::class.java, DetailsAction.ResetToFactory.Start::class.java, diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt index ab1ec2715d..930f33afe6 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/ui/DisclaimerFragment.kt @@ -7,7 +7,7 @@ import android.webkit.WebView import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import com.tangem.core.navigation.AppScreen -import com.tangem.core.ui.fragments.setStatusBarColor +import com.tangem.core.ui.extensions.setStatusBarColor import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show diff --git a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt index 9d28a45db6..2879f9ef13 100644 --- a/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt +++ b/app/src/main/java/com/tangem/tap/features/intentHandler/handlers/SellCurrencyIntentHandler.kt @@ -1,9 +1,9 @@ package com.tangem.tap.features.intentHandler.handlers import android.content.Intent +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.features.intentHandler.IntentHandler -import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.store import timber.log.Timber @@ -22,7 +22,7 @@ class SellCurrencyIntentHandler : IntentHandler { Timber.d("MoonPay Sell: $amount $currency to $destinationAddress") store.dispatchWithMain( - WalletAction.TradeCryptoAction.SendCrypto( + TradeCryptoAction.SendCrypto( currencyId = currency, amount = amount, destinationAddress = destinationAddress, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 6cdb83e4d7..7ac3806126 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -103,13 +103,16 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { tvBody.isVisible = false btnMainAction.text = "" + btnMainAction.icon = null btnAlternativeAction.text = "" + btnAlternativeAction.icon = null tvHeader.text = "" tvBody.text = "" } private fun setupCreateWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) + btnMainAction.setIconResource(R.drawable.ic_tangem_24) btnMainAction.setOnClickListener { Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) store.dispatch(OnboardingNoteAction.CreateWallet) @@ -133,6 +136,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { private fun setupTopUpWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { if (state.isBuyAllowed) { btnMainAction.setText(R.string.onboarding_top_up_button_but_crypto) + btnMainAction.icon = null btnMainAction.setOnClickListener { store.dispatch(OnboardingNoteAction.TopUp) } @@ -144,6 +148,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { } } else { btnMainAction.setText(R.string.onboarding_button_receive_crypto) + btnMainAction.icon = null btnMainAction.setOnClickListener { store.dispatch(OnboardingNoteAction.ShowAddressInfoDialog) } @@ -179,6 +184,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { private fun setupDoneState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { btnMainAction.setText(R.string.common_continue) + btnMainAction.icon = null btnMainAction.setOnClickListener { showConfetti(false) store.dispatch(OnboardingNoteAction.Done) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index 83674d9227..2e6ac715e0 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -72,6 +72,7 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment() { } private fun setupWelcomeState(state: TwinCardsState) { - setupWelcomeState(state) { store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) } + setupWelcomeState(state) { + store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) + } } - private fun setupWelcomeState(state: TwinCardsState, mainAction: VoidCallback) = + private fun setupWelcomeState(state: TwinCardsState, onMainButtonClick: VoidCallback) = with(mainBinding.onboardingActionContainer) { twinsWidget.toWelcome(false) @@ -192,7 +195,12 @@ class TwinsCardsFragment : BaseOnboardingFragment() { ) btnMainAction.setText(R.string.common_continue) - btnMainAction.setOnClickListener { mainAction() } + btnMainAction.icon = when (state.currentStep) { + is TwinCardsStep.WelcomeOnly -> null + is TwinCardsStep.Welcome -> AppCompatResources.getDrawable(requireContext(), R.drawable.ic_tangem_24) + else -> null + } + btnMainAction.setOnClickListener { onMainButtonClick() } } private fun setupWarningState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { @@ -210,6 +218,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { } btnMainAction.isEnabled = state.userWasUnderstandIfWalletRecreate btnMainAction.setText(R.string.common_continue) + btnMainAction.icon = null btnMainAction.setOnClickListener { store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) } @@ -251,6 +260,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { tvBody.setText(R.string.onboarding_twins_interrupt_warning) btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) + btnMainAction.setIconResource(R.drawable.ic_tangem_24) btnMainAction.setOnClickListener { Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) store.dispatch( @@ -274,6 +284,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { btnMainAction.text = getString(R.string.twins_recreate_button_format, twinPairIndexNumber) + btnMainAction.setIconResource(R.drawable.ic_tangem_24) btnMainAction.setOnClickListener { store.dispatch( TwinCardsAction.Wallet.LaunchSecondStep( @@ -298,6 +309,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { tvBody.setText(R.string.onboarding_twins_interrupt_warning) btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) + btnMainAction.setIconResource(R.drawable.ic_tangem_24) btnMainAction.setOnClickListener { store.dispatch( TwinCardsAction.Wallet.LaunchThirdStep( @@ -343,6 +355,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { } } else { btnMainAction.setText(R.string.onboarding_button_receive_crypto) + btnMainAction.icon = null btnMainAction.setOnClickListener { store.dispatch(TwinCardsAction.ShowAddressInfoDialog) } @@ -367,6 +380,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { private fun setupDoneState(state: TwinCardsState) = with(mainBinding.onboardingActionContainer) { btnMainAction.setText(R.string.common_continue) + btnMainAction.icon = null btnMainAction.setOnClickListener { store.dispatch(TwinCardsAction.Confetti.Hide) store.dispatch(TwinCardsAction.Done) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index 49f78995bc..50a7af5d2a 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -204,6 +204,8 @@ class OnboardingWalletFragment : private fun setupCreateWalletState() = with(binding) { layoutButtonsCommon.btnWalletMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) + layoutButtonsCommon.btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) + layoutButtonsCommon.btnWalletMainAction.setOnClickListener { Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) store.dispatch(OnboardingWalletAction.CreateWallet) @@ -243,6 +245,7 @@ class OnboardingWalletFragment : with(layoutButtonsCommon) { btnWalletMainAction.text = getText(R.string.onboarding_button_backup_now) + btnWalletMainAction.icon = null btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.StartBackup) } btnWalletAlternativeAction.text = getText(R.string.onboarding_button_skip_backup) @@ -261,6 +264,7 @@ class OnboardingWalletFragment : with(layoutButtonsCommon) { btnWalletMainAction.text = getString(R.string.onboarding_button_scan_origin_card) + btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) btnWalletAlternativeAction.hide() btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) } } @@ -277,6 +281,7 @@ class OnboardingWalletFragment : layoutButtonsAddCards.root.show() layoutButtonsCommon.root.hide() layoutButtonsAddCards.btnAddCard.text = getText(R.string.onboarding_button_add_backup_card) + layoutButtonsAddCards.btnAddCard.setIconResource(R.drawable.ic_tangem_24) if (state.backupCardsNumber < state.maxBackupCards) { layoutButtonsAddCards.btnAddCard.setOnClickListener { store.dispatch(BackupAction.AddBackupCard) } } else { @@ -358,6 +363,7 @@ class OnboardingWalletFragment : state.primaryCardId?.let { cardIdFormatter.getFormattedCardId(it) }, ) layoutButtonsCommon.btnWalletMainAction.text = getText(R.string.onboarding_button_backup_origin) + layoutButtonsCommon.btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) layoutButtonsCommon.btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.WritePrimaryCard) } animator.showWritePrimaryCard(state) @@ -390,6 +396,7 @@ class OnboardingWalletFragment : R.string.onboarding_button_backup_card_format, cardNumber, ) + layoutButtonsCommon.btnWalletMainAction.setIconResource(R.drawable.ic_tangem_24) layoutButtonsCommon.btnWalletMainAction.setOnClickListener { store.dispatch(BackupAction.WriteBackupCard(cardNumber)) } @@ -408,6 +415,7 @@ class OnboardingWalletFragment : tvBody.text = getText(R.string.onboarding_subtitle_success_tangem_wallet_onboarding) layoutButtonsCommon.btnWalletMainAction.text = getText(R.string.onboarding_button_continue_wallet) + layoutButtonsCommon.btnWalletMainAction.icon = null layoutButtonsCommon.btnWalletAlternativeAction.hide() layoutButtonsCommon.btnWalletMainAction.setOnClickListener { showConfetti(false) diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt index 0a6a076bff..fe5792ad29 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/ui/SaveWalletBottomSheetFragment.kt @@ -6,24 +6,27 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.SnackbarHost import androidx.compose.material.SnackbarHostState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.fragment.app.viewModels -import com.tangem.core.ui.fragments.ComposeBottomSheetFragment +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.screen.ComposeBottomSheetFragment +import com.tangem.core.ui.theme.AppThemeModeHolder import com.tangem.tap.features.details.ui.cardsettings.resolveReference import com.tangem.tap.features.saveWallet.ui.components.EnrollBiometricsDialogContent import com.tangem.tap.features.saveWallet.ui.components.SaveWalletScreenContent import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment() { + + @Inject + override lateinit var appThemeModeHolder: AppThemeModeHolder -internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment() { override val expandedHeightFraction: Float = .98f private val viewModel by viewModels() @@ -34,12 +37,8 @@ internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment { - return viewModel.state.collectAsState() - } - - @Composable - override fun ScreenContent(state: SaveWalletScreenState, modifier: Modifier) { + override fun ScreenContent(modifier: Modifier) { + val state by viewModel.state.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference()) val enrollBiometricsDialog by rememberUpdatedState(newValue = state.enrollBiometricsDialog) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 628e934435..cb2e4c26bd 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -19,6 +19,7 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.extensions.minimalAmount import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic @@ -38,7 +39,6 @@ import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.FeeAction.RequestFee import com.tangem.tap.features.send.redux.states.* import com.tangem.tap.features.wallet.models.Currency -import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers @@ -254,7 +254,7 @@ private fun sendTransaction( ), ) Analytics.sendSelectedCurrencyEvent(mainCurrencyType) - dispatch(WalletAction.TradeCryptoAction.FinishSelling(externalTransactionData.transactionId)) + dispatch(TradeCryptoAction.FinishSelling(externalTransactionData.transactionId)) } else { Analytics.send( Basic.TransactionSent( diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index 748ecacb4b..0e963d3ac5 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -18,6 +18,7 @@ import com.google.android.material.textfield.TextInputEditText import com.tangem.Message import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.NavigationAction +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.sdk.extensions.hideSoftKeyboard import com.tangem.tap.common.KeyboardObserver import com.tangem.tap.common.analytics.events.Token @@ -39,7 +40,6 @@ import com.tangem.tap.features.send.redux.FeeActionUi.* import com.tangem.tap.features.send.redux.states.FeeType import com.tangem.tap.features.send.redux.states.MainCurrencyType import com.tangem.tap.features.send.ui.stateSubscribers.SendStateSubscriber -import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.tap.mainScope import com.tangem.tap.store @@ -337,9 +337,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { if (externalTransactionData == null) { store.dispatch(NavigationAction.PopBackTo()) } else { - store.dispatch( - WalletAction.TradeCryptoAction.FinishSelling(externalTransactionData.transactionId), - ) + store.dispatch(TradeCryptoAction.FinishSelling(externalTransactionData.transactionId)) } } diff --git a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt index b567dce03b..7ddbf49c68 100644 --- a/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt +++ b/app/src/main/java/com/tangem/tap/features/sprinklr/ui/SprinklrActivity.kt @@ -6,14 +6,24 @@ import androidx.activity.viewModels import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.analytics.Analytics -import com.tangem.core.ui.fragments.ComposeActivity +import com.tangem.core.ui.components.SystemBarsEffect +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.screen.ComposeActivity +import com.tangem.core.ui.theme.AppThemeModeHolder import com.tangem.tap.common.analytics.events.Chat +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +internal class SprinklrActivity : ComposeActivity() { + + @Inject + override lateinit var appThemeModeHolder: AppThemeModeHolder -internal class SprinklrActivity : ComposeActivity() { private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { @@ -25,12 +35,14 @@ internal class SprinklrActivity : ComposeActivity() { } @Composable - override fun provideState(): State { - return viewModel.state.collectAsState() - } + override fun ScreenContent(modifier: Modifier) { + val state by viewModel.state.collectAsStateWithLifecycle() + + val systemBarsColor = TangemTheme.colors.background.primary + SystemBarsEffect { + setSystemBarsColor(systemBarsColor) + } - @Composable - override fun ScreenContent(state: SprinklrScreenState, modifier: Modifier) { BackHandler(onBack = state.onNavigateBack) SprinklrScreenContent( modifier = modifier diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt index 174563c6be..ea6ab16083 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/ui/TokensListScreen.kt @@ -7,17 +7,14 @@ import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.FabPosition import androidx.compose.material.Scaffold import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -32,9 +29,7 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.dp import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.items +import androidx.paging.compose.* import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme @@ -134,8 +129,11 @@ private fun TokensListContent( item { DifferentAddressesWarning() } } - items(items = tokens, key = TokenItemState::composedId) { - it?.let { TokenItem(model = it) } + tokens.itemKey(TokenItemState::composedId) + tokens.itemContentType(TokenItemState::composedId) + + items(items = tokens.itemSnapshotList.items, key = TokenItemState::composedId) { + TokenItem(model = it) } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt index 1cf1515b01..8b22dd95e6 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt @@ -7,7 +7,7 @@ import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.store import com.tangem.utils.converter.Converter -class CryptoCurrencyConverter : Converter { +internal class CryptoCurrencyConverter : Converter { private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 65be537ac8..2528753b4e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -4,12 +4,16 @@ import androidx.core.os.bundleOf import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.domain.common.extensions.toCoinId import com.tangem.domain.common.extensions.toNetworkId +import com.tangem.domain.common.util.derivationStyleProvider +import com.tangem.domain.tokens.legacy.TradeCryptoAction +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.feature.swap.presentation.SwapFragment import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token @@ -27,6 +31,7 @@ import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager import com.tangem.tap.network.exchangeServices.buyErc20TestnetTokens +import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.launch @@ -35,19 +40,27 @@ import kotlinx.serialization.json.Json import com.tangem.feature.swap.domain.models.domain.Currency as SwapCurrency class TradeCryptoMiddleware { - fun handle(state: () -> AppState?, action: WalletAction.TradeCryptoAction) { + fun handle(state: () -> AppState?, action: TradeCryptoAction) { if (DemoHelper.tryHandle(state, action)) return when (action) { - is WalletAction.TradeCryptoAction.Buy -> proceedBuyAction(state, action) - is WalletAction.TradeCryptoAction.Sell -> proceedSellAction() - is WalletAction.TradeCryptoAction.SendCrypto -> preconfigureAndOpenSendScreen(action) - is WalletAction.TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId) - is WalletAction.TradeCryptoAction.Swap -> openSwap() + is TradeCryptoAction.Buy -> proceedBuyAction(state, action) + is TradeCryptoAction.Sell -> proceedSellAction() + is TradeCryptoAction.SendCrypto -> preconfigureAndOpenSendScreen(action) + is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId) + is TradeCryptoAction.Swap -> { + openSwap(currency = store.state.walletState.selectedWalletData?.currency?.toSwapCurrency()) + } + is TradeCryptoAction.New.Buy -> proceedNewBuyAction(state, action) + TradeCryptoAction.New.Send -> store.dispatch(WalletAction.Send()) + is TradeCryptoAction.New.Sell -> proceedNewSellAction(action) + is TradeCryptoAction.New.Swap -> { + openSwap(currency = action.cryptoCurrency.toSwapCurrency()) + } } } - private fun proceedBuyAction(state: () -> AppState?, action: WalletAction.TradeCryptoAction.Buy) { + private fun proceedBuyAction(state: () -> AppState?, action: TradeCryptoAction.Buy) { val selectedWalletData = store.state.walletState.selectedWalletData ?: return val currency = chooseAppropriateCurrency(store.state.walletState) ?: return @@ -75,7 +88,7 @@ class TradeCryptoMiddleware { buyErc20TestnetTokens( card = card, walletManager = walletManager, - token = currency.token, + destinationAddress = currency.token.contractAddress, ) } return @@ -93,6 +106,56 @@ class TradeCryptoMiddleware { } } + private fun proceedNewBuyAction(state: () -> AppState?, action: TradeCryptoAction.New.Buy) { + val networkAddress = action.cryptoCurrencyStatus.value.networkAddress?.defaultAddress ?: return + + if (action.checkUserLocation && state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE) { + store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog()) + return + } + + val status = action.cryptoCurrencyStatus + val currency = status.currency + val blockchain = Blockchain.fromId(currency.network.id.value) + if (currency is CryptoCurrency.Token && currency.network.isTestnet) { + scope.launch { + val walletManager = store.state.daggerGraphState + .get(DaggerGraphState::walletManagersFacade) + .getOrCreateWalletManager( + userWallet = action.userWallet, + blockchain = blockchain, + derivationPath = blockchain.derivationPath( + style = action.userWallet.scanResponse.derivationStyleProvider.getDerivationStyle(), + ), + ) + + if (walletManager !is EthereumWalletManager) { + store.dispatchDebugErrorNotification("Testnet tokens available only for the Ethereum") + return@launch + } + + buyErc20TestnetTokens( + card = action.userWallet.scanResponse.card, + walletManager = walletManager, + destinationAddress = currency.contractAddress, + ) + } + return + } + + val exchangeManager = store.state.globalState.exchangeManager + exchangeManager.getUrl( + action = CurrencyExchangeManager.Action.Buy, + blockchain = blockchain, + cryptoCurrencyName = currency.symbol, + fiatCurrencyName = action.appCurrencyCode, + walletAddress = networkAddress, + )?.let { + store.dispatchOpenUrl(it) + Analytics.send(Token.Topup.ScreenOpened()) + } + } + private fun proceedSellAction() { val selectedWalletData = store.state.walletState.selectedWalletData ?: return val currency = chooseAppropriateCurrency(store.state.walletState) ?: return @@ -115,6 +178,22 @@ class TradeCryptoMiddleware { } } + private fun proceedNewSellAction(action: TradeCryptoAction.New.Sell) { + val networkAddress = action.cryptoCurrencyStatus.value.networkAddress?.defaultAddress ?: return + val currency = action.cryptoCurrencyStatus.currency + + store.state.globalState.exchangeManager.getUrl( + action = CurrencyExchangeManager.Action.Sell, + blockchain = Blockchain.fromId(currency.network.id.value), + cryptoCurrencyName = currency.symbol, + fiatCurrencyName = action.appCurrencyCode, + walletAddress = networkAddress, + )?.let { + store.dispatchOpenUrl(it) + Analytics.send(Token.Withdraw.ScreenOpened()) + } + } + private fun chooseAppropriateCurrency(walletState: WalletState): Currency? { return if (walletState.primaryTokenData == null) { walletState.selectedWalletData?.currency @@ -126,7 +205,7 @@ class TradeCryptoMiddleware { } } - private fun preconfigureAndOpenSendScreen(action: WalletAction.TradeCryptoAction.SendCrypto) { + private fun preconfigureAndOpenSendScreen(action: TradeCryptoAction.SendCrypto) { val selectedWalletData = store.state.walletState.selectedWalletData ?: return Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(selectedWalletData.currency))) @@ -160,16 +239,44 @@ class TradeCryptoMiddleware { )?.let { store.dispatchOpenUrl(it) } } - private fun openSwap() { - val currency = store.state.walletState.selectedWalletData?.currency?.toSwapCurrency() - val bundle = - bundleOf( - SwapFragment.CURRENCY_BUNDLE_KEY to Json.encodeToString(currency), - SwapFragment.DERIVATION_PATH to store.state.walletState.selectedWalletData?.currency?.derivationPath, - ) + private fun openSwap(currency: SwapCurrency?) { + val bundle = bundleOf( + SwapFragment.CURRENCY_BUNDLE_KEY to Json.encodeToString(currency), + SwapFragment.DERIVATION_PATH to store.state.walletState.selectedWalletData?.currency?.derivationPath, + ) + store.dispatchOnMain(NavigationAction.NavigateTo(screen = AppScreen.Swap, bundle = bundle)) } + private fun CryptoCurrency.toSwapCurrency(): SwapCurrency { + val blockchain = Blockchain.fromId(network.id.value) + + return when (this) { + is CryptoCurrency.Coin -> { + SwapCurrency.NativeToken( + id = blockchain.toCoinId(), + name = name, + symbol = symbol, + networkId = blockchain.toNetworkId(), + // no need to set logoUrl for blockchain cause + // error when form url with coinId, coinId of eth and arbitrum the same + logoUrl = "", + ) + } + is CryptoCurrency.Token -> { + SwapCurrency.NonNativeToken( + id = id.value, + name = name, + symbol = symbol, + networkId = blockchain.toNetworkId(), + logoUrl = getIconUrl(id.value), + contractAddress = contractAddress, + decimalCount = decimals, + ) + } + } + } + private fun Currency.toSwapCurrency(): SwapCurrency { return when (this) { is Currency.Blockchain -> { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index c84ac7fa2d..a6a5fa0e78 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -12,6 +12,7 @@ import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.datasource.connection.NetworkConnectionManager +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.userwallets.GetCardImageUseCase import com.tangem.domain.wallets.legacy.lockIfLockable import com.tangem.tap.* @@ -87,7 +88,7 @@ class WalletMiddleware { val walletState = store.state.walletState when (action) { - is WalletAction.TradeCryptoAction -> tradeCryptoMiddleware.handle(state, action) + is TradeCryptoAction -> tradeCryptoMiddleware.handle(state, action) is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState) is WalletAction.AppCurrencyAction -> appCurrencyMiddleware.handle(action) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index e91e0a1194..3fb8a17540 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -68,7 +68,6 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS error = null, ) } - is WalletAction.TradeCryptoAction -> return newState is WalletAction.AppCurrencyAction -> { newState = appCurrencyReducer.reduce(action, newState) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 64105fe887..fe767bafda 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -21,6 +21,7 @@ import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.NavigationAction import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.derivationStyleProvider +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.feature.swap.api.SwapFeatureToggleManager import com.tangem.feature.swap.domain.SwapInteractor import com.tangem.sdk.extensions.dpToPx @@ -276,9 +277,9 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeSt ) { val exchangeManager = store.state.globalState.exchangeManager binding.rowButtons.apply { - onBuyClick = { store.dispatch(WalletAction.TradeCryptoAction.Buy()) } - onSellClick = { store.dispatch(WalletAction.TradeCryptoAction.Sell) } - onSwapClick = { store.dispatch(WalletAction.TradeCryptoAction.Swap) } + onBuyClick = { store.dispatch(TradeCryptoAction.Buy()) } + onSellClick = { store.dispatch(TradeCryptoAction.Sell) } + onSwapClick = { store.dispatch(TradeCryptoAction.Swap) } onTradeClick = { store.dispatch( WalletAction.DialogAction.ChooseTradeActionDialog( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index af1d2100aa..cec1e05dd8 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -25,7 +25,7 @@ import com.badoo.mvicore.modelWatcher import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction -import com.tangem.core.ui.fragments.setStatusBarColor +import com.tangem.core.ui.extensions.setStatusBarColor import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.utils.OneTouchClickListener import com.tangem.datasource.connection.NetworkConnectionManager diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ChooseTradeActionBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ChooseTradeActionBottomSheetDialog.kt index 1495219c54..25ce55e44c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ChooseTradeActionBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ChooseTradeActionBottomSheetDialog.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Bundle import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetDialog +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.tap.common.extensions.show import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog @@ -39,15 +40,15 @@ class ChooseTradeActionBottomSheetDialog( dialogBtnBuy.setOnClickListener { dismiss() - store.dispatch(WalletAction.TradeCryptoAction.Buy()) + store.dispatch(TradeCryptoAction.Buy()) } dialogBtnSell.setOnClickListener { dismiss() - store.dispatch(WalletAction.TradeCryptoAction.Sell) + store.dispatch(TradeCryptoAction.Sell) } dialogBtnSwap.setOnClickListener { dismiss() - store.dispatch(WalletAction.TradeCryptoAction.Swap) + store.dispatch(TradeCryptoAction.Swap) } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt index b7ec4ee4a1..185c5e366a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt @@ -6,10 +6,10 @@ import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetDialog import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.NavigationAction +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchOpenUrl -import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.store import com.tangem.wallet.databinding.DialogRussiansCardholdersWarningBinding @@ -40,7 +40,7 @@ class RussianCardholdersWarningBottomSheetDialog( if (dialogData != null) { store.dispatchOpenUrl(dialogData.topUpUrl) } else { - store.dispatch(WalletAction.TradeCryptoAction.Buy(checkUserLocation = false)) + store.dispatch(TradeCryptoAction.Buy(checkUserLocation = false)) } dismiss() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index 23a4645bb2..7ce1a4d49e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -4,6 +4,7 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.LinearLayoutManager import com.tangem.core.analytics.Analytics +import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.* import com.tangem.tap.domain.model.WalletDataModel @@ -151,9 +152,9 @@ class SingleWalletView : WalletView() { val exchangeManager = store.state.globalState.exchangeManager binding?.rowButtons?.apply { - onBuyClick = { store.dispatch(WalletAction.TradeCryptoAction.Buy()) } - onSellClick = { store.dispatch(WalletAction.TradeCryptoAction.Sell) } - onSwapClick = { store.dispatch(WalletAction.TradeCryptoAction.Swap) } + onBuyClick = { store.dispatch(TradeCryptoAction.Buy()) } + onSellClick = { store.dispatch(TradeCryptoAction.Sell) } + onSwapClick = { store.dispatch(TradeCryptoAction.Swap) } onTradeClick = { store.dispatch( WalletAction.DialogAction.ChooseTradeActionDialog( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt index ecb5291d26..2e80036cd4 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/WalletSelectorBottomSheetFragment.kt @@ -7,35 +7,32 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.SnackbarHost import androidx.compose.material.SnackbarHostState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.rememberNestedScrollInteropConnection import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.analytics.Analytics -import com.tangem.core.ui.fragments.ComposeBottomSheetFragment +import com.tangem.core.ui.components.wallets.RenameWalletDialogContent import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.screen.ComposeBottomSheetFragment +import com.tangem.core.ui.theme.AppThemeModeHolder import com.tangem.tap.common.analytics.events.MyWallets import com.tangem.tap.features.details.ui.cardsettings.resolveReference -import com.tangem.tap.features.walletSelector.ui.components.BiometricsDisabledWarningContent -import com.tangem.tap.features.walletSelector.ui.components.BiometricsLockoutWarningContent -import com.tangem.tap.features.walletSelector.ui.components.KeyInvalidatedWarningContent -import com.tangem.tap.features.walletSelector.ui.components.RemoveWalletDialogContent -import com.tangem.tap.features.walletSelector.ui.components.RenameWalletDialogContent -import com.tangem.tap.features.walletSelector.ui.components.WalletSelectorScreenContent +import com.tangem.tap.features.walletSelector.ui.components.* import com.tangem.tap.features.walletSelector.ui.model.DialogModel import com.tangem.tap.features.walletSelector.ui.model.WarningModel import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint -internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment() { +internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment() { + + @Inject + override lateinit var appThemeModeHolder: AppThemeModeHolder + private val viewModel by viewModels() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -45,10 +42,8 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment = viewModel.state.collectAsState() - - @Composable - override fun ScreenContent(state: WalletSelectorScreenState, modifier: Modifier) { + override fun ScreenContent(modifier: Modifier) { + val state by viewModel.state.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference()) val dialog by rememberUpdatedState(newValue = state.dialog) @@ -90,7 +85,13 @@ internal class WalletSelectorBottomSheetFragment : ComposeBottomSheetFragment RemoveWalletDialogContent(dialog) - is DialogModel.RenameWalletDialog -> RenameWalletDialogContent(dialog) + is DialogModel.RenameWalletDialog -> { + RenameWalletDialogContent( + name = dialog.currentName, + onConfirm = dialog.onConfirm, + onDismiss = dialog.onDismiss, + ) + } is WarningModel.BiometricsLockoutWarning -> BiometricsLockoutWarningContent(dialog) is WarningModel.KeyInvalidatedWarning -> KeyInvalidatedWarningContent(dialog) is WarningModel.BiometricsDisabledWarning -> BiometricsDisabledWarningContent(dialog) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt deleted file mode 100644 index 7bc58f301a..0000000000 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/RenameWalletDialogContent.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.tangem.tap.features.walletSelector.ui.components - -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.tooling.preview.Preview -import com.tangem.core.ui.components.AdditionalTextInputDialogParams -import com.tangem.core.ui.components.DialogButton -import com.tangem.core.ui.components.TextInputDialog -import com.tangem.core.ui.res.TangemTheme -import com.tangem.tap.features.walletSelector.ui.model.DialogModel -import com.tangem.wallet.R - -@Composable -internal fun RenameWalletDialogContent(dialog: DialogModel.RenameWalletDialog) { - var value by remember { - mutableStateOf(TextFieldValue(text = dialog.currentName)) - } - - TextInputDialog( - fieldValue = value, - confirmButton = DialogButton( - title = stringResource(id = R.string.common_ok), - enabled = value.text.isNotEmpty() && value.text != dialog.currentName, - onClick = { dialog.onConfirm(value.text) }, - ), - onDismissDialog = dialog.onDismiss, - onValueChange = { newValue -> - value = newValue - }, - title = stringResource(R.string.user_wallet_list_rename_popup_title), - dismissButton = DialogButton( - title = stringResource(id = R.string.common_cancel), - onClick = dialog.onDismiss, - ), - textFieldParams = AdditionalTextInputDialogParams( - label = stringResource(R.string.user_wallet_list_rename_popup_placeholder), - ), - ) -} - -// region Preview -@Composable -private fun RenameWalletDialogContentSample(modifier: Modifier = Modifier) { - Column( - modifier = modifier, - ) { - RenameWalletDialogContent(dialog = DialogModel.RenameWalletDialog("", {}, {})) - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun RenameWalletDialogContentPreview_Light() { - TangemTheme { - RenameWalletDialogContentSample() - } -} - -@Preview(showBackground = true, widthDp = 360) -@Composable -private fun RenameWalletDialogContentPreview_Dark() { - TangemTheme(isDark = true) { - RenameWalletDialogContentSample() - } -} -// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt index 0554bdf27c..9e2c09d0d5 100644 --- a/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/welcome/ui/WelcomeFragment.kt @@ -1,35 +1,36 @@ package com.tangem.tap.features.welcome.ui import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material.SnackbarHost import androidx.compose.material.SnackbarHostState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.colorResource import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.tangem.core.analytics.Analytics import com.tangem.core.ui.components.SystemBarsEffect -import com.tangem.core.ui.fragments.ComposeFragment import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.screen.ComposeFragment +import com.tangem.core.ui.theme.AppThemeModeHolder import com.tangem.tap.common.analytics.events.SignIn import com.tangem.tap.common.extensions.eraseContext import com.tangem.tap.features.details.ui.cardsettings.resolveReference import com.tangem.tap.features.welcome.ui.components.WarningDialog import com.tangem.tap.features.welcome.ui.components.WelcomeScreenContent -import com.tangem.wallet.R +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject -internal class WelcomeFragment : ComposeFragment() { +@AndroidEntryPoint +internal class WelcomeFragment : ComposeFragment() { + + @Inject + override lateinit var appThemeModeHolder: AppThemeModeHolder private val viewModel by viewModels() @@ -40,19 +41,15 @@ internal class WelcomeFragment : ComposeFragment() { } @Composable - override fun provideState(): State { - return viewModel.state.collectAsState() - } - - @Composable - override fun ScreenContent(state: WelcomeScreenState, modifier: Modifier) { + override fun ScreenContent(modifier: Modifier) { + val state by viewModel.state.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference()) val warning by rememberUpdatedState(newValue = state.warning) - val backgroundColor = colorResource(id = R.color.background_primary) + val backgroundColor = TangemTheme.colors.background.primary SystemBarsEffect { - setSystemBarsColor(color = backgroundColor) + setSystemBarsColor(backgroundColor) } BackHandler { @@ -61,7 +58,8 @@ internal class WelcomeFragment : ComposeFragment() { Box( modifier = modifier - .systemBarsPadding(), + .systemBarsPadding() + .background(backgroundColor), ) { WelcomeScreenContent( showUnlockProgress = state.showUnlockWithBiometricsProgress, diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt index d3294b1ed2..ad03f2c04a 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/CurrencyExchangeManager.kt @@ -5,7 +5,6 @@ import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.blockchain.extensions.Result import com.tangem.domain.models.scan.CardDTO @@ -87,17 +86,12 @@ class CurrencyExchangeManager( } } -suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletManager, token: Token) { +suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletManager, destinationAddress: String) { walletManager.safeUpdate() val amountToSend = Amount(walletManager.wallet.blockchain) - val destinationAddress = token.contractAddress - - val feeResult = walletManager.getFee( - amountToSend, - destinationAddress, - ) as? Result.Success ?: return + val feeResult = walletManager.getFee(amountToSend, destinationAddress) as? Result.Success ?: return val fee = when (val feeForTx = feeResult.data) { is TransactionFee.Choosable -> feeForTx.minimum is TransactionFee.Single -> feeForTx.normal @@ -106,8 +100,6 @@ suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletMa val coinValue = walletManager.wallet.amounts[AmountType.Coin]?.value ?: BigDecimal.ZERO if (coinValue < fee.amount.value) return - val transaction = walletManager.createTransaction(amountToSend, fee, destinationAddress) - val signer = TangemSigner( card = card, tangemSdk = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk, @@ -121,5 +113,13 @@ suspend fun buyErc20TestnetTokens(card: CardDTO, walletManager: EthereumWalletMa ), ) } - walletManager.send(transaction, signer) + + walletManager.send( + transactionData = walletManager.createTransaction( + amount = amountToSend, + fee = fee, + destination = destinationAddress, + ), + signer = signer, + ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt index 8ea80aec87..b89e7cbe68 100644 --- a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt @@ -4,6 +4,7 @@ import com.tangem.core.navigation.NavigationAction import com.tangem.core.navigation.NavigationStateHolder import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.WalletsStateHolder import com.tangem.tap.common.entities.FiatCurrency @@ -14,6 +15,7 @@ import com.tangem.tap.domain.walletStores.WalletStoresManager import com.tangem.tap.features.wallet.redux.WalletState import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import org.rekotlin.Action import org.rekotlin.Store import javax.inject.Inject @@ -21,7 +23,7 @@ import javax.inject.Inject * Holds objects from old modules, that missing in DI graph. * Object sets manually to use in new modules and [AppStateHolder] proxies its to DI. */ -class AppStateHolder @Inject constructor() : WalletsStateHolder, NavigationStateHolder { +class AppStateHolder @Inject constructor() : WalletsStateHolder, NavigationStateHolder, ReduxStateHolder { override var userWalletsListManager: UserWalletsListManager? = null set(value) { @@ -50,4 +52,8 @@ class AppStateHolder @Inject constructor() : WalletsStateHolder, NavigationState override fun navigate(action: NavigationAction) { mainStore?.dispatch(action) } + + override fun dispatch(action: Action) { + mainStore?.dispatch(action) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt index b9be4b9f93..c677f70300 100644 --- a/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt +++ b/app/src/main/java/com/tangem/tap/proxy/redux/DaggerGraphState.kt @@ -6,6 +6,7 @@ import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.ScanCardUseCase import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.features.tester.api.TesterRouter import com.tangem.features.tokendetails.featuretoggles.TokenDetailsFeatureToggles import com.tangem.features.tokendetails.navigation.TokenDetailsRouter @@ -33,6 +34,7 @@ data class DaggerGraphState( val scanCardProcessor: ScanCardProcessor? = null, val cardSdkConfigRepository: CardSdkConfigRepository? = null, val appCurrencyRepository: AppCurrencyRepository? = null, + val walletManagersFacade: WalletManagersFacade? = null, ) : StateType { inline fun get(getDependency: DaggerGraphState.() -> T?): T { diff --git a/app/src/main/res/color/selector_btn_text_primary.xml b/app/src/main/res/color/selector_btn_content_primary.xml similarity index 100% rename from app/src/main/res/color/selector_btn_text_primary.xml rename to app/src/main/res/color/selector_btn_content_primary.xml diff --git a/app/src/main/res/color/selector_btn_text_secondary.xml b/app/src/main/res/color/selector_btn_content_secondary.xml similarity index 100% rename from app/src/main/res/color/selector_btn_text_secondary.xml rename to app/src/main/res/color/selector_btn_content_secondary.xml diff --git a/app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml b/app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml index b098f5f0ae..32d2544981 100644 --- a/app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml +++ b/app/src/main/res/layout-h680dp/layout_onboarding_container_bottom.xml @@ -74,7 +74,8 @@ + tools:icon="@drawable/ic_tangem_24" + tools:text="Add backup card" /> - - - \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 6c451317c2..70af1872c5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,8 @@ - - - + + + +