diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index 7a386bdfd1..cbf8eebb27 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -6,6 +6,8 @@ import com.tangem.domain.exchange.RampStateManager import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository +import com.tangem.feature.tester.ActivityClassWrapper +import com.tangem.tap.MainActivity import com.tangem.tap.domain.sdk.TangemSdkManager import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository import com.tangem.tap.network.exchangeServices.DefaultRampManager @@ -65,4 +67,10 @@ internal object ActivityModule { ): GetPolkadotCheckHasImmortalUseCase { return GetPolkadotCheckHasImmortalUseCase(polkadotAccountHealthCheckRepository) } + + @Provides + @Singleton + fun provideActivityClassWrapper(): ActivityClassWrapper { + return ActivityClassWrapper(MainActivity::class.java) + } } \ No newline at end of file diff --git a/features/tester/api/src/main/java/com/tangem/features/tester/api/AppRestarter.kt b/features/tester/api/src/main/java/com/tangem/features/tester/api/AppRestarter.kt new file mode 100644 index 0000000000..a64be25542 --- /dev/null +++ b/features/tester/api/src/main/java/com/tangem/features/tester/api/AppRestarter.kt @@ -0,0 +1,9 @@ +package com.tangem.features.tester.api + +/** + * Interface for app restarter + */ +interface AppRestarter { + + fun restart() +} \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/ActivityClassWrapper.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/ActivityClassWrapper.kt new file mode 100644 index 0000000000..22d2d4d3a9 --- /dev/null +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/ActivityClassWrapper.kt @@ -0,0 +1,12 @@ +package com.tangem.feature.tester + +import android.app.Activity + +/** + * Wraps the main activity class to avoid type erasure issues during injection. + * + * @property clazz activity class + */ +class ActivityClassWrapper( + val clazz: Class, +) \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/apprestarter/DefaultAppRestarter.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/apprestarter/DefaultAppRestarter.kt new file mode 100644 index 0000000000..34cd927e71 --- /dev/null +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/apprestarter/DefaultAppRestarter.kt @@ -0,0 +1,27 @@ +package com.tangem.feature.tester.apprestarter + +import android.app.Activity +import android.content.Context +import android.content.Intent +import com.tangem.feature.tester.ActivityClassWrapper +import com.tangem.features.tester.api.AppRestarter + +/** + * Entity that kills the process and restarts the main activity + * @property context Activity context + */ +internal class DefaultAppRestarter( + private val context: Context, + private val activityClassWrapper: ActivityClassWrapper, +) : AppRestarter { + + override fun restart() { + if (context !is Activity) return + + context.finish() + context.startActivity( + Intent(context, activityClassWrapper.clazz).apply { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP }, + ) + Runtime.getRuntime().exit(0) + } +} \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/di/RestarterModule.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/di/RestarterModule.kt new file mode 100644 index 0000000000..4891a60f12 --- /dev/null +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/di/RestarterModule.kt @@ -0,0 +1,26 @@ +package com.tangem.feature.tester.di + +import android.content.Context +import com.tangem.feature.tester.ActivityClassWrapper +import com.tangem.feature.tester.apprestarter.DefaultAppRestarter +import com.tangem.features.tester.api.AppRestarter +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import dagger.hilt.android.qualifiers.ActivityContext +import dagger.hilt.android.scopes.ActivityScoped + +@Module +@InstallIn(ActivityComponent::class) +internal object RestarterModule { + + @Provides + @ActivityScoped + fun provideAppRestarter( + @ActivityContext context: Context, + activityClassWrapper: ActivityClassWrapper, + ): AppRestarter { + return DefaultAppRestarter(context, activityClassWrapper) + } +} \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/TesterActivity.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/TesterActivity.kt index 2ddfba7af0..ef7ab21998 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/TesterActivity.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/TesterActivity.kt @@ -18,6 +18,7 @@ import com.tangem.feature.tester.presentation.menu.state.TesterMenuContentState import com.tangem.feature.tester.presentation.menu.ui.TesterMenuScreen import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter import com.tangem.feature.tester.presentation.navigation.TesterScreen +import com.tangem.features.tester.api.AppRestarter import com.tangem.features.tester.api.TesterRouter import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -33,6 +34,9 @@ internal class TesterActivity : ComposeActivity() { @Inject lateinit var testerRouter: TesterRouter + @Inject + lateinit var appRestarter: AppRestarter + private val innerTesterRouter: InnerTesterRouter get() = requireNotNull(testerRouter as? InnerTesterRouter) { "TesterRouter must be InnerTesterRouter for tester feature" @@ -66,7 +70,7 @@ internal class TesterActivity : ComposeActivity() { composable(route = TesterScreen.FEATURE_TOGGLES.name) { val viewModel = hiltViewModel().apply { - setupNavigation(innerTesterRouter) + setupInteractions(innerTesterRouter, appRestarter) } FeatureTogglesScreen(state = viewModel.uiState) diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt index fa65d935e4..c814bf750b 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsContentState.kt @@ -3,15 +3,16 @@ package com.tangem.feature.tester.presentation.actions import com.tangem.domain.apptheme.model.AppThemeMode internal data class TesterActionsContentState( - val onBackClick: () -> Unit, val hideAllCurrenciesConfig: HideAllCurrenciesConfig, val toggleAppThemeConfig: ToggleAppThemeConfig, + val onBackClick: () -> Unit, + val onApplyChangesClick: () -> Unit, ) internal sealed class HideAllCurrenciesConfig { data class Clickable(val onClick: () -> Unit) : HideAllCurrenciesConfig() - object Progress : HideAllCurrenciesConfig() + data object Progress : HideAllCurrenciesConfig() } internal data class ToggleAppThemeConfig( diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt index 830d10591c..1cc0845d8c 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsScreen.kt @@ -78,9 +78,10 @@ private fun TesterActionsScreenSample(modifier: Modifier = Modifier) { ) { TesterActionsScreen( state = TesterActionsContentState( - onBackClick = {}, hideAllCurrenciesConfig = HideAllCurrenciesConfig.Clickable {}, toggleAppThemeConfig = ToggleAppThemeConfig(AppThemeMode.DEFAULT) {}, + onBackClick = {}, + onApplyChangesClick = {}, ), ) } diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt index b919f37132..514edb448d 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/actions/TesterActionsViewModel.kt @@ -31,9 +31,10 @@ internal class TesterActionsViewModel @Inject constructor( private val initialState: TesterActionsContentState get() = TesterActionsContentState( - onBackClick = { /* no-op */ }, hideAllCurrenciesConfig = HideAllCurrenciesConfig.Clickable(this::hideAllCurrencies), toggleAppThemeConfig = ToggleAppThemeConfig(AppThemeMode.DEFAULT, this::toggleAppTheme), + onBackClick = { /* no-op */ }, + onApplyChangesClick = { /* no-op */ }, ) init { diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/state/FeatureTogglesContentState.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/state/FeatureTogglesContentState.kt index 4c55258e0d..736e01b6c6 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/state/FeatureTogglesContentState.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/state/FeatureTogglesContentState.kt @@ -8,9 +8,11 @@ import com.tangem.feature.tester.presentation.featuretoggles.models.TesterFeatur * @property featureToggles feature toggles list * @property onBackClick the lambda to be invoked when back button is pressed * @property onToggleValueChange the lambda to be invoked when switch button is pressed + * @property onApplyChangesClick the lambda to be invoked when apply changes button is pressed */ internal data class FeatureTogglesContentState( val featureToggles: List, - val onBackClick: () -> Unit, val onToggleValueChange: (String, Boolean) -> Unit, + val onBackClick: () -> Unit, + val onApplyChangesClick: () -> Unit, ) \ No newline at end of file diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/ui/FeatureTogglesScreen.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/ui/FeatureTogglesScreen.kt index 74dddd26f0..b43d13d2f3 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/ui/FeatureTogglesScreen.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/ui/FeatureTogglesScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.components.appbar.AppBarWithBackButton import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -51,6 +52,14 @@ internal fun FeatureTogglesScreen(state: FeatureTogglesContentState) { onCheckedChange = { isChange -> state.onToggleValueChange(featureToggle.name, isChange) }, ) } + item { + PrimaryButton( + text = stringResource(id = R.string.apply_changes), + onClick = state.onApplyChangesClick, + modifier = Modifier.fillMaxWidth() + .padding(TangemTheme.dimens.spacing16), + ) + } } } @@ -95,6 +104,7 @@ private fun PreviewFeatureTogglesScreen() { ), onToggleValueChange = { _, _ -> }, onBackClick = {}, + onApplyChangesClick = {}, ), ) } diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt index 037946a145..d3459ac31f 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt @@ -10,6 +10,7 @@ import com.tangem.core.featuretoggle.manager.MutableFeatureTogglesManager import com.tangem.feature.tester.presentation.featuretoggles.models.TesterFeatureToggle import com.tangem.feature.tester.presentation.featuretoggles.state.FeatureTogglesContentState import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter +import com.tangem.features.tester.api.AppRestarter import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -38,16 +39,20 @@ internal class FeatureTogglesViewModel @Inject constructor( "Feature toggle manager must be mutable (debug build type)" } - /** Setup navigation state property by router [router] */ - fun setupNavigation(router: InnerTesterRouter) { - uiState = uiState.copy(onBackClick = router::back) + /** Setup navigation state property by router [router] and provides app restart method by [appRestarter] */ + fun setupInteractions(router: InnerTesterRouter, appRestarter: AppRestarter) { + uiState = uiState.copy( + onBackClick = router::back, + onApplyChangesClick = appRestarter::restart, + ) } private fun initState(): FeatureTogglesContentState { return FeatureTogglesContentState( featureToggles = mutableFeatureTogglesManager.getTesterFeatureToggles(), - onBackClick = {}, onToggleValueChange = ::onToggleValueChange, + onBackClick = {}, + onApplyChangesClick = {}, ) } diff --git a/features/tester/impl/src/main/res/values/strings.xml b/features/tester/impl/src/main/res/values/strings.xml index 9a5a5846b6..ffc3114361 100644 --- a/features/tester/impl/src/main/res/values/strings.xml +++ b/features/tester/impl/src/main/res/values/strings.xml @@ -2,6 +2,7 @@ Tester menu Feature toggles + Apply changes Stand toggles Tester actions Hide all currencies