mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 08:55:48 +03:00
PM-15038: Update custom switches to use standard component (#4327)
This commit is contained in:
parent
2d15c4864f
commit
ccd4fd9aba
3 changed files with 182 additions and 104 deletions
|
@ -1,14 +1,11 @@
|
|||
package com.x8bit.bitwarden.ui.auth.feature.createaccount
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -17,31 +14,23 @@ import androidx.compose.foundation.layout.imePadding
|
|||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import androidx.compose.ui.semantics.toggleableState
|
||||
import androidx.compose.ui.state.ToggleableState
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
|
@ -76,7 +65,6 @@ import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
|
|||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.text.BitwardenClickableText
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.color.bitwardenSwitchColors
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
|
@ -283,6 +271,9 @@ fun CreateAccountScreen(
|
|||
onPrivacyPolicyClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(PrivacyPolicyClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
|
@ -290,52 +281,24 @@ fun CreateAccountScreen(
|
|||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun TermsAndPrivacySwitch(
|
||||
isChecked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
onTermsClick: () -> Unit,
|
||||
onPrivacyPolicyClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.semantics(mergeDescendants = true) {
|
||||
testTag = "AcceptPoliciesToggle"
|
||||
toggleableState = ToggleableState(isChecked)
|
||||
}
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(
|
||||
color = BitwardenTheme.colorScheme.background.pressed,
|
||||
),
|
||||
onClick = { onCheckedChange.invoke(!isChecked) },
|
||||
)
|
||||
.padding(start = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Switch(
|
||||
modifier = Modifier
|
||||
.height(32.dp)
|
||||
.width(52.dp),
|
||||
checked = isChecked,
|
||||
onCheckedChange = null,
|
||||
colors = bitwardenSwitchColors(),
|
||||
)
|
||||
Column(Modifier.padding(start = 16.dp, top = 4.dp, bottom = 4.dp)) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.accept_policies),
|
||||
style = BitwardenTheme.typography.bodyLarge,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
)
|
||||
BitwardenSwitch(
|
||||
modifier = modifier,
|
||||
label = stringResource(id = R.string.accept_policies),
|
||||
isChecked = isChecked,
|
||||
contentDescription = "AcceptPoliciesToggle",
|
||||
onCheckedChange = onCheckedChange,
|
||||
subContent = {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
BitwardenClickableText(
|
||||
label = stringResource(id = R.string.terms_of_service),
|
||||
|
@ -357,6 +320,6 @@ private fun TermsAndPrivacySwitch(
|
|||
innerPadding = PaddingValues(vertical = 4.dp, horizontal = 0.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package com.x8bit.bitwarden.ui.auth.feature.startregistration
|
|||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
@ -16,15 +14,12 @@ import androidx.compose.foundation.layout.navigationBarsPadding
|
|||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -38,8 +33,6 @@ import androidx.compose.ui.semantics.CustomAccessibilityAction
|
|||
import androidx.compose.ui.semantics.customActions
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import androidx.compose.ui.semantics.toggleableState
|
||||
import androidx.compose.ui.state.ToggleableState
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
@ -70,7 +63,7 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
|
|||
import com.x8bit.bitwarden.ui.platform.components.dropdown.EnvironmentSelector
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.color.bitwardenSwitchColors
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
|
@ -277,7 +270,9 @@ private fun StartRegistrationContent(
|
|||
isChecked = isReceiveMarketingEmailsToggled,
|
||||
onCheckedChange = handler.onReceiveMarketingEmailsToggle,
|
||||
onUnsubscribeClick = handler.onUnsubscribeMarketingEmailsClick,
|
||||
modifier = Modifier.standardHorizontalMargin(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.standardHorizontalMargin(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
@ -361,7 +356,6 @@ private fun TermsAndPrivacyText(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun ReceiveMarketingEmailsSwitch(
|
||||
isChecked: Boolean,
|
||||
|
@ -373,7 +367,9 @@ private fun ReceiveMarketingEmailsSwitch(
|
|||
|
||||
@Suppress("MaxLineLength")
|
||||
val annotatedLinkString = createClickableAnnotatedString(
|
||||
mainString = stringResource(id = R.string.get_emails_from_bitwarden_for_announcements_advices_and_research_opportunities_unsubscribe_any_time),
|
||||
mainString = stringResource(
|
||||
id = R.string.get_emails_from_bitwarden_for_announcements_advices_and_research_opportunities_unsubscribe_any_time,
|
||||
),
|
||||
highlights = listOf(
|
||||
ClickableTextHighlight(
|
||||
textToHighlight = unsubscribeString,
|
||||
|
@ -381,13 +377,9 @@ private fun ReceiveMarketingEmailsSwitch(
|
|||
),
|
||||
),
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
BitwardenSwitch(
|
||||
modifier = modifier
|
||||
.semantics(mergeDescendants = true) {
|
||||
testTag = "ReceiveMarketingEmailsToggle"
|
||||
toggleableState = ToggleableState(isChecked)
|
||||
customActions = listOf(
|
||||
CustomAccessibilityAction(
|
||||
label = unsubscribeString,
|
||||
|
@ -397,30 +389,12 @@ private fun ReceiveMarketingEmailsSwitch(
|
|||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(
|
||||
color = BitwardenTheme.colorScheme.background.pressed,
|
||||
),
|
||||
onClick = { onCheckedChange.invoke(!isChecked) },
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Switch(
|
||||
modifier = Modifier
|
||||
.height(32.dp)
|
||||
.width(52.dp),
|
||||
checked = isChecked,
|
||||
onCheckedChange = null,
|
||||
colors = bitwardenSwitchColors(),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Text(
|
||||
text = annotatedLinkString,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
},
|
||||
label = annotatedLinkString,
|
||||
isChecked = isChecked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
contentDescription = "ReceiveMarketingEmailsToggle",
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewScreenSizes
|
||||
|
|
|
@ -22,15 +22,17 @@ import androidx.compose.ui.semantics.contentDescription
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.toggleableState
|
||||
import androidx.compose.ui.state.ToggleableState
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.color.bitwardenSwitchColors
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
* A wide custom switch composable
|
||||
* A custom switch composable
|
||||
*
|
||||
* @param label The descriptive text label to be displayed adjacent to the switch.
|
||||
* @param isChecked The current state of the switch (either checked or unchecked).
|
||||
|
@ -45,7 +47,6 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|||
* in between the [label] and the toggle. This lambda extends [RowScope], allowing flexibility in
|
||||
* defining the layout of the actions.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun BitwardenSwitch(
|
||||
label: String,
|
||||
|
@ -57,6 +58,154 @@ fun BitwardenSwitch(
|
|||
readOnly: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
actions: (@Composable RowScope.() -> Unit)? = null,
|
||||
) {
|
||||
BitwardenSwitch(
|
||||
modifier = modifier,
|
||||
label = label.toAnnotatedString(),
|
||||
isChecked = isChecked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
contentDescription = contentDescription,
|
||||
readOnly = readOnly,
|
||||
enabled = enabled,
|
||||
actions = actions,
|
||||
subContent = {
|
||||
description?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = if (enabled) {
|
||||
BitwardenTheme.colorScheme.text.secondary
|
||||
} else {
|
||||
BitwardenTheme.colorScheme.filledButton.foregroundDisabled
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom switch composable
|
||||
*
|
||||
* @param label The descriptive text label to be displayed adjacent to the switch.
|
||||
* @param isChecked The current state of the switch (either checked or unchecked).
|
||||
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
|
||||
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
|
||||
* @param description An optional description label to be displayed below the [label].
|
||||
* @param contentDescription A description of the switch's UI for accessibility purposes.
|
||||
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
|
||||
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
|
||||
* comes with some additional visual changes.
|
||||
* @param actions A lambda containing the set of actions (usually icons or similar) to display
|
||||
* in between the [label] and the toggle. This lambda extends [RowScope], allowing flexibility in
|
||||
* defining the layout of the actions.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenSwitch(
|
||||
label: AnnotatedString,
|
||||
isChecked: Boolean,
|
||||
onCheckedChange: ((Boolean) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
description: String? = null,
|
||||
contentDescription: String? = null,
|
||||
readOnly: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
actions: (@Composable RowScope.() -> Unit)? = null,
|
||||
) {
|
||||
BitwardenSwitch(
|
||||
modifier = modifier,
|
||||
label = label,
|
||||
isChecked = isChecked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
contentDescription = contentDescription,
|
||||
readOnly = readOnly,
|
||||
enabled = enabled,
|
||||
actions = actions,
|
||||
subContent = {
|
||||
description?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = if (enabled) {
|
||||
BitwardenTheme.colorScheme.text.secondary
|
||||
} else {
|
||||
BitwardenTheme.colorScheme.filledButton.foregroundDisabled
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom switch composable
|
||||
*
|
||||
* @param label The descriptive text label to be displayed adjacent to the switch.
|
||||
* @param isChecked The current state of the switch (either checked or unchecked).
|
||||
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
|
||||
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
|
||||
* @param contentDescription A description of the switch's UI for accessibility purposes.
|
||||
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
|
||||
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
|
||||
* comes with some additional visual changes.
|
||||
* @param actions A lambda containing the set of actions (usually icons or similar) to display
|
||||
* in between the [label] and the toggle. This lambda extends [RowScope], allowing flexibility in
|
||||
* defining the layout of the actions.
|
||||
* @param subContent A lambda containing content directly below the label.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenSwitch(
|
||||
label: String,
|
||||
isChecked: Boolean,
|
||||
onCheckedChange: ((Boolean) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
contentDescription: String? = null,
|
||||
readOnly: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
actions: (@Composable RowScope.() -> Unit)? = null,
|
||||
subContent: @Composable () -> Unit,
|
||||
) {
|
||||
BitwardenSwitch(
|
||||
modifier = modifier,
|
||||
label = label.toAnnotatedString(),
|
||||
isChecked = isChecked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
contentDescription = contentDescription,
|
||||
readOnly = readOnly,
|
||||
enabled = enabled,
|
||||
actions = actions,
|
||||
subContent = subContent,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom switch composable
|
||||
*
|
||||
* @param label The descriptive text label to be displayed adjacent to the switch.
|
||||
* @param isChecked The current state of the switch (either checked or unchecked).
|
||||
* @param onCheckedChange A lambda that is invoked when the switch's state changes.
|
||||
* @param modifier A [Modifier] that you can use to apply custom modifications to the composable.
|
||||
* @param contentDescription A description of the switch's UI for accessibility purposes.
|
||||
* @param readOnly Disables the click functionality without modifying the other UI characteristics.
|
||||
* @param enabled Whether or not this switch is enabled. This is similar to setting [readOnly] but
|
||||
* comes with some additional visual changes.
|
||||
* @param actions A lambda containing the set of actions (usually icons or similar) to display
|
||||
* in between the [label] and the toggle. This lambda extends [RowScope], allowing flexibility in
|
||||
* defining the layout of the actions.
|
||||
* @param subContent A lambda containing content directly below the label.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun BitwardenSwitch(
|
||||
label: AnnotatedString,
|
||||
isChecked: Boolean,
|
||||
onCheckedChange: ((Boolean) -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
contentDescription: String? = null,
|
||||
readOnly: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
actions: (@Composable RowScope.() -> Unit)? = null,
|
||||
subContent: @Composable () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
@ -95,17 +244,7 @@ fun BitwardenSwitch(
|
|||
},
|
||||
modifier = Modifier.testTag(tag = "SwitchText"),
|
||||
)
|
||||
description?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
color = if (enabled) {
|
||||
BitwardenTheme.colorScheme.text.secondary
|
||||
} else {
|
||||
BitwardenTheme.colorScheme.filledButton.foregroundDisabled
|
||||
},
|
||||
)
|
||||
}
|
||||
subContent()
|
||||
}
|
||||
|
||||
actions
|
||||
|
@ -131,6 +270,7 @@ private fun BitwardenSwitch_preview() {
|
|||
Column {
|
||||
BitwardenSwitch(
|
||||
label = "Label",
|
||||
description = "description",
|
||||
isChecked = true,
|
||||
onCheckedChange = {},
|
||||
)
|
||||
|
@ -141,6 +281,7 @@ private fun BitwardenSwitch_preview() {
|
|||
)
|
||||
BitwardenSwitch(
|
||||
label = "Label",
|
||||
description = "description",
|
||||
isChecked = true,
|
||||
onCheckedChange = {},
|
||||
actions = {
|
||||
|
|
Loading…
Reference in a new issue