├── .DS_Store ├── .github └── workflows │ ├── store-screenshots.yml │ └── verify-screenshot-test.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── joco │ │ └── composeshowcase │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── joco │ │ │ └── composeshowcase │ │ │ ├── MainActivity.kt │ │ │ ├── MyShowcaseDialog.kt │ │ │ ├── dialog │ │ │ ├── MyArrowDialog.kt │ │ │ ├── SkeletonArrowDialog.kt │ │ │ └── TransparentDialog.kt │ │ │ └── ui │ │ │ └── theme │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── joco │ └── composeshowcase │ ├── ExampleUnitTest.kt │ └── ShowcaseSequenceTest.kt ├── build.gradle.kts ├── dialog ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── joco │ └── dialog │ └── arrow │ └── ArrowDialog.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts ├── showcase-sequence ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── joco │ │ └── showcase │ │ └── sequence │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── joco │ │ └── showcase │ │ └── sequence │ │ ├── SequenceShowcase.kt │ │ └── SequenceShowcaseState.kt │ └── test │ └── java │ └── com │ └── joco │ └── showcase │ └── sequence │ └── ExampleUnitTest.kt └── showcaseview ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml └── java └── com └── joco └── showcaseview ├── AnimationDuration.kt ├── BackgroundAlpha.kt ├── ShowcaseAlignment.kt ├── ShowcaseDisplayState.kt ├── ShowcasePosition.kt ├── ShowcaseView.kt └── highlight ├── HighlightProperties.kt └── ShowcaseHighlight.kt /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/.DS_Store -------------------------------------------------------------------------------- /.github/workflows/store-screenshots.yml: -------------------------------------------------------------------------------- 1 | name: store screenshots 2 | 3 | on: 4 | workflow_dispatch 5 | 6 | env: 7 | GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" 8 | 9 | jobs: 10 | test: 11 | runs-on: macos-latest 12 | 13 | permissions: 14 | contents: read 15 | actions: write 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/setup-java@v3.9.0 20 | with: 21 | distribution: 'zulu' 22 | java-version: 19 23 | 24 | - name: Gradle cache 25 | uses: gradle/gradle-build-action@v2 26 | 27 | - name: test 28 | run: | 29 | # Create screenshots 30 | ./gradlew app:recordRoborazziDebug --stacktrace 31 | 32 | - uses: actions/upload-artifact@v4 33 | if: ${{ always() }} 34 | with: 35 | name: screenshot 36 | path: app/build/outputs/roborazzi 37 | retention-days: 30 38 | 39 | - uses: actions/upload-artifact@v4 40 | if: ${{ always() }} 41 | with: 42 | name: screenshot-reports 43 | path: app/build/reports 44 | retention-days: 30 45 | 46 | - uses: actions/upload-artifact@v4 47 | if: ${{ always() }} 48 | with: 49 | name: screenshot-test-results 50 | path: app/build/test-results 51 | retention-days: 30 -------------------------------------------------------------------------------- /.github/workflows/verify-screenshot-test.yml: -------------------------------------------------------------------------------- 1 | name: screenshot test 2 | 3 | on: 4 | push 5 | 6 | env: 7 | GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" 8 | 9 | jobs: 10 | test: 11 | runs-on: macos-latest 12 | 13 | permissions: 14 | contents: read 15 | actions: write 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/setup-java@v3.9.0 20 | with: 21 | distribution: 'zulu' 22 | java-version: 19 23 | 24 | - name: Gradle cache 25 | uses: gradle/gradle-build-action@v2 26 | 27 | - uses: dawidd6/action-download-artifact@v3 28 | with: 29 | name: screenshot 30 | path: app/build/outputs/roborazzi 31 | workflow: store-screenshots.yml 32 | branch: main 33 | 34 | - name: verify test 35 | id: verify-test 36 | run: | 37 | ./gradlew app:verifyRoborazziDebug --stacktrace 38 | 39 | - uses: actions/upload-artifact@v4 40 | if: ${{ always() }} 41 | with: 42 | name: screenshot-diff 43 | path: app/build/outputs/roborazzi 44 | retention-days: 30 45 | 46 | - uses: actions/upload-artifact@v4 47 | if: ${{ always() }} 48 | with: 49 | name: screenshot-diff-reports 50 | path: app/build/reports 51 | retention-days: 30 52 | 53 | - uses: actions/upload-artifact@v4 54 | if: ${{ always() }} 55 | with: 56 | name: screenshot-diff-test-results 57 | path: app/build/test-results 58 | retention-days: 30 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle/ 3 | build/ 4 | 5 | # Local configuration file (sdk path, etc) 6 | local.properties 7 | 8 | # Log/OS Files 9 | *.log 10 | 11 | # Android Studio generated files and folders 12 | captures/ 13 | .externalNativeBuild/ 14 | .cxx/ 15 | *.apk 16 | output.json 17 | 18 | # IntelliJ 19 | *.iml 20 | .idea/ 21 | misc.xml 22 | deploymentTargetDropDown.xml 23 | render.experimental.xml 24 | 25 | # Keystore files 26 | *.jks 27 | *.keystore 28 | 29 | # Google Services (e.g. APIs or Firebase) 30 | google-services.json 31 | 32 | # Android Profiling 33 | *.hprof -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 jocoand 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # Compose Showcase 4 | 5 | platform 6 | license 7 | status 8 | 9 |

10 | 11 | A library for showcasing your feature in Jetpack Compose. 12 | 13 |

14 | 15 | 16 |
17 | 18 | ## 🍁 Sequence Showcase 19 |

20 | version 21 | 22 | Creating a sequence of showcases in a specific order. 23 | 24 | preview 25 | 26 | preview2 27 | 28 |

29 | 30 | ### Installation 31 | - Gradle 32 | ``` 33 | implementation("io.github.jocoand:showcase-sequence:1.3.0") 34 | ``` 35 | 36 | ### Usage 37 | - #### Create your Showcase dialog 38 | 39 | - ``` 40 | @Composable 41 | fun MyShowcaseDialog(text: String, onClick: () -> Unit) { 42 | Column { 43 | Text(text = text) 44 | Spacer(modifier = Modifier.height(8.dp)) 45 | Button(onClick = onClick) { 46 | Text("Nice !") 47 | } 48 | } 49 | } 50 | ``` 51 | or you can use our [Predefined Dialog](https://github.com/jocoand/compose-showcase?tab=readme-ov-file#-dialog) 52 | - #### Declare the `SequenceShowcase` & `sequenceShowcaseState` 53 | - ``` 54 | val sequenceShowcaseState = rememberSequenceShowcaseState() 55 | 56 | SequenceShowcase(state = sequenceShowcaseState) { 57 | Scaffold( 58 | ... 59 | ``` 60 | 61 | - #### Mark your target view (view to be highlighted) with `sequenceShowcaseTarget` modifier 62 | 63 | - ``` 64 | 65 | MyView1( // View to be highlighted 66 | modifier = Modifier 67 | .sequenceShowcaseTarget( // Mark with sequenceShowcaseTarget 68 | index = 0, 69 | content = { 70 | MyShowcaseDialog( // Dialog to be displayed 71 | text = "Hey, this is Greetings showcase", 72 | ) 73 | } 74 | ), 75 | onClick = { sequenceShowcaseState.start() } 76 | ) 77 | ``` 78 | `index`: the order to be shown in the sequence 79 | 80 | `content`: dialog to be displayed 81 | 82 | - #### Use `SequenceShowcaseState.start()` to start the showcase 83 | - ``` 84 | LaunchButton( 85 | ... 86 | onClick = { sequenceShowcaseState.start() } 87 | ) 88 | ``` 89 | `index`: value to start at certain index (optional) 90 | 91 | - #### Use `SequenceShowcaseState.next()` to navigate to the next showcase 92 | - ``` 93 | MyView2( 94 | modifier = Modifier 95 | .sequenceShowcaseTarget( 96 | index = 1, 97 | content = { 98 | MyShowcaseDialog( 99 | text = "Hey, this is Article show case", 100 | onClick = { 101 | sequenceShowcaseState.next() // Navigate to next showcase 102 | } 103 | ) 104 | } 105 | ) 106 | ) 107 | ``` 108 | 109 | - You can also dismiss the the showcase using `dimiss()` 110 | 111 | - See [sample](https://github.com/jocoand/compose-showcase/blob/main/app/src/main/java/com/joco/composeshowcase/MainActivity.kt) for more more details 112 | 113 | ### Config 114 | - `position` 115 | 116 | 117 | 120 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
118 | 119 | 121 | 122 |
TopBottom
130 | 131 | `Default`: relative to target position 132 | 133 | - `alignment` 134 | 135 | 136 | 139 | 142 | 145 | 146 | 147 | 148 | 149 | 150 | 151 |
137 | 138 | 140 | 141 | 143 | 144 |
StartCenterEnd
152 | 153 | `Default`: relative to target position 154 | 155 | - `highlight` 156 | 157 | 158 | 161 | 164 | 165 | 166 | 167 | 168 | 169 |
159 | 160 | 162 | 163 |
RectangularCircular
170 | 171 | - `animationDuration`: duration of the enter and exit animation. 172 | 173 | ### Inspired by 💡 174 | - https://github.com/canopas/compose-intro-showcase 175 | 176 | ### Sample 🎨 177 | - See [MainActivity](https://github.com/jocoand/compose-showcase/blob/main/app/src/main/java/com/joco/composeshowcase/MainActivity.kt) 178 | 179 | 180 | ## 🌀 ShowcaseView 181 | version 182 | 183 | In case you need more basic usage, you can you use [ShowcaseView](https://github.com/jocoand/compose-showcaseview/tree/main) 184 | 185 | ``` 186 | implementation("io.github.jocoand:showcase-sequence:1.4.4") 187 | ``` 188 | 189 | ## 🏮 Dialog 190 | 191 | ### Arrow Dialog 192 | 193 | A predefined dialog with arrow shape pointer. 194 | 195 | Screen Shot 2025-04-03 at 13 15 05 196 | 197 | ### Usage 198 | ``` 199 | .sequenceShowcaseTarget( 200 | ... 201 | .content = { 202 | ArrowDialog( 203 | targetRect = it, 204 | content = { 205 | // Your dialog content 206 | } 207 | ) 208 | } 209 | ``` 210 | 211 | ## Contributing 212 | Contribution are welcome! 213 | Feel free to open an issue or a pull request, if you find any bugs or have any suggestions. 214 | If you're new to the project, we recommend starting with a [`good first issue`](https://github.com/jocoand/compose-showcase/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). that are tailored for first time contributors in the project. 215 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.androidApplication) 3 | alias(libs.plugins.jetbrainsKotlinAndroid) 4 | alias(libs.plugins.roborazzi) 5 | } 6 | 7 | android { 8 | namespace = "com.joco.composeshowcase" 9 | compileSdk = 34 10 | 11 | defaultConfig { 12 | applicationId = "com.joco.composeshowcase" 13 | minSdk = 21 14 | targetSdk = 34 15 | versionCode = 1 16 | versionName = "1.0" 17 | 18 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 19 | vectorDrawables { 20 | useSupportLibrary = true 21 | } 22 | } 23 | 24 | buildTypes { 25 | release { 26 | isMinifyEnabled = false 27 | proguardFiles( 28 | getDefaultProguardFile("proguard-android-optimize.txt"), 29 | "proguard-rules.pro" 30 | ) 31 | } 32 | } 33 | compileOptions { 34 | sourceCompatibility = JavaVersion.VERSION_17 35 | targetCompatibility = JavaVersion.VERSION_17 36 | } 37 | kotlinOptions { 38 | jvmTarget = "17" 39 | } 40 | buildFeatures { 41 | compose = true 42 | } 43 | composeOptions { 44 | kotlinCompilerExtensionVersion = "1.5.1" 45 | } 46 | packaging { 47 | resources { 48 | excludes += "/META-INF/{AL2.0,LGPL2.1}" 49 | } 50 | } 51 | testOptions { 52 | unitTests { 53 | isIncludeAndroidResources = true 54 | } 55 | } 56 | } 57 | 58 | dependencies { 59 | 60 | implementation(libs.androidx.core.ktx) 61 | implementation(libs.androidx.lifecycle.runtime.ktx) 62 | implementation(libs.androidx.activity.compose) 63 | implementation(platform(libs.androidx.compose.bom)) 64 | implementation(libs.androidx.ui.tooling.preview) 65 | implementation(libs.androidx.material3) 66 | 67 | implementation(project(":showcase-sequence")) 68 | 69 | testImplementation(libs.junit) 70 | testImplementation(libs.robolectric) 71 | testImplementation(libs.androidx.espresso.core) 72 | testImplementation(libs.ui.test.junit4) 73 | 74 | testImplementation(libs.roborazzi) 75 | testImplementation(libs.roborazzi.compose) 76 | testImplementation(libs.roborazzi.rule) 77 | 78 | androidTestImplementation(libs.androidx.junit) 79 | androidTestImplementation(libs.androidx.espresso.core) 80 | androidTestImplementation(platform(libs.androidx.compose.bom)) 81 | androidTestImplementation(libs.androidx.ui.test.junit4) 82 | 83 | debugImplementation(libs.androidx.ui.tooling) 84 | debugImplementation(libs.androidx.ui.test.manifest) 85 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/joco/composeshowcase/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.joco.composeshowcase", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.ScrollState 7 | import androidx.compose.foundation.clickable 8 | import androidx.compose.foundation.layout.Column 9 | import androidx.compose.foundation.layout.PaddingValues 10 | import androidx.compose.foundation.layout.Row 11 | import androidx.compose.foundation.layout.Spacer 12 | import androidx.compose.foundation.layout.fillMaxSize 13 | import androidx.compose.foundation.layout.fillMaxWidth 14 | import androidx.compose.foundation.layout.height 15 | import androidx.compose.foundation.layout.padding 16 | import androidx.compose.foundation.layout.width 17 | import androidx.compose.foundation.rememberScrollState 18 | import androidx.compose.foundation.verticalScroll 19 | import androidx.compose.material.icons.Icons 20 | import androidx.compose.material.icons.filled.Favorite 21 | import androidx.compose.material.icons.filled.Share 22 | import androidx.compose.material3.ExperimentalMaterial3Api 23 | import androidx.compose.material3.Icon 24 | import androidx.compose.material3.MaterialTheme 25 | import androidx.compose.material3.Scaffold 26 | import androidx.compose.material3.Surface 27 | import androidx.compose.material3.Text 28 | import androidx.compose.material3.TopAppBar 29 | import androidx.compose.material3.TopAppBarDefaults 30 | import androidx.compose.runtime.Composable 31 | import androidx.compose.ui.Alignment 32 | import androidx.compose.ui.Modifier 33 | import androidx.compose.ui.graphics.Color 34 | import androidx.compose.ui.res.stringResource 35 | import androidx.compose.ui.text.font.FontWeight 36 | import androidx.compose.ui.unit.dp 37 | import com.joco.composeshowcase.dialog.MyArrowDialog 38 | import com.joco.composeshowcase.dialog.SkeletonArrowDialog 39 | import com.joco.composeshowcase.dialog.TransparentDialog 40 | import com.joco.composeshowcase.ui.theme.ComposeShowcaseTheme 41 | import com.joco.showcase.sequence.SequenceShowcase 42 | import com.joco.showcase.sequence.SequenceShowcaseScope 43 | import com.joco.showcase.sequence.SequenceShowcaseState 44 | import com.joco.showcase.sequence.rememberSequenceShowcaseState 45 | import com.joco.showcaseview.AnimationDuration 46 | import com.joco.showcaseview.BackgroundAlpha 47 | import com.joco.showcaseview.ShowcaseAlignment 48 | import com.joco.showcaseview.ShowcasePosition 49 | import com.joco.showcaseview.highlight.ShowcaseHighlight 50 | 51 | 52 | class MainActivity : ComponentActivity() { 53 | @OptIn(ExperimentalMaterial3Api::class) 54 | override fun onCreate(savedInstanceState: Bundle?) { 55 | super.onCreate(savedInstanceState) 56 | setContent { 57 | ComposeShowcaseTheme { 58 | val sequenceShowcaseState = rememberSequenceShowcaseState() 59 | val columnScrollState = rememberScrollState() 60 | 61 | SequenceShowcase(state = sequenceShowcaseState) { 62 | Scaffold( 63 | topBar = { 64 | TopAppBar( 65 | title = { Text(text = "Showcase App") }, 66 | colors = TopAppBarDefaults.topAppBarColors( 67 | containerColor = MaterialTheme.colorScheme.primary, 68 | titleContentColor = Color.White 69 | ), 70 | ) 71 | } 72 | ) { innerPadding -> 73 | MainContent(innerPadding, columnScrollState, sequenceShowcaseState) 74 | } 75 | } 76 | } 77 | } 78 | } 79 | 80 | companion object { 81 | const val SHOWCASE_2_DURATION = 900 82 | const val SHOWCASE_3_DURATION = 300 83 | } 84 | } 85 | 86 | @Composable 87 | fun SequenceShowcaseScope.MainContent( 88 | innerPadding: PaddingValues, 89 | columnScrollState: ScrollState, 90 | sequenceShowcaseState: SequenceShowcaseState 91 | ) { 92 | Surface( 93 | modifier = Modifier 94 | .fillMaxSize() 95 | .then(if (sequenceShowcaseState.currentTargetIndex == 3) { 96 | Modifier.clickable { sequenceShowcaseState.next() } 97 | } else { 98 | Modifier 99 | }) 100 | .padding(innerPadding), 101 | color = MaterialTheme.colorScheme.background 102 | ) { 103 | val loremIpsumText = """ 104 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 105 | """ 106 | Column( 107 | modifier = Modifier 108 | .fillMaxWidth() 109 | .padding(16.dp) 110 | .verticalScroll(columnScrollState) 111 | ) { 112 | Greeting( 113 | modifier = Modifier 114 | .sequenceShowcaseTarget( 115 | index = 0, 116 | content = { 117 | MyShowcaseDialog( 118 | text = "Hello Andy, Welcome abroad! ", 119 | onClick = { sequenceShowcaseState.next() } 120 | ) 121 | } 122 | ), 123 | name = "Andy", 124 | onClick = { sequenceShowcaseState.start() } 125 | ) 126 | Spacer(modifier = Modifier.height(30.dp)) 127 | Article( 128 | modifier = Modifier 129 | .align(Alignment.Start) 130 | .sequenceShowcaseTarget( 131 | index = 1, 132 | highlight = ShowcaseHighlight.Rectangular(24.dp), 133 | animationDuration = AnimationDuration.create( 134 | MainActivity.SHOWCASE_2_DURATION, 135 | MainActivity.SHOWCASE_2_DURATION 136 | ), 137 | content = { 138 | MyArrowDialog( 139 | targetRect = it, 140 | text = "You can read cool articles here!", 141 | onClick = { sequenceShowcaseState.next() } 142 | ) 143 | } 144 | ), 145 | subheading = "Today's Article", 146 | paragraph = loremIpsumText 147 | ) 148 | Row(modifier = Modifier.align(Alignment.CenterHorizontally)) { 149 | LikeButton( 150 | modifier = Modifier 151 | .sequenceShowcaseTarget( 152 | index = 2, 153 | position = ShowcasePosition.Top, 154 | highlight = ShowcaseHighlight.Circular(targetMargin = 12.dp), 155 | animationDuration = AnimationDuration.create( 156 | MainActivity.SHOWCASE_3_DURATION, 157 | MainActivity.SHOWCASE_3_DURATION 158 | ), 159 | alignment = ShowcaseAlignment.CenterHorizontal, 160 | content = { 161 | SkeletonArrowDialog( 162 | targetRect = it, 163 | pointerSize = 28.dp, 164 | text = "Click here if you love the article!", 165 | onClick = { sequenceShowcaseState.next() } 166 | ) 167 | } 168 | ) 169 | ) 170 | Spacer(modifier = Modifier.width(16.dp)) 171 | ShareButton( 172 | modifier = Modifier 173 | .sequenceShowcaseTarget( 174 | index = 3, 175 | position = ShowcasePosition.Bottom, 176 | highlight = ShowcaseHighlight.Rectangular(0.dp), 177 | alignment = ShowcaseAlignment.CenterHorizontal, 178 | backgroundAlpha = BackgroundAlpha.Dark, 179 | content = { 180 | TransparentDialog( 181 | title = "Share Article", 182 | text = "You also can share the article!", 183 | alignment = Alignment.End 184 | ) 185 | } 186 | ) 187 | ) 188 | } 189 | Spacer(modifier = Modifier.height(16.dp)) 190 | Article( 191 | modifier = Modifier 192 | .align(Alignment.Start), 193 | subheading = "Today's Article 2", 194 | paragraph = loremIpsumText 195 | ) 196 | } 197 | } 198 | } 199 | 200 | @Composable 201 | fun Greeting(modifier: Modifier = Modifier, name: String, onClick: () -> Unit) { 202 | Text( 203 | text = stringResource(id = R.string.label_greetings, name), 204 | modifier = modifier.clickable { onClick() }, 205 | ) 206 | } 207 | 208 | @Composable 209 | fun Article( 210 | modifier: Modifier = Modifier, 211 | subheading: String, 212 | paragraph: String 213 | ) { 214 | Column(modifier = modifier.padding(horizontal = 16.dp, vertical = 8.dp)) { 215 | Text( 216 | text = subheading, 217 | style = MaterialTheme.typography.headlineSmall, 218 | color = MaterialTheme.colorScheme.primary, 219 | fontWeight = FontWeight.W500 220 | ) 221 | Text( 222 | text = paragraph, 223 | style = MaterialTheme.typography.labelMedium, 224 | color = MaterialTheme.colorScheme.secondary 225 | ) 226 | } 227 | } 228 | 229 | @Composable 230 | fun LikeButton(modifier: Modifier = Modifier) { 231 | Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { 232 | Icon( 233 | imageVector = Icons.Default.Favorite, 234 | contentDescription = "Like Icon", 235 | tint = Color.Gray 236 | ) 237 | Spacer(modifier = Modifier.width(8.dp)) 238 | Text( 239 | text = "Love It!", 240 | style = MaterialTheme.typography.labelMedium, 241 | color = MaterialTheme.colorScheme.primary 242 | ) 243 | } 244 | } 245 | 246 | @Composable 247 | fun ShareButton(modifier: Modifier = Modifier) { 248 | Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { 249 | Icon( 250 | imageVector = Icons.Default.Share, 251 | contentDescription = "Share Icon", 252 | tint = Color.Gray 253 | ) 254 | Spacer(modifier = Modifier.width(8.dp)) 255 | Text( 256 | text = "Share", 257 | style = MaterialTheme.typography.labelMedium, 258 | color = MaterialTheme.colorScheme.primary 259 | ) 260 | } 261 | } -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/MyShowcaseDialog.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.height 8 | import androidx.compose.foundation.layout.padding 9 | import androidx.compose.foundation.shape.RoundedCornerShape 10 | import androidx.compose.material3.Button 11 | import androidx.compose.material3.Text 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.res.stringResource 17 | import androidx.compose.ui.unit.dp 18 | 19 | @Composable 20 | fun MyShowcaseDialog(text: String, onClick: () -> Unit) { 21 | Column( 22 | modifier = Modifier 23 | .background(Color.White, shape = RoundedCornerShape(12.dp)) 24 | .padding(16.dp), 25 | verticalArrangement = Arrangement.Center, 26 | horizontalAlignment = Alignment.End 27 | ) { 28 | Text(text = text) 29 | Spacer(modifier = Modifier.height(8.dp)) 30 | Button( 31 | shape = RoundedCornerShape(8.dp), 32 | onClick = onClick 33 | ) { 34 | Text(stringResource(R.string.button_nice)) 35 | } 36 | } 37 | } 38 | 39 | @Composable 40 | fun MyShowcaseDialog2(text: String, onClick: () -> Unit) { 41 | Column( 42 | modifier = Modifier 43 | .background(Color.White, shape = RoundedCornerShape(16.dp)) 44 | .padding(16.dp), 45 | verticalArrangement = Arrangement.Center, 46 | horizontalAlignment = Alignment.End 47 | ) { 48 | Text(text = text) 49 | Spacer(modifier = Modifier.height(8.dp)) 50 | Button( 51 | modifier = Modifier.align(Alignment.CenterHorizontally), 52 | shape = RoundedCornerShape(24.dp), 53 | onClick = onClick 54 | ) { 55 | Text(stringResource(R.string.button_awesome)) 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/dialog/MyArrowDialog.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase.dialog 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.height 8 | import androidx.compose.foundation.layout.padding 9 | import androidx.compose.foundation.shape.RoundedCornerShape 10 | import androidx.compose.material3.Button 11 | import androidx.compose.material3.Text 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.draw.clip 16 | import androidx.compose.ui.geometry.Rect 17 | import androidx.compose.ui.graphics.Color 18 | import androidx.compose.ui.res.stringResource 19 | import androidx.compose.ui.unit.Dp 20 | import androidx.compose.ui.unit.dp 21 | import com.joco.composeshowcase.R 22 | import com.joco.dialog.arrow.ArrowDialog 23 | import com.joco.dialog.arrow.ArrowDialogDefaults 24 | 25 | @Composable 26 | fun MyArrowDialog( 27 | targetRect: Rect, 28 | text: String, 29 | pointerSize: Dp = ArrowDialogDefaults.pointerSize, 30 | onClick: () -> Unit 31 | ) { 32 | ArrowDialog( 33 | targetRect = targetRect, 34 | pointerColor = Color.White, 35 | pointerSize = pointerSize, 36 | content = { color -> 37 | InnerDialog(text, color, onClick) 38 | } 39 | ) 40 | } 41 | 42 | @Composable 43 | private fun InnerDialog( 44 | text: String, 45 | color: Color, 46 | onClick: () -> Unit 47 | ) { 48 | 49 | Column( 50 | modifier = Modifier 51 | .clip(RoundedCornerShape(16.dp)) 52 | .background(color) 53 | .padding(16.dp), 54 | verticalArrangement = Arrangement.Center, 55 | ) { 56 | Text(text = text) 57 | Spacer(modifier = Modifier.height(8.dp)) 58 | Button( 59 | modifier = Modifier.align(Alignment.End), 60 | shape = RoundedCornerShape(8.dp), 61 | onClick = onClick 62 | ) { 63 | Text(stringResource(R.string.button_nice)) 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/dialog/SkeletonArrowDialog.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase.dialog 2 | 3 | import androidx.compose.foundation.border 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.height 8 | import androidx.compose.foundation.layout.padding 9 | import androidx.compose.foundation.shape.RoundedCornerShape 10 | import androidx.compose.material3.Button 11 | import androidx.compose.material3.Text 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.draw.clip 16 | import androidx.compose.ui.geometry.Rect 17 | import androidx.compose.ui.graphics.Color 18 | import androidx.compose.ui.res.stringResource 19 | import androidx.compose.ui.unit.Dp 20 | import androidx.compose.ui.unit.dp 21 | import com.joco.composeshowcase.R 22 | import com.joco.dialog.arrow.ArrowDialog 23 | 24 | @Composable 25 | fun SkeletonArrowDialog(targetRect: Rect, pointerSize: Dp, text: String, onClick: () -> Unit) { 26 | ArrowDialog( 27 | targetRect = targetRect, 28 | pointerSize = pointerSize, 29 | pointerColor = Color.White, 30 | content = { 31 | InnerDialog(text, onClick) 32 | } 33 | ) 34 | } 35 | 36 | @Composable 37 | private fun InnerDialog( 38 | text: String, 39 | onClick: () -> Unit 40 | ) { 41 | 42 | Column( 43 | modifier = Modifier 44 | .clip(RoundedCornerShape(16.dp)) 45 | .border(1.dp, Color.Red) 46 | .padding(16.dp), 47 | verticalArrangement = Arrangement.Center, 48 | horizontalAlignment = Alignment.CenterHorizontally 49 | ) { 50 | Text( 51 | text = text, 52 | color = Color.White 53 | ) 54 | Spacer(modifier = Modifier.height(8.dp)) 55 | Button( 56 | modifier = Modifier, 57 | shape = RoundedCornerShape(24.dp), 58 | onClick = onClick 59 | ) { 60 | Text( 61 | stringResource(R.string.button_awesome), 62 | color = Color.White 63 | ) 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/dialog/TransparentDialog.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase.dialog 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.Column 7 | import androidx.compose.foundation.layout.Spacer 8 | import androidx.compose.foundation.layout.height 9 | import androidx.compose.material3.MaterialTheme 10 | import androidx.compose.material3.Text 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.ui.Alignment 13 | import androidx.compose.ui.Modifier 14 | import androidx.compose.ui.graphics.Color 15 | import androidx.compose.ui.tooling.preview.Preview 16 | import androidx.compose.ui.unit.dp 17 | 18 | @Composable 19 | fun TransparentDialog(title: String, text: String, alignment: Alignment.Horizontal = Alignment.Start) { 20 | Column( 21 | modifier = Modifier 22 | .background(Color.Transparent), 23 | horizontalAlignment = alignment, 24 | verticalArrangement = Arrangement.Center, 25 | ) { 26 | Text(text = title, color = Color.White, style = MaterialTheme.typography.headlineMedium) 27 | Spacer(modifier = Modifier.height(8.dp)) 28 | Text(text = text, color = Color.White) 29 | } 30 | } 31 | 32 | @Preview(showBackground = true) 33 | @Composable 34 | fun PreviewTransparentDialog() { 35 | Box(Modifier.background(Color.Black)) { 36 | TransparentDialog( 37 | title = "Preview Title", 38 | text = "This is a preview of the TransparentDialog." 39 | ) 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Purple80 = Color(0xFFD0BCFF) 6 | val PurpleGrey80 = Color(0xFFCCC2DC) 7 | val Pink80 = Color(0xFFEFB8C8) 8 | 9 | val Purple40 = Color(0xFF6650a4) 10 | val PurpleGrey40 = Color(0xFF625b71) 11 | val Pink40 = Color(0xFF7D5260) 12 | 13 | val Orange = Color(0xFFFF9811) 14 | val Red = Color(0xFFDF4A33) -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase.ui.theme 2 | 3 | import android.app.Activity 4 | import android.os.Build 5 | import androidx.compose.foundation.isSystemInDarkTheme 6 | import androidx.compose.material3.MaterialTheme 7 | import androidx.compose.material3.darkColorScheme 8 | import androidx.compose.material3.dynamicDarkColorScheme 9 | import androidx.compose.material3.dynamicLightColorScheme 10 | import androidx.compose.material3.lightColorScheme 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.SideEffect 13 | import androidx.compose.ui.graphics.toArgb 14 | import androidx.compose.ui.platform.LocalContext 15 | import androidx.compose.ui.platform.LocalView 16 | import androidx.core.view.WindowCompat 17 | 18 | private val DarkColorScheme = darkColorScheme( 19 | primary = Purple80, 20 | secondary = PurpleGrey80, 21 | tertiary = Pink80 22 | ) 23 | 24 | private val LightColorScheme = lightColorScheme( 25 | primary = Red, 26 | secondary = PurpleGrey40, 27 | tertiary = Pink40 28 | 29 | /* Other default colors to override 30 | background = Color(0xFFFFFBFE), 31 | surface = Color(0xFFFFFBFE), 32 | onPrimary = Color.White, 33 | onSecondary = Color.White, 34 | onTertiary = Color.White, 35 | onBackground = Color(0xFF1C1B1F), 36 | onSurface = Color(0xFF1C1B1F), 37 | */ 38 | ) 39 | 40 | @Composable 41 | fun ComposeShowcaseTheme( 42 | darkTheme: Boolean = isSystemInDarkTheme(), 43 | // Dynamic color is available on Android 12+ 44 | dynamicColor: Boolean = true, 45 | content: @Composable () -> Unit 46 | ) { 47 | val colorScheme = when { 48 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { 49 | val context = LocalContext.current 50 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) 51 | } 52 | 53 | darkTheme -> DarkColorScheme 54 | else -> LightColorScheme 55 | } 56 | val view = LocalView.current 57 | if (!view.isInEditMode) { 58 | SideEffect { 59 | val window = (view.context as Activity).window 60 | window.statusBarColor = colorScheme.primary.toArgb() 61 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme 62 | } 63 | } 64 | 65 | MaterialTheme( 66 | colorScheme = colorScheme, 67 | typography = Typography, 68 | content = content 69 | ) 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/joco/composeshowcase/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.joco.composeshowcase.ui.theme 2 | 3 | import androidx.compose.material3.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.FontFamily 6 | import androidx.compose.ui.text.font.FontWeight 7 | import androidx.compose.ui.unit.sp 8 | 9 | // Set of Material typography styles to start with 10 | val Typography = Typography( 11 | bodyLarge = TextStyle( 12 | fontFamily = FontFamily.Default, 13 | fontWeight = FontWeight.Normal, 14 | fontSize = 16.sp, 15 | lineHeight = 24.sp, 16 | letterSpacing = 0.5.sp 17 | ) 18 | /* Other default text styles to override 19 | titleLarge = TextStyle( 20 | fontFamily = FontFamily.Default, 21 | fontWeight = FontWeight.Normal, 22 | fontSize = 22.sp, 23 | lineHeight = 28.sp, 24 | letterSpacing = 0.sp 25 | ), 26 | labelSmall = TextStyle( 27 | fontFamily = FontFamily.Default, 28 | fontWeight = FontWeight.Medium, 29 | fontSize = 11.sp, 30 | lineHeight = 16.sp, 31 | letterSpacing = 0.5.sp 32 | ) 33 | */ 34 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jocoand/compose-showcase/1deae3176475f70f750a2e16cd41951cf53d6aa7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Compose Showcase 3 | 4 | Hello %s! 5 | 6 | Awesome ! 7 | Nice ! 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |