diff --git a/Jetpack-Compose-Playground/.gitignore b/Jetpack-Compose-Playground/.gitignore new file mode 100644 index 000000000..8f51b42bb --- /dev/null +++ b/Jetpack-Compose-Playground/.gitignore @@ -0,0 +1,17 @@ +*.iml +.gradle +/local.properties +.idea +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/misc.xml +.DS_Store +/build +/captures +.externalNativeBuild +/.idea/vcs.xml +/compose/build/ +/desktop/build/ diff --git a/Jetpack-Compose-Playground/LICENSE b/Jetpack-Compose-Playground/LICENSE new file mode 100644 index 000000000..89228658a --- /dev/null +++ b/Jetpack-Compose-Playground/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Jens Klingenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Jetpack-Compose-Playground/README.md b/Jetpack-Compose-Playground/README.md new file mode 100644 index 000000000..477786444 --- /dev/null +++ b/Jetpack-Compose-Playground/README.md @@ -0,0 +1,183 @@ +

Jetpack Compose Playground

+ +## Introduction 🙋‍♂️ +This is a Jetpack Compose example project. I'm collecting a bunch of sample codes for Jetpack Compose. I also collect information/tutorials on the GitHub page https://foso.github.io/compose. + +[![Kotlin](https://img.shields.io/badge/Kotlin-2.0.20-green.svg)]() [![Compose](https://img.shields.io/badge/Compose-1.7.0-green.svg)]() + +[![jCenter](https://img.shields.io/badge/MIT-green.svg)](https://github.com/Foso/Jetpack-Compose-Playground/blob/master/LICENSE) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) +![Android Weekly](https://androidweekly.net/issues/issue-431/badge) +[![Contributors](https://img.shields.io/github/contributors/Foso/Jetpack-Compose-Playground.svg)](#contributors) + +### Show some :heart: and star the repo to support the project + +[![GitHub stars](https://img.shields.io/github/stars/Foso/Jetpack-Compose-Playground.svg?style=social&label=Star)](https://github.com/Foso/Jetpack-Compose-Playground) [![GitHub forks](https://img.shields.io/github/forks/Foso/Jetpack-Compose-Playground.svg?style=social&label=Fork)](https://github.com/Foso/Jetpack-Compose-Playground/fork) [![GitHub watchers](https://img.shields.io/github/watchers/Foso/Jetpack-Compose-Playground.svg?style=social&label=Watch)](https://github.com/Foso/Jetpack-Compose-Playground) [![Twitter Follow](https://img.shields.io/twitter/follow/jklingenberg_.svg?style=social)](https://twitter.com/jklingenberg_) Tweet +## Composable of the week!! 🎉 +The [SubComposeLayout](https://foso.github.io/Jetpack-Compose-Playground/ui/layout/subcomposelayout/) + +## New to Compose? +Check [Compose for Android Developers](https://foso.github.io/Jetpack-Compose-Playground/compose_for/android_devs/) or [Hello World Compose](https://foso.github.io/Jetpack-Compose-Playground/general/helloworld/) + +## 📙 Jetpack Compose examples/tutorials and demos +Look in the [repo](https://github.com/Foso/Jetpack-Compose-Playground/tree/master/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github) or take a look at the GitHub page: https://foso.github.io/compose + +### Animation +* [Crossfade](https://foso.github.io/Jetpack-Compose-Playground/animation/crossfade) + +### Layouts +* [ConstraintLayout](https://foso.github.io/Jetpack-Compose-Playground/layout/constraintlayout) +* [Scaffold](https://foso.github.io/Jetpack-Compose-Playground/material/scaffold) +* [Column](https://foso.github.io/Jetpack-Compose-Playground/layout/column) +* [Row](https://foso.github.io/Jetpack-Compose-Playground/layout/row) +* [Stack](https://foso.github.io/Jetpack-Compose-Playground/layout/stack) + +### Foundation +* [Canvas](https://foso.github.io/Jetpack-Compose-Playground/foundation/canvas) +* [Image](https://foso.github.io/Jetpack-Compose-Playground/foundation/image) +* [LazyColumn](https://foso.github.io/Jetpack-Compose-Playground/foundation/lazycolumn) +* [LazyRow](https://foso.github.io/Jetpack-Compose-Playground/foundation/lazyrow) +* [Shape](https://foso.github.io/Jetpack-Compose-Playground/foundation/shape) +* [Text](https://foso.github.io/Jetpack-Compose-Playground/foundation/text) + +### Material +* [AlertDialog](https://foso.github.io/Jetpack-Compose-Playground/material/alertdialog) +* [BadgeBox](https://foso.github.io/Jetpack-Compose-Playground/material/badgedbox/) +* Buttons: [Button](https://foso.github.io/Jetpack-Compose-Playground/material/button), [FloatingActionButton](https://foso.github.io/Jetpack-Compose-Playground/material/floatingactionbutton/), [OutlinedButton](https://foso.github.io/Jetpack-Compose-Playground/material/button/), [TextButton](https://foso.github.io/Jetpack-Compose-Playground/material/button/) +* [Card](https://foso.github.io/Jetpack-Compose-Playground/material/card) +* [Divider](https://foso.github.io/Jetpack-Compose-Playground/material/divider) +* [DropdownMenu](https://foso.github.io/Jetpack-Compose-Playground/material/dropdownmenu/) +* [ModalBottomSheetLayout](https://foso.github.io/Jetpack-Compose-Playground/material/modalbottomsheetlayout/) +* [ModalDrawerLayout](https://foso.github.io/Jetpack-Compose-Playground/material/modaldrawer) +* [NavigationRail](https://foso.github.io/Jetpack-Compose-Playground/material/navigationrail/) +* Progress Indicators: [CircularProgressIndicator](https://foso.github.io/Jetpack-Compose-Playground/material/circularprogressindicator), [LinearProgressIndicator](https://foso.github.io/Jetpack-Compose-Playground/material/linearprogressindicator/) +* [Scaffold](https://foso.github.io/Jetpack-Compose-Playground/material/scaffold) +* Selection Controls: [Checkbox](https://foso.github.io/Jetpack-Compose-Playground/material/checkbox), [RadioButton](https://foso.github.io/Jetpack-Compose-Playground/material/radiobutton), [Switch](https://foso.github.io/Jetpack-Compose-Playground/material/switch) +* [Slider](https://foso.github.io/Jetpack-Compose-Playground/material/slider/) +* [Snackbar](https://foso.github.io/Jetpack-Compose-Playground/material/snackbar/) +* [Surface](https://foso.github.io/Jetpack-Compose-Playground/material/surface/) +* [Text](https://foso.github.io/Jetpack-Compose-Playground/foundation/text/) +* [TextField](https://foso.github.io/Jetpack-Compose-Playground/material/textfield) +* [TopAppBar](https://foso.github.io/Jetpack-Compose-Playground/material/topappbar/) + +### Cookbook + +* [Overview](https://foso.github.io/Jetpack-Compose-Playground/cookbook/overview/) +* [Handle changes to a TextField](https://foso.github.io/Jetpack-Compose-Playground/cookbook/textfield_changes/) + + +> Some of the code samples in this Repository: + +| Overview | DialogExample | CircularProgress | +| ------------------ | --------------------------- | ------------------ | +|Screenshot | Screenshot | Screenshot | + +

+ +### Project Structure + +* [/app](https://github.com/Foso/Jetpack-Compose-Playground/tree/master/app) - Android project directory + +# Resources + +## Talks +| Name | Description | +| ----------------------------------------- | ------------------------------------ | +| [Thinking in Compose](https://www.youtube.com/watch?v=SMOhl9RK0BA) | Jetpack Compose is the new next generation UI toolkit. It uses a declarative component based paradigm for building UIs easily and quickly. It’s written entirely in Kotlin and embraces the style and ergonomics of the Kotlin language. | +| [Compose by example](https://www.youtube.com/watch?v=DDd6IOlH3io) | Jetpack Compose is a new declarative UI toolkit built for the demands of creating modern user interfaces. Get started with Compose and learn about the new APIs and Material components that make up the toolkit by examining concrete UIs we’ve created with it. We’ll walk through examples of theming, animation, layout and more, demonstrating how to customize and combine components to build real UIs. We’ll show how the new toolkit simplifies your development experience and enables new possibilities. | +| [Compose for existing apps](https://www.youtube.com/watch?v=PjQdFmiDgwk) | Jetpack Compose is now in alpha and you might want to start adding it to your existing apps. In this talk, you'll learn how to do that! We'll cover topics such as: adding Compose to your existing Views and embedding Views in Compose, using your existing View theme and current app architecture in Compose, testing all of that code, and much more. | +| [Jetpack Compose](https://www.youtube.com/watch?v=U5BwfqBpiWU) | Jetpack Compose is Android’s new modern UI toolkit. Learn how Compose simplifies & accelerates your UI development, allowing you to create richer, more robust and responsive UIs. We outline our roadmap, what is ready for use right now, share our direction in areas that are still evolving, and show how the tight integration with tooling makes the development experience even better. Get up to speed with Compose and how it can help you to build better apps! | +| [droidcon Online 2020: Become A Composer By Brian Gardner ](https://www.droidcon.com/media-detail?video=412304809) | | +| [KotlinConf 2019: The Compose Runtime, Demystified by Leland Richardson](https://www.youtube.com/watch?v=6BRlI5zfCCk) | Jetpack Compose is an ambitious multi-team effort to reimagine Android's UI Toolkit more than 10 years after the Android Platform launched with the original UI Toolkit. Compose follows a declarative programming model, and the runtime is coupled with a Kotlin compiler plugin to enable a novel new approach to declarative programming. In this talk, Leland will go over the mechanics of how the Compose runtime and compiler plugin work together, demystifying how it can be used to enable efficient and performant user interfaces. In addition, this talk will describe how Compose can operate completely independent of the Android Platform and Compose UI, allowing it to be used as a general language feature for Incremental Computing and the management of tree-like data structures. | +| [KotlinConf 2019: Compose Yourself: Designing a Kotlin First UI Toolkit by Anna-Chiara & Clara](https://www.youtube.com/watch?v=WqnR_XhEiVI) | #Jetpack Compose is an unbundled UI Toolkit for #Android, designed to simplify UI development. It combines a reactive programming model with the conciseness and ease of use of Kotlin. Learn directly from engineers on the project about the decisions that went into making this toolkit and how a Kotlin-first approach has influenced API design from the project's inception. | +| [What's New in Jetpack Compose (Android Dev Summit '19)](https://www.youtube.com/watch?v=dtm2h-_sNDQ&list=PLWz5rJ2EKKc_xXXubDti2eRnIKU0p7wHd&index=8&t=0s) | Jetpack Compose was announced at Google I/O and the team has been hard at work ever since. This talk introduces Compose to new audiences, including what the project is and how it is taking shape. The talk also updates people who already know about Jetpack Compose, including how the project has evolved. | +| [Understanding Compose (Android Dev Summit '19)](https://www.youtube.com/watch?v=Q9MtlmmN4Q0) | This session covers the benefits of a declarative reactive UI system like Jetpack Compose and how it applies to real problems that Android developers have today. Additionally, this talk expands on the programming model of Jetpack Compose and some of its implementation details the can help you understand how Compose works. | +| [#AskAndroid at Android Dev Summit 2019 - Jetpack Compose](https://www.youtube.com/watch?v=oEy6nJaMtLM) | Missed the #AskAndroid livestream segment of Android Dev Summit 2019? Don’t worry, we got you covered. Hosts Lyla Fujiwara and Dan Galpin are joined by Anna-Chiara Bellini and Adam Powell to discuss Jetpack Compose questions submitted by Android developers online. Anna-Chiara Bellini is a product manager, and Adam Powell is an engineering lead. | +| [Google IO19 - Declarative UI patterns](https://youtu.be/VsStyq4Lzxo) | Explore how reactive and declarative paradigms can be applied to Android UI development, making it easier for developers to integrate these patterns into their Android apps with Kotlin. | +| [DroidconBerlin - Jetpack Compose — Next Gen Kotlin UI Toolkit for Android](https://www.droidcon.com/media-detail?video=353079951) | | +| [DroidconBerlin - Jumping into Jetpack Compose way too early to see what's inside](https://www.droidcon.com/media-detail?video=352686988) | | +| [KotlinEverywhere - Jetpack Compose](https://www.youtube.com/watch?v=I5zRmCheVVg) | | +| [DevFest Kolkata 2019 - Let's Talk Composing UI](https://www.youtube.com/watch?v=kfNC-MKAGzc) | | + +## Podcasts +| Name | Episode | Description | +| ----------------------------------------- | ------------------------------------ | -- | +| Android Developers Backstage | [Episode 147](http://androidbackstage.blogspot.com/2020/08/episode-147-jetpack-compose-alpha.html) | Jetpack Compose Alpha | +| Android Developers Backstage | [Episode 131](http://androidbackstage.blogspot.com/2020/01/episode-131-jetpack-compose-and.html) | Jetpack Compose and Declarative UIs | +| Android Developers Backstage | [Episode 115](http://androidbackstage.blogspot.com/2019/06/episode-115-jetpack-compose.html) | Jetpack Compose | +| Fragmented Podcast | [Episode 171](https://fragmentedpodcast.com/episodes/172/) | Jetpack Compose with Leland Richardson | +| The Kodeco Podcast | [S09 E09](https://podcasts.google.com/?feed=aHR0cHM6Ly93d3cucmF5d2VuZGVybGljaC5jb20vY2F0ZWdvcnkvcG9kY2FzdC9mZWVk&episode=aHR0cHM6Ly93d3cucmF5d2VuZGVybGljaC5jb20vP3A9MjMxMjI0&hl=en-IN&ep=6&at=1567914736470) | Google’s Android Toolkit Lead Developer Romain Guy | + +## Other Links + +| Name | Description | +| ----------------------------------------- | ------------------------------------ | +| [Jetpack Compose](https://developer.android.com/jetpack/compose) | | +| [Jetpack Compose UI Readme](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/ui/README.md) | | +| [Compose Readme](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/compose/) | | +| [Video - Kotlin and Jetpack Compose](https://www.youtube.com/watch?v=KjQU_QrlbEI) | | +| `#compose` channel on [Kotlin Slack](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) | | +| [Compose from first Principles ](http://intelligiblebabble.com/compose-from-first-principles/) | | +| [Jetpack Compose Tutorial ](https://developer.android.com/jetpack/compose) | | +| [AndroidX Git Compose](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/compose/) | | +| [Release Notes](https://developer.android.com/jetpack/androidx/releases/ui) | | +| [Compose UI Docu](https://developer.android.com/reference/kotlin/androidx/ui/packages) | | +| [Video - Jetpack compose - MVVM State management in a simple way](https://youtu.be/KTvP27FpXd0) | | +| [Jetpack Compose Twitter Bot](https://twitter.com/ComposeBot) | | +| [SSComposeCookBook](https://github.com/SimformSolutionsPvtLtd/SSComposeCookBook/) | | +| [SSJetPackComposeProgressButton](https://github.com/SimformSolutionsPvtLtd/SSJetPackComposeProgressButton/) | | +| [SSJetpackComposeSwipeableView](https://github.com/SimformSolutionsPvtLtd/SSJetpackComposeSwipeableView/) | | +| [SSComposeOTPPinView](https://github.com/SimformSolutionsPvtLtd/SSComposeOTPPinView) | | + +Feel free to contribute! + +## ✍️ Feedback + +If you want to improve Compose, join the [Kotlin Slack](https://slack.kotlinlang.org) and the #compose channel or file a Compose bug on the [Google Issue Tracker](https://issuetracker.google.com/issues?q=componentid:612128) + +### Find this project useful? :heart: +* Support it by clicking the :star: button on the upper right of this page. :v: + +## + +

+

This project is proudly supported by JetBrains OSS License
+ +

+ +[License](https://github.com/Foso/Jetpack-Compose-Playground/blob/master/LICENSE) +------- + + ``` +MIT License + +Copyright (c) 2019-2023 Jens Klingenberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + +## Acknowledgments +Projects that helped me understand how to setup the project: +* [Mishkun/try-compose +](https://github.com/Mishkun/try-compose) + +## Credits +Jetpack-Compose-Playground is brought to you by these [contributors](https://github.com/Foso/Jetpack-Compose-Playground/graphs/contributors). + diff --git a/Jetpack-Compose-Playground/app/.gitignore b/Jetpack-Compose-Playground/app/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Jetpack-Compose-Playground/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Jetpack-Compose-Playground/app/build.gradle.kts b/Jetpack-Compose-Playground/app/build.gradle.kts new file mode 100644 index 000000000..d1ebb804c --- /dev/null +++ b/Jetpack-Compose-Playground/app/build.gradle.kts @@ -0,0 +1,104 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("com.android.application") + id("kotlin-android") + alias(libs.plugins.compose.compiler) +} + +android { + compileSdk = 35 + + defaultConfig { + applicationId = "de.jensklingenberg.jetpackcomposeplayground" + minSdk = 21 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + getByName("release") { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } + + namespace = "de.jensklingenberg.jetpackcomposeplayground" + +} + +tasks.withType().configureEach { + kotlinOptions { + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler" + ) + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler" + ) + } +} +val compose_version = libs.versions.compose.version.get() + +dependencies { + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) + implementation("androidx.activity:activity-compose:1.10.0") + implementation("androidx.appcompat:appcompat:1.7.0") + implementation("androidx.compose.animation:animation-core:$compose_version") + implementation("androidx.compose.animation:animation:$compose_version") + implementation("androidx.compose.foundation:foundation-layout:$compose_version") + implementation("androidx.compose.foundation:foundation:$compose_version") + implementation("androidx.compose.material:material-icons-core:$compose_version") + implementation("androidx.compose.material:material-icons-extended:$compose_version") + implementation("androidx.compose.material:material:$compose_version") + implementation("androidx.compose.material:material:$compose_version") + implementation("androidx.compose.runtime:runtime-livedata:$compose_version") + implementation("androidx.compose.runtime:runtime-rxjava2:$compose_version") + implementation("androidx.compose.ui:ui-geometry:$compose_version") + implementation("androidx.compose.ui:ui-graphics:$compose_version") + implementation("androidx.compose.ui:ui-tooling:$compose_version") + implementation("androidx.compose.ui:ui-tooling:$compose_version") + implementation("androidx.compose.ui:ui:$compose_version") + implementation("androidx.core:core-ktx:1.15.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") + implementation("com.google.android.material:material:1.12.0") + implementation("androidx.compose.ui:ui-viewbinding:$compose_version") + implementation("androidx.compose.ui:ui-text:$compose_version") + implementation("androidx.compose.ui:ui-util:$compose_version") + implementation("androidx.compose.ui:ui:$compose_version") + implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0") + + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") + androidTestImplementation("androidx.test:runner:1.6.2") + androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_version") + androidTestImplementation("androidx.compose.ui:ui-test:$compose_version") + androidTestImplementation("androidx.test.espresso:espresso-intents:3.6.1") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + androidTestImplementation("androidx.test:core:1.6.1") + androidTestImplementation("androidx.test:rules:1.6.1") + androidTestImplementation("androidx.test:runner:1.6.2") + androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2") + androidTestImplementation("org.mockito:mockito-core:5.12.0") + debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version") + + androidTestImplementation("com.adevinta.android:barista:4.3.0") { + exclude(group = "org.jetbrains.kotlin") + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/proguard-rules.pro b/Jetpack-Compose-Playground/app/proguard-rules.pro new file mode 100644 index 000000000..2fe953834 --- /dev/null +++ b/Jetpack-Compose-Playground/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradl. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithAndroidComposeRule.kt b/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithAndroidComposeRule.kt new file mode 100644 index 000000000..3046527d2 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithAndroidComposeRule.kt @@ -0,0 +1,41 @@ +package de.jensklingenberg.jetpackcomposeplayground + +import androidx.compose.material.Text +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import org.junit.Rule +import org.junit.Test +import java.util.concurrent.CountDownLatch + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUiTestWithAndroidComposeRule { + + @Rule + @JvmField + var composeTestRule: ComposeContentTestRule = createAndroidComposeRule() + + @Test + fun whenIClickOnButton_TheTextShouldChange() { + composeTestRule.onNodeWithText("Hello").assertTextEquals("Hello") + composeTestRule.onNodeWithText("Hello").performClick() + composeTestRule.onNodeWithText("Hello").assertDoesNotExist() + composeTestRule.onNodeWithText("Bye").assertExists() + } + + + @Test + fun whenIClickOnButton_TheTextShouldChange_WithTag() { + composeTestRule.onNodeWithTag("MyTestTag").printToLog("XXX") + composeTestRule.onNodeWithTag("MyTestTag").performClick() + composeTestRule.onNodeWithText("Hello").assertDoesNotExist() + composeTestRule.onNodeWithTag("MyTestTag").assertTextEquals("Bye") + + } +} + + diff --git a/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithComposeRule.kt b/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithComposeRule.kt new file mode 100644 index 000000000..7d53d2ee6 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithComposeRule.kt @@ -0,0 +1,47 @@ +package de.jensklingenberg.jetpackcomposeplayground + +import androidx.compose.ui.test.* +import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.junit4.createComposeRule +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.testing.TestingExample +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUiTestWithComposeRule { + + @Rule + @JvmField + var composeTestRule: ComposeContentTestRule = createComposeRule() + + @Before + fun before(){ + composeTestRule.setContent { + TestingExample() + } + } + + @Test + fun whenIClickOnButton_TheTextShouldChange() { + composeTestRule.onNodeWithText("Hello").assertTextEquals("Hello") + composeTestRule.onNodeWithText("Hello").performClick() + composeTestRule.onNodeWithText("Hello").assertDoesNotExist() + composeTestRule.onNodeWithText("Bye").assertExists() + } + + + @Test + fun whenIClickOnButton_TheTextShouldChange_WithTag() { + composeTestRule.onNodeWithTag("MyTestTag").assertTextEquals("Hello") + composeTestRule.onNodeWithTag("MyTestTag").performClick() + composeTestRule.onNodeWithText("Hello").assertDoesNotExist() + composeTestRule.onNodeWithTag("MyTestTag").assertTextEquals("Bye") + } + + +} diff --git a/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/test.text b/Jetpack-Compose-Playground/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/test.text new file mode 100644 index 000000000..e69de29bb diff --git a/Jetpack-Compose-Playground/app/src/main/AndroidManifest.xml b/Jetpack-Compose-Playground/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..3e2e596d7 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/MainActivity.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/MainActivity.kt new file mode 100644 index 000000000..c2465fee8 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/MainActivity.kt @@ -0,0 +1,18 @@ +package de.jensklingenberg.jetpackcomposeplayground + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoActivity + + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + startActivity(Intent(this, DemoActivity::class.java)) + + } + +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/UiTestingDemoActivity.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/UiTestingDemoActivity.kt new file mode 100644 index 000000000..46abf1974 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/UiTestingDemoActivity.kt @@ -0,0 +1,18 @@ +package de.jensklingenberg.jetpackcomposeplayground + + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.testing.TestingExample + + +class UiTestingDemoActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + TestingExample() + } + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/MyTestActivity.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/MyTestActivity.kt new file mode 100644 index 000000000..6613e501c --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/MyTestActivity.kt @@ -0,0 +1,41 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples + + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf + +data class User(val name: String, val age: Int) + +val LocalActiveUser = compositionLocalOf { error("No user found!") } + +class MyTestActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + MyUserScreen() + } + } +} +@Composable +private fun MyUserScreen() { + val user = User("Jens", 31) + CompositionLocalProvider(LocalActiveUser provides user) { + UserInfo() + } +} + + +@Composable +fun UserInfo() { + Column { + Text("Name: " + LocalActiveUser.current.name) + Text("Age: " + LocalActiveUser.current.age) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Demo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Demo.kt new file mode 100644 index 000000000..ecf54f60e --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Demo.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.demo + +import android.app.Activity +import androidx.activity.ComponentActivity +import androidx.compose.runtime.Composable +import kotlin.reflect.KClass + +/** + * Generic demo with a [title] that will be displayed in the list of demos. + */ +sealed class Demo(val title: String) { + override fun toString() = title +} + +/** + * Demo that launches an [Activity] when selected. + * + * This should only be used for demos that need to customize the activity, the large majority of + * demos should just use [ComposableDemo] instead. + * + * @property activityClass the KClass (Foo::class) of the activity that will be launched when + * this demo is selected. + */ +class ActivityDemo(title: String, val activityClass: KClass) : Demo(title) + +/** + * Demo that displays [Composable] [content] when selected. + */ +class ComposableDemo(title: String, val content: @Composable () -> Unit) : Demo(title) + +/** + * A category of [Demo]s, that will display a list of [demos] when selected. + */ +class DemoCategory(title: String, val demos: List) : Demo(title) + +/** + * Flattened recursive DFS [List] of every demo in [this]. + */ +fun DemoCategory.allDemos(): List { + val allDemos = mutableListOf() + fun DemoCategory.addAllDemos() { + demos.forEach { demo -> + allDemos += demo + if (demo is DemoCategory) { + demo.addAllDemos() + } + } + } + addAllDemos() + return allDemos +} + +/** + * Flattened recursive DFS [List] of every launchable demo in [this]. + */ +fun DemoCategory.allLaunchableDemos(): List { + return allDemos().filter { it !is DemoCategory } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoActivity.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoActivity.kt new file mode 100644 index 000000000..013d868e9 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoActivity.kt @@ -0,0 +1,312 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.demo + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.os.Bundle +import android.view.Window +import androidx.activity.ComponentActivity +import androidx.activity.OnBackPressedCallback +import androidx.activity.OnBackPressedDispatcher +import androidx.compose.material.Colors +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.Saver +import androidx.compose.runtime.saveable.listSaver +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.ComposeView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver + +/** + * Main [Activity] containing all Compose related demos. + */ +class DemoActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + ComposeView(this).also { + setContentView(it) + }.setContent { + val activityStarter = fun(demo: ActivityDemo<*>) { + startActivity(Intent(this, demo.activityClass.java)) + } + val navigator = rememberSaveable( + saver = Navigator.Saver(AllDemosCategory, onBackPressedDispatcher, activityStarter) + ) { + Navigator(AllDemosCategory, onBackPressedDispatcher, activityStarter) + } + val demoColors = remember { + DemoColors().also { + lifecycle.addObserver( + LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_RESUME) { + it.loadColorsFromSharedPreferences(this) + } + } + ) + } + } + DemoTheme(demoColors, window) { + val filteringMode = rememberSaveable( + saver = FilterMode.Saver(onBackPressedDispatcher) + ) { + FilterMode(onBackPressedDispatcher) + } + val onStartFiltering = { filteringMode.isFiltering = true } + val onEndFiltering = { filteringMode.isFiltering = false } + DemoApp( + currentDemo = navigator.currentDemo, + backStackTitle = navigator.backStackTitle, + isFiltering = filteringMode.isFiltering, + onStartFiltering = onStartFiltering, + onEndFiltering = onEndFiltering, + onNavigateToDemo = { demo -> + if (filteringMode.isFiltering) { + onEndFiltering() + navigator.popAll() + } + navigator.navigateTo(demo) + }, + canNavigateUp = !navigator.isRoot, + onNavigateUp = { + onBackPressed() + }, + launchSettings = { + // startActivity(Intent(this, DemoSettingsActivity::class.java)) + } + ) + } + } + } +} + +@Composable +private fun DemoTheme( + demoColors: DemoColors, + window: Window, + content: @Composable () -> Unit +) { + MaterialTheme() { + val statusBarColor = with(MaterialTheme.colors) { + (if (isLight) primaryVariant else Color.Black).toArgb() + } + SideEffect { + window.statusBarColor = statusBarColor + } + content() + } +} + +private class Navigator private constructor( + private val backDispatcher: OnBackPressedDispatcher, + private val launchActivityDemo: (ActivityDemo<*>) -> Unit, + private val rootDemo: Demo, + initialDemo: Demo, + private val backStack: MutableList +) { + constructor( + rootDemo: Demo, + backDispatcher: OnBackPressedDispatcher, + launchActivityDemo: (ActivityDemo<*>) -> Unit + ) : this(backDispatcher, launchActivityDemo, rootDemo, rootDemo, mutableListOf()) + + private val onBackPressed = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + popBackStack() + } + }.apply { + isEnabled = !isRoot + backDispatcher.addCallback(this) + } + + private var _currentDemo by mutableStateOf(initialDemo) + var currentDemo: Demo + get() = _currentDemo + private set(value) { + _currentDemo = value + onBackPressed.isEnabled = !isRoot + } + + val isRoot: Boolean get() = backStack.isEmpty() + + val backStackTitle: String + get() = + (backStack.drop(1) + currentDemo).joinToString(separator = " > ") { it.title } + + fun navigateTo(demo: Demo) { + if (demo is ActivityDemo<*>) { + launchActivityDemo(demo) + } else { + backStack.add(currentDemo) + currentDemo = demo + } + } + + fun popAll() { + if (!isRoot) { + backStack.clear() + currentDemo = rootDemo + } + } + + private fun popBackStack() { + currentDemo = backStack.removeAt(backStack.lastIndex) + } + + companion object { + fun Saver( + rootDemo: DemoCategory, + backDispatcher: OnBackPressedDispatcher, + launchActivityDemo: (ActivityDemo<*>) -> Unit + ): Saver = listSaver( + save = { navigator -> + (navigator.backStack + navigator.currentDemo).map { it.title } + }, + restore = { restored -> + require(restored.isNotEmpty()) + val backStack = restored.mapTo(mutableListOf()) { + requireNotNull(findDemo(rootDemo, it)) + } + val initial = backStack.removeAt(backStack.lastIndex) + Navigator(backDispatcher, launchActivityDemo, rootDemo, initial, backStack) + } + ) + + private fun findDemo(demo: Demo, title: String): Demo? { + if (demo.title == title) { + return demo + } + if (demo is DemoCategory) { + demo.demos.forEach { child -> + findDemo(child, title) + ?.let { return it } + } + } + return null + } + } +} + +private class FilterMode(backDispatcher: OnBackPressedDispatcher, initialValue: Boolean = false) { + + private var _isFiltering by mutableStateOf(initialValue) + + private val onBackPressed = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + isFiltering = false + } + }.apply { + isEnabled = initialValue + backDispatcher.addCallback(this) + } + + var isFiltering + get() = _isFiltering + set(value) { + _isFiltering = value + onBackPressed.isEnabled = value + } + + companion object { + fun Saver(backDispatcher: OnBackPressedDispatcher) = Saver( + save = { it.isFiltering }, + restore = { FilterMode(backDispatcher, it) } + ) + } +} + +/** + * Returns a [DemoColors] from the values saved to [SharedPreferences]. If a given color is + * not present in the [SharedPreferences], its default value as defined in [Colors] + * will be returned. + */ +fun DemoColors.loadColorsFromSharedPreferences(context: Context) { + +} + +/** + * TODO: remove after b/154329050 is fixed + * Inline classes don't play well with reflection, so we want boxed classes for our + * call to [lightColors]. + */ +internal fun reflectLightColors( + primary: Long = 0xFF6200EE, + primaryVariant: Long = 0xFF3700B3, + secondary: Long = 0xFF03DAC6, + secondaryVariant: Long = 0xFF018786, + background: Long = 0xFFFFFFFF, + surface: Long = 0xFFFFFFFF, + error: Long = 0xFFB00020, + onPrimary: Long = 0xFFFFFFFF, + onSecondary: Long = 0xFF000000, + onBackground: Long = 0xFF000000, + onSurface: Long = 0xFF000000, + onError: Long = 0xFFFFFFFF +) = lightColors( + primary = Color(primary), + primaryVariant = Color(primaryVariant), + secondary = Color(secondary), + secondaryVariant = Color(secondaryVariant), + background = Color(background), + surface = Color(surface), + error = Color(error), + onPrimary = Color(onPrimary), + onSecondary = Color(onSecondary), + onBackground = Color(onBackground), + onSurface = Color(onSurface), + onError = Color(onError) +) + +/** + * TODO: remove after b/154329050 is fixed + * Inline classes don't play well with reflection, so we want boxed classes for our + * call to [darkColors]. + */ +internal fun reflectDarkColors( + primary: Long = 0xFFBB86FC, + primaryVariant: Long = 0xFF3700B3, + secondary: Long = 0xFF03DAC6, + background: Long = 0xFF121212, + surface: Long = 0xFF121212, + error: Long = 0xFFCF6679, + onPrimary: Long = 0xFF000000, + onSecondary: Long = 0xFF000000, + onBackground: Long = 0xFFFFFFFF, + onSurface: Long = 0xFFFFFFFF, + onError: Long = 0xFF000000 +) = darkColors( + primary = Color(primary), + primaryVariant = Color(primaryVariant), + secondary = Color(secondary), + background = Color(background), + surface = Color(surface), + error = Color(error), + onPrimary = Color(onPrimary), + onSecondary = Color(onSecondary), + onBackground = Color(onBackground), + onSurface = Color(onSurface), + onError = Color(onError) +) \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoApp.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoApp.kt new file mode 100644 index 000000000..42727c2f0 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoApp.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.demo + +import androidx.compose.animation.Crossfade +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.integration.demos.DemoFilter +import androidx.compose.integration.demos.FilterAppBar +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.ListItem +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.ArrowForward +import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.filled.Settings +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp + +@Composable +fun DemoApp( + currentDemo: Demo, + backStackTitle: String, + isFiltering: Boolean, + onStartFiltering: () -> Unit, + onEndFiltering: () -> Unit, + onNavigateToDemo: (Demo) -> Unit, + canNavigateUp: Boolean, + onNavigateUp: () -> Unit, + launchSettings: () -> Unit +) { + val navigationIcon = (@Composable { AppBarIcons.Back(onNavigateUp) }).takeIf { canNavigateUp } + + var filterText by rememberSaveable { mutableStateOf("") } + + Scaffold( + topBar = { + DemoAppBar( + title = backStackTitle, + navigationIcon = navigationIcon, + launchSettings = launchSettings, + isFiltering = isFiltering, + filterText = filterText, + onFilter = { filterText = it }, + onStartFiltering = onStartFiltering, + onEndFiltering = onEndFiltering + ) + } + ) { innerPadding -> + val modifier = Modifier.padding(innerPadding) + DemoContent(modifier, currentDemo, isFiltering, filterText, onNavigateToDemo) + } +} + +@Composable +private fun DemoContent( + modifier: Modifier, + currentDemo: Demo, + isFiltering: Boolean, + filterText: String, + onNavigate: (Demo) -> Unit +) { + Crossfade(isFiltering to currentDemo) { (filtering, demo) -> + Surface(modifier.fillMaxSize(), color = MaterialTheme.colors.background) { + if (filtering) { + DemoFilter( + launchableDemos = AllDemosCategory.allLaunchableDemos(), + filterText = filterText, + onNavigate = onNavigate + ) + } else { + DisplayDemo(demo, onNavigate) + } + } + } +} + +@Composable +private fun DisplayDemo(demo: Demo, onNavigate: (Demo) -> Unit) { + when (demo) { + is ActivityDemo<*> -> { + /* should never get here as activity demos are not added to the backstack*/ + } + is ComposableDemo -> demo.content() + is DemoCategory -> DisplayDemoCategory(demo, onNavigate) + } +} + +@Composable +@OptIn(ExperimentalMaterialApi::class) +private fun DisplayDemoCategory(category: DemoCategory, onNavigate: (Demo) -> Unit) { + // TODO: migrate to LazyColumn after b/175671850 + Column(Modifier.verticalScroll(rememberScrollState())) { + category.demos.forEach { demo -> + ListItem( + text = { + Text( + modifier = Modifier.height(56.dp) + .wrapContentSize(Alignment.Center), + text = demo.title + ) + }, + modifier = Modifier.clickable { onNavigate(demo) } + ) + } + } +} + +@Suppress("ComposableLambdaParameterNaming", "ComposableLambdaParameterPosition") +@Composable +private fun DemoAppBar( + title: String, + navigationIcon: @Composable (() -> Unit)?, + isFiltering: Boolean, + filterText: String, + onFilter: (String) -> Unit, + onStartFiltering: () -> Unit, + onEndFiltering: () -> Unit, + launchSettings: () -> Unit +) { + if (isFiltering) { + FilterAppBar( + filterText = filterText, + onFilter = onFilter, + onClose = onEndFiltering + ) + } else { + TopAppBar( + title = { + Text(title, Modifier.testTag(Tags.AppBarTitle)) + }, + navigationIcon = navigationIcon, + actions = { + AppBarIcons.Filter(onClick = onStartFiltering) + } + ) + } +} + +private object AppBarIcons { + @Composable + fun Back(onClick: () -> Unit) { + val icon = when (LocalLayoutDirection.current) { + LayoutDirection.Ltr -> Icons.Filled.ArrowBack + LayoutDirection.Rtl -> Icons.Filled.ArrowForward + } + IconButton(onClick = onClick) { + Icon(icon, null) + } + } + + @Composable + fun Filter(onClick: () -> Unit) { + IconButton(modifier = Modifier.testTag(Tags.FilterButton), onClick = onClick) { + Icon(Icons.Filled.Search, null) + } + } + + @Composable + fun Settings(onClick: () -> Unit) { + IconButton(onClick = onClick) { + Icon(Icons.Filled.Settings, null) + } + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoColors.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoColors.kt new file mode 100644 index 000000000..9543e39d4 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoColors.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.demo + +import android.content.SharedPreferences +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.Colors +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors + +/** + * Wrapper class that contains a light and dark [Colors], to allow saving and + * restoring the entire light / dark theme to and from [SharedPreferences]. + */ +@Stable +class DemoColors { + var light: Colors by mutableStateOf(lightColors()) + var dark: Colors by mutableStateOf(darkColors()) + + +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoFilter.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoFilter.kt new file mode 100644 index 000000000..bffa0aa5a --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/DemoFilter.kt @@ -0,0 +1,159 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.compose.integration.demos + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.verticalScroll + +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.ListItem +import androidx.compose.material.LocalContentColor +import androidx.compose.material.LocalTextStyle +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.compositeOver +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.Demo + +/** + * A scrollable list of [launchableDemos], filtered by [filterText]. + */ +@Composable +fun DemoFilter(launchableDemos: List, filterText: String, onNavigate: (Demo) -> Unit) { + val filteredDemos = launchableDemos + .filter { it.title.contains(filterText, ignoreCase = true) } + .sortedBy { it.title } + // TODO: migrate to LazyColumn after b/175671850 + Column(Modifier.verticalScroll(rememberScrollState())) { + filteredDemos.forEach { demo -> + FilteredDemoListItem( + demo, + filterText = filterText, + onNavigate = onNavigate + ) + } + } +} + +/** + * [TopAppBar] with a text field allowing filtering all the demos. + */ +@Composable +fun FilterAppBar( + filterText: String, + onFilter: (String) -> Unit, + onClose: () -> Unit +) { + with(MaterialTheme.colors) { + val appBarColor = if (isLight) { + surface + } else { + // Blending primary over surface according to Material design guidance for brand + // surfaces in dark theme + primary.copy(alpha = 0.08f).compositeOver(surface) + } + TopAppBar(backgroundColor = appBarColor, contentColor = onSurface) { + IconButton(modifier = Modifier.align(Alignment.CenterVertically), onClick = onClose) { + Icon(Icons.Filled.Close, null) + } + FilterField( + filterText, + onFilter, + Modifier.fillMaxWidth().align(Alignment.CenterVertically) + ) + } + } +} + +/** + * [BasicTextField] that edits the current [filterText], providing [onFilter] when edited. + */ +@Composable +@OptIn(ExperimentalFoundationApi::class) +private fun FilterField( + filterText: String, + onFilter: (String) -> Unit, + modifier: Modifier = Modifier +) { + +} + +/** + * [ListItem] that displays a [demo] and highlights any matches for [filterText] inside [Demo.title] + */ +@Composable +@OptIn(ExperimentalMaterialApi::class) +private fun FilteredDemoListItem( + demo: Demo, + filterText: String, + onNavigate: (Demo) -> Unit +) { + val primary = MaterialTheme.colors.primary + val annotatedString = buildAnnotatedString { + val title = demo.title + var currentIndex = 0 + val pattern = filterText.toRegex(option = RegexOption.IGNORE_CASE) + pattern.findAll(title).forEach { result -> + val index = result.range.first + if (index > currentIndex) { + append(title.substring(currentIndex, index)) + currentIndex = index + } + withStyle(SpanStyle(color = primary)) { + append(result.value) + } + currentIndex = result.range.last + 1 + } + if (currentIndex <= title.lastIndex) { + append(title.substring(currentIndex, title.length)) + } + } + key(demo.title) { + ListItem( + text = { + Text( + modifier = Modifier.height(56.dp).wrapContentSize(Alignment.Center), + text = annotatedString + ) + }, + modifier = Modifier.clickable { onNavigate(demo) } + ) + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Demos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Demos.kt new file mode 100644 index 000000000..1fae7da65 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Demos.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.demo + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.activity.ActivityDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.animation.AnimationDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation.FoundationDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.general.GeneralDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.layout.LayoutDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.MaterialDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.other.OtherDemos +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.ui.UIDemos + + +/** + * [DemoCategory] containing all the top level demo categories. + */ +val AllDemosCategory = DemoCategory( + "Jetpack Compose Playground Demos", + listOf( + AnimationDemos, + FoundationDemos, + LayoutDemos, + MaterialDemos, + GeneralDemos, + OtherDemos, + ActivityDemos, + UIDemos + ) +) \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Tags.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Tags.kt new file mode 100644 index 000000000..216db989c --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/demo/Tags.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.demo + +/** + * Tags used for testing + */ +object Tags { + const val AppBarTitle = "AppBarTitle" + const val FilterButton = "FilterButton" +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/activity/ActivityDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/activity/ActivityDemos.kt new file mode 100644 index 000000000..354038584 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/activity/ActivityDemos.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.activity + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.activity.backhandler.BackHandlerExample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.animation.crossfade.CrossfadeDemo + + +val ActivityDemos = DemoCategory( + "Activity", + listOf( + ComposableDemo("BackHandler") { BackHandlerExample() } + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/activity/backhandler/BackHandlerExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/activity/backhandler/BackHandlerExample.kt new file mode 100644 index 000000000..710274bc5 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/activity/backhandler/BackHandlerExample.kt @@ -0,0 +1,16 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.activity.backhandler + +import androidx.activity.compose.BackHandler +import androidx.compose.material.Text +import androidx.compose.runtime.* + +//# --8<-- [start:func] +@Composable +fun BackHandlerExample() { + var backPressedCount by remember { mutableStateOf(0) } + BackHandler(enabled = true, onBack = { + backPressedCount += 1 + }) + Text(text="Backbutton was pressed : $backPressedCount times") +} +//# --8<-- [end:func] \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/androidview/embeddedAndroidViewDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/androidview/embeddedAndroidViewDemo.kt new file mode 100644 index 000000000..7737201a2 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/androidview/embeddedAndroidViewDemo.kt @@ -0,0 +1,63 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.androidview + +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.content.ContextCompat +import de.jensklingenberg.jetpackcomposeplayground.R + + +@Preview(showBackground = true) +@Composable +fun EmbeddedAndroidViewDemo() { + Column { + val state = remember { mutableStateOf(0) } + + //widget.ImageView + AndroidView(factory = { ctx -> + ImageView(ctx).apply { + val drawable = ContextCompat.getDrawable(ctx, R.drawable.composelogo) + setImageDrawable(drawable) + } + }) + + //Compose Button + androidx.compose.material.Button(onClick = { state.value++ }) { + Text("MyComposeButton") + } + + //widget.Button + AndroidView(factory = { ctx -> + //Here you can construct your View + android.widget.Button(ctx).apply { + text = "MyAndroidButton" + layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) + setOnClickListener { + state.value++ + } + } + }, modifier = Modifier.padding(8.dp)) + + //widget.TextView + AndroidView(factory = { ctx -> + //Here you can construct your View + TextView(ctx).apply { + layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) + } + }, update = { + it.text = "You have clicked the buttons: " + state.value.toString() + " times" + }) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/animation/AnimationDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/animation/AnimationDemos.kt new file mode 100644 index 000000000..01e06a66b --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/animation/AnimationDemos.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.animation + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.animation.crossfade.CrossfadeDemo + + +val AnimationDemos = DemoCategory( + "Animation", + listOf( + ComposableDemo("CrossfadeDemo") { CrossfadeDemo() } + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/animation/crossfade/CrossfadeDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/animation/crossfade/CrossfadeDemo.kt new file mode 100644 index 000000000..50ec0ec47 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/animation/crossfade/CrossfadeDemo.kt @@ -0,0 +1,42 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.animation.crossfade + +import androidx.compose.animation.Crossfade +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + + +enum class MyColors(val color: Color) { + Red(Color.Red), Green(Color.Green), Blue(Color.Blue) +} + +@Preview(showBackground = true) +@Composable +fun CrossfadeDemo() { + var currentColor by remember { mutableStateOf(MyColors.Red) } + Column { + Row { + MyColors.values().forEach { myColors -> + Button( + onClick = { currentColor = myColors }, + Modifier.weight(1f, true) + .height(48.dp).background(myColors.color),colors = ButtonDefaults.buttonColors(backgroundColor = myColors.color) + ) { + Text(myColors.name) + } + } + } + Crossfade(targetState = currentColor, animationSpec = tween(3000)) { selectedColor -> + Box(modifier = Modifier.fillMaxSize().background(selectedColor.color)) + } + } +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/cookbook/textfieldchange/HandleTextFieldChanges.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/cookbook/textfieldchange/HandleTextFieldChanges.kt new file mode 100644 index 000000000..b2368e010 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/cookbook/textfieldchange/HandleTextFieldChanges.kt @@ -0,0 +1,20 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.cookbook.textfieldchange + + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.material.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.runtime.* + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun HandleTextFieldChanges() { + var textState by remember { mutableStateOf(TextFieldValue()) } + + TextField(value = textState, onValueChange = { + textState = it + }) +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/CanvasDrawExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/CanvasDrawExample.kt new file mode 100644 index 000000000..47f917287 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/CanvasDrawExample.kt @@ -0,0 +1,32 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview + +@Preview(showBackground = true) +@Composable +fun CanvasDrawExample() { + Canvas(modifier = Modifier.fillMaxSize()) { + drawRect(Color.Blue, topLeft = Offset(0f, 0f), size = Size(this.size.width, 55f)) + drawCircle(Color.Red, center = Offset(50f, 200f), radius = 40f) + drawLine( + Color.Green, Offset(20f, 0f), + Offset(200f, 200f), strokeWidth = 5f + ) + + drawArc( + Color.Black, + 0f, + 60f, + useCenter = true, + size = Size(300f, 300f), + topLeft = Offset(60f, 60f) + ) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/FoundationDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/FoundationDemos.kt new file mode 100644 index 000000000..888e5dd3c --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/FoundationDemos.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation.basictextfield.BasicTextFieldDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation.layout.BoxWithConstraintsDemo + + +val FoundationDemos = DemoCategory( + "Foundation", + listOf( + ComposableDemo("BaseTextFieldDemo") { BasicTextFieldDemo() }, + ComposableDemo("BoxWithConstraints") { BoxWithConstraintsDemo() }, + ComposableDemo("Canvas") { CanvasDrawExample() }, + ComposableDemo("LazyRowDemo") { LazyRowDemo() }, + ComposableDemo("LazyColumnDemo") { LazyColumnDemo() }, + ComposableDemo("LazyVerticalGridDemo") { LazyVerticalGridDemo() }, + ComposableDemo("TextDemo") { TextExample() }, + ComposableDemo("CircleShapeDemo") { ShapeDemo() }, + ComposableDemo("ImageResourceDemo") { ImageResourceDemo() }, + + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/ImageResourceDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/ImageResourceDemo.kt new file mode 100644 index 000000000..ba43c97ec --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/ImageResourceDemo.kt @@ -0,0 +1,15 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import de.jensklingenberg.jetpackcomposeplayground.R + + +@Composable +fun ImageResourceDemo() { + val image: Painter = painterResource(id = R.drawable.composelogo) + Image(painter = image,contentDescription = "") +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyColumnDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyColumnDemo.kt new file mode 100644 index 000000000..f7806ba4d --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyColumnDemo.kt @@ -0,0 +1,48 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + +import android.util.Log +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.shape.RoundedCornerShape + +import androidx.compose.material.Button +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp + +@Composable +fun LazyColumnDemo() { + val list = listOf( + "A", "B", "C", "D" + ) + ((0..100).map { it.toString() }) + LazyColumn(modifier = Modifier.fillMaxHeight()) { + items(items = list, itemContent = { item -> + Log.d("COMPOSE", "This get rendered $item") + when (item) { + "A" -> { + Text(text = item, style = TextStyle(fontSize = 80.sp)) + } + "B" -> { + Button(onClick = {}) { + Text(text = item, style = TextStyle(fontSize = 80.sp)) + } + } + "C" -> { + //Do Nothing + } + "D" -> { + Text(text = item) + } + else -> { + Text(text = item, style = TextStyle(fontSize = 80.sp)) + } + } + }) + } +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyRowDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyRowDemo.kt new file mode 100644 index 000000000..5cf72114c --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyRowDemo.kt @@ -0,0 +1,48 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + +import android.util.Log +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.shape.RoundedCornerShape + +import androidx.compose.material.Button +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp + +@Composable +fun LazyRowDemo() { + val list = listOf( + "A", "B", "C", "D" + ) + ((0..100).map { it.toString() }) + LazyRow(modifier = Modifier.fillMaxHeight()) { + items(items = list, itemContent = { item -> + Log.d("COMPOSE", "This get rendered $item") + when (item) { + "A" -> { + Text(text = item, style = TextStyle(fontSize = 80.sp)) + } + "B" -> { + Button(onClick = {}) { + Text(text = item, style = TextStyle(fontSize = 80.sp)) + } + } + "C" -> { + //Do Nothing + } + "D" -> { + Text(text = item) + } + else -> { + Text(text = item, style = TextStyle(fontSize = 80.sp)) + } + } + }) + } +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyVerticalGridDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyVerticalGridDemo.kt new file mode 100644 index 000000000..7cde3bd29 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/LazyVerticalGridDemo.kt @@ -0,0 +1,53 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun LazyVerticalGridDemo(){ + val list = (1..10).map { it.toString() } + + LazyVerticalGrid( + columns = GridCells.Adaptive(128.dp), + + // content padding + contentPadding = PaddingValues( + start = 12.dp, + top = 16.dp, + end = 12.dp, + bottom = 16.dp + ), + content = { + items(list.size) { index -> + Card( + backgroundColor = Color.Red, + modifier = Modifier + .padding(4.dp) + .fillMaxWidth(), + elevation = 8.dp, + ) { + Text( + text = list[index], + fontWeight = FontWeight.Bold, + fontSize = 30.sp, + color = Color(0xFFFFFFFF), + textAlign = TextAlign.Center, + modifier = Modifier.padding(16.dp) + ) + } + } + } + ) +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/ShapeDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/ShapeDemo.kt new file mode 100644 index 000000000..1d71a1e7d --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/ShapeDemo.kt @@ -0,0 +1,183 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.CutCornerShape +import androidx.compose.foundation.shape.GenericShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.dp +import androidx.compose.foundation.layout.* +import androidx.compose.material.Text +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.LayoutDirection + +@Composable +fun CircleShapeDemo() { + BoxDemo(CircleShape) +} + +@Composable +fun ShapeDemo() { + Column { + Text("CircleShapeDemo:") + CircleShapeDemo() + Text("RoundedCornerShapeDemo:") + RoundedCornerShapeDemo() + Text("CutCornerShapeDemo:") + CutCornerShapeDemo() + Text("RectangleShapeDemo:") + RectangleShapeDemo() + Text("TriangleShapeDemo:") + TriangleShapeDemo() + } + + +} + +@Composable +fun BoxDemo(shape: Shape) { + Column(modifier = Modifier.fillMaxWidth().wrapContentSize(Alignment.Center).clip(shape)) { + Box( + modifier = Modifier.size(100.dp).background(Color.Red) + ) { + + } + } +} + +@Composable +fun RoundedCornerShapeDemo() { + BoxDemo(shape = RoundedCornerShape(10.dp)) +} + +@Composable +fun CutCornerShapeDemo() { + BoxDemo(shape = CutCornerShape(10.dp)) +} + + +@Composable +fun RectangleShapeDemo() { + BoxDemo(shape = RectangleShape) +} + +@Composable +fun TriangleShapeDemo() { + BoxDemo(shape = CustomShape()) +} + + +/** + * You can draw custom shapes. + * Use a GenericShape. + */ + + +private val TriangleShape = GenericShape { size, direction -> + /** + * + Inside the GenericShape you can draw your custom shape. + You have access to the **size**-object. This is size of the composable that the shape is applied to. + You can get the height with **size.height.value** and the width with **size.width.value** + + + 1) Initially the painter will start at the top left of the parent composable(0x,0y). + With **moveTo()** you can set the coordinates of the painter. Here the coordinates will be set to the half width of the parent layout + and a 0y coordinate. + + 2) This will draw a line from the painter coordinates, which were set in **1)**, to the bottom right corner of the parent layout. + The painter coordinates are then automatically set to this corner. + + 3) This will draw a line to the bottom left corner. GenericShape will implicit execute the **close()**-function. **close()** will draw a line from the last painter coordinates to the first definied. + */ + + /** + * 1) + */ + /** + * + Inside the GenericShape you can draw your custom shape. + You have access to the **size**-object. This is size of the composable that the shape is applied to. + You can get the height with **size.height.value** and the width with **size.width.value** + + + 1) Initially the painter will start at the top left of the parent composable(0x,0y). + With **moveTo()** you can set the coordinates of the painter. Here the coordinates will be set to the half width of the parent layout + and a 0y coordinate. + + 2) This will draw a line from the painter coordinates, which were set in **1)**, to the bottom right corner of the parent layout. + The painter coordinates are then automatically set to this corner. + + 3) This will draw a line to the bottom left corner. GenericShape will implicit execute the **close()**-function. **close()** will draw a line from the last painter coordinates to the first definied. + */ + + + /** + * 1) + */ + moveTo(size.width / 2f, 0f) + //This will draw a line from the cursor to the x/y coordinates + + /** + * 2) + */ + + /** + * 2) + */ + lineTo(size.width, size.height) + + /** + * 3) + */ + + /** + * 3) + */ + lineTo(0f, size.height) +} + + +class CustomShape : Shape { + + + override fun createOutline( + size: Size, + layoutDirection: LayoutDirection, + density: Density + ): Outline { + val path = Path().apply { + moveTo(size.width / 2f, 0f) + lineTo(size.width, size.height) + lineTo(0f, size.height) + close() + } + return Outline.Generic(path) + + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/TextExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/TextExample.kt new file mode 100644 index 000000000..cc3b0ab15 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/TextExample.kt @@ -0,0 +1,80 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation + + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration + +@Composable +fun TextExample(){ + Column { + Text("Just Text") + Text("Text with cursive font", style = TextStyle(fontFamily = FontFamily.Cursive)) + Text( + text = "Text with LineThrough", + style = TextStyle(textDecoration = TextDecoration.LineThrough) + ) + Text( + text = "Text with underline", + style = TextStyle(textDecoration = TextDecoration.Underline) + ) + Text( + text = "Text with underline, linethrough and bold", + style = TextStyle( + textDecoration = TextDecoration.combine( + listOf( + TextDecoration.Underline, + TextDecoration.LineThrough + ) + ), fontWeight = FontWeight.Bold + ) + ) + } +} + + +@Composable +fun NormalTextExample(){ + Text("Just Text") +} + +@Composable +fun CursiveTextExample(){ + Text("Text with cursive font", style = TextStyle(fontFamily = FontFamily.Cursive)) +} + +@Composable +fun TextWithLineThroughExample(){ + Text( + text = "Text with LineThrough", + style = TextStyle(textDecoration = TextDecoration.LineThrough) + ) +} + +@Composable +fun TextWithUnderline(){ + Text( + text = "Text with underline", + style = TextStyle(textDecoration = TextDecoration.Underline) + ) +} + + +@Composable +fun TextWithUnderlineStrikeThroughAndBold(){ + Text( + text = "Text with underline, linethrough and bold", + style = TextStyle( + textDecoration = TextDecoration.combine( + listOf( + TextDecoration.Underline, + TextDecoration.LineThrough + ) + ), fontWeight = FontWeight.Bold + ) + ) +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/basictextfield/BasicTextFieldDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/basictextfield/BasicTextFieldDemo.kt new file mode 100644 index 000000000..410a42632 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/basictextfield/BasicTextFieldDemo.kt @@ -0,0 +1,21 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation.basictextfield + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.text.input.TextFieldValue + +//# --8<-- [start:func] +@Composable +fun BasicTextFieldDemo() { + var textState by remember { mutableStateOf(TextFieldValue("Hello World")) } + Column { + BasicTextField(value = textState, onValueChange = { + textState = it + }) + Text("The textfield has this text: " + textState.text) + } +} +//# --8<-- [end:func] \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/layout/BoxWithConstraintsExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/layout/BoxWithConstraintsExample.kt new file mode 100644 index 000000000..d5198c4bb --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/layout/BoxWithConstraintsExample.kt @@ -0,0 +1,41 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation.layout + +import androidx.compose.foundation.layout.* +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun BoxWithConstraintsDemo() { + Column { + Column { + MyBoxWithConstraintsDemo() + } + + Text("Here we set the size to 150.dp", modifier = Modifier.padding(top = 20.dp)) + Column(modifier = Modifier.size(150.dp)) { + MyBoxWithConstraintsDemo() + } + } +} + +@Composable +private fun MyBoxWithConstraintsDemo() { + BoxWithConstraints { + val boxWithConstraintsScope = this + //You can use this scope to get the minWidth, maxWidth, minHeight, maxHeight in dp and constraints + + Column { + if (boxWithConstraintsScope.maxHeight >= 200.dp) { + Text( + "This is only visible when the maxHeight is >= 200.dp", + style = TextStyle(fontSize = 20.sp) + ) + } + Text("minHeight: ${boxWithConstraintsScope.minHeight}, maxHeight: ${boxWithConstraintsScope.maxHeight}, minWidth: ${boxWithConstraintsScope.minWidth} maxWidth: ${boxWithConstraintsScope.maxWidth}") + } + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/layout/SpacerDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/layout/SpacerDemo.kt new file mode 100644 index 000000000..49ee5cfaf --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/foundation/layout/SpacerDemo.kt @@ -0,0 +1,21 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.foundation.layout + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SpacerDemo() { + Column { + Text("Hello") + Spacer( + modifier = Modifier + .size(30.dp) + ) + Text("World") + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/CompositionLocalExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/CompositionLocalExample.kt new file mode 100644 index 000000000..73e5a4b03 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/CompositionLocalExample.kt @@ -0,0 +1,43 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.general + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf + + +data class User(val name: String, val age: Int) + +val LocalActiveUser = compositionLocalOf { error("No user found!") } + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + MyUserScreen() + } + } +} + +@Composable +private fun MyUserScreen() { + val user = User("Jens", 31) + CompositionLocalProvider(LocalActiveUser provides user) { + UserInfo() + } +} + + +@Composable +fun UserInfo() { + Column { + Text("Name: " + LocalActiveUser.current.name) + Text("Age: " + LocalActiveUser.current.age) + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/GeneralDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/GeneralDemos.kt new file mode 100644 index 000000000..6c045d448 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/GeneralDemos.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.general + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory + + +val GeneralDemos = DemoCategory( + "General", + listOf( + ComposableDemo("LifecycleDemo") { LifecycleDemo() }, + ComposableDemo("PaddingDemo") { PaddingDemo() }, + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/LifecycleDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/LifecycleDemo.kt new file mode 100644 index 000000000..44feaefd5 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/LifecycleDemo.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.general + + +import android.util.Log +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.* + + +@Composable +fun LifecycleDemo() { + + val count = remember { mutableStateOf(0) } + + Column { + Button(onClick = { + count.value++ + }) { + Text("Click me") + } + + if (count.value < 3) { + SideEffect { + Log.d("Compose", "onactive with value: " + count.value) + } + DisposableEffect(Unit) { + onDispose { + Log.d("Compose", "onDispose because value=" + count.value) + } + } + + Text(text = "You have clicked the button: " + count.value.toString()) + } + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/PaddingDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/PaddingDemo.kt new file mode 100644 index 000000000..50c50e1ef --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/general/PaddingDemo.kt @@ -0,0 +1,29 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.general + + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + + +@Composable +fun PaddingDemo() { + + Column { + Text("TextWithoutPadding") + Column(modifier = Modifier.padding(start = 80.dp)){ + Text("TextWith80dpOnlyLeftPadding") + + } + + + Column(Modifier.padding(all = 80.dp)){ + Text("TextWith80dpPadding") + } + + } + +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/BoxExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/BoxExample.kt new file mode 100644 index 000000000..5f5e1f1b8 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/BoxExample.kt @@ -0,0 +1,35 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.layout + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.FloatingActionButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + + +@Preview(showBackground = true) +//# --8<-- [start:func] +@Composable +fun BoxExample() { + Box(Modifier.fillMaxSize()) { + Text("This text is drawn first", modifier = Modifier.align(Alignment.TopCenter)) + Box( + Modifier.align(Alignment.TopCenter).fillMaxHeight().width( + 50.dp + ).background( Color.Blue) + ) + Text("This text is drawn last", modifier = Modifier.align(Alignment.Center)) + FloatingActionButton( + modifier = Modifier.align(Alignment.BottomEnd).padding(12.dp), + onClick = {} + ) { + Text("+") + } + } +} +//# --8<-- [end:func] \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/ColumnExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/ColumnExample.kt new file mode 100644 index 000000000..8cc09f636 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/ColumnExample.kt @@ -0,0 +1,30 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.layout + + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable + + + + +@Composable +fun ColumnDemo() { + + MaterialTheme { + ColumnExample() + } + +} + +@Composable +fun ColumnExample() { + + Column { + Text(text = " Hello World!") + Text(text = " Hello World!2") + } + + +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/ConstraintLayoutDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/ConstraintLayoutDemo.kt new file mode 100644 index 000000000..96652122e --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/ConstraintLayoutDemo.kt @@ -0,0 +1,47 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.layout + + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ConstraintLayout + + +@Composable +fun ConstraintLayoutDemo() { + ConstraintLayout(modifier = Modifier.size(200.dp)) { + val (redBox, blueBox, yellowBox, text) = createRefs() + + Box(modifier = Modifier + .size(50.dp) + .background(Color.Red) + .constrainAs(redBox) {}) + + Box(modifier = Modifier + .size(50.dp) + .background(Color.Blue) + .constrainAs(blueBox) { + top.linkTo(redBox.bottom) + start.linkTo(redBox.end) + }) + + Box(modifier = Modifier + .size(50.dp) + .background(Color.Yellow) + .constrainAs(yellowBox) { + bottom.linkTo(blueBox.bottom) + start.linkTo(blueBox.end, 20.dp) + }) + + Text("Hello World", modifier = Modifier.constrainAs(text) { + top.linkTo(parent.top) + start.linkTo(yellowBox.start) + }) + + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/LayoutDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/LayoutDemos.kt new file mode 100644 index 000000000..ef9fc46af --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/LayoutDemos.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.layout + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory + + +val LayoutDemos = DemoCategory( + "LayoutDemos", + listOf( + ComposableDemo("BoxExample") { BoxExample() }, + ComposableDemo("ConstraintLayoutDemo") { ConstraintLayoutDemo() }, + + ComposableDemo("ColumnExample") { ColumnExample() }, + ComposableDemo("RowExample") { RowExample() }, + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/RowExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/RowExample.kt new file mode 100644 index 000000000..73bd0ad9f --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/layout/RowExample.kt @@ -0,0 +1,23 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.layout + +import androidx.compose.foundation.layout.Row +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable + + +@Composable +fun RowDemo() { + MaterialTheme { + RowExample() + } + +} + +@Composable +fun RowExample() { + Row { + Text(text = " Hello World!", style = (MaterialTheme.typography).body1) + Text(text = " Hello World!2", style = (MaterialTheme.typography).body1) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/MaterialDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/MaterialDemos.kt new file mode 100644 index 000000000..de936d1a7 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/MaterialDemos.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material + + +import SnackbarDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.button.ButtonExample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.card.CardDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.checkbox.CheckBoxDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.circularprogress.CircularProgressIndicatorSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.dropdown.DropdownDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.floatingactionbutton.FloatingActionButtonDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.linearprogress.LinearProgressIndicatorSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.modaldrawer.ModalDrawerSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.radiobutton.RadioButtonSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.alertdialog.AlertDialogSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.appbar.topappbar.TopAppBarSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.button.ProgressButtonExample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.divider.DividerExample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.modalbottomsheetlayout.ModalBottomSheetSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.navigationrail.NavigationRailSample +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.scaffold.ScaffoldDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.surface.SurfaceDemo + + +val MaterialDemos = DemoCategory( + "MaterialDemos", + listOf( + ComposableDemo("AlertDialogSample") { AlertDialogSample() }, + ComposableDemo("ButtonExample") { ButtonExample() }, + ComposableDemo("ProgressButtonExample") { ProgressButtonExample() }, + ComposableDemo("CardDemo") { CardDemo() }, + ComposableDemo("CheckBoxDemo") { CheckBoxDemo() }, + ComposableDemo("CircularProgressIndicatorSample") { CircularProgressIndicatorSample() }, + ComposableDemo("Divider") { DividerExample() }, + ComposableDemo("DropdownDemo") { DropdownDemo() }, + ComposableDemo("FloatingActionButtonDemo") { FloatingActionButtonDemo() }, + ComposableDemo("LinearProgressIndicatorSample") { LinearProgressIndicatorSample() }, + ComposableDemo("ModalBottomSheetSample") { ModalBottomSheetSample() }, + ComposableDemo("ModalDrawerLayoutSample") { ModalDrawerSample() }, + ComposableDemo("NavigationRailSample") { NavigationRailSample() }, + ComposableDemo("RadioButtonSample") { RadioButtonSample() }, + ComposableDemo("ScaffoldDemo") { ScaffoldDemo() }, + ComposableDemo("SnackbarDemo") { SnackbarDemo() }, + ComposableDemo("SurfaceDemo") { SurfaceDemo() }, + ComposableDemo("TopAppBarSample") { TopAppBarSample() }, + + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/alertdialog/AlertDialogSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/alertdialog/AlertDialogSample.kt new file mode 100644 index 000000000..cd207555d --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/alertdialog/AlertDialogSample.kt @@ -0,0 +1,61 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.alertdialog + + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember + + +@Composable +fun AlertDialogSample() { + MaterialTheme { + Column { + val openDialog = remember { mutableStateOf(false) } + + Button(onClick = { + openDialog.value = true + }) { + Text("Click me") + } + + if (openDialog.value) { + + AlertDialog( + onDismissRequest = { + // Dismiss the dialog when the user clicks outside the dialog or on the back + // button. If you want to disable that functionality, simply use an empty + // onCloseRequest. + openDialog.value = false + }, + title = { + Text(text = "Dialog Title") + }, + text = { + Text("Here is a text ") + }, + confirmButton = { + Button( + + onClick = { + openDialog.value = false + }) { + Text("This is the Confirm Button") + } + }, + dismissButton = { + Button( + + onClick = { + openDialog.value = false + }) { + Text("This is the dismiss Button") + } + } + ) + } + } + + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/appbar/topappbar/TopAppBarSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/appbar/topappbar/TopAppBarSample.kt new file mode 100644 index 000000000..ebe4e233f --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/appbar/topappbar/TopAppBarSample.kt @@ -0,0 +1,37 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.appbar.topappbar + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.Share +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp + +@Composable +fun TopAppBarSample(){ + Column { + TopAppBar( + elevation = 4.dp, + title = { + Text("I'm a TopAppBar") + }, + backgroundColor = MaterialTheme.colors.primarySurface, + navigationIcon = { + IconButton(onClick = {/* Do Something*/ }) { + Icon(Icons.Filled.ArrowBack, null) + } + }, actions = { + IconButton(onClick = {/* Do Something*/ }) { + Icon(Icons.Filled.Share, null) + } + IconButton(onClick = {/* Do Something*/ }) { + Icon(Icons.Filled.Settings, null) + } + }) + + Text("Hello World") + + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/badgebox/BadgeBoxDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/badgebox/BadgeBoxDemo.kt new file mode 100644 index 000000000..0a2e321ea --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/badgebox/BadgeBoxDemo.kt @@ -0,0 +1,27 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.badgebox + +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview + +@OptIn(ExperimentalMaterialApi::class) +@Preview +@Composable +fun BadgeBoxDemo() { + BottomNavigation { + BottomNavigationItem( + icon = { + BadgedBox(badge = { Badge { Text("8") } }) { + Icon( + Icons.Filled.Favorite, + contentDescription = "Favorite" + ) + } + + }, + selected = false, + onClick = {}) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/button/ButtonExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/button/ButtonExample.kt new file mode 100644 index 000000000..030034e06 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/button/ButtonExample.kt @@ -0,0 +1,102 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.button + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.material.OutlinedButton +import androidx.compose.material.R +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.unit.dp + +@Composable +fun ButtonExample() { + Button( + onClick = { /* Do something! */ }, colors = ButtonDefaults.textButtonColors( + backgroundColor = Color.Red + ) + ) { + Text("Button") + } +} + +@Composable +fun OutlinedButtonExample() { + OutlinedButton(onClick = { /* Do something! */ }) { + Text("I'm an Outlined Button") + } +} + +@Composable +fun TextButtonExample() { + TextButton(onClick = { /* Do something! */ }) { + Text("I'm a Text Button") + } +} + + +@Composable +fun ProgressButtonExample() { + var loading by remember { + mutableStateOf(false) + } + Box() { + ProgressButton( + onClick = { loading = !loading }, + modifier = Modifier + .padding(16.dp) + .height(46.dp) + .align(Alignment.Center), + loading = loading, + color = Color.Black, + progressColor = Color.White + ) { + Text( + color = Color.White, + text = "Refresh" + ) + } + } +} + +@Composable +fun ProgressButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + loading: Boolean = false, + color: Color, + progressColor: Color, + content: @Composable () -> Unit, +) { + val contentAlpha by animateFloatAsState(targetValue = if (loading) 0f else 1f) + val loadingAlpha by animateFloatAsState(targetValue = if (loading) 1f else 0f) + Button( + onClick = onClick, + modifier = modifier, + colors = ButtonDefaults.buttonColors(backgroundColor = color), + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + contentAlignment = Alignment.Center, + ) { + CircularProgressIndicator( + modifier = Modifier + .size(size = 16.dp) + .graphicsLayer { alpha = loadingAlpha }, + color = progressColor, + strokeWidth = 2.dp, + ) + Box( + modifier = Modifier.graphicsLayer { alpha = contentAlpha } + ) { + content() + } + } + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/card/CardDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/card/CardDemo.kt new file mode 100644 index 000000000..023a86c92 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/card/CardDemo.kt @@ -0,0 +1,50 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.card + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp + +@Composable +fun CardDemo() { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(15.dp) + .clickable{ }, + elevation = 10.dp + ) { + Column( + modifier = Modifier.padding(15.dp) + ) { + Text( + buildAnnotatedString { + append("welcome to ") + withStyle(style = SpanStyle(fontWeight = FontWeight.W900, color = Color(0xFF4552B8)) + ) { + append("Jetpack Compose Playground") + } + } + ) + Text( + buildAnnotatedString { + append("Now you are in the ") + withStyle(style = SpanStyle(fontWeight = FontWeight.W900)) { + append("Card") + } + append(" section") + } + ) + } + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/checkbox/CheckBoxDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/checkbox/CheckBoxDemo.kt new file mode 100644 index 000000000..7334bae06 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/checkbox/CheckBoxDemo.kt @@ -0,0 +1,16 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.checkbox + +import androidx.compose.material.Checkbox +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember + +@Composable +fun CheckBoxDemo() { + val checkedState = remember { mutableStateOf(true) } + Checkbox( + checked = checkedState.value, + onCheckedChange = { checkedState.value = it } + ) +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/circularprogress/CircularProgressIndicatorSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/circularprogress/CircularProgressIndicatorSample.kt new file mode 100644 index 000000000..90d295ca9 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/circularprogress/CircularProgressIndicatorSample.kt @@ -0,0 +1,49 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.circularprogress + + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.OutlinedButton +import androidx.compose.material.ProgressIndicatorDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun CircularProgressIndicatorSample() { + var progress by remember { mutableStateOf(0.1f) } + val animatedProgress = animateFloatAsState( + targetValue = progress, + animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec + ).value + + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Spacer(Modifier.height(30.dp)) + Text("CircularProgressIndicator with undefined progress") + CircularProgressIndicator() + Spacer(Modifier.height(30.dp)) + Text("CircularProgressIndicator with progress set by buttons") + CircularProgressIndicator(progress = animatedProgress) + Spacer(Modifier.height(30.dp)) + OutlinedButton( + onClick = { + if (progress < 1f) progress += 0.1f + } + ) { + Text("Increase") + } + + OutlinedButton( + onClick = { + if (progress > 0f) progress -= 0.1f + } + ) { + Text("Decrease") + } + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/divider/DividerDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/divider/DividerDemo.kt new file mode 100644 index 000000000..36b9985b1 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/divider/DividerDemo.kt @@ -0,0 +1,19 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.divider + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Preview +@Composable +fun DividerExample(){ + Column { + Text("Foo") + Divider(startIndent = 8.dp, thickness = 1.dp, color = Color.Black) + Text("Bar") + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/dropdown/DropdownDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/dropdown/DropdownDemo.kt new file mode 100644 index 000000000..fe4178e77 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/dropdown/DropdownDemo.kt @@ -0,0 +1,49 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.dropdown + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview + +@Preview +@Composable +fun DropdownDemo() { + var expanded by remember { mutableStateOf(false) } + val items = listOf("A", "B", "C", "D", "E", "F") + val disabledValue = "B" + var selectedIndex by remember { mutableStateOf(0) } + Box(modifier = Modifier.fillMaxSize().wrapContentSize(Alignment.TopStart)) { + Text(items[selectedIndex],modifier = Modifier.fillMaxWidth().clickable(onClick = { expanded = true }).background( + Color.Gray)) + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.fillMaxWidth().background( + Color.Red) + ) { + items.forEachIndexed { index, s -> + DropdownMenuItem(onClick = { + selectedIndex = index + expanded = false + }) { + val disabledText = if (s == disabledValue) { + " (Disabled)" + } else { + "" + } + Text(text = s + disabledText) + } + } + } + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/floatingactionbutton/FabDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/floatingactionbutton/FabDemo.kt new file mode 100644 index 000000000..fe9fa3e54 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/floatingactionbutton/FabDemo.kt @@ -0,0 +1,25 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.floatingactionbutton + +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp + +@Composable +fun FloatingActionButtonDemo() { + FloatingActionButton(onClick = { /*do something*/}) { + Text("FloatingActionButton") + } +} + +@Composable +fun ExtendedFloatingActionButtonDemo() { + ExtendedFloatingActionButton( + icon = { Icon(Icons.Filled.Favorite,"") }, + text = { Text("FloatingActionButton") }, + onClick = { /*do something*/ }, + elevation = FloatingActionButtonDefaults.elevation(8.dp) + ) +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/linearprogress/LinearProgressIndicatorSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/linearprogress/LinearProgressIndicatorSample.kt new file mode 100644 index 000000000..c59a6c42e --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/linearprogress/LinearProgressIndicatorSample.kt @@ -0,0 +1,47 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.linearprogress + +import androidx.compose.animation.core.animateFloatAsState + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun LinearProgressIndicatorSample() { + var progress by remember { mutableStateOf(0.1f) } + val animatedProgress = animateFloatAsState( + targetValue = progress, + animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec + ).value + + Column(horizontalAlignment = Alignment.CenterHorizontally) { + + Spacer(Modifier.height(30.dp)) + Text("LinearProgressIndicator with undefined progress") + LinearProgressIndicator() + Spacer(Modifier.height(30.dp)) + Text("LinearProgressIndicator with progress set by buttons") + LinearProgressIndicator(progress = animatedProgress) + Spacer(Modifier.height(30.dp)) + OutlinedButton( + onClick = { + if (progress < 1f) progress += 0.1f + } + ) { + Text("Increase") + } + + OutlinedButton( + onClick = { + if (progress > 0f) progress -= 0.1f + } + ) { + Text("Decrease") + } + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/modalbottomsheetlayout/ModalBottomSheetLayout.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/modalbottomsheetlayout/ModalBottomSheetLayout.kt new file mode 100644 index 000000000..487fcd20b --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/modalbottomsheetlayout/ModalBottomSheetLayout.kt @@ -0,0 +1,50 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.modalbottomsheetlayout + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch + + +@Composable +@OptIn(ExperimentalMaterialApi::class) +fun ModalBottomSheetSample() { + val state = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden) + val scope = rememberCoroutineScope() + ModalBottomSheetLayout( + sheetState = state, + sheetContent = { + LazyColumn { + items(50) { + ListItem( + text = { Text("Item $it") }, + icon = { + Icon( + Icons.Default.Favorite, + contentDescription = "Localized description" + ) + } + ) + } + } + } + ) { + Column( + modifier = Modifier.fillMaxSize().padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Rest of the UI") + Spacer(Modifier.height(20.dp)) + Button(onClick = { scope.launch { state.show() } }) { + Text("Click to show sheet") + } + } + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/modaldrawer/ModalDrawerSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/modaldrawer/ModalDrawerSample.kt new file mode 100644 index 000000000..d96525e6a --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/modaldrawer/ModalDrawerSample.kt @@ -0,0 +1,43 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.modaldrawer + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import kotlinx.coroutines.launch + +@Composable +fun ModalDrawerSample() { + val drawerState = rememberDrawerState(DrawerValue.Closed) + val scope = rememberCoroutineScope() + + ModalDrawer( + drawerState = drawerState, + drawerContent = { + Column { + Text("Text in Drawer") + Button(onClick = { + scope.launch { + drawerState.close() + } + }) { + Text("Close Drawer") + } + } + }, + content = { + Column { + Text("Text in Bodycontext") + Button(onClick = { + + scope.launch { + drawerState.open() + } + + }) { + Text("Click to open") + } + } + } + ) +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/navigationrail/NavigationRailSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/navigationrail/NavigationRailSample.kt new file mode 100644 index 000000000..648fd1c5a --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/navigationrail/NavigationRailSample.kt @@ -0,0 +1,63 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.navigationrail + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Icon +import androidx.compose.material.NavigationRail +import androidx.compose.material.NavigationRailItem +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home +import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.filled.Settings +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.dp + +enum class Page(val title:String, val content: String){ + HOME("home","Show only icon"), + SEARCH("Search","Show icon with label"), + SETTINGS("Settings","Show icon /Show the label only when selected") +} + +@Composable +fun NavigationRailSample() { + var selectedItem by remember { mutableStateOf(0) } + val pages = Page.values() + val icons = listOf(Icons.Filled.Home, Icons.Filled.Search, Icons.Filled.Settings) + Row { + NavigationRail { + pages.forEachIndexed { index, item -> + when(item){ + Page.HOME -> { + NavigationRailItem( + icon = { Icon(icons[index], contentDescription = "") }, + selected = selectedItem == index, + onClick = { selectedItem = index } + ) + } + Page.SEARCH -> { + NavigationRailItem( + label = { Text(item.title) }, + icon = { Icon(icons[index], contentDescription = "") }, + selected = selectedItem == index, + onClick = { selectedItem = index } + ) + } + Page.SETTINGS -> { + NavigationRailItem( + label = { Text(item.title) }, + icon = { Icon(icons[index], contentDescription = "") }, + selected = selectedItem == index, + onClick = { selectedItem = index }, + alwaysShowLabel = false + ) + } + } + } + } + + Text(pages[selectedItem].content, Modifier.padding(start = 8.dp)) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/radiobutton/RadioButtonSample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/radiobutton/RadioButtonSample.kt new file mode 100644 index 000000000..1352548be --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/radiobutton/RadioButtonSample.kt @@ -0,0 +1,49 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.radiobutton + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.selectable +import androidx.compose.material.MaterialTheme +import androidx.compose.material.RadioButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember + +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + + +@Composable +fun RadioButtonSample() { + val radioOptions = listOf("A", "B", "C") + val (selectedOption, onOptionSelected) = remember { mutableStateOf(radioOptions[1] ) } + Column { + radioOptions.forEach { text -> + Row( + Modifier + .fillMaxWidth() + .selectable( + selected = (text == selectedOption), + onClick = { + onOptionSelected + (text) + } + ) + .padding(horizontal = 16.dp) + ) { + RadioButton( + selected = (text == selectedOption), + onClick = { onOptionSelected(text) } + ) + Text( + text = text, + style = MaterialTheme.typography.body1.merge(), + modifier = Modifier.padding(start = 16.dp) + ) + } + } + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/scaffold/ScaffoldDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/scaffold/ScaffoldDemo.kt new file mode 100644 index 000000000..79f708416 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/scaffold/ScaffoldDemo.kt @@ -0,0 +1,26 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.scaffold + +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + + +@Composable +fun ScaffoldDemo() { + val materialBlue700= Color(0xFF1976D2) + val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Open)) + Scaffold( + scaffoldState = scaffoldState, + topBar = { TopAppBar(title = {Text("TopAppBar")},backgroundColor = materialBlue700) }, + floatingActionButtonPosition = FabPosition.End, + floatingActionButton = { FloatingActionButton(onClick = {}){ + Text("X") + } }, + drawerContent = { Text(text = "drawerContent") }, + content = { + + Text("BodyContent") }, + bottomBar = { BottomAppBar(backgroundColor = materialBlue700) { Text("BottomAppBar") } } + ) +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/slider/MySliderDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/slider/MySliderDemo.kt new file mode 100644 index 000000000..b615f2300 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/slider/MySliderDemo.kt @@ -0,0 +1,11 @@ + +import androidx.compose.material.Slider +import androidx.compose.material.Text +import androidx.compose.runtime.* + +@Composable +fun MySliderDemo() { + var sliderPosition by remember { mutableStateOf(0f) } + Text(text = sliderPosition.toString()) + Slider(value = sliderPosition, onValueChange = { sliderPosition = it }) +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/snackbar/SnackbarDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/snackbar/SnackbarDemo.kt new file mode 100644 index 000000000..0b1bedbbd --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/snackbar/SnackbarDemo.kt @@ -0,0 +1,37 @@ +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.Snackbar +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SnackbarDemo() { + Column { + val (snackbarVisibleState, setSnackBarState) = remember { mutableStateOf(false) } + + Button(onClick = { setSnackBarState(!snackbarVisibleState) }) { + if (snackbarVisibleState) { + Text("Hide Snackbar") + } else { + Text("Show Snackbar") + } + } + if (snackbarVisibleState) { + Snackbar( + + action = { + Button(onClick = {}) { + Text("MyAction") + } + }, + modifier = Modifier.padding(8.dp) + ) { Text(text = "This is a snackbar!") } + } + } +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/surface/SurfaceDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/surface/SurfaceDemo.kt new file mode 100644 index 000000000..14235b9bc --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/surface/SurfaceDemo.kt @@ -0,0 +1,24 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.surface + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun SurfaceDemo() { + Surface( + modifier = Modifier.padding(8.dp), + border = BorderStroke(2.dp, Color.Red), + contentColor = Color.Blue, + elevation = 8.dp, + shape = CircleShape + ) { + Text("Hello World", modifier = Modifier.padding(8.dp)) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/switch/SwitchDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/switch/SwitchDemo.kt new file mode 100644 index 000000000..25713ecc1 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/switch/SwitchDemo.kt @@ -0,0 +1,21 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.switch + +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Switch +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember + + + +@Composable +fun SwitchDemo() { + MaterialTheme { + val checkedState = remember { mutableStateOf(true) } + Switch( + checked = checkedState.value, + onCheckedChange = { checkedState.value = it } + ) + } +} + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/textfield/TextFieldDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/textfield/TextFieldDemo.kt new file mode 100644 index 000000000..4a79dc5c4 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/material/textfield/TextFieldDemo.kt @@ -0,0 +1,25 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.material.textfield + + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.runtime.* +import androidx.compose.ui.unit.dp +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.TextFieldValue + +@Composable +fun TextFieldDemo() { + Column(Modifier.padding(16.dp)) { + val textState = remember { mutableStateOf(TextFieldValue()) } + TextField( + value = textState.value, + onValueChange = { textState.value = it } + ) + Text("The textfield has this text: " + textState.value.text) + } +} + + diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/AndroidContextComposeDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/AndroidContextComposeDemo.kt new file mode 100644 index 000000000..1837b1b48 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/AndroidContextComposeDemo.kt @@ -0,0 +1,16 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.other + +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import de.jensklingenberg.jetpackcomposeplayground.R + + +@Composable +fun AndroidContextComposeDemo() { + MaterialTheme { + val context = LocalContext.current + Text(text = "Read this string from Context: "+context.getString(R.string.app_name)) + } +} diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/GeneralDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/GeneralDemos.kt new file mode 100644 index 000000000..ff5bd4417 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/GeneralDemos.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.other + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory + + +val OtherDemos = DemoCategory( + "Other", + listOf( + ComposableDemo("TextFieldDemo") { TextFieldDemo() }, + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/TextFieldDemo.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/TextFieldDemo.kt new file mode 100644 index 000000000..1bdbe1cf2 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/other/TextFieldDemo.kt @@ -0,0 +1,20 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.other + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.input.TextFieldValue + + +@Composable +fun TextFieldDemo() { + Column { + var state = TextFieldValue("") + BasicTextField( + value = state, + onValueChange = {value-> state= value } + ) + Text("The textfield has this text: "+state) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/testing/TestLayout.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/testing/TestLayout.kt new file mode 100644 index 000000000..d99926ce8 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/testing/TestLayout.kt @@ -0,0 +1,17 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.testing + +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag + +@Composable +fun TestingExample() { + val state = remember { mutableStateOf("Hello") } + Button(onClick = { state.value = "Bye" }, modifier = Modifier.testTag("MyTestTag")) { + Text(state.value) + } +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/ui/UiDemos.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/ui/UiDemos.kt new file mode 100644 index 000000000..c606c70e7 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/ui/UiDemos.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.ui + + +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.ComposableDemo +import de.jensklingenberg.jetpackcomposeplayground.mysamples.demo.DemoCategory +import de.jensklingenberg.jetpackcomposeplayground.mysamples.github.ui.layout.SubComposeLayoutDemo + + +val UIDemos = DemoCategory( + "UIDemos", + listOf( + ComposableDemo("SubComposeLayoutDemo") { SubComposeLayoutDemo() }, + ) +) diff --git a/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/ui/layout/SubComposeLayoutExample.kt b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/ui/layout/SubComposeLayoutExample.kt new file mode 100644 index 000000000..1418a8827 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/java/de/jensklingenberg/jetpackcomposeplayground/mysamples/github/ui/layout/SubComposeLayoutExample.kt @@ -0,0 +1,91 @@ +package de.jensklingenberg.jetpackcomposeplayground.mysamples.github.ui.layout + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.Placeable +import androidx.compose.ui.layout.SubcomposeLayout +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp + + +@Composable +fun SubComposeLayoutDemo() { + ResizeWidthColumn(Modifier.fillMaxWidth(), true) { + + Box( + modifier = Modifier + .background(Color.Red) + ) { + Text("Hello") + } + + Box( + modifier = Modifier + .padding(top = 8.dp) + .background(Color.Red) + ) { + Text("This is a long messsage \n and its longer") + } + } +} + +@Composable +fun ResizeWidthColumn(modifier: Modifier, resize: Boolean, mainContent: @Composable () -> Unit) { + SubcomposeLayout(modifier) { constraints -> + val mainPlaceables = subcompose(SlotsEnum.Main, mainContent).map { + // Here we measure the width/height of the child Composables + it.measure(Constraints()) + } + + //Here we find the max width/height of the child Composables + val maxSize = mainPlaceables.fold(IntSize.Zero) { currentMax, placeable -> + IntSize( + width = maxOf(currentMax.width, placeable.width), + height = maxOf(currentMax.height, placeable.height) + ) + } + + val resizedPlaceables: List = + subcompose(SlotsEnum.Dependent, mainContent).map { + if (resize) { + /** Here we rewrite the child Composables to have the width of + * widest Composable + */ + it.measure( + Constraints( + minWidth = maxSize.width + ) + ) + } else { + // Ask the child for its preferred size. + it.measure(Constraints()) + } + } + + /** + * We can place the Composables on the screen + * with layout() and the place() functions + */ + + layout(constraints.maxWidth, constraints.maxHeight) { + resizedPlaceables.forEachIndexed { index, placeable -> + val widthStart = resizedPlaceables.take(index).sumOf { it.measuredHeight } + placeable.place(0, widthStart) + } + } + } +} + + +enum class SlotsEnum { + Main, + Dependent + +} \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable-v21/ic_account_circle_black_24dp.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable-v21/ic_account_circle_black_24dp.xml new file mode 100644 index 000000000..ab8be5907 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable-v21/ic_account_circle_black_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..6348baae3 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/composelogo.png b/Jetpack-Compose-Playground/app/src/main/res/drawable/composelogo.png new file mode 100644 index 000000000..ff971a110 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/drawable/composelogo.png differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/favorite.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/favorite.xml new file mode 100644 index 000000000..52d4d9bb7 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/favorite.xml @@ -0,0 +1,10 @@ + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_account_box.png b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_account_box.png new file mode 100644 index 000000000..cdd05ccda Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_account_box.png differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_account_circle_black_24dp.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_account_circle_black_24dp.xml new file mode 100644 index 000000000..ab8be5907 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_account_circle_black_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_android.png b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_android.png new file mode 100644 index 000000000..4696f99e3 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_android.png differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_bluetooth.png b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_bluetooth.png new file mode 100644 index 000000000..7bc240299 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_bluetooth.png differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_crane.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_crane.xml new file mode 100644 index 000000000..3d0a138c6 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_crane.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_favorite.png b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_favorite.png new file mode 100644 index 000000000..5a76a28f7 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_favorite.png differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_hourglass.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_hourglass.xml new file mode 100644 index 000000000..1666c76e9 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_hourglass.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_launcher_background.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..a0ad202f9 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_sample_vector.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_sample_vector.xml new file mode 100644 index 000000000..d49a476d7 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ic_sample_vector.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/placeholder_1_1.png b/Jetpack-Compose-Playground/app/src/main/res/drawable/placeholder_1_1.png new file mode 100644 index 000000000..55fb3c2ac Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/drawable/placeholder_1_1.png differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ripple.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ripple.xml new file mode 100644 index 000000000..c235e6361 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ripple.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/res/drawable/ripple_shape.xml b/Jetpack-Compose-Playground/app/src/main/res/drawable/ripple_shape.xml new file mode 100644 index 000000000..def926180 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/drawable/ripple_shape.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/domine_bold.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/domine_bold.ttf new file mode 100644 index 000000000..329288c6b Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/font/domine_bold.ttf differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/domine_regular.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/domine_regular.ttf new file mode 100644 index 000000000..c387575c2 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/font/domine_regular.ttf differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_medium.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_medium.ttf new file mode 100644 index 000000000..6e079f698 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_medium.ttf differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_regular.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_regular.ttf new file mode 100644 index 000000000..8d443d5d5 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_regular.ttf differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_semibold.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_semibold.ttf new file mode 100644 index 000000000..f8a43f2b2 Binary files /dev/null and b/Jetpack-Compose-Playground/app/src/main/res/font/montserrat_semibold.ttf differ diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/my_font_400_italic.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/my_font_400_italic.ttf new file mode 100644 index 000000000..52c37a488 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/font/my_font_400_italic.ttf @@ -0,0 +1 @@ +This is a dummy font file used for sample code. diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/my_font_400_regular.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/my_font_400_regular.ttf new file mode 100644 index 000000000..52c37a488 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/font/my_font_400_regular.ttf @@ -0,0 +1 @@ +This is a dummy font file used for sample code. diff --git a/Jetpack-Compose-Playground/app/src/main/res/font/myfont.ttf b/Jetpack-Compose-Playground/app/src/main/res/font/myfont.ttf new file mode 100644 index 000000000..52c37a488 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/font/myfont.ttf @@ -0,0 +1 @@ +This is a dummy font file used for sample code. diff --git a/Jetpack-Compose-Playground/app/src/main/res/layout/activity.xml b/Jetpack-Compose-Playground/app/src/main/res/layout/activity.xml new file mode 100644 index 000000000..48038f967 --- /dev/null +++ b/Jetpack-Compose-Playground/app/src/main/res/layout/activity.xml @@ -0,0 +1,25 @@ + + + + +