diff --git a/.gitignore b/.gitignore index c7e6e20..d8a86b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.iml .gradle .idea +!.idea/runConfigurations .DS_Store build captures diff --git a/android-tests/build.gradle.kts b/android-tests/build.gradle.kts index a857bb9..b96243b 100644 --- a/android-tests/build.gradle.kts +++ b/android-tests/build.gradle.kts @@ -51,6 +51,7 @@ android { dependencies { implementation(project(":reveal-core")) + implementation(project(":reveal-shapes")) val composeBom = platform(libs.androidx.compose.bom) implementation(composeBom) @@ -59,6 +60,7 @@ dependencies { implementation(libs.androidx.compose.animation) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.material3) + implementation(libs.androidx.activity.compose) debugImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/android-tests/src/main/AndroidManifest.xml b/android-tests/src/main/AndroidManifest.xml index 8072ee0..694006a 100644 --- a/android-tests/src/main/AndroidManifest.xml +++ b/android-tests/src/main/AndroidManifest.xml @@ -1,2 +1,19 @@ - + + + + + + + + + + + + diff --git a/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/.gitcreate b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/.gitcreate deleted file mode 100644 index e69de29..0000000 diff --git a/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/App.kt b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/App.kt new file mode 100644 index 0000000..e460e45 --- /dev/null +++ b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/App.kt @@ -0,0 +1,14 @@ +package com.svenjacobs.reveal.android.tests + +import android.app.Application +import android.util.Log +import com.svenjacobs.reveal.common.internal.log.Logger + +class App : Application() { + + override fun onCreate() { + super.onCreate() + + Logger.adapter = Logger.Adapter { message, tag -> Log.d(tag, message) } + } +} diff --git a/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/MainActivity.kt b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/MainActivity.kt new file mode 100644 index 0000000..288c6f8 --- /dev/null +++ b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/MainActivity.kt @@ -0,0 +1,20 @@ +package com.svenjacobs.reveal.android.tests + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.core.view.WindowCompat +import com.svenjacobs.reveal.android.tests.presentation.App + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + WindowCompat.setDecorFitsSystemWindows(window, false) + + setContent { + App() + } + } +} diff --git a/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/App.kt b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/App.kt new file mode 100644 index 0000000..82d58c5 --- /dev/null +++ b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/App.kt @@ -0,0 +1,21 @@ +package com.svenjacobs.reveal.android.tests.presentation + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.svenjacobs.reveal.RevealCanvas +import com.svenjacobs.reveal.android.tests.presentation.theme.AppTheme +import com.svenjacobs.reveal.rememberRevealCanvasState + +@Composable +fun App(modifier: Modifier = Modifier) { + AppTheme { + val revealCanvasState = rememberRevealCanvasState() + + RevealCanvas( + revealCanvasState = revealCanvasState, + modifier = modifier, + ) { + MainScreen(revealCanvasState = revealCanvasState) + } + } +} diff --git a/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/MainScreen.kt b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/MainScreen.kt new file mode 100644 index 0000000..a0d3cf2 --- /dev/null +++ b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/MainScreen.kt @@ -0,0 +1,145 @@ +package com.svenjacobs.reveal.android.tests.presentation + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.svenjacobs.reveal.Key +import com.svenjacobs.reveal.Reveal +import com.svenjacobs.reveal.RevealCanvasState +import com.svenjacobs.reveal.RevealOverlayArrangement +import com.svenjacobs.reveal.RevealOverlayScope +import com.svenjacobs.reveal.RevealShape +import com.svenjacobs.reveal.rememberRevealState +import com.svenjacobs.reveal.shapes.balloon.Arrow +import com.svenjacobs.reveal.shapes.balloon.Balloon +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +private enum class Keys { Fab, Explanation } + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +fun MainScreen(revealCanvasState: RevealCanvasState, modifier: Modifier = Modifier) { + val scope = rememberCoroutineScope() + val revealState = rememberRevealState() + + LaunchedEffect(Unit) { + if (revealState.isVisible) return@LaunchedEffect + delay(2.seconds) + revealState.reveal(Keys.Fab) + } + + Reveal( + onOverlayClick = { scope.launch { revealState.hide() } }, + modifier = modifier, + revealCanvasState = revealCanvasState, + revealState = revealState, + overlayContent = { key -> RevealOverlayContent(key) }, + ) { + Scaffold( + modifier = Modifier.fillMaxSize(), + topBar = { + CenterAlignedTopAppBar( + title = { Text("Reveal Demo") }, + ) + }, + floatingActionButton = { + FloatingActionButton( + modifier = Modifier.revealable( + key = Keys.Fab, + shape = RevealShape.RoundRect(16.dp), + onClick = { + scope.launch { revealState.reveal(Keys.Explanation) } + }, + ), + onClick = { + scope.launch { revealState.reveal(Keys.Explanation) } + }, + ) { + Icon( + Icons.Filled.Add, + contentDescription = null, + ) + } + }, + ) { contentPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(contentPadding) + .padding(horizontal = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + modifier = Modifier + .padding(top = 16.dp) + .revealable( + key = Keys.Explanation, + onClick = { + scope.launch { revealState.hide() } + }, + ), + text = "Reveal is a lightweight, simple reveal effect (also known as " + + "coach mark or onboarding) library for Compose Multiplatform.", + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Justify, + ) + } + } + } +} + +@Composable +private fun RevealOverlayScope.RevealOverlayContent(key: Key) { + when (key) { + Keys.Fab -> OverlayText( + modifier = Modifier.align( + horizontalArrangement = RevealOverlayArrangement.Start, + ), + text = "Click button to get started", + arrow = Arrow.end(), + ) + + Keys.Explanation -> OverlayText( + modifier = Modifier.align( + verticalArrangement = RevealOverlayArrangement.Bottom, + ), + text = "Actually we already started. This was an example of the reveal effect.", + arrow = Arrow.top(), + ) + } +} + +@Composable +private fun OverlayText(text: String, arrow: Arrow, modifier: Modifier = Modifier) { + Balloon( + modifier = modifier.padding(8.dp), + arrow = arrow, + backgroundColor = MaterialTheme.colorScheme.secondaryContainer, + elevation = 2.dp, + ) { + Text( + modifier = Modifier.padding(8.dp), + text = text, + style = MaterialTheme.typography.labelLarge, + textAlign = TextAlign.Center, + ) + } +} diff --git a/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/theme/Theme.kt b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/theme/Theme.kt new file mode 100644 index 0000000..24c9851 --- /dev/null +++ b/android-tests/src/main/kotlin/com/svenjacobs/reveal/android/tests/presentation/theme/Theme.kt @@ -0,0 +1,11 @@ +package com.svenjacobs.reveal.android.tests.presentation.theme + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable + +@Composable +fun AppTheme(content: @Composable () -> Unit) { + MaterialTheme( + content = content, + ) +} diff --git a/android-tests/src/main/res/.gitcreate b/android-tests/src/main/res/.gitcreate deleted file mode 100644 index e69de29..0000000 diff --git a/android-tests/src/main/res/values/styles.xml b/android-tests/src/main/res/values/styles.xml new file mode 100644 index 0000000..400580f --- /dev/null +++ b/android-tests/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/reveal-common/src/commonMain/kotlin/com/svenjacobs/reveal/common/internal/log/Logger.kt b/reveal-common/src/commonMain/kotlin/com/svenjacobs/reveal/common/internal/log/Logger.kt new file mode 100644 index 0000000..3d8b98a --- /dev/null +++ b/reveal-common/src/commonMain/kotlin/com/svenjacobs/reveal/common/internal/log/Logger.kt @@ -0,0 +1,18 @@ +package com.svenjacobs.reveal.common.internal.log + +/** + * Minimal logging adapter for development purposes. + * For internal use only. + */ +public object Logger { + + public fun interface Adapter { + public fun d(message: String, tag: String) + } + + public var adapter: Adapter? = null + + public fun d(message: String, tag: String = "Reveal") { + adapter?.d(message, tag) + } +}