Updated on 2026-08-14
This commit is contained in:
parent
26bba893ff
commit
51e650c360
47 changed files with 1628 additions and 73 deletions
1
features/force-update/api/.gitignore
vendored
Normal file
1
features/force-update/api/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
19
features/force-update/api/build.gradle.kts
Normal file
19
features/force-update/api/build.gradle.kts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.features.forceupdate.api"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/* Project - Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
|
||||
/* Compose */
|
||||
implementation(deps.compose.runtime)
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.forceupdate
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface ForceUpdateComponent : ComposableContentComponent {
|
||||
|
||||
interface Factory : ComponentFactory<Params, ForceUpdateComponent>
|
||||
|
||||
data class Params(val mode: Mode)
|
||||
|
||||
enum class Mode { Force, Brick, OsTooOld, Optional }
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.forceupdate
|
||||
|
||||
/**
|
||||
* Resumes the regular app startup after an optional update screen is dismissed.
|
||||
*
|
||||
* The startup awaits [awaitDismiss] while the optional update is shown, and the screen calls
|
||||
* [dismiss] on "Later" to let the normal startup (and its side effects) run afterwards.
|
||||
*/
|
||||
interface ForceUpdateContinuation {
|
||||
|
||||
suspend fun awaitDismiss()
|
||||
|
||||
fun dismiss()
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.features.forceupdate
|
||||
|
||||
interface ForceUpdateFeatureToggles {
|
||||
|
||||
val isForceUpdateEnabled: Boolean
|
||||
}
|
||||
1
features/force-update/impl/.gitignore
vendored
Normal file
1
features/force-update/impl/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
40
features/force-update/impl/build.gradle.kts
Normal file
40
features/force-update/impl/build.gradle.kts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.features.forceupdate.impl"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/* AndroidX */
|
||||
implementation(deps.lifecycle.compose)
|
||||
implementation(deps.androidx.activity.compose)
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.material3)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.configToggles)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.decompose)
|
||||
|
||||
/** Feature modules */
|
||||
implementation(projects.features.forceUpdate.api)
|
||||
|
||||
/** Domain modules */
|
||||
implementation(projects.domain.appUpdate)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.forceupdate.impl
|
||||
|
||||
import com.tangem.features.forceupdate.ForceUpdateContinuation
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
internal class DefaultForceUpdateContinuation @Inject constructor() : ForceUpdateContinuation {
|
||||
|
||||
private val dismissals = Channel<Unit>(capacity = Channel.CONFLATED)
|
||||
|
||||
override suspend fun awaitDismiss() {
|
||||
dismissals.receive()
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
dismissals.trySend(Unit)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.forceupdate.impl
|
||||
|
||||
import com.tangem.core.configtoggle.FeatureToggles
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.features.forceupdate.ForceUpdateFeatureToggles
|
||||
|
||||
internal class DefaultForceUpdateFeatureToggles(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) : ForceUpdateFeatureToggles {
|
||||
|
||||
override val isForceUpdateEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1322_FORCE_UPDATE_ENABLED)
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.features.forceupdate.impl.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.forceupdate.ForceUpdateComponent
|
||||
import com.tangem.features.forceupdate.impl.model.ForceUpdateModel
|
||||
import com.tangem.features.forceupdate.impl.ui.ForceUpdateContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultForceUpdateComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted params: ForceUpdateComponent.Params,
|
||||
) : ForceUpdateComponent, AppComponentContext by context {
|
||||
|
||||
private val model: ForceUpdateModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
ForceUpdateContent(state = state, modifier = modifier)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ForceUpdateComponent.Factory {
|
||||
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: ForceUpdateComponent.Params,
|
||||
): DefaultForceUpdateComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.features.forceupdate.impl.di
|
||||
|
||||
import com.tangem.features.forceupdate.ForceUpdateComponent
|
||||
import com.tangem.features.forceupdate.ForceUpdateContinuation
|
||||
import com.tangem.features.forceupdate.impl.DefaultForceUpdateContinuation
|
||||
import com.tangem.features.forceupdate.impl.component.DefaultForceUpdateComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindForceUpdateComponentFactory(factory: DefaultForceUpdateComponent.Factory): ForceUpdateComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindForceUpdateContinuation(impl: DefaultForceUpdateContinuation): ForceUpdateContinuation
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.forceupdate.impl.di
|
||||
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.features.forceupdate.ForceUpdateFeatureToggles
|
||||
import com.tangem.features.forceupdate.impl.DefaultForceUpdateFeatureToggles
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object ForceUpdateFeatureModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideForceUpdateFeatureToggles(featureTogglesManager: FeatureTogglesManager): ForceUpdateFeatureToggles =
|
||||
DefaultForceUpdateFeatureToggles(featureTogglesManager)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.forceupdate.impl.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.forceupdate.impl.model.ForceUpdateModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface ModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(ForceUpdateModel::class)
|
||||
fun provideForceUpdateModel(model: ForceUpdateModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.tangem.features.forceupdate.impl.model
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.navigation.url.AppStoreOpener
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.appupdate.model.AppUpdateState
|
||||
import com.tangem.domain.appupdate.usecase.GetAppUpdateStateUseCase
|
||||
import com.tangem.features.forceupdate.ForceUpdateComponent
|
||||
import com.tangem.features.forceupdate.ForceUpdateContinuation
|
||||
import com.tangem.features.forceupdate.impl.R
|
||||
import com.tangem.features.forceupdate.impl.ui.state.ForceUpdateUM
|
||||
import com.tangem.features.forceupdate.impl.ui.state.ForceUpdateUM.Accent
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class ForceUpdateModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val appStoreOpener: AppStoreOpener,
|
||||
private val forceUpdateContinuation: ForceUpdateContinuation,
|
||||
private val getAppUpdateStateUseCase: GetAppUpdateStateUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
private val params: ForceUpdateComponent.Params = paramsContainer.require()
|
||||
|
||||
val state: StateFlow<ForceUpdateUM>
|
||||
field = MutableStateFlow(createState(params.mode))
|
||||
|
||||
init {
|
||||
checkAppUpdateState()
|
||||
}
|
||||
|
||||
private fun createState(mode: ForceUpdateComponent.Mode): ForceUpdateUM = when (mode) {
|
||||
ForceUpdateComponent.Mode.Force -> ForceUpdateUM(
|
||||
mode = mode,
|
||||
accent = Accent.Red,
|
||||
title = resourceReference(R.string.force_update_warning_title),
|
||||
description = resourceReference(R.string.force_update_warning_message),
|
||||
isBlocking = true,
|
||||
onUpdateClick = ::onUpdateClick,
|
||||
onLaterClick = null,
|
||||
)
|
||||
ForceUpdateComponent.Mode.Optional -> ForceUpdateUM(
|
||||
mode = mode,
|
||||
accent = Accent.Yellow,
|
||||
title = resourceReference(R.string.force_update_warning_title),
|
||||
description = resourceReference(R.string.force_update_warning_message),
|
||||
isBlocking = false,
|
||||
onUpdateClick = ::onUpdateClick,
|
||||
onLaterClick = ::onLaterClick,
|
||||
)
|
||||
ForceUpdateComponent.Mode.Brick -> ForceUpdateUM(
|
||||
mode = mode,
|
||||
accent = Accent.Red,
|
||||
title = resourceReference(R.string.force_update_brick_title),
|
||||
description = resourceReference(R.string.force_update_brick_description),
|
||||
isBlocking = true,
|
||||
onUpdateClick = null,
|
||||
onLaterClick = null,
|
||||
)
|
||||
ForceUpdateComponent.Mode.OsTooOld -> ForceUpdateUM(
|
||||
mode = mode,
|
||||
accent = Accent.Red,
|
||||
title = resourceReference(R.string.force_update_os_title),
|
||||
description = resourceReference(R.string.force_update_os_description),
|
||||
isBlocking = true,
|
||||
onUpdateClick = null,
|
||||
onLaterClick = null,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onUpdateClick() {
|
||||
appStoreOpener.openStorePage()
|
||||
}
|
||||
|
||||
private fun onLaterClick() {
|
||||
forceUpdateContinuation.dismiss()
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-checks the update state once when the screen opens. A concrete result refines the displayed mode
|
||||
* (e.g. escalates an optional update to a blocking one). When the update is no longer required — or the
|
||||
* state can't be resolved — the screen is dismissed so the regular startup can proceed. Network errors
|
||||
* fall back to the cached thresholds, so a transient failure keeps the current screen.
|
||||
*/
|
||||
private fun checkAppUpdateState() {
|
||||
modelScope.launch {
|
||||
val mode = getAppUpdateStateUseCase.refresh().toModeOrNull()
|
||||
if (mode == null) {
|
||||
forceUpdateContinuation.dismiss()
|
||||
} else {
|
||||
state.update { current -> if (current.mode == mode) current else createState(mode) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun AppUpdateState.toModeOrNull(): ForceUpdateComponent.Mode? = when (this) {
|
||||
AppUpdateState.ForceUpdate -> ForceUpdateComponent.Mode.Force
|
||||
AppUpdateState.Brick -> ForceUpdateComponent.Mode.Brick
|
||||
AppUpdateState.OsTooOld -> ForceUpdateComponent.Mode.OsTooOld
|
||||
AppUpdateState.OptionalUpdate -> ForceUpdateComponent.Mode.Optional
|
||||
AppUpdateState.NoUpdate -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
package com.tangem.features.forceupdate.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.ds2.button.TangemButton
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.res.generated.icons.Icons
|
||||
import com.tangem.core.ui.res.generated.icons.ic_error_24
|
||||
import com.tangem.core.ui.res.generated.icons.ic_warning_24
|
||||
import com.tangem.features.forceupdate.impl.R
|
||||
import com.tangem.features.forceupdate.ForceUpdateComponent
|
||||
import com.tangem.features.forceupdate.impl.ui.state.ForceUpdateUM
|
||||
import com.tangem.features.forceupdate.impl.ui.state.ForceUpdateUM.Accent
|
||||
|
||||
@Composable
|
||||
internal fun ForceUpdateContent(state: ForceUpdateUM, modifier: Modifier = Modifier) {
|
||||
BackHandler(enabled = !state.isBlocking) {
|
||||
state.onLaterClick?.invoke()
|
||||
}
|
||||
|
||||
val accentColor = when (state.accent) {
|
||||
Accent.Red -> TangemTheme.colors3.icon.accent.red
|
||||
Accent.Yellow -> TangemTheme.colors3.icon.accent.yellow
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(TangemTheme.colors3.bg.primary)
|
||||
.glow(accentColor),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
Content(
|
||||
state = state,
|
||||
accentColor = accentColor,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
Buttons(
|
||||
state = state,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(state: ForceUpdateUM, accentColor: Color, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier) {
|
||||
Spacer(modifier = Modifier.height(64.dp))
|
||||
Icon(
|
||||
modifier = Modifier.size(32.dp),
|
||||
imageVector = when (state.accent) {
|
||||
Accent.Red -> Icons.ic_error_24
|
||||
Accent.Yellow -> Icons.ic_warning_24
|
||||
},
|
||||
contentDescription = null,
|
||||
tint = accentColor,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography3.heading.medium,
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = state.description.resolveReference(),
|
||||
style = TangemTheme.typography3.heading.medium,
|
||||
color = TangemTheme.colors3.text.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Buttons(state: ForceUpdateUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
state.onUpdateClick?.let { onClick ->
|
||||
TangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
variant = TangemButton.Variant.Primary,
|
||||
text = resourceReference(R.string.force_update_action),
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
state.onLaterClick?.let { onClick ->
|
||||
TangemButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
variant = TangemButton.Variant.Secondary,
|
||||
text = resourceReference(R.string.common_later),
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.glow(color: Color): Modifier = drawBehind {
|
||||
drawRect(
|
||||
brush = Brush.radialGradient(
|
||||
colors = listOf(color.copy(alpha = GLOW_ALPHA), Color.Transparent),
|
||||
center = Offset(x = size.width * GLOW_CENTER_X_FRACTION, y = 0f),
|
||||
radius = size.width,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private const val GLOW_ALPHA = 0.32f
|
||||
private const val GLOW_CENTER_X_FRACTION = 0.3f
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 780)
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 780, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewForce() {
|
||||
TangemThemePreviewRedesign {
|
||||
ForceUpdateContent(
|
||||
state = ForceUpdateUM(
|
||||
mode = ForceUpdateComponent.Mode.Force,
|
||||
accent = Accent.Red,
|
||||
title = TextReference.Str("Update Required"),
|
||||
description = TextReference.Str("Please update the application to the latest version."),
|
||||
isBlocking = true,
|
||||
onUpdateClick = {},
|
||||
onLaterClick = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 780)
|
||||
@Preview(showBackground = true, widthDp = 360, heightDp = 780, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewOptional() {
|
||||
TangemThemePreviewRedesign {
|
||||
ForceUpdateContent(
|
||||
state = ForceUpdateUM(
|
||||
mode = ForceUpdateComponent.Mode.Optional,
|
||||
accent = Accent.Yellow,
|
||||
title = TextReference.Str("Update Required"),
|
||||
description = TextReference.Str("Please update the application to the latest version."),
|
||||
isBlocking = false,
|
||||
onUpdateClick = {},
|
||||
onLaterClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.features.forceupdate.impl.ui.state
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.forceupdate.ForceUpdateComponent
|
||||
|
||||
@Immutable
|
||||
internal data class ForceUpdateUM(
|
||||
val mode: ForceUpdateComponent.Mode,
|
||||
val accent: Accent,
|
||||
val title: TextReference,
|
||||
val description: TextReference,
|
||||
val isBlocking: Boolean,
|
||||
val onUpdateClick: (() -> Unit)?,
|
||||
val onLaterClick: (() -> Unit)?,
|
||||
) {
|
||||
|
||||
enum class Accent { Red, Yellow }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue