Skip to content

Commit

Permalink
PM-16622 PM-16623 and PM-16624 Add the first three coach marks to the…
Browse files Browse the repository at this point in the history
… generator tour (#4613)
  • Loading branch information
dseverns-livefront authored Jan 28, 2025
1 parent 3c7262d commit a681402
Show file tree
Hide file tree
Showing 16 changed files with 413 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
import kotlinx.coroutines.launch

private const val ROUNDED_RECT_RADIUS = 8f

/**
* A composable container that manages and displays coach mark highlights.
*
Expand Down Expand Up @@ -79,17 +77,17 @@ fun <T : Enum<T>> CoachMarkContainer(
bottomRight = boundedRectangle.bottomRight,
)
Path().apply {
when (currentHighlightShape) {
CoachMarkHighlightShape.SQUARE -> addRoundRect(
when (val shape = currentHighlightShape) {
is CoachMarkHighlightShape.RoundedRectangle -> addRoundRect(
RoundRect(
rect = highlightArea,
cornerRadius = CornerRadius(
x = ROUNDED_RECT_RADIUS,
x = shape.radius,
),
),
)

CoachMarkHighlightShape.OVAL -> addOval(highlightArea)
CoachMarkHighlightShape.Oval -> addOval(highlightArea)
}
}
}
Expand Down Expand Up @@ -189,7 +187,7 @@ private fun BitwardenCoachMarkContainer_preview() {
style = BitwardenTheme.typography.labelLarge,
)
},
shape = CoachMarkHighlightShape.OVAL,
shape = CoachMarkHighlightShape.Oval,
) {
BitwardenStandardIconButton(
painter = rememberVectorPainter(R.drawable.ic_puzzle),
Expand All @@ -203,6 +201,7 @@ private fun BitwardenCoachMarkContainer_preview() {
key = Foo.Baz,
title = "Foo",
description = "Baz",
shape = CoachMarkHighlightShape.RoundedRectangle(radius = 50f),
leftAction = {
BitwardenClickableText(
label = "Back",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ interface CoachMarkScope<T : Enum<T>> {
title: String,
description: String,
modifier: Modifier = Modifier,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.SQUARE,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.RoundedRectangle(),
onDismiss: (() -> Unit)? = null,
leftAction: (@Composable RowScope.() -> Unit)? = null,
rightAction: (@Composable RowScope.() -> Unit)? = null,
Expand Down Expand Up @@ -81,7 +81,7 @@ interface CoachMarkScope<T : Enum<T>> {
title: Text,
description: Text,
modifier: Modifier = Modifier,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.SQUARE,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.RoundedRectangle(),
onDismiss: (() -> Unit)? = null,
leftAction: (@Composable RowScope.() -> Unit)? = null,
rightAction: (@Composable RowScope.() -> Unit)? = null,
Expand Down Expand Up @@ -112,7 +112,7 @@ interface CoachMarkScope<T : Enum<T>> {
title: Text,
description: Text,
modifier: Modifier = Modifier,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.SQUARE,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.RoundedRectangle(),
items: List<R>,
onDismiss: (() -> Unit)? = null,
leftAction: (@Composable RowScope.() -> Unit)? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ open class CoachMarkState<T : Enum<T>>(
val currentHighlight: State<T?> = mutableCurrentHighlight
private val mutableCurrentHighlightBounds = mutableStateOf(Rect.Zero)
val currentHighlightBounds: State<Rect> = mutableCurrentHighlightBounds
private val mutableCurrentHighlightShape = mutableStateOf(CoachMarkHighlightShape.SQUARE)
private val mutableCurrentHighlightShape = mutableStateOf<CoachMarkHighlightShape>(
CoachMarkHighlightShape.RoundedRectangle(),
)
val currentHighlightShape: State<CoachMarkHighlightShape> = mutableCurrentHighlightShape

private val mutableIsVisible = mutableStateOf(isCoachMarkVisible)
Expand All @@ -53,13 +55,13 @@ open class CoachMarkState<T : Enum<T>>(
* Rect.Zero.
* @param toolTipState The state of the tooltip associated with this highlight.
* @param shape The shape of the highlight (e.g., square, oval). Defaults to
* [CoachMarkHighlightShape.SQUARE].
* [CoachMarkHighlightShape.RoundedRectangle].
*/
fun updateHighlight(
key: T,
bounds: Rect?,
toolTipState: BitwardenToolTipState,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.SQUARE,
shape: CoachMarkHighlightShape = CoachMarkHighlightShape.RoundedRectangle(),
) {
highlights[key] = CoachMarkHighlightState(
key = key,
Expand Down Expand Up @@ -168,7 +170,7 @@ open class CoachMarkState<T : Enum<T>>(
getCurrentHighlight()?.toolTipState?.cleanUp()
mutableCurrentHighlight.value = null
mutableCurrentHighlightBounds.value = Rect.Zero
mutableCurrentHighlightShape.value = CoachMarkHighlightShape.SQUARE
mutableCurrentHighlightShape.value = CoachMarkHighlightShape.RoundedRectangle()
mutableIsVisible.value = false
onComplete?.invoke()
}
Expand All @@ -184,7 +186,8 @@ open class CoachMarkState<T : Enum<T>>(

private fun updateCoachMarkStateInternal(highlight: CoachMarkHighlightState<T>?) {
mutableIsVisible.value = highlight != null
mutableCurrentHighlightShape.value = highlight?.shape ?: CoachMarkHighlightShape.SQUARE
mutableCurrentHighlightShape.value =
highlight?.shape ?: CoachMarkHighlightShape.RoundedRectangle()
if (currentHighlightBounds.value != highlight?.highlightBounds) {
mutableCurrentHighlightBounds.value = highlight?.highlightBounds ?: Rect.Zero
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark.model

private const val ROUNDED_RECT_DEFAULT_RADIUS = 8f

/**
* Defines the available shapes for a coach mark highlight.
*/
enum class CoachMarkHighlightShape {
sealed class CoachMarkHighlightShape {
/**
* A square-shaped highlight.
* A rounded rectangle shape which has a radius to round the corners by.
*
* @property radius the radius to use to round the corners of the rectangle shape.
* Defaults to [ROUNDED_RECT_DEFAULT_RADIUS]
*/
SQUARE,
data class RoundedRectangle(
val radius: Float = ROUNDED_RECT_DEFAULT_RADIUS,
) : CoachMarkHighlightShape()

/**
* An oval-shaped highlight.
*/
OVAL,
data object Oval : CoachMarkHighlightShape()
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.union
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.SingleChoiceSegmentedButtonRowScope
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -39,6 +40,14 @@ fun BitwardenSegmentedButton(
windowInsets: WindowInsets = WindowInsets.displayCutout
.union(WindowInsets.navigationBars)
.only(WindowInsetsSides.Horizontal),
optionContent: @Composable SingleChoiceSegmentedButtonRowScope.(
Int,
SegmentedButtonState,
) -> Unit = { _, optionState ->
this.SegmentedButtonOptionContent(
option = optionState,
)
},
) {
if (options.isEmpty()) return
Box(
Expand All @@ -58,29 +67,39 @@ fun BitwardenSegmentedButton(
space = 0.dp,
) {
options.forEachIndexed { index, option ->
SegmentedButton(
enabled = option.isEnabled,
selected = option.isChecked,
onClick = option.onClick,
colors = bitwardenSegmentedButtonColors(),
shape = BitwardenTheme.shapes.segmentedControl,
border = BorderStroke(width = 0.dp, color = Color.Transparent),
label = {
Text(
text = option.text,
style = BitwardenTheme.typography.labelLarge,
)
},
icon = {
// No icon required
},
modifier = Modifier.semantics { option.testTag?.let { testTag = it } },
)
optionContent(index, option)
}
}
}
}

/**
* Default content definition for each option in a [BitwardenSegmentedButton].
*/
@Composable
fun SingleChoiceSegmentedButtonRowScope.SegmentedButtonOptionContent(
option: SegmentedButtonState,
) {
SegmentedButton(
enabled = option.isEnabled,
selected = option.isChecked,
onClick = option.onClick,
colors = bitwardenSegmentedButtonColors(),
shape = BitwardenTheme.shapes.segmentedControl,
border = BorderStroke(width = 0.dp, color = Color.Transparent),
label = {
Text(
text = option.text,
style = BitwardenTheme.typography.labelLarge,
)
},
icon = {
// No icon required
},
modifier = Modifier.semantics { option.testTag?.let { testTag = it } },
)
}

/**
* Models state for an individual button in a [BitwardenSegmentedButton].
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
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.Modifier
import androidx.compose.ui.layout.onGloballyPositioned
Expand Down Expand Up @@ -172,7 +173,7 @@ private fun VaultUnlockedNavBarScaffold(
onNavigateToSetupAutoFillScreen: () -> Unit,
onNavigateToImportLogins: (SnackbarRelay) -> Unit,
) {
var shouldDimNavBar by remember { mutableStateOf(false) }
var shouldDimNavBar by rememberSaveable { mutableStateOf(false) }

// This scaffold will host screens that contain top bars while not hosting one itself.
// We need to ignore the all insets here and let the content screens handle it themselves.
Expand Down Expand Up @@ -239,6 +240,9 @@ private fun VaultUnlockedNavBarScaffold(
)
generatorGraph(
onNavigateToPasswordHistory = { navigateToPasswordHistory() },
onDimNavBarRequest = { shouldDim ->
shouldDimNavBar = shouldDim
},
)
settingsGraph(
navController = navController,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ const val GENERATOR_GRAPH_ROUTE: String = "generator_graph"
*/
fun NavGraphBuilder.generatorGraph(
onNavigateToPasswordHistory: () -> Unit,
onDimNavBarRequest: (Boolean) -> Unit,
) {
navigation(
route = GENERATOR_GRAPH_ROUTE,
startDestination = GENERATOR_ROUTE,
) {
generatorDestination(
onNavigateToPasswordHistory = onNavigateToPasswordHistory,
onDimNavBarRequest = onDimNavBarRequest,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ data class GeneratorArgs(
*/
fun NavGraphBuilder.generatorDestination(
onNavigateToPasswordHistory: () -> Unit,
onDimNavBarRequest: (Boolean) -> Unit,
) {
composable(GENERATOR_ROUTE) {
GeneratorScreen(
onNavigateToPasswordHistory = onNavigateToPasswordHistory,
onNavigateBack = {},
onDimNavBarRequest = onDimNavBarRequest,
)
}
}
Expand All @@ -76,6 +78,7 @@ fun NavGraphBuilder.generatorModalDestination(
GeneratorScreen(
onNavigateToPasswordHistory = {},
onNavigateBack = onNavigateBack,
onDimNavBarRequest = {},
)
}
}
Expand Down
Loading

0 comments on commit a681402

Please sign in to comment.