From 581e8d81cf5b71c290d8adbd27cdd769033f5a7f Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 16:57:16 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(core):=20TapT?= =?UTF-8?q?arget=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TapTarget.kt 파일의 CompositionLocal 관련 import 문 정리 및 상태 관리 로직 개선 - App.kt 파일에서 TapTargetCoordinator의 파라미터 구조 변경 및 인덱스 변경 로그 추가 - libs.versions.toml 파일에서 AGP, Kotlin, Compose Plugin, AndroidX 버전 업데이트 - gradle-wrapper.properties 파일에서 Gradle 버전 9.1.0에서 9.5.1로 업데이트 --- .../zone/ien/taptargetcmp/example/App.kt | 9 +- gradle/libs.versions.toml | 10 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../kotlin/zone/ien/taptargetcmp/TapTarget.kt | 217 ++++++++++-------- 4 files changed, 131 insertions(+), 107 deletions(-) diff --git a/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt b/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt index bd01ffa..514e831 100644 --- a/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt +++ b/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt @@ -38,7 +38,13 @@ import zone.ien.taptargetcmp.example.ui.theme.AppTheme @Composable fun App() { AppTheme { - TapTargetCoordinator(showTapTargets = true, onComplete = {}) { + TapTargetCoordinator( + showTapTargets = true, + onIndexChanged = { index -> + println("tap target index $index") + }, + onComplete = {} + ) { Surface(modifier = Modifier.fillMaxSize()) { Content() } @@ -55,6 +61,7 @@ private fun TapTargetScope.Content() { description = "This is a toolbar, tap it!", ) + val tab2TapTarget = getStandardTapTargetDefinition( precedence = 2, title = "Tab2 tap target", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9184c14..fd9b727 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] -agp = "9.0.0" -kotlin = "2.3.21" +agp = "9.1.0" +kotlin = "2.4.0" android-minSdk = "29" android-compileSdk = "36" android-targetSdk = "36" -lib-version-name = "1.2.1" +lib-version-name = "1.3.0" # plugin -compose-plugin = "1.11.0-rc01" +compose-plugin = "1.11.1" compose-plugin-experimental = "1.11.0-alpha07" compose-navigation3 = "1.1.1" @@ -15,7 +15,7 @@ compose-navigation3 = "1.1.1" activity-compose = "1.13.0" # functionality -androidx-core = "1.18.0" +androidx-core = "1.19.0" # backend vanniktechMavenPublish = "0.36.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 61bcd03..a05b773 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,6 +2,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806 -distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index ac22306..a61a802 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -3,6 +3,8 @@ package zone.ien.taptargetcmp import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateMapOf @@ -10,6 +12,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.onGloballyPositioned @@ -23,135 +26,149 @@ import androidx.compose.ui.unit.TextUnit @Composable fun TapTargetCoordinator( - showTapTargets: Boolean, - modifier: Modifier = Modifier, - onComplete: () -> Unit = { }, - state: TapTargetCoordinatorState = remember { TapTargetCoordinatorState() }, - contentAlignment: Alignment = Alignment.Center, - content: @Composable TapTargetScope.() -> Unit, + showTapTargets: Boolean, + modifier: Modifier = Modifier, + onComplete: () -> Unit = { }, + onIndexChanged: (Int) -> Unit = {}, + state: TapTargetCoordinatorState = remember { TapTargetCoordinatorState() }, + contentAlignment: Alignment = Alignment.Center, + content: @Composable TapTargetScope.() -> Unit, ) { - val scope = remember(state) { TapTargetScope(state) } + val scope = remember(state) { TapTargetScope(state) } - Box( - contentAlignment = contentAlignment, - modifier = modifier - ) { - scope.content() + CompositionLocalProvider(LocalTapTargetScope provides scope) { + Box( + contentAlignment = contentAlignment, + modifier = modifier + ) { + scope.content() - if (showTapTargets) { - val currentTapTarget = state.currentTarget - if (currentTapTarget != null) { - Box(modifier = Modifier.fillMaxSize()) { - TapTarget( - tapTarget = currentTapTarget, - onComplete = { - state.currentTargetIndex++ - if (state.currentTargetIndex >= state.tapTargets.size) { - onComplete() - } + if (showTapTargets) { + val currentTapTarget = state.currentTarget + if (currentTapTarget != null) { + Box(modifier = Modifier.fillMaxSize()) { + TapTarget( + tapTarget = currentTapTarget, + onComplete = { + state.currentTargetIndex++ + onIndexChanged(state.currentTargetIndex) + if (state.currentTargetIndex >= state.tapTargets.size) { + onComplete() + } + } + ) + } + } } - ) } - } } - } } class TapTargetScope internal constructor(private val state: TapTargetCoordinatorState) { - fun Modifier.tapTarget( - title: TextDefinition, - description: TextDefinition, - precedence: Int, - tapTargetStyle: TapTargetStyle = TapTargetStyle.Default, - onTargetClick: () -> Unit = { }, - onTargetCancel: () -> Unit = { }, - ): Modifier { - return onGloballyPositioned { layoutCoordinates -> - state.tapTargets[precedence] = TapTarget( - precedence = precedence, - coordinates = layoutCoordinates, - title = title, - description = description, - style = tapTargetStyle, - onTargetClick = onTargetClick, - onTargetCancel = onTargetCancel, - ) + fun Modifier.tapTarget( + title: TextDefinition, + description: TextDefinition, + precedence: Int, + tapTargetStyle: TapTargetStyle = TapTargetStyle.Default, + onTargetClick: () -> Unit = { }, + onTargetCancel: () -> Unit = { }, + ): Modifier { + return onGloballyPositioned { layoutCoordinates -> + state.tapTargets[precedence] = TapTarget( + precedence = precedence, + coordinates = layoutCoordinates, + title = title, + description = description, + style = tapTargetStyle, + onTargetClick = onTargetClick, + onTargetCancel = onTargetCancel, + ) + } } - } - fun Modifier.tapTarget(tapTargetDefinition: TapTargetDefinition): Modifier { - return tapTarget( - tapTargetDefinition.title, - tapTargetDefinition.description, - tapTargetDefinition.precedence, - tapTargetDefinition.tapTargetStyle, - tapTargetDefinition.onTargetClick, - tapTargetDefinition.onTargetCancel - ) - } + fun Modifier.tapTarget(tapTargetDefinition: TapTargetDefinition): Modifier { + return tapTarget( + tapTargetDefinition.title, + tapTargetDefinition.description, + tapTargetDefinition.precedence, + tapTargetDefinition.tapTargetStyle, + tapTargetDefinition.onTargetClick, + tapTargetDefinition.onTargetCancel + ) + } +} + +val LocalTapTargetScope = compositionLocalOf { null } + +fun Modifier.ifTapTarget(definition: TapTargetDefinition?): Modifier { + return composed { + val scope = LocalTapTargetScope.current + if (scope == null || definition == null) return@composed this + with(scope) { this@composed.tapTarget(definition) } + } } data class TapTargetDefinition( - val title: TextDefinition, - val description: TextDefinition, - val precedence: Int, - val tapTargetStyle: TapTargetStyle = TapTargetStyle.Default, - val onTargetClick: () -> Unit = { }, - val onTargetCancel: () -> Unit = { }, + val title: TextDefinition, + val description: TextDefinition, + val precedence: Int, + val tapTargetStyle: TapTargetStyle = TapTargetStyle.Default, + val onTargetClick: () -> Unit = { }, + val onTargetCancel: () -> Unit = { }, ) class TapTargetCoordinatorState internal constructor() { - internal val tapTargets = mutableStateMapOf() - internal var currentTargetIndex by mutableIntStateOf(0) + internal val tapTargets = mutableStateMapOf() + internal var currentTargetIndex by mutableIntStateOf(0) - val currentTarget get() = tapTargets[currentTargetIndex] + val currentTarget get() = tapTargets[currentTargetIndex] } class TapTarget internal constructor( - val precedence: Int, - val title: TextDefinition, - val description: TextDefinition, - val coordinates: LayoutCoordinates, - val style: TapTargetStyle = TapTargetStyle.Default, - val onTargetClick: () -> Unit, - val onTargetCancel: () -> Unit, + val precedence: Int, + val title: TextDefinition, + val description: TextDefinition, + val coordinates: LayoutCoordinates, + val style: TapTargetStyle = TapTargetStyle.Default, + val onTargetClick: () -> Unit, + val onTargetCancel: () -> Unit, ) data class TextDefinition( - val text: String, - internal val textStyle: TextStyle = TextStyle.Default, - internal val color: Color = Color.Unspecified, - internal val fontSize: TextUnit = TextUnit.Unspecified, - internal val fontStyle: FontStyle? = null, - internal val fontWeight: FontWeight? = null, - internal val fontFamily: FontFamily? = null, - internal val letterSpacing: TextUnit = TextUnit.Unspecified, - internal val textDecoration: TextDecoration? = null, - internal val textAlign: TextAlign? = null, - internal val lineHeight: TextUnit = TextUnit.Unspecified, + val text: String, + internal val textStyle: TextStyle = TextStyle.Default, + internal val color: Color = Color.Unspecified, + internal val fontSize: TextUnit = TextUnit.Unspecified, + internal val fontStyle: FontStyle? = null, + internal val fontWeight: FontWeight? = null, + internal val fontFamily: FontFamily? = null, + internal val letterSpacing: TextUnit = TextUnit.Unspecified, + internal val textDecoration: TextDecoration? = null, + internal val textAlign: TextAlign? = null, + internal val lineHeight: TextUnit = TextUnit.Unspecified, ) { - val style = textStyle.merge( - TextStyle( - color = color, - fontSize = fontSize, - fontWeight = fontWeight, - textAlign = textAlign ?: TextAlign.Unspecified, - lineHeight = lineHeight, - fontFamily = fontFamily, - textDecoration = textDecoration, - fontStyle = fontStyle, - letterSpacing = letterSpacing + val style = textStyle.merge( + TextStyle( + color = color, + fontSize = fontSize, + fontWeight = fontWeight, + textAlign = textAlign ?: TextAlign.Unspecified, + lineHeight = lineHeight, + fontFamily = fontFamily, + textDecoration = textDecoration, + fontStyle = fontStyle, + letterSpacing = letterSpacing + ) ) - ) } data class TapTargetStyle( - val backgroundColor: Color = Color.Blue, - val backgroundAlpha: Float = 1f, - val tapTargetHighlightColor: Color = Color.White, + val backgroundColor: Color = Color.Blue, + val backgroundAlpha: Float = 1f, + val tapTargetHighlightColor: Color = Color.White, ) { - companion object { - val Default = TapTargetStyle() - } + companion object { + val Default = TapTargetStyle() + } } \ No newline at end of file From dfb2284bdb25d32028a95d3c7a4242966a51048d Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:01:03 +0900 Subject: [PATCH 2/8] Update taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index a61a802..d204b43 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -4,7 +4,8 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateMapOf From a8b40a1a594b78eed641f648de2a7df50cc02928 Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:01:19 +0900 Subject: [PATCH 3/8] Update taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index d204b43..e97300b 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -100,7 +100,7 @@ class TapTargetScope internal constructor(private val state: TapTargetCoordinato } } -val LocalTapTargetScope = compositionLocalOf { null } +val LocalTapTargetScope = staticCompositionLocalOf { null } fun Modifier.ifTapTarget(definition: TapTargetDefinition?): Modifier { return composed { From e34415c6ad96f0106b076e3b63462ba6b9996775 Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:01:56 +0900 Subject: [PATCH 4/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(core):=20TapT?= =?UTF-8?q?arget=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TapTargetCoordinator 함수로 로직 분리 및 상태 관리 개선 - Modifier 확장 함수를 통해 TapTarget 정의 방식 변경 - TapTargetScope 및 TapTargetDefinition 클래스 추가로 컴포지션 로컬 활용 개선 --- .../src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index e97300b..17b045d 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf From a9bae98081df6d3e31aea02401b15fb42c5de3ca Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:04:41 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=E2=9A=A1=20fix(core):=20gradle=20wrapper?= =?UTF-8?q?=20=ED=95=B4=EC=8B=9C=EA=B0=92=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gradle-wrapper.properties 파일의 distributionSha256Sum 값 변경 - 빌드 환경 일관성 유지 위한 의존성 해시 업데이트 - gradle 빌드 정상 동작을 위한 필수 수정 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a05b773..d14b7a8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ #Thu May 07 22:10:16 KST 2026 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806 +distributionSha256Sum=bafc141b619ad6350fd975fc903156dd5c151998cc8b058e8c1044ab5f7b031f distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 0fd2bbbef322ac2fa68c3e1af6ae3f67c5abe995 Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:06:05 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=20fix(core):=20TapTarget.kt=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=9D=98=20Modifier.ifTapTarget=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=95=EC=9D=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Modifier.ifTapTarget 함수에 @Composable 어노테이션 추가 및 로직 개선 - TapTargetDefinition, TapTargetCoordinatorState, TapTarget, TextDefinition, TapTargetStyle 데이터 클래스 정의 순서 변경 - 코드 구조 개선을 위한 파일 내부 정의 순서 조정 --- .../kotlin/zone/ien/taptargetcmp/TapTarget.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index 17b045d..ccda47d 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -101,11 +101,13 @@ class TapTargetScope internal constructor(private val state: TapTargetCoordinato val LocalTapTargetScope = staticCompositionLocalOf { null } +@Composable fun Modifier.ifTapTarget(definition: TapTargetDefinition?): Modifier { - return composed { - val scope = LocalTapTargetScope.current - if (scope == null || definition == null) return@composed this - with(scope) { this@composed.tapTarget(definition) } + val scope = LocalTapTargetScope.current + return if (scope != null && definition != null) { + with(scope) { this@ifTapTarget.tapTarget(definition) } + } else { + this } } From f1dad51ec7b370073435b35252753a1277799288 Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:07:30 +0900 Subject: [PATCH 7/8] =?UTF-8?q?fix(core):=20TapTargetCoordinator=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TapTargetCoordinator 상태 변경 시 onIndexChanged 콜백 호출 로직 개선 - LaunchedEffect를 사용한 현재 타겟 인덱스 변경 감지 로직 추가 - CompositionLocalProvider 내부에서 타겟 좌표 계산 및 표시 로직 정리 --- .../commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index ccda47d..860ef62 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf @@ -36,6 +37,10 @@ fun TapTargetCoordinator( ) { val scope = remember(state) { TapTargetScope(state) } + LaunchedEffect(state.currentTargetIndex) { + onIndexChanged(state.currentTargetIndex) + } + CompositionLocalProvider(LocalTapTargetScope provides scope) { Box( contentAlignment = contentAlignment, @@ -51,7 +56,6 @@ fun TapTargetCoordinator( tapTarget = currentTapTarget, onComplete = { state.currentTargetIndex++ - onIndexChanged(state.currentTargetIndex) if (state.currentTargetIndex >= state.tapTargets.size) { onComplete() } From e514813407d2c8abf5c8066bcdac348e8f49e731 Mon Sep 17 00:00:00 2001 From: IENGROUND Date: Tue, 9 Jun 2026 17:41:04 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(core):=20TapT?= =?UTF-8?q?arget=20=EC=BD=9C=EB=B0=B1=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=EB=AA=85=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - onIndexChanged를 onTargetChanged로 변경 - 타겟 변경 시 precedence 값으로 변경하여 콘솔 출력 로직 개선 - ifTapTarget Modifier 내부 로직 재구성 및 null 체크 개선 --- .../kotlin/zone/ien/taptargetcmp/example/App.kt | 14 ++++++++------ .../kotlin/zone/ien/taptargetcmp/TapTarget.kt | 15 +++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt b/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt index 514e831..fe126ef 100644 --- a/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt +++ b/example/composeApp/src/commonMain/kotlin/zone/ien/taptargetcmp/example/App.kt @@ -40,10 +40,12 @@ fun App() { AppTheme { TapTargetCoordinator( showTapTargets = true, - onIndexChanged = { index -> - println("tap target index $index") + onTargetChanged = { precedence -> + println("this tap target $precedence") }, - onComplete = {} + onComplete = { + println("this tap target end") + } ) { Surface(modifier = Modifier.fillMaxSize()) { Content() @@ -56,14 +58,14 @@ fun App() { @Composable private fun TapTargetScope.Content() { val toolbarTapTarget = getStandardTapTargetDefinition( - precedence = 1, + precedence = 350, title = "Toolbar tap target", description = "This is a toolbar, tap it!", ) val tab2TapTarget = getStandardTapTargetDefinition( - precedence = 2, + precedence = 200, title = "Tab2 tap target", description = "A moving target", ) @@ -83,7 +85,7 @@ private fun TapTargetScope.Content() { text = { Text(text = "Click here") }, modifier = Modifier.tapTarget( getStandardTapTargetDefinition( - precedence = 0, + precedence = 150, title = "Button tap target", description = "This is a button, tap it!", ) diff --git a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt index 860ef62..137a65a 100644 --- a/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt +++ b/taptarget/src/commonMain/kotlin/zone/ien/taptargetcmp/TapTarget.kt @@ -30,7 +30,7 @@ fun TapTargetCoordinator( showTapTargets: Boolean, modifier: Modifier = Modifier, onComplete: () -> Unit = { }, - onIndexChanged: (Int) -> Unit = {}, + onTargetChanged: (Int) -> Unit = {}, state: TapTargetCoordinatorState = remember { TapTargetCoordinatorState() }, contentAlignment: Alignment = Alignment.Center, content: @Composable TapTargetScope.() -> Unit, @@ -38,7 +38,7 @@ fun TapTargetCoordinator( val scope = remember(state) { TapTargetScope(state) } LaunchedEffect(state.currentTargetIndex) { - onIndexChanged(state.currentTargetIndex) + state.currentTarget?.let { onTargetChanged(it.precedence) } } CompositionLocalProvider(LocalTapTargetScope provides scope) { @@ -105,11 +105,10 @@ class TapTargetScope internal constructor(private val state: TapTargetCoordinato val LocalTapTargetScope = staticCompositionLocalOf { null } -@Composable -fun Modifier.ifTapTarget(definition: TapTargetDefinition?): Modifier { +fun Modifier.ifTapTarget(definition: TapTargetDefinition?): Modifier = composed { val scope = LocalTapTargetScope.current - return if (scope != null && definition != null) { - with(scope) { this@ifTapTarget.tapTarget(definition) } + if (scope != null && definition != null) { + with(scope) { this@composed.tapTarget(definition) } } else { this } @@ -127,8 +126,8 @@ data class TapTargetDefinition( class TapTargetCoordinatorState internal constructor() { internal val tapTargets = mutableStateMapOf() internal var currentTargetIndex by mutableIntStateOf(0) - - val currentTarget get() = tapTargets[currentTargetIndex] + val currentTarget: TapTarget? + get() = tapTargets.keys.sorted().getOrNull(currentTargetIndex)?.let { tapTargets[it] } } class TapTarget internal constructor(