This commit is contained in:
coco
2026-07-15 16:57:36 +08:00
parent 723ce1af5c
commit 95aa018b8b
314 changed files with 8910 additions and 0 deletions
+17
View File
@@ -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/
+21
View File
@@ -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.
+183
View File
@@ -0,0 +1,183 @@
<h1 align="center">Jetpack Compose Playground</h1>
## 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_) <a href="https://twitter.com/intent/tweet?text=Hey, check out Jetpack-Compose-Playground https://github.com/Foso/Jetpack-Compose-Playground via @jklingenberg_ #Android
"><img src="https://img.shields.io/twitter/url/https/github.com/angular-medellin/meetup.svg?style=social" alt="Tweet"></a>
## 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 |
| ------------------ | --------------------------- | ------------------ |
|<img src="https://github.com/Foso/Jetpack-Compose-Playground/blob/master/docs/images/readme/DemoActivity.png" height="400" alt="Screenshot"/> | <img src="https://raw.githubusercontent.com/Foso/Jetpack-Compose-Playground/master/docs/images/DialogExample.png" height="400" alt="Screenshot"/> | <img src="https://github.com/Foso/Jetpack-Compose-Playground/blob/master/docs/images/readme/circprog.png" height="400" alt="Screenshot"/> |
</p>
### Project Structure
* <kbd>[/app](https://github.com/Foso/Jetpack-Compose-Playground/tree/master/app)</kbd> - 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. Its 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 weve created with it. Well walk through examples of theming, animation, layout and more, demonstrating how to customize and combine components to build real UIs. Well 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 Androids 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? Dont 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) | Googles 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:
##
<p>
<div style="vertical-align: baseline;">This project is proudly supported by JetBrains OSS License</div>
<a href="https://jb.gg/OpenSourceSupport"><img src="https://github.com/cherryleafroad/kmagick/blob/main/readme_files/jb_beam.png" height="150px" width="150px"/></a>
</p>
[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).
@@ -0,0 +1 @@
/build
@@ -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<KotlinCompile>().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")
}
}
+21
View File
@@ -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
@@ -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<UiTestingDemoActivity>()
@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")
}
}
@@ -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")
}
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.jensklingenberg.jetpackcomposeplayground">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="androidx.activity.ComponentActivity" />
<activity android:name=".mysamples.demo.DemoActivity"/>
<activity android:name=".UiTestingDemoActivity" />
</application>
</manifest>
@@ -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))
}
}
@@ -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()
}
}
}
@@ -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<User> { 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)
}
}
@@ -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<T : ComponentActivity>(title: String, val activityClass: KClass<T>) : 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>) : Demo(title)
/**
* Flattened recursive DFS [List] of every demo in [this].
*/
fun DemoCategory.allDemos(): List<Demo> {
val allDemos = mutableListOf<Demo>()
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<Demo> {
return allDemos().filter { it !is DemoCategory }
}
@@ -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<Demo>
) {
constructor(
rootDemo: Demo,
backDispatcher: OnBackPressedDispatcher,
launchActivityDemo: (ActivityDemo<*>) -> Unit
) : this(backDispatcher, launchActivityDemo, rootDemo, rootDemo, mutableListOf<Demo>())
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<Navigator, *> = listSaver<Navigator, String>(
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<FilterMode, Boolean>(
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)
)
@@ -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)
}
}
}
@@ -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())
}
@@ -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<Demo>, 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) }
)
}
}
@@ -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
)
)
@@ -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"
}
@@ -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() }
)
)
@@ -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]
@@ -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"
})
}
}
@@ -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() }
)
)
@@ -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))
}
}
}
@@ -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
})
}
@@ -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)
)
}
}
@@ -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() },
)
)
@@ -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 = "")
}
@@ -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))
}
}
})
}
}
@@ -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))
}
}
})
}
}
@@ -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)
)
}
}
}
)
}
@@ -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)
}
}
@@ -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
)
)
}
@@ -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]
@@ -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}")
}
}
}
@@ -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")
}
}
@@ -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<User> { 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)
}
}
@@ -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() },
)
)
@@ -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())
}
}
}
@@ -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")
}
}
}
@@ -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]
@@ -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")
}
}
@@ -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)
})
}
}
@@ -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() },
)
)
@@ -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)
}
}
@@ -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() },
)
)
@@ -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")
}
}
)
}
}
}
}
@@ -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")
}
}
@@ -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 = {})
}
}
@@ -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()
}
}
}
}
@@ -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")
}
)
}
}
}
@@ -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 }
)
}
@@ -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")
}
}
}
@@ -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")
}
}
@@ -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)
}
}
}
}
}
@@ -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)
)
}
@@ -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")
}
}
}
@@ -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")
}
}
}
}
@@ -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")
}
}
}
)
}
@@ -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))
}
}
@@ -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)
)
}
}
}
}
@@ -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") } }
)
}
@@ -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 })
}
@@ -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!") }
}
}
}
@@ -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))
}
}
@@ -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 }
)
}
}
@@ -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)
}
}
@@ -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))
}
}
@@ -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() },
)
)
@@ -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)
}
}
@@ -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)
}
}
@@ -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() },
)
)
@@ -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<Placeable> =
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
}
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
@@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

@@ -0,0 +1,35 @@
<!--
~ 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.
-->
<vector android:height="480dp" android:viewportHeight="144"
android:viewportWidth="144" android:width="480dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#F79D80" android:pathData="M69.26,55.73m-53.39,0a53.39,53.39 0,1 1,106.78 0a53.39,53.39 0,1 1,-106.78 0"/>
<path android:fillColor="#37474F" android:pathData="M47.66,76.35h2.26v65.31h-2.26z"/>
<path android:fillColor="#FFFFFF" android:pathData="M61.47,22.88l7.59,0.63C69.06,23.51 65.07,22.59 61.47,22.88z"/>
<path android:fillColor="#FFFFFF" android:pathData="M78.86,44.71c-6.8,-5.5 -22.66,-7.48 -22.99,-17.32c-0.11,-3.17 2.61,-4.26 5.6,-4.5l-11.02,-0.92c-3.05,9.16 1.58,18.08 14.69,24.18c10.96,5.1 6.86,12.67 3.64,16.47c-3.13,-3.32 -7.57,-5.4 -12.49,-5.4c-0.78,0 -1.54,0.06 -2.29,0.16c-6.08,0.37 -39.94,5.23 -35.41,67.19c0,0 56.87,-40.62 56.95,-40.68c4.87,-3.48 9.11,-8.88 11.13,-14.5C89.88,60.43 86.05,50.53 78.86,44.71z"/>
<path android:fillColor="#434343" android:pathData="M68.8,62.41c-3.13,-3.32 -7.57,-5.4 -12.49,-5.4c-0.78,0 -1.54,0.06 -2.29,0.16c-6.08,0.37 -39.94,5.23 -35.41,67.19c0,0 1.34,-0.96 3.61,-2.58c-2.04,-56.41 29.85,-60.98 35.73,-61.34c0.75,-0.1 1.51,-0.16 2.29,-0.16C65.16,60.29 66.58,61.23 68.8,62.41"/>
<path android:fillColor="#FFD54F" android:pathData="M83.23,22.46l20.76,1.43c0.4,0.03 0.52,-0.52 0.16,-0.67l-19.1,-7.78c-0.2,-0.08 -0.42,0.03 -0.47,0.24l-1.66,6.35C82.86,22.23 83.01,22.44 83.23,22.46z"/>
<path android:fillColor="#F9BF2C" android:pathData="M86.66,16.09l-1.62,-0.66c-0.2,-0.08 -0.42,0.03 -0.47,0.24l-1.66,6.36c-0.06,0.21 0.1,0.42 0.31,0.44l10.52,0.72L86.66,16.09z"/>
<path android:fillColor="#1B2428" android:pathData="M47.66,103.79l0,3.86l2.24,2.24l0,-7.7z"/>
<path android:fillColor="#FFFFFF" android:pathData="M71.76,7.67c-5.16,-0.35 -9.83,0.75 -12.82,2.74l0,0c-7.5,4.2 -9.01,13.44 -9.18,14.36c-0.18,0.93 3.05,2.01 3.05,2.01l4.12,-4.16l4.52,-0.06c2.52,1.27 5.61,2.55 9.09,2.79c8.62,0.59 15.88,-2.89 16.22,-7.77C87.1,12.7 80.38,8.26 71.76,7.67z"/>
<path android:fillColor="#881A51" android:pathData="M71.76,7.67c-5.16,-0.35 -9.83,0.75 -12.82,2.74l0,0c-7.5,4.2 -9.01,13.44 -9.18,14.36c-0.18,0.93 3.05,2.01 3.05,2.01l4.12,-4.16l4.67,-0.38c2.52,1.27 7.02,1.03 10.5,1.27c8.62,0.59 14.33,-1.05 14.66,-5.93C87.1,12.7 80.38,8.26 71.76,7.67z"/>
<path android:fillColor="#FFFFFF" android:pathData="M71.83,11.32c-5.16,-0.29 -9.83,0.61 -12.82,2.21l0,0c-7.5,3.39 -9.16,10.46 -9.25,11.23c-0.15,1.18 3.05,3.13 3.05,3.13l4.2,-4.48l4.47,-0.54c2.52,1.03 5.59,2.28 9.07,2.47c8.62,0.48 15.08,-2.54 15.41,-6.49C86.29,14.92 80.45,11.8 71.83,11.32z"/>
<path android:fillColor="#BDBDBD" android:pathData="M73.53,24.78c-3.48,-0.19 -6.55,-1.44 -9.07,-2.47c0,0 0,0 0,0l-1.08,0.13c-0.68,0.11 -1.33,0.28 -1.91,0.52l0.11,-0.01c0,0 0,0 0,0c2.52,1.03 5.59,2.28 9.07,2.47c3.37,0.19 6.4,-0.16 8.87,-0.89C77.7,24.8 75.68,24.9 73.53,24.78z"/>
<path android:fillColor="#EEEEEE" android:pathData="M82.13,48.13c1.75,4.57 2.05,9.63 0.33,14.43c-2.02,5.62 -6.26,11.01 -11.13,14.5c-0.33,0.24 -41.01,29.29 -53.34,38.1c0.03,2.98 0.16,6.12 0.41,9.41c0,0 56.87,-40.62 56.95,-40.68c4.87,-3.48 9.11,-8.88 11.13,-14.5C89.13,62.01 86.99,53.98 82.13,48.13z"/>
<path android:fillColor="#BDBDBD" android:pathData="M78.86,44.91c-0.16,-0.13 -0.33,-0.26 -0.5,-0.39c5.68,5.93 8.39,14.63 5.53,22.58c-2.02,5.62 -6.26,11.01 -11.13,14.5c-0.07,0.05 -43.58,31.16 -54.59,39.02c0.06,1.4 0.15,2.8 0.26,4.26c0,0 57.03,-40.74 57.11,-40.79c4.87,-3.48 9.11,-8.88 11.13,-14.5C89.88,60.64 86.05,50.73 78.86,44.91z"/>
<path android:fillColor="#BDBDBD" android:pathData="M78.94,44.76c-6.8,-5.5 -22.66,-7.48 -22.99,-17.32c-0.04,-1.21 0.33,-2.11 0.97,-2.78c-1.81,0.6 -3.12,1.8 -3.04,4.02C54.2,38.52 70.07,40.5 76.86,46c7.19,5.82 11.02,15.73 7.81,24.68c-2.02,5.62 -6.26,11.01 -11.13,14.5c-0.07,0.05 -44.69,31.92 -54.89,39.21c0.01,0.08 0.01,0.16 0.02,0.24c0,0 56.87,-40.62 56.95,-40.68c4.87,-3.48 9.11,-8.88 11.13,-14.5C89.96,60.49 86.13,50.59 78.94,44.76z"/>
<path android:fillColor="#BDBDBD" android:pathData="M54.5,28.8c0,0 -0.52,0.61 -0.52,0.61c0.01,-0.01 -0.02,-0.11 -0.02,-0.12c-0.02,-0.11 -0.03,-0.23 -0.05,-0.34c-0.04,-0.4 -0.06,-0.79 -0.04,-1.19c0.02,-0.55 0.1,-1.1 0.24,-1.64c0.17,-0.63 0.43,-1.24 0.78,-1.79c0.42,-0.65 0.96,-1.21 1.58,-1.66c0.32,-0.23 0.66,-0.43 1.01,-0.61c0.47,-0.24 0.93,-0.43 1.46,-0.49c0.27,-0.03 0.55,-0.05 0.82,-0.05c0.89,-0.02 1.78,0.07 2.65,0.24c0.37,0.07 0.73,0.16 1.09,0.26c0.19,0.05 0.39,0.11 0.58,0.17c0.1,0.03 0.2,0.07 0.3,0.1c0.04,0.01 0.27,0.13 0.3,0.11c0,0 -1.79,1.07 -1.79,1.07s-5.78,-1.34 -6.91,3.25L54.5,28.8z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24" >
<group
android:name="hourglass_frame"
android:translateX="12"
android:translateY="12"
android:scaleX="0.75"
android:scaleY="0.75" >
<group
android:name="hourglass_frame_pivot"
android:translateX="-12"
android:translateY="-12" >
<group
android:name="group_2_2"
android:translateX="12"
android:translateY="6.5" >
<path
android:name="path_2_2"
android:pathData="M 6.52099609375 -3.89300537109 c 0.0 0.0 -6.52099609375 6.87901306152 -6.52099609375 6.87901306152 c 0 0.0 -6.52099609375 -6.87901306152 -6.52099609375 -6.87901306152 c 0.0 0.0 13.0419921875 0.0 13.0419921875 0.0 Z M 9.99800109863 -6.5 c 0.0 0.0 -19.9960021973 0.0 -19.9960021973 0.0 c -0.890991210938 0.0 -1.33700561523 1.07699584961 -0.707000732422 1.70700073242 c 0.0 0.0 10.7050018311 11.2929992676 10.7050018311 11.2929992676 c 0 0.0 10.7050018311 -11.2929992676 10.7050018311 -11.2929992676 c 0.630004882812 -0.630004882812 0.183990478516 -1.70700073242 -0.707000732422 -1.70700073242 Z"
android:fillColor="#FF777777" />
</group>
<group
android:name="group_1_2"
android:translateX="12"
android:translateY="17.5" >
<path
android:name="path_2_1"
android:pathData="M 0 -2.98600769043 c 0 0.0 6.52099609375 6.87901306152 6.52099609375 6.87901306152 c 0.0 0.0 -13.0419921875 0.0 -13.0419921875 0.0 c 0.0 0.0 6.52099609375 -6.87901306152 6.52099609375 -6.87901306152 Z M 0 -6.5 c 0 0.0 -10.7050018311 11.2929992676 -10.7050018311 11.2929992676 c -0.630004882812 0.630004882812 -0.184005737305 1.70700073242 0.707000732422 1.70700073242 c 0.0 0.0 19.9960021973 0.0 19.9960021973 0.0 c 0.890991210938 0.0 1.33699035645 -1.07699584961 0.707000732422 -1.70700073242 c 0.0 0.0 -10.7050018311 -11.2929992676 -10.7050018311 -11.2929992676 Z"
android:fillColor="#FF777777" />
</group>
</group>
</group>
<group
android:name="fill_outlines"
android:translateX="12"
android:translateY="12"
android:scaleX="0.75"
android:scaleY="0.75" >
<group
android:name="fill_outlines_pivot"
android:translateX="-12"
android:translateY="-12" >
<clip-path
android:name="mask_1"
android:pathData="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z" />
<group
android:name="group_1_3"
android:translateX="12"
android:translateY="12" >
<path
android:name="path_1_6"
android:pathData="M 10.7100067139 10.2900085449 c 0.629989624023 0.629989624023 0.179992675781 1.70999145508 -0.710006713867 1.70999145508 c 0 0 -20 0 -20 0 c -0.889999389648 0 -1.33999633789 -1.08000183105 -0.710006713867 -1.70999145508 c 0.0 0.0 9.76000976562 -10.2900085449 9.76000976563 -10.2900085449 c 0.0 0 -9.76000976562 -10.2899932861 -9.76000976563 -10.2899932861 c -0.629989624023 -0.630004882812 -0.179992675781 -1.71000671387 0.710006713867 -1.71000671387 c 0 0 20 0 20 0 c 0.889999389648 0 1.33999633789 1.08000183105 0.710006713867 1.71000671387 c 0.0 0.0 -9.76000976562 10.2899932861 -9.76000976563 10.2899932861 c 0.0 0 9.76000976562 10.2900085449 9.76000976563 10.2900085449 Z"
android:fillColor="#FF777777" />
</group>
</group>
</group>
</vector>
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>
@@ -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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20000000">
<item android:drawable="@drawable/ripple_shape" />
<item android:id="@android:id/mask"
android:drawable="@drawable/ripple_shape" />
</ripple>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="100px"/>
<solid android:color="@android:color/white"/>
<stroke android:color="#80000000" android:width="1dp"/>
</shape>
@@ -0,0 +1 @@
This is a dummy font file used for sample code.
@@ -0,0 +1 @@
This is a dummy font file used for sample code.
@@ -0,0 +1 @@
This is a dummy font file used for sample code.
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AndroidX Samples" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="My Samples" />
</LinearLayout>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Some files were not shown because too many files have changed in this diff Show More