Skip to content

Commit

Permalink
Merge pull request #34 from pseudoankit/feat/separate-tooltip
Browse files Browse the repository at this point in the history
Provide capability to have separate tooltip for each composable
  • Loading branch information
pseudoankit authored May 12, 2024
2 parents 46f9df9 + 9d160ba commit 8386aab
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,49 @@ import com.pseudoankit.coachmark.model.OverlayClickEvent
import com.pseudoankit.coachmark.overlay.UnifyOverlayEffect
import com.pseudoankit.coachmark.scope.CoachMarkScope
import com.pseudoankit.coachmark.scope.CoachMarkScopeImpl
import com.pseudoankit.coachmark.scope.enableCoachMark
import com.pseudoankit.coachmark.ui.CoachMarkImpl
import com.pseudoankit.coachmark.util.CoachMarkDefaults
import com.pseudoankit.coachmark.util.CoachMarkKey

public val LocalCoachMarkScope: ProvidableCompositionLocal<CoachMarkScope> =
compositionLocalOf { error("CompositionLocal CoachMarkScope not present") }

/**
* Entry point to show coachmark,
* This screen should to be called at the root level so that coachmark can be visible at very top
* @param overlayEffect configure overlay effect to be shown when tooltip is visible
* @param content actual screen content
*/
@Composable
public fun UnifyCoachmark(
overlayEffect: UnifyOverlayEffect = CoachMarkDefaults.Overlay.background,
onOverlayClicked: (CoachMarkKey) -> OverlayClickEvent = { CoachMarkDefaults.Overlay.clickEvent },
content: @Composable CoachMarkScope.() -> Unit
) {
UnifyCoachmark(
tooltip = {},
overlayEffect = overlayEffect,
onOverlayClicked = onOverlayClicked,
content = content
)
}

@Deprecated(
message = "Please avoid passing tooltip at top level, tooltips can be simply passed when calling `enableCoachMark` for each view",
)
/**
* This method is deprecated, not recommended to pass tooltip at top level
* as now it can be passed when calling [enableCoachMark] method for each view
* for backward compatibility [tooltip] field will still work as expected
* but [enableCoachMark]'s tooltip will take priority over [tooltip] if passed.
*
* Entry point to show coachmark,
* This screen should to be called at the root level so that coachmark can be visible at very top
* @param tooltip view to be shown when any view is highlighted
* @param overlayEffect configure overlay effect to be shown when tooltip is visible
* @param content actual screen content
*/
@Composable
public fun UnifyCoachmark(
tooltip: @Composable CoachMarkScope.(CoachMarkKey) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,21 @@ public fun UnifyCoachmarkDemo() {
) {
PlotTextsAndUseLocalCoachMarkScope()
Button(
onClick = {
show(Keys.Text1)
},
onClick = { show(Keys.Text1) },
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text(text = "Highlight 1")
}
Button(
onClick = {
show(*Keys.values())
},
onClick = { show(*Keys.values()) },
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text(text = "Highlight All")
}
Button(onClick = { show(Keys.TextBottom, Keys.TextTop) }) {
Button(
onClick = { show(Keys.TextBottom, Keys.TextTop) },
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text(text = "Highlight Some")
}
}
Expand All @@ -67,31 +66,50 @@ public fun UnifyCoachmarkDemo() {
@Composable
private fun ColumnScope.PlotTextsAndUseLocalCoachMarkScope() {

CoachMarkTargetText("Will show tooltip 1", Alignment.Start, Keys.Text1, ToolTipPlacement.End)

CoachMarkTargetText("Will show tooltip 2", Alignment.Start, Keys.Text2, ToolTipPlacement.End)
CoachMarkTargetText(
text = "Will show tooltip 1",
alignment = Alignment.Start,
key = Keys.Text1,
placement = ToolTipPlacement.End,
tooltip = {
Balloon(arrow = Arrow.Start()) {
Text(text = "Highlighting Text1 at enableCoachmark method", color = Color.White)
}
}
)

CoachMarkTargetText(
"Will show tooltip to left",
Alignment.End,
Keys.TextStart,
ToolTipPlacement.Start
text = "Will show tooltip 2",
alignment = Alignment.Start,
key = Keys.Text2,
placement = ToolTipPlacement.End
)

CoachMarkTargetText(
"Will show tooltip below",
Alignment.CenterHorizontally,
Keys.TextBottom,
ToolTipPlacement.Bottom
text = "Will show tooltip to left",
alignment = Alignment.End,
key = Keys.TextStart,
placement = ToolTipPlacement.Start,
tooltip = {
Balloon(arrow = Arrow.End()) {
Text(text = "tooltip to left at enableCoachmark method", color = Color.White)
}
}
)

CoachMarkTargetText(
"Will show tooltip above",
Alignment.CenterHorizontally,
Keys.TextTop,
ToolTipPlacement.Top
text = "Will show tooltip below",
alignment = Alignment.CenterHorizontally,
key = Keys.TextBottom,
placement = ToolTipPlacement.Bottom
)

CoachMarkTargetText(
text = "Will show tooltip above",
alignment = Alignment.CenterHorizontally,
key = Keys.TextTop,
placement = ToolTipPlacement.Top
)
}

@Composable
Expand All @@ -100,6 +118,7 @@ private fun ColumnScope.CoachMarkTargetText(
alignment: Alignment.Horizontal,
key: Keys,
placement: ToolTipPlacement,
tooltip: @Composable (() -> Unit)? = null
) {
val coachMarkScope = LocalCoachMarkScope.current

Expand All @@ -114,7 +133,8 @@ private fun ColumnScope.CoachMarkTargetText(
shape = HighlightedViewConfig.Shape.Rect(12.dp),
padding = PaddingValues(8.dp)
),
coachMarkScope = coachMarkScope
coachMarkScope = coachMarkScope,
tooltip = tooltip
)
.padding(16.dp),
color = Color.Black
Expand All @@ -126,31 +146,31 @@ private fun Tooltip(key: CoachMarkKey) {
when (key) {
Keys.Text1 -> {
Balloon(arrow = Arrow.Start()) {
Text(text = "Highlighting Text1", color = Color.White)
Text(text = "Highlighting Text1 root level", color = Color.White)
}
}

Keys.Text2 -> {
Balloon(arrow = Arrow.Start()) {
Text(text = "Highlighting Text2", color = Color.White)
Text(text = "Highlighting Text2 root level", color = Color.White)
}
}

Keys.TextStart -> {
Balloon(arrow = Arrow.End()) {
Text(text = "A tooltip to the left", color = Color.White)
Text(text = "A tooltip to the left root level", color = Color.White)
}
}

Keys.TextBottom -> {
Balloon(arrow = Arrow.Top()) {
Text(text = "A tooltip below", color = Color.White)
Text(text = "A tooltip below root level", color = Color.White)
}
}

Keys.TextTop -> {
Balloon(arrow = Arrow.Bottom()) {
Text(text = "A tooltip above", color = Color.White)
Text(text = "A tooltip above root level", color = Color.White)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.pseudoankit.coachmark.model

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import com.pseudoankit.coachmark.scope.CoachMarkScope
import com.pseudoankit.coachmark.util.CoachMarkKey
Expand All @@ -20,7 +21,8 @@ public data class TooltipConfig(
val toolTipPlacement: ToolTipPlacement,
val key: CoachMarkKey,
val highlightedViewShape: HighlightedViewConfig.Shape,
val animationState: AnimationState
val animationState: AnimationState,
val tooltip: @Composable (() -> Unit)? = null
) {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.pseudoankit.coachmark.scope

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import com.pseudoankit.coachmark.model.HighlightedViewConfig
Expand Down Expand Up @@ -37,7 +38,8 @@ public interface CoachMarkScope {
key: CoachMarkKey,
toolTipPlacement: ToolTipPlacement,
tooltipAnimationSpec: AnimationSpec<Float> = CoachMarkDefaults.ToolTip.animationSpec,
highlightedViewConfig: HighlightedViewConfig = HighlightedViewConfig()
highlightedViewConfig: HighlightedViewConfig = HighlightedViewConfig(),
tooltip: @Composable (() -> Unit)? = null
): Modifier

/**
Expand Down Expand Up @@ -70,12 +72,14 @@ public fun Modifier.enableCoachMark(
key: CoachMarkKey,
toolTipPlacement: ToolTipPlacement,
tooltipAnimationSpec: AnimationSpec<Float> = CoachMarkDefaults.ToolTip.animationSpec,
highlightedViewConfig: HighlightedViewConfig = HighlightedViewConfig()
highlightedViewConfig: HighlightedViewConfig = HighlightedViewConfig(),
tooltip: @Composable (() -> Unit)? = null
): Modifier = with(coachMarkScope) {
enableCoachMark(
key = key,
toolTipPlacement = toolTipPlacement,
tooltipAnimationSpec = tooltipAnimationSpec,
highlightedViewConfig = highlightedViewConfig
highlightedViewConfig = highlightedViewConfig,
tooltip = tooltip
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.pseudoankit.coachmark.scope
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand Down Expand Up @@ -54,6 +55,7 @@ internal class CoachMarkScopeImpl(
toolTipPlacement: ToolTipPlacement,
tooltipAnimationSpec: AnimationSpec<Float>,
highlightedViewConfig: HighlightedViewConfig,
tooltip: @Composable (() -> Unit)?
): Modifier = onGloballyPositioned { layoutCoordinates ->
val startPadding =
highlightedViewConfig.padding.calculateStartPadding(layoutDirection).toPx(density)
Expand All @@ -74,7 +76,8 @@ internal class CoachMarkScopeImpl(
highlightedViewShape = highlightedViewConfig.shape,
animationState = TooltipConfig.AnimationState(
tooltipAnimationSpec = tooltipAnimationSpec
)
),
tooltip = tooltip
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,14 @@ internal fun CoachMarkImpl(
tooltipHolder = currentTooltip,
modifier = Modifier.layoutId(TooltipId.current),
) {
coachMarkScope.tooltip(it)
coachMarkScope.currentVisibleTooltip?.tooltip?.invoke()
?: coachMarkScope.tooltip(it)
}
Tooltip(
tooltipHolder = previousTooltip,
modifier = Modifier.layoutId(TooltipId.previous),
) {
coachMarkScope.tooltip(it)
coachMarkScope.lastVisibleTooltip?.tooltip?.invoke() ?: coachMarkScope.tooltip(it)
}
}
}
Expand Down

0 comments on commit 8386aab

Please sign in to comment.