diff --git a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt index 038f6f9a6a..aec8799cdd 100644 --- a/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt +++ b/app/src/main/java/com/tangem/tap/ApplicationEntryPoint.kt @@ -18,6 +18,7 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.feedback.FeedbackManagerFeatureToggles +import com.tangem.domain.feedback.GetCardInfoUseCase import com.tangem.domain.feedback.GetFeedbackEmailUseCase import com.tangem.domain.feedback.SaveBlockchainErrorUseCase import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase @@ -112,6 +113,8 @@ interface ApplicationEntryPoint { fun getDetailsFeatureToggles(): DetailsFeatureToggles + fun getGetCardInfoUseCase(): GetCardInfoUseCase + fun getUrlOpener(): UrlOpener fun getShareManager(): ShareManager diff --git a/app/src/main/java/com/tangem/tap/TangemApplication.kt b/app/src/main/java/com/tangem/tap/TangemApplication.kt index 2b87ffb1f0..d92288e204 100644 --- a/app/src/main/java/com/tangem/tap/TangemApplication.kt +++ b/app/src/main/java/com/tangem/tap/TangemApplication.kt @@ -33,6 +33,7 @@ import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.common.LogConfig import com.tangem.domain.feedback.FeedbackManagerFeatureToggles +import com.tangem.domain.feedback.GetCardInfoUseCase import com.tangem.domain.feedback.GetFeedbackEmailUseCase import com.tangem.domain.feedback.SaveBlockchainErrorUseCase import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase @@ -183,6 +184,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase get() = entryPoint.getSaveBlockchainErrorUseCase() + private val getCardInfoUseCase: GetCardInfoUseCase + get() = entryPoint.getGetCardInfoUseCase() + private val detailsFeatureToggles: DetailsFeatureToggles get() = entryPoint.getDetailsFeatureToggles() @@ -284,6 +288,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory { settingsRepository = settingsRepository, blockchainSDKFactory = blockchainSDKFactory, saveBlockchainErrorUseCase = saveBlockchainErrorUseCase, + getFeedbackEmailUseCase = getFeedbackEmailUseCase, + getCardInfoUseCase = getCardInfoUseCase, + assetLoader = assetLoader, detailsFeatureToggles = detailsFeatureToggles, urlOpener = urlOpener, shareManager = shareManager, diff --git a/app/src/main/java/com/tangem/tap/common/feedback/LegacyFeedbackManager.kt b/app/src/main/java/com/tangem/tap/common/feedback/LegacyFeedbackManager.kt index ed99833b04..9f2f6bb335 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/LegacyFeedbackManager.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/LegacyFeedbackManager.kt @@ -7,13 +7,14 @@ import com.tangem.domain.common.TapWorkarounds import com.tangem.domain.feedback.FeedbackManagerFeatureToggles import com.tangem.domain.feedback.GetFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType +import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.chat.ChatManager import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.extensions.sendEmail import com.tangem.tap.common.log.TangemLogCollector import com.tangem.tap.foregroundActivityObserver -import com.tangem.tap.mainScope import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.withForegroundActivity import kotlinx.coroutines.launch @@ -36,16 +37,24 @@ class LegacyFeedbackManager( private var sessionFeedbackFile: File? = null private var sessionLogsFile: File? = null - fun sendEmail(feedbackData: FeedbackData, onFail: ((Exception) -> Unit)? = null) { + fun sendEmail(feedbackData: FeedbackData, scanResponse: ScanResponse?) { if (feedbackManagerFeatureToggles.isLocalLogsEnabled) { - mainScope.launch { + scope.launch { + val getCardInfo = suspend { + scanResponse ?: error("ScanResponse must be not null") + store.inject(DaggerGraphState::getCardInfoUseCase).invoke(scanResponse).getOrNull() + ?: error("CardInfo must be not null") + } + val email = getFeedbackEmailUseCase( - when (feedbackData) { - is FeedbackEmail -> FeedbackEmailType.DirectUserRequest - is RateCanBeBetterEmail -> FeedbackEmailType.RateCanBeBetter + type = when (feedbackData) { + is FeedbackEmail -> FeedbackEmailType.DirectUserRequest(cardInfo = getCardInfo()) + is RateCanBeBetterEmail -> FeedbackEmailType.RateCanBeBetter(cardInfo = getCardInfo()) is ScanFailsEmail -> FeedbackEmailType.ScanningProblem - is SendTransactionFailedEmail -> FeedbackEmailType.TransactionSendingProblem - else -> FeedbackEmailType.DirectUserRequest + is SendTransactionFailedEmail -> { + FeedbackEmailType.TransactionSendingProblem(cardInfo = getCardInfo()) + } + else -> FeedbackEmailType.DirectUserRequest(cardInfo = getCardInfo()) }, ) @@ -66,12 +75,28 @@ class LegacyFeedbackManager( subject = activity.getString(feedbackData.subjectResId), message = feedbackData.joinTogether(activity, infoHolder), file = getLogFile(activity), - onFail = onFail, ) } } } + fun sendEmail(type: FeedbackEmailType) { + if (!feedbackManagerFeatureToggles.isLocalLogsEnabled) error("LOCAL_LOGS feature toggle must be enabled") + + scope.launch { + val email = getFeedbackEmailUseCase(type = type) + + store.inject(DaggerGraphState::emailSender).send( + email = EmailSender.Email( + address = email.address, + subject = email.subject, + message = email.message, + attachment = email.file, + ), + ) + } + } + fun openChat(config: ChatConfig, feedbackData: FeedbackData) { chatManager.open( config = config, diff --git a/app/src/main/java/com/tangem/tap/common/feedback/ProxyFeedbackManager.kt b/app/src/main/java/com/tangem/tap/common/feedback/ProxyFeedbackManager.kt index 680468bef1..d013937813 100644 --- a/app/src/main/java/com/tangem/tap/common/feedback/ProxyFeedbackManager.kt +++ b/app/src/main/java/com/tangem/tap/common/feedback/ProxyFeedbackManager.kt @@ -1,13 +1,13 @@ package com.tangem.tap.common.feedback -import com.tangem.core.navigation.feedback.FeedbackManager -import com.tangem.core.navigation.feedback.FeedbackType +import com.tangem.domain.feedback.FeedbackManager +import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.tap.store import timber.log.Timber internal class ProxyFeedbackManager : FeedbackManager { - override fun sendEmail(type: FeedbackType) { + override fun sendEmail(type: FeedbackEmailType) { val manager = store.state.globalState.feedbackManager if (manager == null) { @@ -15,14 +15,6 @@ internal class ProxyFeedbackManager : FeedbackManager { return } - val data = when (type) { - is FeedbackType.Feedback -> FeedbackEmail() - is FeedbackType.RateCanBeBetter -> RateCanBeBetterEmail() - is FeedbackType.ScanFails -> ScanFailsEmail() - is FeedbackType.SendTransactionFailed -> SendTransactionFailedEmail(type.error) - is FeedbackType.Support -> FeedbackEmail() - } - - manager.sendEmail(data) + manager.sendEmail(type) } } \ No newline at end of file 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 4aa4c0b58b..ba7a0ac095 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 @@ -81,7 +81,7 @@ sealed class GlobalAction : Action { data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction() data class SetFeedbackManager(val feedbackManager: LegacyFeedbackManager) : GlobalAction() - data class SendEmail(val feedbackData: FeedbackData) : GlobalAction() + data class SendEmail(val feedbackData: FeedbackData, val scanResponse: ScanResponse?) : GlobalAction() data class OpenChat(val feedbackData: FeedbackData, val chatConfig: ChatConfig? = null) : GlobalAction() object ExchangeManager : GlobalAction() { diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index f1d80acbf8..957b756803 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -69,7 +69,10 @@ private fun handleAction(action: Action, appState: () -> AppState?) { } } is GlobalAction.SendEmail -> { - store.state.globalState.feedbackManager?.sendEmail(action.feedbackData) + store.state.globalState.feedbackManager?.sendEmail( + feedbackData = action.feedbackData, + scanResponse = action.scanResponse, + ) } is GlobalAction.OpenChat -> { val globalState = store.state.globalState diff --git a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt index 7cf0e08bf1..0b0af1a01b 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/legacy/LegacyMiddleware.kt @@ -1,8 +1,11 @@ package com.tangem.tap.common.redux.legacy +import com.tangem.blockchain.common.AmountType +import com.tangem.domain.feedback.models.BlockchainErrorInfo import com.tangem.domain.redux.LegacyAction import com.tangem.domain.tokens.utils.convertToAmount import com.tangem.tap.common.extensions.inject +import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.feedback.RateCanBeBetterEmail import com.tangem.tap.common.feedback.SendTransactionFailedEmail import com.tangem.tap.common.redux.AppState @@ -19,7 +22,10 @@ internal object LegacyMiddleware { { action -> when (action) { is LegacyAction.SendEmailRateCanBeBetter -> { - store.state.globalState.feedbackManager?.sendEmail(RateCanBeBetterEmail()) + store.state.globalState.feedbackManager?.sendEmail( + feedbackData = RateCanBeBetterEmail(), + scanResponse = action.scanResponse, + ) } is LegacyAction.StartOnboardingProcess -> { store.dispatch( @@ -28,8 +34,28 @@ internal object LegacyMiddleware { } is LegacyAction.SendEmailTransactionFailed -> { if (store.inject(DaggerGraphState::feedbackManagerFeatureToggles).isLocalLogsEnabled) { + + val amount = action.amount?.convertToAmount(action.cryptoCurrency) + store.inject(DaggerGraphState::saveBlockchainErrorUseCase).invoke( + error = BlockchainErrorInfo( + errorMessage = action.errorMessage, + blockchainId = action.cryptoCurrency.network.id.value, + derivationPath = action.cryptoCurrency.network.derivationPath.value, + destinationAddress = action.destinationAddress.orEmpty(), + tokenSymbol = if (amount?.type is AmountType.Token) { + amount.currencySymbol + } else { + "" + }, + amount = amount?.value?.stripZeroPlainString() ?: "unknown", + fee = action.fee?.convertToAmount(action.cryptoCurrency) + ?.value?.stripZeroPlainString() ?: "unknown", + ), + ) + store.state.globalState.feedbackManager?.sendEmail( - SendTransactionFailedEmail(action.errorMessage), + feedbackData = SendTransactionFailedEmail(action.errorMessage), + scanResponse = action.scanResponse, ) } else { scope.launch { @@ -46,7 +72,8 @@ internal object LegacyMiddleware { ) } store.state.globalState.feedbackManager?.sendEmail( - SendTransactionFailedEmail(action.errorMessage), + feedbackData = SendTransactionFailedEmail(action.errorMessage), + scanResponse = null, ) } } diff --git a/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt b/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt index ed7c3c4c90..410f81e1c6 100644 --- a/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/common/ui/ScanFailsDialog.kt @@ -65,7 +65,7 @@ internal object ScanFailsDialog { } customView.findViewById(R.id.request_support_button)?.setOnClickListener { Analytics.send(Basic.ButtonSupport(sourceAnalytics)) - store.dispatch(GlobalAction.SendEmail(ScanFailsEmail())) + store.dispatch(GlobalAction.SendEmail(feedbackData = ScanFailsEmail(), scanResponse = null)) } customView.findViewById(R.id.cancel_button)?.setOnClickListener { store.dispatchDialogHide() diff --git a/app/src/main/java/com/tangem/tap/di/UtilsModule.kt b/app/src/main/java/com/tangem/tap/di/UtilsModule.kt index 2db04791cf..9c29c8598b 100644 --- a/app/src/main/java/com/tangem/tap/di/UtilsModule.kt +++ b/app/src/main/java/com/tangem/tap/di/UtilsModule.kt @@ -1,11 +1,11 @@ package com.tangem.tap.di import android.content.Context -import com.tangem.core.navigation.feedback.FeedbackManager import com.tangem.core.navigation.finisher.AppFinisher import com.tangem.core.navigation.settings.SettingsManager import com.tangem.core.navigation.share.ShareManager import com.tangem.core.navigation.url.UrlOpener +import com.tangem.domain.feedback.FeedbackManager import com.tangem.tap.common.feedback.ProxyFeedbackManager import com.tangem.tap.common.finisher.AndroidAppFinisher import com.tangem.tap.common.settings.IntentSettingsManager diff --git a/app/src/main/java/com/tangem/tap/di/domain/FeedbackDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/FeedbackDomainModule.kt index 033e322536..04f4f03fb8 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/FeedbackDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/FeedbackDomainModule.kt @@ -1,6 +1,7 @@ package com.tangem.tap.di.domain import android.content.Context +import com.tangem.domain.feedback.GetCardInfoUseCase import com.tangem.domain.feedback.GetFeedbackEmailUseCase import com.tangem.domain.feedback.SaveBlockchainErrorUseCase import com.tangem.domain.feedback.repository.FeedbackRepository @@ -15,6 +16,12 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) internal object FeedbackDomainModule { + @Provides + @Singleton + fun provideGetCardInfoUseCase(feedbackRepository: FeedbackRepository): GetCardInfoUseCase { + return GetCardInfoUseCase(feedbackRepository = feedbackRepository) + } + @Provides @Singleton fun provideGetFeedbackEmailUseCase( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index e0122f240b..4cc6783772 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -142,7 +142,13 @@ internal class DetailsViewModel( private fun sendFeedback() { Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Settings)) - store.dispatchOnMain(GlobalAction.SendEmail(FeedbackEmail())) + store.dispatchOnMain( + GlobalAction.SendEmail( + feedbackData = FeedbackEmail(), + scanResponse = userWalletsListManager.selectedUserWalletSync?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) } private fun navigateToAppSettings() { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt index 5e0028b00d..89ffc2161c 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingMenuProvider.kt @@ -7,15 +7,20 @@ import androidx.core.view.MenuProvider import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.Basic +import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.common.feedback.SupportInfo import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.store +import com.tangem.utils.Provider import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ -class OnboardingMenuProvider : MenuProvider { +class OnboardingMenuProvider( + private val scanResponseProvider: Provider, +) : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_onboarding, menu) } @@ -24,7 +29,12 @@ class OnboardingMenuProvider : MenuProvider { R.id.menu_item_chat_support -> { Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro)) // changed on email support [REDACTED_TASK_KEY] - store.dispatch(GlobalAction.SendEmail(SupportInfo())) + store.dispatch( + GlobalAction.SendEmail( + feedbackData = SupportInfo(), + scanResponse = scanResponseProvider(), + ), + ) true } else -> false diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt index 032cce60d3..0922d3f023 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/BaseOnboardingFragment.kt @@ -9,6 +9,8 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.common.transitions.HomeToOnboardingTransition import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.onboarding.OnboardingMenuProvider +import com.tangem.tap.store +import com.tangem.utils.Provider import com.tangem.wallet.R import com.tangem.wallet.databinding.FragmentOnboardingMainBinding import com.tangem.wallet.databinding.ViewOnboardingProgressBinding @@ -32,7 +34,13 @@ abstract class BaseOnboardingFragment : BaseStoreFragment(R.layout.fragment_o (activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar) } - override fun loadToolbarMenu(): MenuProvider? = OnboardingMenuProvider() + override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider( + scanResponseProvider = Provider { + store.state.globalState.onboardingState.onboardingManager?.scanResponse + ?: store.state.detailsState.scanResponse + ?: error("ScanResponse must be not null") + }, + ) protected fun showConfetti(show: Boolean) = with(binding.vConfetti) { lavConfetti.show(show) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt index 9ba9492c54..594dd4e77c 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt @@ -1,7 +1,7 @@ package com.tangem.tap.features.onboarding.products.twins.redux -import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.getTwinCardNumber +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.tap.common.redux.AppState import org.rekotlin.Action @@ -35,7 +35,10 @@ private fun internalReduce(action: Action, state: AppState): TwinCardsState { ) } is TwinCardsAction.SetStepOfScreen -> { - state = state.copy(currentStep = action.step) + state = state.copy( + currentStep = action.step, + welcomeOnlyScanResponse = (action.step as? TwinCardsStep.WelcomeOnly)?.scanResponse, + ) } is TwinCardsAction.SetUserUnderstand -> { state = state.copy(userWasUnderstandIfWalletRecreate = action.isUnderstand) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt index a5608d4371..fcc38388ac 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsState.kt @@ -1,8 +1,8 @@ package com.tangem.tap.features.onboarding.products.twins.redux import com.tangem.blockchain.common.WalletManager -import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.common.TwinCardNumber +import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.domain.TapError import com.tangem.tap.domain.twins.TwinCardsManager import com.tangem.tap.features.onboarding.OnboardingWalletBalance @@ -29,6 +29,7 @@ data class TwinCardsState( val balanceNonCriticalError: TapError? = null, val balanceCriticalError: TapError? = null, val showConfetti: Boolean = false, + val welcomeOnlyScanResponse: ScanResponse? = null, ) : StateType { val steps: List diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt index 2cbf5949d1..e1e0a58536 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/OnboardingTwinsFragment.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.animation.OvershootInterpolator import androidx.annotation.LayoutRes import androidx.constraintlayout.widget.ConstraintSet +import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.transition.TransitionManager import coil.load @@ -25,12 +26,14 @@ import com.tangem.tap.common.toggleWidget.RefreshBalanceWidget import com.tangem.tap.common.transitions.InternalNoteLayoutTransition import com.tangem.tap.domain.twins.TwinsCardWidget import com.tangem.tap.features.addBackPressHandler +import com.tangem.tap.features.onboarding.OnboardingMenuProvider import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep import com.tangem.tap.store +import com.tangem.utils.Provider import com.tangem.wallet.R import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding import dagger.hilt.android.AndroidEntryPoint @@ -61,6 +64,15 @@ internal class OnboardingTwinsFragment : BaseOnboardingFragment( } } + override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider( + scanResponseProvider = Provider { + store.state.twinCardsState.welcomeOnlyScanResponse + ?: store.state.globalState.onboardingState.onboardingManager?.scanResponse + ?: store.state.detailsState.scanResponse + ?: error("ScanResponse must be not null") + }, + ) + @Suppress("MagicNumber") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) 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 b66984164b..e0577994f9 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 @@ -46,6 +46,7 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.* import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AccessCodeDialog import com.tangem.tap.mainScope import com.tangem.tap.store +import com.tangem.utils.Provider import com.tangem.wallet.R import com.tangem.wallet.databinding.FragmentOnboardingWalletBinding import com.tangem.wallet.databinding.LayoutOnboardingSeedPhraseBinding @@ -115,7 +116,12 @@ class OnboardingWalletFragment : ) } - override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider() + override fun loadToolbarMenu(): MenuProvider = OnboardingMenuProvider( + scanResponseProvider = Provider { + store.state.globalState.onboardingState.onboardingManager?.scanResponse + ?: error("ScanResponse must be not null") + }, + ) private fun reInitCardsWidgetIfNeeded(backupCardsCounts: Int) = with(binding) { val viewBackupCount = flCardsContainer.childCount - 1 @@ -507,7 +513,13 @@ class OnboardingWalletFragment : onOpenChat = { Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro)) // changed on email support [REDACTED_TASK_KEY] - store.dispatch(GlobalAction.SendEmail(SupportInfo())) + store.dispatch( + GlobalAction.SendEmail( + feedbackData = SupportInfo(), + scanResponse = store.state.globalState.onboardingState.onboardingManager?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) }, onOpenUriClick = { uri -> store.dispatchOpenUrl(uri.toString()) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt index ace9edcf19..45c8213362 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/dialogs/WalletActivationErrorDialog.kt @@ -23,7 +23,13 @@ object WalletActivationErrorDialog { setNegativeButton(R.string.common_support) { _, _ -> // changed on email support [REDACTED_TASK_KEY] Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Intro)) - store.dispatch(GlobalAction.SendEmail(SupportInfo())) + store.dispatch( + GlobalAction.SendEmail( + feedbackData = SupportInfo(), + scanResponse = store.state.globalState.onboardingState.onboardingManager?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) } setOnDismissListener { store.dispatchDialogHide() } setCancelable(false) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt index 5663b7cec7..35ee864987 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/SendScreenAction.kt @@ -7,6 +7,7 @@ import com.tangem.blockchain.common.FeePaidCurrency import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.common.core.TangemSdkError +import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.redux.StateDialog import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.tap.common.analytics.events.Token.Send.AddressEntered @@ -185,12 +186,16 @@ sealed class SendAction : SendScreenAction { ) : Dialog() sealed class SendTransactionFails : Dialog() { - data class CardSdkError(val error: TangemSdkError) : Dialog() - data class BlockchainSdkError(val error: com.tangem.blockchain.common.BlockchainSdkError) : Dialog() + data class CardSdkError(val error: TangemSdkError, val scanResponse: ScanResponse) : Dialog() + data class BlockchainSdkError( + val error: com.tangem.blockchain.common.BlockchainSdkError, + val scanResponse: ScanResponse, + ) : Dialog() } data class RequestFeeError( val error: com.tangem.blockchain.common.BlockchainSdkError, + val scanResponse: ScanResponse, val onRetry: () -> Unit, ) : Dialog() diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt index e3096c6a4f..ea4092c252 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt @@ -1,6 +1,9 @@ package com.tangem.tap.features.send.redux.middlewares -import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.BlockchainSdkError +import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.blockchain.extensions.Result import com.tangem.common.extensions.isZero @@ -92,6 +95,7 @@ class RequestFeeMiddleware { dispatch( SendAction.Dialog.RequestFeeError( error = blockchainSdkError, + scanResponse = scanResponse, onRetry = { dispatch(FeeAction.RequestFee) }, ), ) 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 94378ee16e..ecb0e071d8 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 @@ -288,11 +288,25 @@ private fun sendTransaction( val tangemSdkError = error.tangemError as? TangemSdkError ?: return@withMainContext if (tangemSdkError is TangemSdkError.UserCancelled) return@withMainContext - dispatch(SendAction.Dialog.SendTransactionFails.CardSdkError(tangemSdkError)) + dispatch( + SendAction.Dialog.SendTransactionFails.CardSdkError( + error = tangemSdkError, + scanResponse = store.inject(DaggerGraphState::generalUserWalletsListManager) + .selectedUserWalletSync?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) } is BlockchainSdkError.CreateAccountUnderfunded -> { // from XLM, XRP, Polkadot - dispatch(SendAction.Dialog.SendTransactionFails.BlockchainSdkError(error)) + dispatch( + SendAction.Dialog.SendTransactionFails.BlockchainSdkError( + error = error, + scanResponse = store.inject(DaggerGraphState::generalUserWalletsListManager) + .selectedUserWalletSync?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) } is BlockchainSdkError.Kaspa.UtxoAmountError -> { dispatch( @@ -331,7 +345,14 @@ private fun sendTransaction( ) } else -> { - dispatch(SendAction.Dialog.SendTransactionFails.BlockchainSdkError(error)) + dispatch( + SendAction.Dialog.SendTransactionFails.BlockchainSdkError( + error = error, + scanResponse = store.inject(DaggerGraphState::generalUserWalletsListManager) + .selectedUserWalletSync?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) } } } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt index cf27394348..bb8a5ea183 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/RequestFeeErrorDialog.kt @@ -23,7 +23,12 @@ object RequestFeeErrorDialog { setMessage(context.getString(R.string.alert_failed_to_send_transaction_message, errorMessage)) setNegativeButton(R.string.details_row_title_contact_to_support) { _, _ -> Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Send)) - store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(errorMessage))) + store.dispatch( + GlobalAction.SendEmail( + feedbackData = SendTransactionFailedEmail(errorMessage), + scanResponse = dialog.scanResponse, + ), + ) } setPositiveButton(R.string.common_retry) { _, _ -> dialog.onRetry() } setNeutralButton(R.string.common_cancel) { _, _ -> } diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt index 5687caa590..a768ea033b 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/dialogs/SendTransactionFailsDialog.kt @@ -8,6 +8,7 @@ import com.tangem.common.module.ModuleMessageConverter import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.Basic +import com.tangem.domain.models.scan.ScanResponse import com.tangem.sdk.extensions.localizedDescription import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.feedback.SendTransactionFailedEmail @@ -21,21 +22,21 @@ import com.tangem.wallet.R */ object SendTransactionFailsDialog { fun create(context: Context, dialog: SendAction.Dialog.SendTransactionFails.CardSdkError): AlertDialog { - return create(context, dialog.error.localizedDescription(context)) + return create(context, dialog.error.localizedDescription(context), dialog.scanResponse) } fun create(context: Context, dialog: SendAction.Dialog.SendTransactionFails.BlockchainSdkError): AlertDialog { val errorConverter = BlockchainSdkErrorConverter(context) - return create(context, errorConverter.convert(dialog.error)) + return create(context, errorConverter.convert(dialog.error), dialog.scanResponse) } - private fun create(context: Context, errorMessage: String): AlertDialog { + private fun create(context: Context, errorMessage: String, scanResponse: ScanResponse): AlertDialog { return AlertDialog.Builder(context).apply { setTitle(R.string.alert_failed_to_send_transaction_title) setMessage(context.getString(R.string.alert_failed_to_send_transaction_message, errorMessage)) setNeutralButton(R.string.details_row_title_contact_to_support) { _, _ -> Analytics.send(Basic.ButtonSupport(AnalyticsParam.ScreensSources.Send)) - store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(errorMessage))) + store.dispatch(GlobalAction.SendEmail(SendTransactionFailedEmail(errorMessage), scanResponse)) } setPositiveButton(R.string.common_cancel) { _, _ -> } setOnDismissListener { store.dispatch(SendAction.Dialog.Hide) } 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 1e0ddd0477..6ca986bc42 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 @@ -16,6 +16,8 @@ import com.tangem.domain.card.ScanCardUseCase import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.feedback.FeedbackManagerFeatureToggles +import com.tangem.domain.feedback.GetCardInfoUseCase +import com.tangem.domain.feedback.GetFeedbackEmailUseCase import com.tangem.domain.feedback.SaveBlockchainErrorUseCase import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase @@ -82,6 +84,8 @@ data class DaggerGraphState( val blockchainSDKFactory: BlockchainSDKFactory? = null, val emailSender: EmailSender? = null, val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase? = null, + val getFeedbackEmailUseCase: GetFeedbackEmailUseCase? = null, + val getCardInfoUseCase: GetCardInfoUseCase? = null, val assetLoader: AssetLoader? = null, val detailsFeatureToggles: DetailsFeatureToggles? = null, val stakingRouter: StakingRouter? = null, diff --git a/core/navigation/src/main/java/com/tangem/core/navigation/feedback/DummyFeedbackManager.kt b/core/navigation/src/main/java/com/tangem/core/navigation/feedback/DummyFeedbackManager.kt deleted file mode 100644 index 2f92f40ad9..0000000000 --- a/core/navigation/src/main/java/com/tangem/core/navigation/feedback/DummyFeedbackManager.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.core.navigation.feedback - -class DummyFeedbackManager : FeedbackManager { - - override fun sendEmail(type: FeedbackType) { - /* no-op */ - } -} \ No newline at end of file diff --git a/core/navigation/src/main/java/com/tangem/core/navigation/feedback/FeedbackManager.kt b/core/navigation/src/main/java/com/tangem/core/navigation/feedback/FeedbackManager.kt deleted file mode 100644 index a76d2704e6..0000000000 --- a/core/navigation/src/main/java/com/tangem/core/navigation/feedback/FeedbackManager.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.tangem.core.navigation.feedback - -interface FeedbackManager { - - fun sendEmail(type: FeedbackType) -} \ No newline at end of file diff --git a/core/navigation/src/main/java/com/tangem/core/navigation/feedback/FeedbackType.kt b/core/navigation/src/main/java/com/tangem/core/navigation/feedback/FeedbackType.kt deleted file mode 100644 index b1470f5e4d..0000000000 --- a/core/navigation/src/main/java/com/tangem/core/navigation/feedback/FeedbackType.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.core.navigation.feedback - -sealed class FeedbackType { - data object RateCanBeBetter : FeedbackType() - - data object ScanFails : FeedbackType() - - data class SendTransactionFailed(val error: String) : FeedbackType() - - data object Feedback : FeedbackType() - - data object Support : FeedbackType() -} \ No newline at end of file diff --git a/data/feedback/build.gradle.kts b/data/feedback/build.gradle.kts index 4847e15ddd..e936310c64 100644 --- a/data/feedback/build.gradle.kts +++ b/data/feedback/build.gradle.kts @@ -37,7 +37,9 @@ dependencies { implementation(projects.domain.feedback) implementation(projects.domain.legacy) - implementation(projects.libs.blockchainSdk) implementation(projects.domain.models) + implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) + + implementation(projects.libs.blockchainSdk) } \ No newline at end of file diff --git a/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt b/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt index 4bf2f7eb2a..b5313ac608 100644 --- a/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt +++ b/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt @@ -9,12 +9,14 @@ import com.tangem.data.feedback.converters.CardInfoConverter import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectMap -import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.walletmanager.WalletManagersStore import com.tangem.domain.feedback.models.* import com.tangem.domain.feedback.repository.FeedbackRepository -import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.runCatching import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import timber.log.Timber @@ -25,43 +27,47 @@ import java.io.StringWriter /** * Implementation of [FeedbackRepository] * - * @property appPreferencesStore application preferences store - * @property userWalletsStore user wallets store - * @property walletManagersStore wallet managers store - * @property context context for getting app version + * @property appPreferencesStore application preferences store + * @property userWalletsListManager user wallets list manager + * @property walletManagersStore wallet managers store + * @property context context for getting app version + * @property dispatchers coroutine dispatchers provider * [REDACTED_AUTHOR] */ internal class DefaultFeedbackRepository( private val appPreferencesStore: AppPreferencesStore, - private val userWalletsStore: UserWalletsStore, + private val userWalletsListManager: UserWalletsListManager, private val walletManagersStore: WalletManagersStore, private val context: Context, + private val dispatchers: CoroutineDispatcherProvider, ) : FeedbackRepository { private val blockchainsErrors = MutableStateFlow>(emptyMap()) - override suspend fun getUserWalletsInfo(): UserWalletsInfo { + override suspend fun getCardInfo(scanResponse: ScanResponse) = CardInfoConverter.convert(value = scanResponse) + + override suspend fun getUserWalletsInfo(userWalletId: UserWalletId?): UserWalletsInfo { return UserWalletsInfo( - selectedUserWalletId = getSelectedUserWallet().walletId.stringValue, - totalUserWallets = userWalletsStore.getAllSyncOrNull()?.size ?: error("No user wallets found"), + selectedUserWalletId = userWalletId?.stringValue ?: "card isn't activated", + totalUserWallets = userWalletsListManager.walletsCount, ) } - override suspend fun getCardInfo(): CardInfo { - return CardInfoConverter.convert(value = getSelectedUserWallet()) - } - - override suspend fun getBlockchainInfoList(): List { + override suspend fun getBlockchainInfoList(userWalletId: UserWalletId): List { return walletManagersStore - .getAllSync(userWalletId = getSelectedUserWallet().walletId) + .getAllSync(userWalletId = userWalletId) .map(BlockchainInfoConverter::convert) } - override suspend fun getBlockchainInfo(blockchainId: String, derivationPath: String?): BlockchainInfo? { + override suspend fun getBlockchainInfo( + userWalletId: UserWalletId, + blockchainId: String, + derivationPath: String?, + ): BlockchainInfo? { return walletManagersStore .getSyncOrNull( - userWalletId = getSelectedUserWallet().walletId, + userWalletId = userWalletId, blockchain = Blockchain.fromId(blockchainId), derivationPath = derivationPath, ) @@ -77,18 +83,18 @@ internal class DefaultFeedbackRepository( } override fun saveBlockchainErrorInfo(error: BlockchainErrorInfo) { + val userWallet = userWalletsListManager.selectedUserWalletSync ?: error("UserWallet is not selected") + blockchainsErrors.update { it.toMutableMap().apply { - put(getSelectedUserWallet().walletId, error) + put(userWallet.walletId, error) } } } - override suspend fun getBlockchainErrorInfo(): BlockchainErrorInfo? { - return blockchainsErrors.value[getSelectedUserWallet().walletId].also { - if (it == null) { - Timber.e("Blockchain error info is null for ${getSelectedUserWallet().walletId}") - } + override suspend fun getBlockchainErrorInfo(userWalletId: UserWalletId): BlockchainErrorInfo? { + return blockchainsErrors.value[userWalletId].also { + if (it == null) Timber.e("Blockchain error info is null for $userWalletId") } } @@ -99,7 +105,7 @@ internal class DefaultFeedbackRepository( } override suspend fun createLogFile(logs: String): File? { - return try { + return runCatching(dispatchers.io) { val file = File(context.filesDir, LOGS_FILE) file.delete() file.createNewFile() @@ -113,8 +119,8 @@ internal class DefaultFeedbackRepository( fileWriter.close() file - } catch (ex: Exception) { - Timber.e(ex, "Logs file isn't created") + }.getOrElse { + Timber.e(it, "Logs file isn't created") null } } @@ -130,11 +136,6 @@ internal class DefaultFeedbackRepository( ) } - private fun getSelectedUserWallet(): UserWallet { - return userWalletsStore.selectedUserWalletOrNull - ?: error("UserWallet is not selected") - } - private companion object { const val LOGS_FILE = "logs.txt" } diff --git a/data/feedback/src/main/java/com/tangem/data/feedback/converters/CardInfoConverter.kt b/data/feedback/src/main/java/com/tangem/data/feedback/converters/CardInfoConverter.kt index 7d16454467..c4aafd2bf2 100644 --- a/data/feedback/src/main/java/com/tangem/data/feedback/converters/CardInfoConverter.kt +++ b/data/feedback/src/main/java/com/tangem/data/feedback/converters/CardInfoConverter.kt @@ -2,28 +2,36 @@ package com.tangem.data.feedback.converters import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.feedback.models.CardInfo -import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.wallets.builder.UserWalletIdBuilder +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.converter.Converter /** - * Converter from [UserWallet] to [CardInfo] + * Converter from [ScanResponse] to [CardInfo] * [REDACTED_AUTHOR] */ -internal object CardInfoConverter : Converter { +internal object CardInfoConverter : Converter { - override fun convert(value: UserWallet): CardInfo { - return with(value.scanResponse) { + override fun convert(value: ScanResponse): CardInfo { + return with(value) { CardInfo( + userWalletId = createUserWalletId(scanResponse = value), cardId = card.cardId, firmwareVersion = card.firmwareVersion.stringValue, cardBlockchain = walletData?.blockchain, signedHashesList = card.wallets.map { CardInfo.SignedHashes(curve = it.curve.curve, total = it.totalSignedHashes?.toString()) }, - isImported = value.isImported, - isStart2Coin = value.scanResponse.card.isStart2Coin, + isImported = value.card.wallets.any(CardDTO.Wallet::isImported), + isStart2Coin = value.card.isStart2Coin, ) } } + + private fun createUserWalletId(scanResponse: ScanResponse): UserWalletId? { + return UserWalletIdBuilder.scanResponse(scanResponse = scanResponse).build() + } } \ No newline at end of file diff --git a/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackRepositoryModule.kt b/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackRepositoryModule.kt index 5a00938959..393a30cf25 100644 --- a/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackRepositoryModule.kt +++ b/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackRepositoryModule.kt @@ -3,9 +3,10 @@ package com.tangem.data.feedback.di import android.content.Context import com.tangem.data.feedback.DefaultFeedbackRepository import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.walletmanager.WalletManagersStore import com.tangem.domain.feedback.repository.FeedbackRepository +import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -21,10 +22,17 @@ internal object FeedbackRepositoryModule { @Singleton fun provideFeedbackRepository( appPreferencesStore: AppPreferencesStore, - userWalletsStore: UserWalletsStore, + userWalletsListManager: UserWalletsListManager, walletManagersStore: WalletManagersStore, @ApplicationContext context: Context, + dispatchers: CoroutineDispatcherProvider, ): FeedbackRepository { - return DefaultFeedbackRepository(appPreferencesStore, userWalletsStore, walletManagersStore, context) + return DefaultFeedbackRepository( + appPreferencesStore = appPreferencesStore, + userWalletsListManager = userWalletsListManager, + walletManagersStore = walletManagersStore, + context = context, + dispatchers = dispatchers, + ) } } \ No newline at end of file diff --git a/domain/feedback/build.gradle.kts b/domain/feedback/build.gradle.kts index 6a21560035..28fe483e00 100644 --- a/domain/feedback/build.gradle.kts +++ b/domain/feedback/build.gradle.kts @@ -13,5 +13,6 @@ dependencies { implementation(deps.jodatime) implementation(projects.core.res) + implementation(projects.domain.models) implementation(projects.domain.wallets.models) } \ No newline at end of file diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackManager.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackManager.kt new file mode 100644 index 0000000000..bc18ec66ec --- /dev/null +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/FeedbackManager.kt @@ -0,0 +1,8 @@ +package com.tangem.domain.feedback + +import com.tangem.domain.feedback.models.FeedbackEmailType + +interface FeedbackManager { + + fun sendEmail(type: FeedbackEmailType) +} \ No newline at end of file diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/GetCardInfoUseCase.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/GetCardInfoUseCase.kt new file mode 100644 index 0000000000..9d9fc6995c --- /dev/null +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/GetCardInfoUseCase.kt @@ -0,0 +1,23 @@ +package com.tangem.domain.feedback + +import arrow.core.Either +import arrow.core.Either.Companion.catch +import com.tangem.domain.feedback.models.CardInfo +import com.tangem.domain.feedback.repository.FeedbackRepository +import com.tangem.domain.models.scan.ScanResponse + +/** + * UseCase for creating 'CardInfo' + * + * @property feedbackRepository feedback repository + * +[REDACTED_AUTHOR] + */ +class GetCardInfoUseCase( + private val feedbackRepository: FeedbackRepository, +) { + + suspend operator fun invoke(scanResponse: ScanResponse): Either { + return catch { feedbackRepository.getCardInfo(scanResponse) } + } +} \ No newline at end of file diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/GetFeedbackEmailUseCase.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/GetFeedbackEmailUseCase.kt index 50998a4ed8..acdcc492b7 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/GetFeedbackEmailUseCase.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/GetFeedbackEmailUseCase.kt @@ -25,23 +25,21 @@ class GetFeedbackEmailUseCase( private val emailMessageBodyResolver = EmailMessageBodyResolver(feedbackRepository) suspend operator fun invoke(type: FeedbackEmailType): FeedbackEmail { - val cardInfo = feedbackRepository.getCardInfo() - val formattedLogs = AppLogsFormatter().format(appLogs = feedbackRepository.getAppLogs()) return FeedbackEmail( - address = getAddress(cardInfo), - subject = emailSubjectResolver.resolve(type, cardInfo), - message = createMessage(type, cardInfo), + address = getAddress(type.cardInfo), + subject = emailSubjectResolver.resolve(type), + message = createMessage(type), file = feedbackRepository.createLogFile(logs = formattedLogs), ) } - private fun getAddress(cardInfo: CardInfo): String { - return if (cardInfo.isStart2Coin) START2COIN_SUPPORT_EMAIL else TANGEM_SUPPORT_EMAIL + private fun getAddress(cardInfo: CardInfo?): String { + return if (cardInfo?.isStart2Coin == true) START2COIN_SUPPORT_EMAIL else TANGEM_SUPPORT_EMAIL } - private suspend fun createMessage(type: FeedbackEmailType, cardInfo: CardInfo): String { + private suspend fun createMessage(type: FeedbackEmailType): String { return StringBuilder().apply { val title = emailMessageTitleResolver.resolve(type) append(title) @@ -50,9 +48,7 @@ class GetFeedbackEmailUseCase( appendDisclaimerIfNeeded(type) - skipLine() - - val body = emailMessageBodyResolver.resolve(type, cardInfo) + val body = emailMessageBodyResolver.resolve(type) append(body) }.toString() } @@ -62,6 +58,7 @@ class GetFeedbackEmailUseCase( this } else { append(resources.getString(R.string.feedback_data_collection_message)) + skipLine() } } } \ No newline at end of file diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/models/CardInfo.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/models/CardInfo.kt index 7ae84ac608..2e7e710cc1 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/models/CardInfo.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/models/CardInfo.kt @@ -1,6 +1,9 @@ package com.tangem.domain.feedback.models +import com.tangem.domain.wallets.models.UserWalletId + data class CardInfo( + val userWalletId: UserWalletId?, val cardId: String, val firmwareVersion: String, val cardBlockchain: String?, diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt index 6bbd5a9670..1e4971e4cf 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/models/FeedbackEmailType.kt @@ -7,15 +7,19 @@ package com.tangem.domain.feedback.models */ sealed interface FeedbackEmailType { + val cardInfo: CardInfo? + /** User initiate request yourself. Example, button on DetailsScreen or OnboardingScreen */ - data object DirectUserRequest : FeedbackEmailType + data class DirectUserRequest(override val cardInfo: CardInfo) : FeedbackEmailType /** User rate the app as "can be better" */ - data object RateCanBeBetter : FeedbackEmailType + data class RateCanBeBetter(override val cardInfo: CardInfo) : FeedbackEmailType /** User has problem with scanning */ - data object ScanningProblem : FeedbackEmailType + data object ScanningProblem : FeedbackEmailType { + override val cardInfo: CardInfo? = null + } /** User has problem with sending transaction */ - data object TransactionSendingProblem : FeedbackEmailType + data class TransactionSendingProblem(override val cardInfo: CardInfo) : FeedbackEmailType } \ No newline at end of file diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/repository/FeedbackRepository.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/repository/FeedbackRepository.kt index c9d6806eea..1b5de9c70c 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/repository/FeedbackRepository.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/repository/FeedbackRepository.kt @@ -1,23 +1,29 @@ package com.tangem.domain.feedback.repository import com.tangem.domain.feedback.models.* +import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.wallets.models.UserWalletId import java.io.File interface FeedbackRepository { - suspend fun getUserWalletsInfo(): UserWalletsInfo + suspend fun getCardInfo(scanResponse: ScanResponse): CardInfo - suspend fun getCardInfo(): CardInfo + suspend fun getUserWalletsInfo(userWalletId: UserWalletId?): UserWalletsInfo - suspend fun getBlockchainInfoList(): List - - suspend fun getBlockchainInfo(blockchainId: String, derivationPath: String?): BlockchainInfo? + suspend fun getBlockchainInfoList(userWalletId: UserWalletId): List fun getPhoneInfo(): PhoneInfo + suspend fun getBlockchainInfo( + userWalletId: UserWalletId, + blockchainId: String, + derivationPath: String?, + ): BlockchainInfo? + fun saveBlockchainErrorInfo(error: BlockchainErrorInfo) - suspend fun getBlockchainErrorInfo(): BlockchainErrorInfo? + suspend fun getBlockchainErrorInfo(userWalletId: UserWalletId): BlockchainErrorInfo? suspend fun getAppLogs(): List diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt index 8574fb1010..a9bb1a64dd 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt @@ -16,25 +16,33 @@ internal class EmailMessageBodyResolver( private val feedbackRepository: FeedbackRepository, ) { - /** Resolve email message body by [type] using [cardInfo] */ - suspend fun resolve(type: FeedbackEmailType, cardInfo: CardInfo): String = with(FeedbackDataBuilder()) { + /** Resolve email message body by [type] */ + suspend fun resolve(type: FeedbackEmailType): String = with(FeedbackDataBuilder()) { when (type) { - FeedbackEmailType.DirectUserRequest -> addUserRequestBody(cardInfo) - FeedbackEmailType.RateCanBeBetter -> addCardAndPhoneInfo(cardInfo) - FeedbackEmailType.ScanningProblem -> addScanningProblemBody() - FeedbackEmailType.TransactionSendingProblem -> addTransactionSendingProblemBody(cardInfo) + is FeedbackEmailType.DirectUserRequest -> addUserRequestBody(type.cardInfo) + is FeedbackEmailType.RateCanBeBetter -> addCardAndPhoneInfo(type.cardInfo) + is FeedbackEmailType.ScanningProblem -> addScanningProblemBody() + is FeedbackEmailType.TransactionSendingProblem -> addTransactionSendingProblemBody(type.cardInfo) } return build() } private suspend fun FeedbackDataBuilder.addUserRequestBody(cardInfo: CardInfo) { - addUserWalletsInfo(userWalletsInfo = feedbackRepository.getUserWalletsInfo()) + addUserWalletsInfo(userWalletsInfo = feedbackRepository.getUserWalletsInfo(cardInfo.userWalletId)) addDelimiter() addCardInfo(cardInfo) addDelimiter() - addBlockchainInfoList(blockchainInfoList = feedbackRepository.getBlockchainInfoList()) - addDelimiter() + + if (cardInfo.userWalletId != null) { + val blockchainInfoList = feedbackRepository.getBlockchainInfoList(cardInfo.userWalletId) + + if (blockchainInfoList.isNotEmpty()) { + addBlockchainInfoList(blockchainInfoList = blockchainInfoList) + addDelimiter() + } + } + addPhoneInfo(phoneInfo = feedbackRepository.getPhoneInfo()) } @@ -46,9 +54,11 @@ internal class EmailMessageBodyResolver( addCardInfo(cardInfo) addDelimiter() - val blockchainError = feedbackRepository.getBlockchainErrorInfo() + val userWalletId = requireNotNull(cardInfo.userWalletId) { "UserWalletId must be not null" } + val blockchainError = feedbackRepository.getBlockchainErrorInfo(userWalletId = userWalletId) val blockchainInfo = blockchainError?.let { feedbackRepository.getBlockchainInfo( + userWalletId = userWalletId, blockchainId = blockchainError.blockchainId, derivationPath = blockchainError.derivationPath, ) diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt index 38c983c617..6ab001b775 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt @@ -16,10 +16,10 @@ internal class EmailMessageTitleResolver(private val resources: Resources) { /** Resolve email message title by [type] */ fun resolve(type: FeedbackEmailType): String { return when (type) { - FeedbackEmailType.DirectUserRequest -> R.string.feedback_preface_support - FeedbackEmailType.RateCanBeBetter -> R.string.feedback_preface_rate_negative - FeedbackEmailType.ScanningProblem -> R.string.feedback_preface_scan_failed - FeedbackEmailType.TransactionSendingProblem -> R.string.feedback_preface_tx_failed + is FeedbackEmailType.DirectUserRequest -> R.string.feedback_preface_support + is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_preface_rate_negative + is FeedbackEmailType.ScanningProblem -> R.string.feedback_preface_scan_failed + is FeedbackEmailType.TransactionSendingProblem -> R.string.feedback_preface_tx_failed } .let(resources::getString) } diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt index 392fa7d2f4..beb89739bd 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt @@ -2,7 +2,6 @@ package com.tangem.domain.feedback.utils import android.content.res.Resources import com.tangem.domain.feedback.R -import com.tangem.domain.feedback.models.CardInfo import com.tangem.domain.feedback.models.FeedbackEmailType /** @@ -14,19 +13,19 @@ import com.tangem.domain.feedback.models.FeedbackEmailType */ internal class EmailSubjectResolver(private val resources: Resources) { - /** Resolve email message body by [type] using [cardInfo] */ - fun resolve(type: FeedbackEmailType, cardInfo: CardInfo): String { + /** Resolve email message body by [type] */ + fun resolve(type: FeedbackEmailType): String { return when (type) { - FeedbackEmailType.DirectUserRequest -> { - if (cardInfo.isStart2Coin) { + is FeedbackEmailType.DirectUserRequest -> { + if (type.cardInfo.isStart2Coin) { R.string.feedback_subject_support } else { R.string.feedback_subject_support_tangem } } - FeedbackEmailType.RateCanBeBetter -> R.string.feedback_subject_rate_negative - FeedbackEmailType.ScanningProblem -> R.string.feedback_subject_scan_failed - FeedbackEmailType.TransactionSendingProblem -> R.string.feedback_subject_tx_failed + is FeedbackEmailType.RateCanBeBetter -> R.string.feedback_subject_rate_negative + is FeedbackEmailType.ScanningProblem -> R.string.feedback_subject_scan_failed + is FeedbackEmailType.TransactionSendingProblem -> R.string.feedback_subject_tx_failed } .let(resources::getString) } diff --git a/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt b/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt index 3e0b022afd..68c6988923 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/redux/LegacyAction.kt @@ -8,7 +8,7 @@ import java.math.BigDecimal sealed interface LegacyAction : Action { - object SendEmailRateCanBeBetter : LegacyAction + data class SendEmailRateCanBeBetter(val scanResponse: ScanResponse) : LegacyAction /** * Initiate an onboarding process. @@ -34,5 +34,6 @@ sealed interface LegacyAction : Action { val fee: BigDecimal?, val destinationAddress: String?, val errorMessage: String, + val scanResponse: ScanResponse, ) : LegacyAction } \ No newline at end of file diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index 1edff72903..c1f2899eff 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { /* Project - Domain */ implementation(projects.domain.models) + implementation(projects.domain.feedback) implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) implementation(projects.domain.card) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt index ccbc7f2409..5d2d2b67d0 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/component/preview/PreviewDetailsComponent.kt @@ -3,7 +3,6 @@ package com.tangem.features.details.component.preview import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.tangem.core.decompose.navigation.DummyRouter -import com.tangem.core.navigation.feedback.DummyFeedbackManager import com.tangem.core.navigation.url.DummyUrlOpener import com.tangem.features.details.component.DetailsComponent import com.tangem.features.details.entity.DetailsFooterUM @@ -19,8 +18,7 @@ internal class PreviewDetailsComponent : DetailsComponent { ItemsBuilder( router = DummyRouter(), urlOpener = DummyUrlOpener(), - feedbackManager = DummyFeedbackManager(), - ).buldAll(isWalletConnectAvailable = true) + ).buildAll(isWalletConnectAvailable = true, onSupportClick = {}) } private val previewFooter = DetailsFooterUM( diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index f1bbd73bdb..8bd54c48e9 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -5,7 +5,11 @@ import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router +import com.tangem.domain.feedback.FeedbackManager +import com.tangem.domain.feedback.GetCardInfoUseCase +import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.walletconnect.CheckIsWalletConnectAvailableUseCase +import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.features.details.component.DetailsComponent import com.tangem.features.details.entity.DetailsFooterUM import com.tangem.features.details.entity.DetailsItemUM @@ -33,6 +37,9 @@ internal class DetailsModel @Inject constructor( private val checkIsWalletConnectAvailableUseCase: CheckIsWalletConnectAvailableUseCase, private val router: Router, private val paramsContainer: ParamsContainer, + private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, + private val getCardInfoUseCase: GetCardInfoUseCase, + private val feedbackManager: FeedbackManager, override val dispatchers: CoroutineDispatcherProvider, ) : Model() { @@ -66,7 +73,22 @@ internal class DetailsModel @Inject constructor( false } - items.value = itemsBuilder.buldAll(isWalletConnectAvailable) + items.value = itemsBuilder.buildAll( + isWalletConnectAvailable = isWalletConnectAvailable, + onSupportClick = ::sendFeedback, + ) + } + + private fun sendFeedback() { + modelScope.launch { + val scanResponse = getSelectedWalletSyncUseCase().getOrNull()?.scanResponse + ?: error("Selected wallet is null") + + val cardInfo = getCardInfoUseCase(scanResponse = scanResponse).getOrNull() + ?: error("CardInfo must be not null") + + feedbackManager.sendEmail(type = FeedbackEmailType.DirectUserRequest(cardInfo)) + } } private suspend fun updateState(items: ImmutableList) { diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt index 6ce516821b..ecb5d93de7 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/ItemsBuilder.kt @@ -3,8 +3,6 @@ package com.tangem.features.details.utils import com.tangem.common.routing.AppRoute import com.tangem.core.decompose.di.ComponentScoped import com.tangem.core.decompose.navigation.Router -import com.tangem.core.navigation.feedback.FeedbackManager -import com.tangem.core.navigation.feedback.FeedbackType import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.components.block.model.BlockUM import com.tangem.core.ui.extensions.resourceReference @@ -21,18 +19,18 @@ import javax.inject.Inject internal class ItemsBuilder @Inject constructor( private val router: Router, private val urlOpener: UrlOpener, - private val feedbackManager: FeedbackManager, ) { - suspend fun buldAll(isWalletConnectAvailable: Boolean): ImmutableList = buildList { - buildWalletConnectBlock(isWalletConnectAvailable)?.let(::add) - buildUserWalletListBlock().let(::add) - buildShopBlock().let(::add) - buildSettingsBlock().let(::add) - buildSupportBlock().let(::add) - }.toImmutableList() + fun buildAll(isWalletConnectAvailable: Boolean, onSupportClick: () -> Unit): ImmutableList = + buildList { + buildWalletConnectBlock(isWalletConnectAvailable)?.let(::add) + buildUserWalletListBlock().let(::add) + buildShopBlock().let(::add) + buildSettingsBlock().let(::add) + buildSupportBlock(onSupportClick).let(::add) + }.toImmutableList() - private suspend fun buildWalletConnectBlock(isWalletConnectAvailable: Boolean): DetailsItemUM? { + private fun buildWalletConnectBlock(isWalletConnectAvailable: Boolean): DetailsItemUM? { return if (isWalletConnectAvailable) { DetailsItemUM.WalletConnect( onClick = { router.push(AppRoute.WalletConnectSessions) }, @@ -83,7 +81,7 @@ internal class ItemsBuilder @Inject constructor( }.toImmutableList(), ) - private fun buildSupportBlock(): DetailsItemUM = DetailsItemUM.Basic( + private fun buildSupportBlock(onClick: () -> Unit): DetailsItemUM = DetailsItemUM.Basic( id = "support", items = persistentListOf( DetailsItemUM.Basic.Item( @@ -91,7 +89,7 @@ internal class ItemsBuilder @Inject constructor( block = BlockUM( text = resourceReference(R.string.details_send_feedback), iconRes = R.drawable.ic_comment_24, - onClick = { feedbackManager.sendEmail(FeedbackType.Feedback) }, + onClick = onClick, ), ), DetailsItemUM.Basic.Item( diff --git a/features/send/impl/build.gradle.kts b/features/send/impl/build.gradle.kts index 3937749519..9a3de6d8cb 100644 --- a/features/send/impl/build.gradle.kts +++ b/features/send/impl/build.gradle.kts @@ -74,6 +74,7 @@ dependencies { implementation(projects.domain.card) implementation(projects.domain.balanceHiding) implementation(projects.domain.balanceHiding.models) + implementation(projects.domain.feedback) implementation(projects.domain.qrScanning) implementation(projects.domain.qrScanning.models) implementation(projects.domain.settings) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index cc5d43f0ec..6fd5854725 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -530,6 +530,7 @@ internal class SendViewModel @Inject constructor( fee = feeValue, destinationAddress = recipient, errorMessage = errorMessage, + scanResponse = userWallet.scanResponse, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index 087ec87d35..c27292d883 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -204,7 +204,12 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( viewModelScope.launch(dispatchers.main) { neverToSuggestRateAppUseCase() - reduxStateHolder.dispatch(LegacyAction.SendEmailRateCanBeBetter) + reduxStateHolder.dispatch( + LegacyAction.SendEmailRateCanBeBetter( + scanResponse = getSelectedUserWallet()?.scanResponse + ?: error("ScanResponse must be not null"), + ), + ) } } @@ -250,7 +255,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( } } - private suspend fun getSelectedUserWallet(): UserWallet? { + private fun getSelectedUserWallet(): UserWallet? { val userWalletId = stateHolder.getSelectedWalletId() return getUserWalletUseCase(userWalletId).getOrElse { Timber.e(