mirror of
https://github.com/bitwarden/android.git
synced 2026-03-11 20:54:58 -05:00
PM-16625 PM-16626 PM-16627 Coach marks 4-6 on generator screen (#4640)
This commit is contained in:
@@ -199,8 +199,8 @@ class CoachMarkScopeInstance<T : Enum<T>>(
|
||||
anchorContent: @Composable () -> Unit,
|
||||
) {
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(
|
||||
spacingBetweenTooltipAndAnchor = 12.dp,
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(
|
||||
spacingBetweenTooltipAndAnchor = 10.dp,
|
||||
),
|
||||
tooltip = {
|
||||
BitwardenToolTip(
|
||||
@@ -213,7 +213,7 @@ class CoachMarkScopeInstance<T : Enum<T>>(
|
||||
leftAction = leftAction,
|
||||
rightAction = rightAction,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.padding(horizontal = 6.dp)
|
||||
.semantics { isCoachMarkToolTip = true },
|
||||
)
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@ class LazyListCoachMarkState<T : Enum<T>>(
|
||||
}
|
||||
|
||||
private suspend fun LazyListState.searchForKey(keyToFind: T) {
|
||||
layoutInfo
|
||||
val keyFound = layoutInfo
|
||||
.visibleItemsInfo
|
||||
.any { it.key == keyToFind }
|
||||
.takeIf { itemAlreadyVisible ->
|
||||
@@ -59,6 +59,10 @@ class LazyListCoachMarkState<T : Enum<T>>(
|
||||
}
|
||||
?: scrollUpToKey(keyToFind).takeIf { it }
|
||||
?: scrollDownToKey(keyToFind)
|
||||
if (!keyFound) {
|
||||
// if key not found scroll back to the top.
|
||||
scrollToItem(index = 0)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun LazyListState.scrollUpToKey(
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components.tooltip
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredSizeIn
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.RichTooltip
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.tooltip.color.bitwardenTooltipColors
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
private val MIN_TOOLTIP_WIDTH = 312.dp
|
||||
|
||||
/**
|
||||
* Bitwarden themed rich tool-tip to show within a [TooltipScope].
|
||||
*/
|
||||
@@ -33,17 +39,30 @@ fun TooltipScope.BitwardenToolTip(
|
||||
leftAction: (@Composable RowScope.() -> Unit)? = null,
|
||||
rightAction: (@Composable RowScope.() -> Unit)? = null,
|
||||
) {
|
||||
RichTooltip(
|
||||
modifier = modifier,
|
||||
caretSize = DpSize(width = 24.dp, height = 16.dp),
|
||||
PlainTooltip(
|
||||
modifier = modifier.requiredSizeIn(minWidth = MIN_TOOLTIP_WIDTH),
|
||||
caretSize = DpSize(width = 24.dp, height = 12.dp),
|
||||
shape = BitwardenTheme.shapes.coachmark,
|
||||
title = {
|
||||
contentColor = BitwardenTheme.colorScheme.text.primary,
|
||||
containerColor = BitwardenTheme.colorScheme.background.secondary,
|
||||
) {
|
||||
// PlainTooltip already applies 8.dp of horizontal padding and 4.dp of vertical to the
|
||||
// content.
|
||||
Column(
|
||||
modifier = Modifier.padding(
|
||||
bottom = 4.dp,
|
||||
start = 8.dp,
|
||||
end = 8.dp,
|
||||
),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = BitwardenTheme.typography.eyebrowMedium,
|
||||
color = BitwardenTheme.colorScheme.text.secondary,
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
onDismiss?.let {
|
||||
@@ -51,25 +70,22 @@ fun TooltipScope.BitwardenToolTip(
|
||||
painter = rememberVectorPainter(R.drawable.ic_close_small),
|
||||
contentDescription = stringResource(R.string.close),
|
||||
onClick = it,
|
||||
modifier = Modifier.offset(x = 16.dp, y = (-16).dp),
|
||||
modifier = Modifier.offset(x = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
action = {
|
||||
Text(
|
||||
text = description,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
leftAction?.invoke(this)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
rightAction?.invoke(this)
|
||||
}
|
||||
},
|
||||
colors = bitwardenTooltipColors(),
|
||||
) {
|
||||
Text(
|
||||
text = description,
|
||||
style = BitwardenTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ import kotlinx.coroutines.withTimeout
|
||||
|
||||
/**
|
||||
* Default implementation of [BitwardenToolTipState]
|
||||
*
|
||||
* This is making use of the implementation of [TooltipState] provided via
|
||||
* [androidx.compose.material3.rememberTooltipState] but overriding [dismiss] to be
|
||||
* no-op.
|
||||
*/
|
||||
class BitwardenToolTipStateImpl(
|
||||
initialIsVisible: Boolean,
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components.tooltip.color
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.RichTooltipColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import com.x8bit.bitwarden.ui.platform.components.tooltip.BitwardenToolTip
|
||||
|
||||
/**
|
||||
* Bitwarden themed colors for the [BitwardenToolTip]
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun bitwardenTooltipColors(
|
||||
contentColor: Color = BitwardenTheme.colorScheme.text.primary,
|
||||
containerColor: Color = BitwardenTheme.colorScheme.background.secondary,
|
||||
titleContentColor: Color = BitwardenTheme.colorScheme.text.secondary,
|
||||
actionContentColor: Color = BitwardenTheme.colorScheme.text.interaction,
|
||||
): RichTooltipColors = RichTooltipColors(
|
||||
contentColor = contentColor,
|
||||
containerColor = containerColor,
|
||||
titleContentColor = titleContentColor,
|
||||
actionContentColor = actionContentColor,
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1138,4 +1138,9 @@ Do you want to switch to this account?</string>
|
||||
<string name="coachmark_1_of_6">1 OF 6</string>
|
||||
<string name="coachmark_2_of_6">2 OF 6</string>
|
||||
<string name="coachmark_3_of_6">3 OF 6</string>
|
||||
<string name="coachmark_4_of_6">4 OF 6</string>
|
||||
<string name="coachmark_5_of_6">5 OF 6</string>
|
||||
<string name="coachmark_6_of_6">6 OF 6</string>
|
||||
<string name="use_these_options_to_adjust_your_password_to_your_account_requirements">Use these options to adjust your password to your account’s requirements.</string>
|
||||
<string name="after_you_save_your_new_password_to_bitwarden_don_t_forget_to_update_it_on_your_account_website">"After you save your new password to Bitwarden, don’t forget to update it on your account website. "</string>
|
||||
</resources>
|
||||
|
||||
@@ -1705,6 +1705,62 @@ class GeneratorScreenTest : BaseComposeTest() {
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `The full coach mark tour can be completed showing all steps`() {
|
||||
mutableEventFlow.tryEmit(GeneratorEvent.StartCoachMarkTour)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("1 OF 6")
|
||||
.assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Next")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("2 OF 6")
|
||||
.assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Next")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("3 OF 6")
|
||||
.assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Next")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("4 OF 6")
|
||||
.assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Next")
|
||||
.performClick()
|
||||
composeTestRule
|
||||
.onNodeWithText("5 OF 6")
|
||||
.assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Next")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("6 OF 6")
|
||||
.assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Done")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNode(isCoachMarkToolTip)
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
//endregion Random Word Tests
|
||||
|
||||
private fun updateState(state: GeneratorState) {
|
||||
|
||||
Reference in New Issue
Block a user