Skip to content

Commit 268e98a

Browse files
committed
first commit
0 parents  commit 268e98a

26 files changed

Lines changed: 2834 additions & 0 deletions

File tree

.gitignore

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Gradle
2+
.gradle/
3+
build/
4+
**/build/
5+
!gradle/wrapper/gradle-wrapper.jar
6+
7+
# Local configuration
8+
local.properties
9+
*.properties.local
10+
11+
# Android Studio / IntelliJ
12+
.idea/
13+
*.iml
14+
*.iws
15+
*.ipr
16+
out/
17+
18+
# Kotlin / Kotlin Native
19+
.kotlin/
20+
.konan/
21+
22+
# Android generated outputs
23+
captures/
24+
.externalNativeBuild/
25+
.cxx/
26+
*.apk
27+
*.aab
28+
*.ap_
29+
*.aar
30+
31+
# iOS / Xcode generated outputs
32+
DerivedData/
33+
*.xcuserstate
34+
*.xcworkspace/xcuserdata/
35+
*.xcodeproj/xcuserdata/
36+
*.xcodeproj/project.xcworkspace/xcuserdata/
37+
38+
# Signing and secrets
39+
*.jks
40+
*.keystore
41+
*.p8
42+
*.p12
43+
*.mobileprovision
44+
45+
# OS files
46+
.DS_Store
47+
Thumbs.db

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Changelog
2+
3+
All notable changes to GuideKit will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows semantic versioning.
6+
7+
## [Unreleased]
8+
9+
### Added
10+
11+
- Initial Compose Multiplatform GuideKit library.
12+
- Coachmark overlay with target highlights, instruction cards, arrows, step indicators, skip/finish callbacks, and auto-scroll support.
13+
- Sample Compose Multiplatform app under `sample/`.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Tharuka Chathura
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# GuideKit
2+
3+
Reusable Compose Multiplatform coachmark overlay.
4+
5+
GuideKit owns step navigation internally. The host app provides the steps, target bounds, and completion callbacks.
6+
7+
## Usage
8+
9+
```kotlin
10+
import androidx.compose.foundation.BorderStroke
11+
import androidx.compose.foundation.gestures.animateScrollBy
12+
import androidx.compose.foundation.layout.PaddingValues
13+
import androidx.compose.foundation.shape.RoundedCornerShape
14+
import androidx.compose.material3.MaterialTheme
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.graphics.Color
18+
import androidx.compose.ui.unit.dp
19+
import io.github.guidekit.GuideKit
20+
import io.github.guidekit.GuideKitAnchor
21+
import io.github.guidekit.GuideKitArrowConfig
22+
import io.github.guidekit.GuideKitArrowHead
23+
import io.github.guidekit.GuideKitArrowLineStyle
24+
import io.github.guidekit.GuideKitArrowStroke
25+
import io.github.guidekit.GuideKitAutoScrollConfig
26+
import io.github.guidekit.GuideKitInstructionBoxShadow
27+
import io.github.guidekit.GuideKitInstructionBoxStyle
28+
import io.github.guidekit.GuideKitStep
29+
import io.github.guidekit.GuideKitStyle
30+
import io.github.guidekit.GuideKitTargetHighlightShape
31+
import io.github.guidekit.GuideKitTargetHighlightStroke
32+
import io.github.guidekit.GuideKitTargetHighlightStyle
33+
import androidx.compose.ui.graphics.StrokeCap
34+
35+
GuideKit(
36+
steps = listOf(
37+
GuideKitStep(
38+
targetBounds = firstTargetBounds,
39+
title = "Your day, at a glance.",
40+
description = "Important updates appear here when they are needed.",
41+
primaryButtonText = null, // Defaults to "Next", or "Got it" on the last step.
42+
descriptionHighlight = null,
43+
descriptionHighlights = emptyList(),
44+
instructionBottomPadding = 104.dp,
45+
arrowConfig = null, // Uses GuideKitStyle.arrowConfig.
46+
targetHighlight = null, // Uses GuideKitStyle.targetHighlight.
47+
instructionBox = null, // Uses GuideKitStyle.instructionBox.
48+
autoScroll = GuideKitAutoScrollConfig(
49+
enabled = true,
50+
minTopVisibleDistance = null, // Defaults to arrowConfig.minVisibleDistance + 1.dp.
51+
spacing = null, // Defaults to arrowConfig.minVisibleDistance + 1.dp.
52+
),
53+
),
54+
GuideKitStep(
55+
targetBounds = secondTargetBounds,
56+
title = "Help is always within reach.",
57+
description = "Press and hold for 3 seconds.",
58+
primaryButtonText = "Done",
59+
arrowConfig = GuideKitArrowConfig(
60+
from = GuideKitAnchor.BottomCenter,
61+
to = GuideKitAnchor.CenterLeft,
62+
arrowHead = GuideKitArrowHead.BothSides,
63+
lineStyle = GuideKitArrowLineStyle.Solid,
64+
),
65+
targetHighlight = GuideKitTargetHighlightStyle(
66+
shape = GuideKitTargetHighlightShape.Circle,
67+
),
68+
instructionBox = GuideKitInstructionBoxStyle(
69+
alignment = Alignment.BottomCenter,
70+
),
71+
autoScroll = GuideKitAutoScrollConfig(enabled = false),
72+
),
73+
),
74+
modifier = Modifier,
75+
initialStepIndex = 0,
76+
showStepIndicator = true,
77+
style = GuideKitStyle(
78+
accentColor = Color(0xFF5ED5B3),
79+
overlayColor = Color.Black.copy(alpha = 0.68f),
80+
titleColor = null, // Defaults to MaterialTheme.colorScheme.onSurface.
81+
descriptionColor = null, // Defaults to MaterialTheme.colorScheme.onSurfaceVariant.
82+
highlightedDescriptionColor = null, // Defaults to accentColor.
83+
stepIndicatorActiveColor = null, // Defaults to accentColor.
84+
stepIndicatorInactiveColor = null, // Defaults to MaterialTheme.colorScheme.outlineVariant.
85+
primaryButtonContainerColor = null, // Defaults to accentColor.
86+
primaryButtonContentColor = Color(0xFF062D25),
87+
skipIconTint = null, // Defaults to MaterialTheme.colorScheme.onSurfaceVariant.
88+
arrowConfig = GuideKitArrowConfig(
89+
enabled = true,
90+
from = GuideKitAnchor.TopCenter,
91+
to = GuideKitAnchor.BottomCenter,
92+
curveSeed = 0,
93+
minVisibleDistance = 20.dp,
94+
lineStyle = GuideKitArrowLineStyle.Dashed,
95+
dashIntervalsPx = floatArrayOf(20f, 15f),
96+
dashPhasePx = 0f,
97+
strokes = listOf(
98+
GuideKitArrowStroke(widthPx = 9f, color = Color.Black.copy(alpha = 0.24f)),
99+
GuideKitArrowStroke(widthPx = 5.5f, color = null, alpha = 0.95f), // Defaults to GuideKitStyle.accentColor.
100+
GuideKitArrowStroke(widthPx = 1.7f, color = Color.White.copy(alpha = 0.62f)),
101+
),
102+
strokeCap = StrokeCap.Round,
103+
arrowHead = GuideKitArrowHead.TargetSide,
104+
arrowHeadLengthPx = 38f,
105+
arrowHeadAngleDegrees = 30f,
106+
arrowHeadStrokes = listOf(
107+
GuideKitArrowStroke(widthPx = 9f, color = Color.Black.copy(alpha = 0.22f)),
108+
GuideKitArrowStroke(widthPx = 5.5f, color = null, alpha = 0.96f), // Defaults to GuideKitStyle.accentColor.
109+
GuideKitArrowStroke(widthPx = 1.6f, color = Color.White.copy(alpha = 0.55f)),
110+
),
111+
),
112+
targetHighlight = GuideKitTargetHighlightStyle(
113+
enabled = true,
114+
shape = GuideKitTargetHighlightShape.RoundedRect,
115+
cutoutEnabled = true,
116+
paddingPx = 10f,
117+
cornerRadius = 28.dp,
118+
glowStrokes = listOf(
119+
GuideKitTargetHighlightStroke(widthPx = 30f, alpha = 0.11f),
120+
GuideKitTargetHighlightStroke(widthPx = 22f, alpha = 0.18f),
121+
GuideKitTargetHighlightStroke(widthPx = 14f, alpha = 0.30f),
122+
GuideKitTargetHighlightStroke(widthPx = 8f, alpha = 0.45f),
123+
),
124+
borderColor = null, // Defaults to GuideKitStyle.accentColor.
125+
borderWidthPx = 2.5f,
126+
innerBorderColor = Color.White.copy(alpha = 0.7f),
127+
innerBorderWidthPx = 1.2f,
128+
innerBorderInsetPx = 2f,
129+
),
130+
instructionBox = GuideKitInstructionBoxStyle(
131+
alignment = Alignment.BottomCenter,
132+
outerPadding = null, // Defaults to start/end 18.dp and step.instructionBottomPadding.
133+
contentPadding = PaddingValues(horizontal = 22.dp, vertical = 24.dp),
134+
fillMaxWidth = true,
135+
minWidth = null,
136+
maxWidth = null,
137+
minHeight = null,
138+
maxHeight = null,
139+
shape = RoundedCornerShape(30.dp),
140+
containerColor = null, // Defaults to MaterialTheme.colorScheme.surface.
141+
contentColor = null, // Defaults to MaterialTheme.colorScheme.onSurface.
142+
border = BorderStroke(1.dp, Color(0xFF5ED5B3).copy(alpha = 0.28f)),
143+
tonalElevation = 0.dp,
144+
shadowElevation = 26.dp,
145+
modifier = Modifier,
146+
shadow = GuideKitInstructionBoxShadow(
147+
elevation = 30.dp,
148+
ambientColor = Color.Black.copy(alpha = 0.42f),
149+
spotColor = Color.Black.copy(alpha = 0.42f),
150+
),
151+
),
152+
),
153+
onStepChanged = { stepIndex -> },
154+
onScrollBy = { deltaPx -> scrollState.animateScrollBy(deltaPx) },
155+
onSkipped = onSkip,
156+
onFinished = onFinished,
157+
)
158+
```
159+
160+
All values shown above are optional defaults. `GuideKitStyle` defines screen-level defaults for arrows, target highlights, and the instruction box. A `GuideKitStep` can override any of them for that specific step; omitted step values inherit from `GuideKitStyle`.
161+
162+
Auto-scroll is enabled by default. GuideKit calculates the smallest scroll needed to keep the highlighted target clear of the instruction box. If scrolling upward, the target highlight is clamped so its top stays at least `minTopVisibleDistance` from the top edge. Set `autoScroll = GuideKitAutoScrollConfig(enabled = false)` on a step to disable it. The host app must provide `onScrollBy` when the page is scrollable.
163+
164+
## Sample App
165+
166+
A Compose Multiplatform sample app is available under `sample/`.
167+
168+
```bash
169+
./gradlew :sample:composeApp:installDebug
170+
```
171+
172+
The sample demonstrates target measurement, step-specific styling, arrow variants, rounded and circular highlights, auto-scroll, and completion callbacks.

build.gradle.kts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
3+
plugins {
4+
alias(libs.plugins.kotlinMultiplatform)
5+
id("com.android.library")
6+
alias(libs.plugins.composeMultiplatform)
7+
alias(libs.plugins.composeCompiler)
8+
id("maven-publish")
9+
}
10+
11+
group = "io.github.tharukack"
12+
version = "0.1.0-SNAPSHOT"
13+
14+
kotlin {
15+
androidTarget {
16+
compilerOptions {
17+
jvmTarget.set(JvmTarget.JVM_11)
18+
}
19+
}
20+
21+
listOf(
22+
iosArm64(),
23+
iosSimulatorArm64(),
24+
).forEach { iosTarget ->
25+
iosTarget.binaries.framework {
26+
baseName = "GuideKit"
27+
isStatic = true
28+
}
29+
}
30+
31+
sourceSets {
32+
commonMain.dependencies {
33+
api(libs.compose.runtime)
34+
api(libs.compose.ui)
35+
implementation(libs.compose.foundation)
36+
implementation(libs.compose.material3)
37+
implementation(libs.compose.material.icons.core)
38+
implementation(libs.compose.material.icons.extended)
39+
}
40+
commonTest.dependencies {
41+
implementation(libs.kotlin.test)
42+
}
43+
}
44+
}
45+
46+
android {
47+
namespace = "io.github.guidekit"
48+
compileSdk = libs.versions.android.compileSdk.get().toInt()
49+
50+
defaultConfig {
51+
minSdk = libs.versions.android.minSdk.get().toInt()
52+
}
53+
54+
compileOptions {
55+
sourceCompatibility = JavaVersion.VERSION_11
56+
targetCompatibility = JavaVersion.VERSION_11
57+
}
58+
}

gradle.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
android.useAndroidX=true
2+
kotlin.code.style=official
3+
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8

gradle/libs.versions.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[versions]
2+
android-compileSdk = "36"
3+
android-minSdk = "23"
4+
android-targetSdk = "36"
5+
androidx-activity = "1.13.0"
6+
compose = "1.11.1"
7+
composeRuntime = "1.10.0"
8+
composeMaterial3 = "1.10.0-alpha05"
9+
composeIcons = "1.7.3"
10+
kotlin = "2.3.0"
11+
12+
[libraries]
13+
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" }
14+
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "composeRuntime" }
15+
compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "composeMaterial3" }
16+
compose-material-icons-core = { module = "org.jetbrains.compose.material:material-icons-core", version.ref = "composeIcons" }
17+
compose-material-icons-extended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "composeIcons" }
18+
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeRuntime" }
19+
compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "composeRuntime" }
20+
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" }
21+
22+
[plugins]
23+
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
24+
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose" }
25+
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }

gradle/wrapper/gradle-wrapper.jar

45.1 KB
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
4+
networkTimeout=10000
5+
validateDistributionUrl=true
6+
zipStoreBase=GRADLE_USER_HOME
7+
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)