PM-25028: Migrate coachmarks and tooltips to UI module (#5757)

This commit is contained in:
David Perez 2025-08-20 11:04:19 -05:00 committed by GitHub
parent d8e319948c
commit e5a1546291
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 49 additions and 51 deletions

View File

@ -50,6 +50,11 @@ import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
import com.bitwarden.ui.platform.components.button.BitwardenTextButton
import com.bitwarden.ui.platform.components.card.BitwardenActionCard
import com.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard
import com.bitwarden.ui.platform.components.coachmark.CoachMarkActionText
import com.bitwarden.ui.platform.components.coachmark.CoachMarkContainer
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.bitwarden.ui.platform.components.coachmark.model.rememberLazyListCoachMarkState
import com.bitwarden.ui.platform.components.coachmark.scope.CoachMarkScope
import com.bitwarden.ui.platform.components.dropdown.BitwardenMultiSelectButton
import com.bitwarden.ui.platform.components.field.BitwardenPasswordField
import com.bitwarden.ui.platform.components.field.BitwardenTextField
@ -78,11 +83,6 @@ import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.platform.manager.model.AppResumeScreenData
import com.x8bit.bitwarden.data.platform.manager.util.AppResumeStateManager
import com.x8bit.bitwarden.data.platform.manager.util.RegisterScreenDataOnLifecycleEffect
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkActionText
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkContainer
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkScope
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.x8bit.bitwarden.ui.platform.components.coachmark.rememberLazyListCoachMarkState
import com.x8bit.bitwarden.ui.platform.composition.LocalAppResumeStateManager
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Passphrase.Companion.PASSPHRASE_MAX_NUMBER_OF_WORDS
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Passphrase.Companion.PASSPHRASE_MIN_NUMBER_OF_WORDS

View File

@ -21,13 +21,13 @@ import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
import com.bitwarden.ui.platform.components.button.BitwardenTextSelectionButton
import com.bitwarden.ui.platform.components.card.BitwardenActionCard
import com.bitwarden.ui.platform.components.card.BitwardenInfoCalloutCard
import com.bitwarden.ui.platform.components.coachmark.scope.CoachMarkScope
import com.bitwarden.ui.platform.components.field.BitwardenTextField
import com.bitwarden.ui.platform.components.header.BitwardenListHeaderText
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkScope
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
import com.x8bit.bitwarden.ui.vault.components.collectionItemsSelector
import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditCardTypeHandlers

View File

@ -22,6 +22,9 @@ import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.base.util.cardStyle
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
import com.bitwarden.ui.platform.components.coachmark.CoachMarkActionText
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.bitwarden.ui.platform.components.coachmark.scope.CoachMarkScope
import com.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
import com.bitwarden.ui.platform.components.field.BitwardenHiddenPasswordField
import com.bitwarden.ui.platform.components.field.BitwardenPasswordField
@ -36,9 +39,6 @@ import com.bitwarden.ui.platform.theme.BitwardenTheme
import com.bitwarden.ui.util.Text
import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkActionText
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkScope
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditLoginTypeHandlers
/**

View File

@ -48,6 +48,8 @@ import com.bitwarden.ui.platform.components.appbar.action.BitwardenOverflowActio
import com.bitwarden.ui.platform.components.appbar.model.OverflowMenuItemData
import com.bitwarden.ui.platform.components.bottomsheet.BitwardenModalBottomSheet
import com.bitwarden.ui.platform.components.button.BitwardenTextButton
import com.bitwarden.ui.platform.components.coachmark.CoachMarkContainer
import com.bitwarden.ui.platform.components.coachmark.model.rememberLazyListCoachMarkState
import com.bitwarden.ui.platform.components.content.BitwardenErrorContent
import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent
import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
@ -68,8 +70,6 @@ import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
import com.bitwarden.ui.util.Text
import com.x8bit.bitwarden.ui.credentials.manager.CredentialProviderCompletionManager
import com.x8bit.bitwarden.ui.platform.components.coachmark.CoachMarkContainer
import com.x8bit.bitwarden.ui.platform.components.coachmark.rememberLazyListCoachMarkState
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPasswordDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenOverwritePasskeyConfirmationDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenPinDialog

View File

@ -32,10 +32,10 @@ import androidx.core.net.toUri
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.ui.platform.manager.IntentManager
import com.bitwarden.ui.util.asText
import com.bitwarden.ui.util.isCoachMarkToolTip
import com.x8bit.bitwarden.data.platform.manager.util.AppResumeStateManager
import com.x8bit.bitwarden.ui.platform.base.BitwardenComposeTest
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
import com.x8bit.bitwarden.ui.util.isCoachMarkToolTip
import io.mockk.every
import io.mockk.just
import io.mockk.mockk

View File

@ -1,13 +0,0 @@
package com.x8bit.bitwarden.ui.util
import androidx.compose.ui.semantics.getOrNull
import androidx.compose.ui.test.SemanticsMatcher
import com.x8bit.bitwarden.ui.platform.components.coachmark.IsCoachMarkToolTipKey
/**
* A [SemanticsMatcher] user to find Popup nodes used specifically for CoachMarkToolTips
*/
val isCoachMarkToolTip: SemanticsMatcher
get() = SemanticsMatcher("Node is used to show tool tip for active coach mark.") {
it.config.getOrNull(IsCoachMarkToolTipKey) == true
}

View File

@ -46,6 +46,7 @@ import com.bitwarden.ui.util.asText
import com.bitwarden.ui.util.assertNoDialogExists
import com.bitwarden.ui.util.assertScrollableNodeDoesNotExist
import com.bitwarden.ui.util.isBottomSheet
import com.bitwarden.ui.util.isCoachMarkToolTip
import com.bitwarden.ui.util.isProgressBar
import com.bitwarden.ui.util.onAllNodesWithContentDescriptionAfterScroll
import com.bitwarden.ui.util.onAllNodesWithTextAfterScroll
@ -61,7 +62,6 @@ import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
import com.x8bit.bitwarden.ui.util.isCoachMarkToolTip
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.CustomFieldAction
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.CustomFieldType
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.UriItem

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark
package com.bitwarden.ui.platform.components.coachmark
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark
package com.bitwarden.ui.platform.components.coachmark
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
@ -32,12 +32,16 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.components.button.BitwardenStandardIconButton
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkState
import com.bitwarden.ui.platform.components.coachmark.model.rememberCoachMarkState
import com.bitwarden.ui.platform.components.coachmark.scope.CoachMarkScope
import com.bitwarden.ui.platform.components.coachmark.scope.CoachMarkScopeInstance
import com.bitwarden.ui.platform.components.text.BitwardenClickableText
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import kotlinx.coroutines.launch
/**

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark.model
package com.bitwarden.ui.platform.components.coachmark.model
private const val ROUNDED_RECT_DEFAULT_RADIUS = 8f

View File

@ -1,7 +1,7 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark.model
package com.bitwarden.ui.platform.components.coachmark.model
import androidx.compose.ui.geometry.Rect
import com.x8bit.bitwarden.ui.platform.components.tooltip.BitwardenToolTipState
import com.bitwarden.ui.platform.components.tooltip.model.BitwardenToolTipState
/**
* Represents a highlight within a coach mark sequence.

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark
package com.bitwarden.ui.platform.components.coachmark.model
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
@ -9,9 +9,7 @@ import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.geometry.Rect
import com.bitwarden.core.data.util.concurrentMapOf
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightState
import com.x8bit.bitwarden.ui.platform.components.tooltip.BitwardenToolTipState
import com.bitwarden.ui.platform.components.tooltip.model.BitwardenToolTipState
import kotlin.math.max
import kotlin.math.min

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark
package com.bitwarden.ui.platform.components.coachmark.model
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollBy

View File

@ -1,13 +1,13 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark
package com.bitwarden.ui.platform.components.coachmark.scope
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.util.Text
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
/**
* Defines the scope for creating coach mark highlights within a user interface.

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.coachmark
package com.bitwarden.ui.platform.components.coachmark.scope
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
@ -25,12 +25,13 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.base.util.toListItemCardStyle
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.bitwarden.ui.platform.components.coachmark.model.CoachMarkState
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.tooltip.BitwardenToolTip
import com.bitwarden.ui.platform.components.tooltip.model.BitwardenToolTipState
import com.bitwarden.ui.platform.components.tooltip.model.rememberBitwardenToolTipState
import com.bitwarden.ui.util.Text
import com.x8bit.bitwarden.ui.platform.components.coachmark.model.CoachMarkHighlightShape
import com.x8bit.bitwarden.ui.platform.components.tooltip.BitwardenToolTip
import com.x8bit.bitwarden.ui.platform.components.tooltip.BitwardenToolTipState
import com.x8bit.bitwarden.ui.platform.components.tooltip.rememberBitwardenToolTipState
import kotlinx.collections.immutable.toImmutableList
import org.jetbrains.annotations.VisibleForTesting
@ -38,7 +39,7 @@ import org.jetbrains.annotations.VisibleForTesting
* Creates an instance of [CoachMarkScope] for a given [CoachMarkState].
*/
@OptIn(ExperimentalMaterial3Api::class)
class CoachMarkScopeInstance<T : Enum<T>>(
internal class CoachMarkScopeInstance<T : Enum<T>>(
private val coachMarkState: CoachMarkState<T>,
) : CoachMarkScope<T> {

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.tooltip
package com.bitwarden.ui.platform.components.tooltip
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.tooltip
package com.bitwarden.ui.platform.components.tooltip.model
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TooltipState

View File

@ -1,4 +1,4 @@
package com.x8bit.bitwarden.ui.platform.components.tooltip
package com.bitwarden.ui.platform.components.tooltip.model
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.foundation.MutatePriority
@ -15,10 +15,9 @@ 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.
* [androidx.compose.material3.rememberTooltipState] but overriding [dismiss] to be no-op.
*/
class BitwardenToolTipStateImpl(
internal class BitwardenToolTipStateImpl(
initialIsVisible: Boolean,
override val isPersistent: Boolean,
private val mutatorMutex: MutatorMutex,

View File

@ -25,6 +25,7 @@ import androidx.compose.ui.test.performScrollToNode
import androidx.compose.ui.test.printToString
import androidx.compose.ui.text.LinkAnnotation
import com.bitwarden.ui.platform.components.bottomsheet.IsBottomSheetKey
import com.bitwarden.ui.platform.components.coachmark.scope.IsCoachMarkToolTipKey
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.jupiter.api.assertThrows
@ -37,6 +38,14 @@ val isBottomSheet: SemanticsMatcher
it.config.getOrNull(IsBottomSheetKey) == true
}
/**
* A [SemanticsMatcher] user to find Popup nodes used specifically for CoachMarkToolTips
*/
val isCoachMarkToolTip: SemanticsMatcher
get() = SemanticsMatcher("Node is used to show tool tip for active coach mark.") {
it.config.getOrNull(IsCoachMarkToolTipKey) == true
}
/**
* A [SemanticsMatcher] used to find editable text nodes.
*/