Updated on 2026-08-14
This commit is contained in:
parent
efaf04920f
commit
af3f8c6c25
16 changed files with 436 additions and 51 deletions
|
|
@ -6,8 +6,6 @@ import com.tangem.tap.common.redux.AppDialog
|
|||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.ui.SimpleAlertDialog
|
||||
import com.tangem.tap.common.ui.SimpleCancelableAlertDialog
|
||||
import com.tangem.tap.features.details.redux.DetailsDialog
|
||||
import com.tangem.tap.features.details.redux.PrivacySetting
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.ApproveWcSessionDialog
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.BnbTransactionDialog
|
||||
|
|
@ -150,18 +148,6 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
)
|
||||
is WalletDialog.RussianCardholdersWarningDialog ->
|
||||
RussianCardholdersWarningBottomSheetDialog(context)
|
||||
is DetailsDialog.ConfirmDisablingSaving -> {
|
||||
val messageRes = when (state.dialog.setting) {
|
||||
PrivacySetting.SAVE_CARDS -> R.string.app_settings_off_saved_wallet_alert_message
|
||||
PrivacySetting.SAVE_ACCESS_CODE -> R.string.app_settings_off_saved_access_code_alert_message
|
||||
}
|
||||
SimpleCancelableAlertDialog.create(
|
||||
titleRes = R.string.common_warning,
|
||||
messageRes = messageRes,
|
||||
context = context,
|
||||
primaryButtonAction = state.dialog.onOk
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
dialog?.show()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.fragment.app.FragmentManager
|
|||
import com.tangem.common.extensions.VoidCallback
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import com.tangem.tap.features.details.ui.appsettings.AppSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.cardsettings.CardSettingsFragment
|
||||
import com.tangem.tap.features.details.ui.details.DetailsFragment
|
||||
import com.tangem.tap.features.details.ui.resetcard.ResetCardFragment
|
||||
|
|
@ -95,7 +96,7 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
|
|||
AppScreen.Details -> DetailsFragment()
|
||||
AppScreen.DetailsSecurity -> SecurityModeFragment()
|
||||
AppScreen.CardSettings -> CardSettingsFragment()
|
||||
AppScreen.AppSettings -> CardSettingsFragment()
|
||||
AppScreen.AppSettings -> AppSettingsFragment()
|
||||
AppScreen.ResetToFactory -> ResetCardFragment()
|
||||
AppScreen.Disclaimer -> DisclaimerFragment()
|
||||
AppScreen.AddTokens -> AddTokensFragment()
|
||||
|
|
|
|||
|
|
@ -44,10 +44,7 @@ sealed class DetailsAction : Action {
|
|||
}
|
||||
|
||||
sealed class AppSettings : DetailsAction() {
|
||||
data class SwitchPrivacySetting(val allow: Boolean, val setting: PrivacySetting) :
|
||||
AppSettings()
|
||||
|
||||
data class ConfirmSwitchingSetting(val allow: Boolean, val setting: PrivacySetting) :
|
||||
data class SwitchPrivacySetting(val enable: Boolean, val setting: PrivacySetting) :
|
||||
AppSettings()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.domain.common.isTangemTwins
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -188,20 +187,8 @@ class DetailsMiddleware {
|
|||
class ManagePrivacyMiddleware {
|
||||
fun handle(action: DetailsAction.AppSettings) {
|
||||
when (action) {
|
||||
is DetailsAction.AppSettings.ConfirmSwitchingSetting -> {
|
||||
// TODO()
|
||||
}
|
||||
is DetailsAction.AppSettings.SwitchPrivacySetting -> {
|
||||
if (action.allow) {
|
||||
store.dispatch(
|
||||
DetailsAction.AppSettings.ConfirmSwitchingSetting(
|
||||
action.allow,
|
||||
action.setting,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
store.dispatchDialogShow(DetailsDialog.ConfirmDisablingSaving(action.setting))
|
||||
}
|
||||
// TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,13 +149,12 @@ private fun handlePrivacyAction(
|
|||
action: DetailsAction.AppSettings, state: DetailsState,
|
||||
): DetailsState {
|
||||
return when (action) {
|
||||
is DetailsAction.AppSettings.ConfirmSwitchingSetting -> {
|
||||
is DetailsAction.AppSettings.SwitchPrivacySetting -> {
|
||||
when (action.setting) {
|
||||
PrivacySetting.SAVE_CARDS -> state.copy(saveCards = action.allow)
|
||||
PrivacySetting.SAVE_ACCESS_CODE -> state.copy(savePasswords = action.allow)
|
||||
PrivacySetting.SaveWallets -> state.copy(saveWallets = action.enable)
|
||||
PrivacySetting.SaveAccessCode -> state.copy(saveAccessCodes = action.enable)
|
||||
}
|
||||
}
|
||||
is DetailsAction.AppSettings.SwitchPrivacySetting -> state
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.common.card.Card
|
|||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.entities.Button
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.StateType
|
||||
|
|
@ -21,8 +20,8 @@ data class DetailsState(
|
|||
val privacyPolicyUrl: String? = null,
|
||||
val createBackupAllowed: Boolean = false,
|
||||
val appCurrency: FiatCurrency = FiatCurrency.Default,
|
||||
val saveCards: Boolean = true,
|
||||
val savePasswords: Boolean = true
|
||||
val saveWallets: Boolean = true,
|
||||
val saveAccessCodes: Boolean = true,
|
||||
) : StateType {
|
||||
|
||||
// if you do not delegate - the application crashes on startup,
|
||||
|
|
@ -58,14 +57,6 @@ data class ManageSecurityState(
|
|||
|
||||
enum class SecurityOption { LongTap, PassCode, AccessCode }
|
||||
|
||||
|
||||
sealed interface DetailsDialog : StateDialog {
|
||||
data class ConfirmDisablingSaving(val setting: PrivacySetting) : DetailsDialog {
|
||||
val onOk: () -> Unit =
|
||||
{ store.dispatch(DetailsAction.AppSettings.ConfirmSwitchingSetting(false, setting)) }
|
||||
}
|
||||
}
|
||||
|
||||
enum class PrivacySetting {
|
||||
SAVE_CARDS, SAVE_ACCESS_CODE
|
||||
SaveWallets, SaveAccessCode
|
||||
}
|
||||
|
|
@ -1,3 +1,71 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
|
||||
class AppSettingsFragment
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.google.accompanist.appcompattheme.AppCompatTheme
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class AppSettingsFragment : Fragment(), StoreSubscriber<DetailsState> {
|
||||
private val viewModel = AppSettingsViewModel(store)
|
||||
private var screenState: MutableState<AppSettingsScreenState> =
|
||||
mutableStateOf(viewModel.updateState(store.state.detailsState))
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
enterTransition = inflater.inflateTransition(R.transition.slide_right)
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
isTransitionGroup = true
|
||||
AppCompatTheme {
|
||||
AppSettingsScreen(
|
||||
state = screenState.value,
|
||||
onBackPressed = {
|
||||
store.dispatch(DetailsAction.ResetCardSettingsData)
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.detailsState == newState.detailsState
|
||||
}.select { it.detailsState }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun newState(state: DetailsState) {
|
||||
if (activity == null || view == null) return
|
||||
screenState.value = viewModel.updateState(state)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,236 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material.AlertDialog
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.SwitchDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.tap.common.compose.TangemTypography
|
||||
import com.tangem.tap.features.details.redux.PrivacySetting
|
||||
import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
fun AppSettingsScreen(
|
||||
|
||||
state: AppSettingsScreenState,
|
||||
onBackPressed: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SettingsScreensScaffold(
|
||||
content = {
|
||||
AppSettings(state = state, modifier = modifier)
|
||||
},
|
||||
titleRes = R.string.app_settings_title,
|
||||
onBackClick = onBackPressed,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppSettings(
|
||||
state: AppSettingsScreenState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var dialogType by remember { mutableStateOf<PrivacySetting?>(null) }
|
||||
val onDialogStateChange: (PrivacySetting?) -> Unit = { dialogType = it }
|
||||
|
||||
dialogType?.let {
|
||||
SettingsAlertDialog(
|
||||
element = it,
|
||||
onDialogStateChange = onDialogStateChange,
|
||||
onSettingToggled = state.onSettingToggled,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
AppSettingsElement(
|
||||
state = state, setting = PrivacySetting.SaveWallets,
|
||||
onDialogStateChange = onDialogStateChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
Spacer(modifier = Modifier.size(32.dp))
|
||||
AppSettingsElement(
|
||||
state = state, setting = PrivacySetting.SaveAccessCode,
|
||||
onDialogStateChange = onDialogStateChange,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppSettingsElement(
|
||||
state: AppSettingsScreenState,
|
||||
setting: PrivacySetting,
|
||||
onDialogStateChange: (PrivacySetting?) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val titleRes = when (setting) {
|
||||
PrivacySetting.SaveWallets -> R.string.app_settings_saved_wallet
|
||||
PrivacySetting.SaveAccessCode -> R.string.app_settings_saved_access_codes
|
||||
}
|
||||
val subtitleRes = when (setting) {
|
||||
PrivacySetting.SaveWallets -> R.string.app_settings_saved_wallet_footer
|
||||
PrivacySetting.SaveAccessCode -> R.string.app_settings_saved_access_codes_footer
|
||||
}
|
||||
val checked = state.settings[setting] ?: false
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 20.dp),
|
||||
// .clickable { state.onSettingToggled(element, !checked) },
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = modifier
|
||||
.weight(0.6f)
|
||||
.padding(end = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = titleRes),
|
||||
style = TangemTypography.subtitle1,
|
||||
color = colorResource(id = R.color.text_primary_1),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(4.dp))
|
||||
Text(
|
||||
text = stringResource(id = subtitleRes),
|
||||
style = TangemTypography.body2,
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
checked = checked,
|
||||
onCheckedChange = {
|
||||
onCheckedChange(
|
||||
element = setting,
|
||||
enabled = it,
|
||||
onSettingToggled = state.onSettingToggled,
|
||||
onDialogStateChange = onDialogStateChange,
|
||||
)
|
||||
},
|
||||
colors = SwitchDefaults.colors(
|
||||
checkedThumbColor = colorResource(id = R.color.control_key),
|
||||
uncheckedThumbColor = colorResource(id = R.color.control_key),
|
||||
checkedTrackColor = colorResource(id = R.color.control_checked),
|
||||
uncheckedTrackColor = colorResource(id = R.color.icon_informative),
|
||||
),
|
||||
modifier = modifier
|
||||
.padding(start = 20.dp, end = 20.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onCheckedChange(
|
||||
element: PrivacySetting, enabled: Boolean,
|
||||
onSettingToggled: (PrivacySetting, Boolean) -> Unit,
|
||||
onDialogStateChange: (PrivacySetting?) -> Unit,
|
||||
) {
|
||||
//Show warning if user wants to disable the switch
|
||||
if (!enabled) {
|
||||
onDialogStateChange(element)
|
||||
} else {
|
||||
onSettingToggled(element, enabled)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsAlertDialog(
|
||||
element: PrivacySetting,
|
||||
onDialogStateChange: (PrivacySetting?) -> Unit,
|
||||
onSettingToggled: (PrivacySetting, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val text = when (element) {
|
||||
PrivacySetting.SaveWallets -> R.string.app_settings_off_saved_wallet_alert_message
|
||||
PrivacySetting.SaveAccessCode -> R.string.app_settings_off_saved_access_code_alert_message
|
||||
}
|
||||
AlertDialog(
|
||||
onDismissRequest = { onDialogStateChange(null) },
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDialogStateChange(null)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.common_cancel),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDialogStateChange(null)
|
||||
onSettingToggled(element, false)
|
||||
},
|
||||
modifier = modifier.padding(bottom = 14.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.common_delete),
|
||||
color = colorResource(id = R.color.text_warning),
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.common_attention),
|
||||
color = colorResource(id = R.color.text_primary_1),
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text = stringResource(id = text),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
)
|
||||
},
|
||||
shape = MaterialTheme.shapes.medium.copy(all = CornerSize(size = 28.dp)),
|
||||
modifier = modifier.padding(vertical = 34.dp, horizontal = 24.dp),
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AppSettingsScreenPreview() {
|
||||
AppSettingsScreen(
|
||||
state = AppSettingsScreenState(
|
||||
settings = mapOf(
|
||||
PrivacySetting.SaveWallets to true,
|
||||
PrivacySetting.SaveAccessCode to false,
|
||||
),
|
||||
onSettingToggled = { _, _ -> },
|
||||
),
|
||||
onBackPressed = { },
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
|
||||
import com.tangem.tap.features.details.redux.PrivacySetting
|
||||
|
||||
data class AppSettingsScreenState(
|
||||
val settings: Map<PrivacySetting, Boolean>,
|
||||
val onSettingToggled: (PrivacySetting, Boolean) -> Unit,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.tap.features.details.ui.appsettings
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.features.details.redux.PrivacySetting
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.rekotlin.Store
|
||||
|
||||
class AppSettingsViewModel(private val store: Store<AppState>) {
|
||||
private val _uiState = MutableStateFlow(updateState(store.state.detailsState))
|
||||
val uiState: StateFlow<AppSettingsScreenState> = _uiState
|
||||
fun updateState(state: DetailsState): AppSettingsScreenState {
|
||||
return AppSettingsScreenState(
|
||||
settings = mapOf(
|
||||
PrivacySetting.SaveWallets to state.saveWallets,
|
||||
PrivacySetting.SaveAccessCode to state.saveAccessCodes,
|
||||
),
|
||||
onSettingToggled = { privacySetting, enabled -> onSettingsToggled(privacySetting, enabled) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun onSettingsToggled(setting: PrivacySetting, enable: Boolean) {
|
||||
store.dispatch(DetailsAction.AppSettings.SwitchPrivacySetting(enable = enable, setting = setting))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.tangem.tap.features.details.ui.common
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.Fill
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
fun TangemSwitch(
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
width: Dp = 48.dp,
|
||||
height: Dp = 24.dp,
|
||||
checkedTrackColor: Color = colorResource(id = R.color.control_checked),
|
||||
uncheckedTrackColor: Color = colorResource(id = R.color.icon_informative),
|
||||
selectorColor: Color = colorResource(id = R.color.background_secondary),
|
||||
gapBetweenThumbAndTrackEdge: Dp = 3.dp,
|
||||
) {
|
||||
val thumbRadius = (height / 2) - gapBetweenThumbAndTrackEdge
|
||||
val animatePosition = animateFloatAsState(
|
||||
targetValue = if (checked)
|
||||
with(LocalDensity.current) { (width - thumbRadius - gapBetweenThumbAndTrackEdge).toPx() }
|
||||
else
|
||||
with(LocalDensity.current) { (thumbRadius + gapBetweenThumbAndTrackEdge).toPx() },
|
||||
)
|
||||
|
||||
Canvas(
|
||||
modifier = modifier
|
||||
.size(width = width, height = height)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onTap = {
|
||||
onCheckedChange(checked)
|
||||
},
|
||||
)
|
||||
},
|
||||
) {
|
||||
drawRoundRect(
|
||||
color = if (checked) checkedTrackColor else uncheckedTrackColor,
|
||||
cornerRadius = CornerRadius(x = 35.dp.toPx(), y = 35.dp.toPx()),
|
||||
style = Fill,
|
||||
)
|
||||
|
||||
drawCircle(
|
||||
color = selectorColor,
|
||||
radius = thumbRadius.toPx(),
|
||||
center = Offset(
|
||||
x = animatePosition.value,
|
||||
y = size.height / 2,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TangemSwitchPreview() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
TangemSwitch(true, {})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue