Browse Source

Add common test samples to widgets-gallery (#4202)

pull/4382/head
Alexander Maryanovsky 10 months ago committed by GitHub
parent
commit
69d3a24295
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      examples/widgets-gallery/gradle.properties
  2. 49
      examples/widgets-gallery/shared/build.gradle.kts
  3. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/ic_instagram.xml
  4. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/ic_send.xml
  5. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/ic_twitter.xml
  6. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p1.jpeg
  7. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p2.jpeg
  8. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p3.jpeg
  9. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p6.jpeg
  10. 0
      examples/widgets-gallery/shared/src/commonMain/composeResources/values/strings.xml
  11. 9
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/platform/Res.kt
  12. 6
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/MainView.kt
  13. 3
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/WidgetView.kt
  14. 5
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/WidgetsType.kt
  15. 37
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/AppBars.kt
  16. 4
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Buttons.kt
  17. 78
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Chips.kt
  18. 33
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Loaders.kt
  19. 48
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/SnackBars.kt
  20. 123
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/TextInputs.kt
  21. 5
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Texts.kt
  22. 4
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Toggles.kt
  23. 167
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/UICards.kt
  24. 9
      examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/utils/ResizablePanel.kt
  25. 34
      examples/widgets-gallery/shared/src/commonTest/kotlin/ExampleTest.kt
  26. 28
      examples/widgets-gallery/shared/src/commonTest/kotlin/WidgetsPanelTest.kt

3
examples/widgets-gallery/gradle.properties

@ -10,4 +10,5 @@ kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.9.21
agp.version=8.0.2
compose.version=1.5.11
# Replace this with release version when it comes out
compose.version=1.6.0-dev1397

49
examples/widgets-gallery/shared/build.gradle.kts

@ -1,4 +1,5 @@
@file:Suppress("OPT_IN_IS_NOT_ENABLED")
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree
plugins {
kotlin("multiplatform")
@ -9,7 +10,19 @@ plugins {
version = "1.0-SNAPSHOT"
kotlin {
androidTarget()
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
instrumentedTestVariant {
sourceSetTree.set(KotlinSourceSetTree.test)
dependencies {
// Remove the dependency on ui-test-junit4-android when 1.7.0 is released,
// as the needed classes in will have moved to ui-test
implementation("androidx.compose.ui:ui-test-junit4-android:1.6.0")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
}
}
jvm("desktop")
@ -32,33 +45,34 @@ kotlin {
implementation(compose.material)
implementation(compose.materialIconsExtended)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation("org.jetbrains.compose.components:components-resources:1.6.0-dev1306")
implementation("org.jetbrains.compose.components:components-resources:${project.property("compose.version")}")
}
}
val androidMain by getting {
dependencies {
api("androidx.activity:activity-compose:1.7.2")
api("androidx.activity:activity-compose:1.8.2")
api("androidx.appcompat:appcompat:1.6.1")
api("androidx.core:core-ktx:1.10.1")
api("androidx.core:core-ktx:1.12.0")
}
}
val iosMain by creating {
dependsOn(commonMain)
}
val iosX64Main by getting {
dependsOn(iosMain)
}
val iosArm64Main by getting {
dependsOn(iosMain)
}
val iosSimulatorArm64Main by getting {
dependsOn(iosMain)
}
val desktopMain by getting {
dependencies {
implementation(compose.desktop.common)
}
}
val desktopTest by getting {
dependencies {
implementation(compose.desktop.currentOs)
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.uiTest)
}
}
}
}
@ -71,6 +85,7 @@ android {
defaultConfig {
minSdk = 26
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/ic_instagram.xml → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/ic_instagram.xml

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/ic_send.xml → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/ic_send.xml

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/ic_twitter.xml → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/ic_twitter.xml

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/p1.jpeg → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p1.jpeg

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/p2.jpeg → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p2.jpeg

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/p3.jpeg → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p3.jpeg

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/images/p6.jpeg → examples/widgets-gallery/shared/src/commonMain/composeResources/drawable/p6.jpeg

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

0
examples/widgets-gallery/shared/src/commonMain/resources/composeRes/values/strings.xml → examples/widgets-gallery/shared/src/commonMain/composeResources/values/strings.xml

9
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/platform/Res.kt

@ -1,9 +0,0 @@
package org.jetbrains.compose.demo.widgets.platform
object Res {
object strings {
val spotify_nav_home = "Home"
val spotify_nav_search = "Search"
val spotify_nav_library = "Your Library"
}
}

6
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/MainView.kt

@ -20,6 +20,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.semantics.semantics
@ -115,6 +116,10 @@ private fun WidgetsListView(widgetsTypeState: MutableState<WidgetsType>) {
}
val WidgetsType.listItemTestTag: String
get() = "${testTag}_list_item"
@Composable
private fun WidgetsListItemViewImpl(
widgetsType: WidgetsType,
@ -133,6 +138,7 @@ private fun WidgetsListItemViewImpl(
}
.height(height)
.padding(start = 16.dp)
.testTag(widgetsType.listItemTestTag)
) {
val inFocusInteractionSource = remember { MutableInteractionSource() }
val inFocus by inFocusInteractionSource.collectIsHoveredAsState()

3
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/WidgetView.kt

@ -2,7 +2,6 @@ package org.jetbrains.compose.demo.widgets.ui
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@ -19,7 +18,7 @@ fun WidgetsView(
modifier: Modifier
) {
ClearFocusBox {
Column(modifier = modifier.verticalScroll(state = rememberScrollState())) {
Box(modifier = modifier.verticalScroll(state = rememberScrollState())) {
@Suppress("UNUSED_VARIABLE")
val exhaustive = when (widgetsTypeState.value) {
WidgetsType.APP_BARS -> AppBars()

5
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/WidgetsType.kt

@ -24,9 +24,12 @@ enum class WidgetsType(private val customTitle: String? = null) {
val title: String
get() = customTitle ?: readableName
val testTag: String
get() = name.lowercase()
companion object {
val sortedValues: List<WidgetsType> by lazy {
values().sortedBy { it.name }
entries.sortedBy { it.name }
}
}
}

37
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/AppBars.kt

@ -5,7 +5,8 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.outlined.ReadMore
import androidx.compose.material.icons.filled.MoreHoriz
import androidx.compose.material.icons.filled.StarBorder
import androidx.compose.material.icons.outlined.*
@ -14,20 +15,24 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.platform.Res
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.demo.widgets.theme.twitterColor
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
import org.jetbrains.compose.demo.widgets.ui.utils.SubtitleText
import org.jetbrains.compose.demo.widgets.ui.utils.TitleText
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.ImageResource
import org.jetbrains.compose.resources.stringResource
import widgets_gallery.shared.generated.resources.Res
@Composable
fun AppBars() {
TopAppBarsDemo()
BottomAppBarDemo()
NavigationBarDemo()
Column(Modifier.testTag(WidgetsType.APP_BARS.testTag)) {
TopAppBarsDemo()
BottomAppBarDemo()
NavigationBarDemo()
}
}
@OptIn(ExperimentalResourceApi::class)
@ -40,7 +45,7 @@ private fun TopAppBarsDemo() {
elevation = 8.dp,
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Default.ArrowBack, contentDescription = "ArrowBack")
Icon(Icons.AutoMirrored.Default.ArrowBack, contentDescription = "ArrowBack")
}
}
)
@ -54,12 +59,12 @@ private fun TopAppBarsDemo() {
elevation = 8.dp,
navigationIcon = {
IconButton(onClick = {}) {
Icon(painterResource(ImageResource("composeRes/images/ic_instagram.xml")), contentDescription = "Instagram")
Icon(painterResource(Res.drawable.ic_instagram), contentDescription = "Instagram")
}
},
actions = {
IconButton(onClick = {}) {
Icon(painterResource(ImageResource("composeRes/images/ic_send.xml")), contentDescription = "Send")
Icon(painterResource(Res.drawable.ic_send), contentDescription = "Send")
}
}
)
@ -69,7 +74,7 @@ private fun TopAppBarsDemo() {
TopAppBar(
title = {
Icon(
painterResource(ImageResource("composeRes/images/ic_twitter.xml")),
painterResource(Res.drawable.ic_twitter),
contentDescription = "Twitter",
tint = twitterColor,
modifier = Modifier.fillMaxWidth()
@ -80,7 +85,7 @@ private fun TopAppBarsDemo() {
elevation = 8.dp,
navigationIcon = {
Image(
painterResource(ImageResource("composeRes/images/p6.jpeg")),
painterResource(Res.drawable.p6),
contentDescription = "",
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
.requiredSize(32.dp).clip(CircleShape)
@ -100,7 +105,7 @@ private fun TopAppBarsDemo() {
@Composable
private fun BottomAppBarDemo() {
Spacer(modifier = Modifier.height(16.dp))
SubtitleText("Bottom app bars: Note bottom app bar support FAB cutouts when used with scafolds see demoUI crypto app")
SubtitleText("Bottom app bars: Note bottom app bar support FAB cutouts when used with scaffolds see demoUI crypto app")
BottomAppBar(
cutoutShape = CircleShape
@ -123,19 +128,19 @@ private fun NavigationBarDemo() {
icon = { Icon(Icons.Outlined.Home, contentDescription = "Home") },
selected = navItemState.value == NavType.HOME,
onClick = { navItemState.value = NavType.HOME },
label = { Text(text = Res.strings.spotify_nav_home) },
label = { Text(text = stringResource(Res.string.spotify_nav_home)) },
)
BottomNavigationItem(
icon = { Icon(Icons.Outlined.Search, contentDescription = "Search") },
selected = navItemState.value == NavType.SEARCH,
onClick = { navItemState.value = NavType.SEARCH },
label = { Text(text = Res.strings.spotify_nav_search) }
label = { Text(text = stringResource(Res.string.spotify_nav_search)) }
)
BottomNavigationItem(
icon = { Icon(Icons.Outlined.LibraryMusic, contentDescription = "LibraryMusic") },
selected = navItemState.value == NavType.LIBRARY,
onClick = { navItemState.value = NavType.LIBRARY },
label = { Text(text = Res.strings.spotify_nav_library) }
label = { Text(text = stringResource(Res.string.spotify_nav_library)) }
)
}
@ -143,7 +148,7 @@ private fun NavigationBarDemo() {
BottomNavigation {
BottomNavigationItem(
icon = { Icon(Icons.Outlined.ReadMore, contentDescription = "ReadMore") },
icon = { Icon(Icons.AutoMirrored.Outlined.ReadMore, contentDescription = "ReadMore") },
selected = navItemState.value == NavType.HOME,
onClick = { navItemState.value = NavType.HOME },
)

4
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Buttons.kt

@ -14,14 +14,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.theme.purple
import org.jetbrains.compose.demo.widgets.theme.purple200
import org.jetbrains.compose.demo.widgets.theme.typography
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
@Composable
fun Buttons() {
Column {
Column(Modifier.testTag(WidgetsType.BUTTONS.testTag)) {
Button(onClick = {}, modifier = Modifier.padding(8.dp)) {
Text(text = "Main Button")
}

78
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Chips.kt

@ -13,44 +13,62 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.demo.widgets.ui.utils.SubtitleText
import org.jetbrains.compose.resources.DrawableResource
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.ImageResource
import widgets_gallery.shared.generated.resources.Res
@OptIn(ExperimentalResourceApi::class)
@Composable
fun Chips() {
// There is no in-built chips but you can make yours like below
SubtitleText(subtitle = "Custom chips with surface")
Column(modifier = Modifier.padding(8.dp)) {
YoutubeChip(selected = true, text = "Chip", modifier = Modifier.padding(horizontal = 8.dp))
Spacer(modifier = Modifier.padding(8.dp))
YoutubeChip(
selected = false,
text = "Inactive",
modifier = Modifier.padding(horizontal = 8.dp)
)
Spacer(modifier = Modifier.padding(8.dp))
CustomImageChip(text = "custom", imageId = ImageResource("composeRes/images/p2.jpeg"), selected = true)
Spacer(modifier = Modifier.padding(8.dp))
CustomImageChip(text = "custom2", imageId = ImageResource("composeRes/images/p6.jpeg"), selected = false)
}
SubtitleText(subtitle = "Buttons with circle clipping.")
Column(modifier = Modifier.padding(8.dp)) {
Button(
onClick = {},
modifier = Modifier.padding(8.dp).clip(CircleShape)
) {
Text(text = "Chip button")
Column(Modifier.testTag(WidgetsType.CHIPS.testTag)) {
// There is no in-built chips but you can make yours like below
SubtitleText(subtitle = "Custom chips with surface")
Column(modifier = Modifier.padding(8.dp)) {
YoutubeChip(
selected = true,
text = "Chip",
modifier = Modifier.padding(horizontal = 8.dp)
)
Spacer(modifier = Modifier.padding(8.dp))
YoutubeChip(
selected = false,
text = "Inactive",
modifier = Modifier.padding(horizontal = 8.dp)
)
Spacer(modifier = Modifier.padding(8.dp))
CustomImageChip(
text = "custom",
imageId = Res.drawable.p2,
selected = true
)
Spacer(modifier = Modifier.padding(8.dp))
CustomImageChip(
text = "custom2",
imageId = Res.drawable.p6,
selected = false
)
}
Button(
onClick = {},
enabled = false,
modifier = Modifier.padding(8.dp).clip(CircleShape)
) {
Text(text = "Disabled chip")
SubtitleText(subtitle = "Buttons with circle clipping.")
Column(modifier = Modifier.padding(8.dp)) {
Button(
onClick = {},
modifier = Modifier.padding(8.dp).clip(CircleShape)
) {
Text(text = "Chip button")
}
Button(
onClick = {},
enabled = false,
modifier = Modifier.padding(8.dp).clip(CircleShape)
) {
Text(text = "Disabled chip")
}
}
}
}
@ -62,7 +80,7 @@ fun Chips() {
@Composable
private fun CustomImageChip(
text: String,
imageId: ImageResource,
imageId: DrawableResource,
selected: Boolean,
modifier: Modifier = Modifier
) {

33
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Loaders.kt

@ -1,41 +1,34 @@
package org.jetbrains.compose.demo.widgets.ui.screens
import androidx.compose.foundation.layout.Arrangement
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.material.CircularProgressIndicator
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
@Composable
fun Loaders() {
AlignedColumn {
Column(
modifier = Modifier
.padding(16.dp)
.testTag(WidgetsType.LOADERS.testTag),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
CircularProgressIndicator()
}
AlignedColumn {
CircularProgressIndicator(strokeWidth = 8.dp)
}
AlignedColumn {
LinearProgressIndicator()
}
AlignedColumn {
LinearProgressIndicator()
Text(text = "Loading with text...", modifier = Modifier.padding(8.dp))
}
}
@Composable
private fun AlignedColumn(content: @Composable () -> Unit) {
Column(
modifier = Modifier.fillMaxWidth().padding(16.dp)
) {
content()
Column {
LinearProgressIndicator()
Text(text = "Loading with text...", modifier = Modifier.padding(8.dp))
}
}
}

48
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/SnackBars.kt

@ -1,38 +1,46 @@
package org.jetbrains.compose.demo.widgets.ui.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Snackbar
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.theme.typography
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
@Composable
fun SnackBars() {
Snackbar(modifier = Modifier.padding(4.dp)) {
Text(text = "This is a basic snackbar")
}
Snackbar(
modifier = Modifier.padding(4.dp),
action = {
TextButton(onClick = {}) {
Text(text = "Remove")
Column(
modifier = Modifier
.padding(4.dp)
.testTag(WidgetsType.SNACK_BARS.testTag),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Snackbar {
Text(text = "This is a basic snackbar")
}
Snackbar(
action = {
TextButton(onClick = {}) {
Text(text = "Remove")
}
}
) {
Text(text = "This is a basic snackbar with action item")
}
) {
Text(text = "This is a basic Snackbar with action item")
}
Snackbar(
modifier = Modifier.padding(4.dp),
actionOnNewLine = true,
action = {
TextButton(onClick = {}) {
Text(text = "Remove")
Snackbar(
actionOnNewLine = true,
action = {
TextButton(onClick = {}) {
Text(text = "Remove")
}
}
) {
Text(text = "Snackbar with action item below text")
}
) {
Text(text = "Snackbar with action item below text")
}
}

123
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/TextInputs.kt

@ -1,6 +1,7 @@
package org.jetbrains.compose.demo.widgets.ui.screens
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
@ -13,80 +14,84 @@ import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Email
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
@Composable
fun TextInputs() {
var text by remember { mutableStateOf(TextFieldValue("")) }
Column(Modifier.testTag(WidgetsType.TEXT_INPUTS.testTag)) {
var text by remember { mutableStateOf(TextFieldValue("")) }
// TODO Explore CoreTextField
// TODO Explore CoreTextField
// CoreTextField(
// value = text,
// onValueChange = { newValue -> text = newValue },
// modifier = Modifier.padding(8.dp).preferredSize(0.dp),
// cursorColor = Color.Magenta
// )
TextField(
value = text,
onValueChange = { newValue -> text = newValue },
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
label = { Text("label") },
placeholder = { Text("placeholder") },
)
TextField(
value = text,
onValueChange = { newValue -> text = newValue },
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
label = { Text("label") },
placeholder = { Text("placeholder") },
)
OutlinedTextField(
value = text,
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
label = { Text(text = "Password") },
placeholder = { Text(text = "12334444") },
visualTransformation = PasswordVisualTransformation(),
onValueChange = {
text = it
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
OutlinedTextField(
value = text,
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
label = { Text(text = "Password") },
placeholder = { Text(text = "12334444") },
visualTransformation = PasswordVisualTransformation(),
onValueChange = {
text = it
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
)
OutlinedTextField(
value = text,
leadingIcon = { Icon(Icons.Default.Email, contentDescription = "Email") },
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
label = { Text(text = "Email address") },
placeholder = { Text(text = "Your email") },
onValueChange = {
text = it
}
)
OutlinedTextField(
value = text,
leadingIcon = { Icon(Icons.Default.Email, contentDescription = "Email") },
trailingIcon = { Icon(Icons.Default.Edit, contentDescription = "Edit") },
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
label = { Text(text = "Email address") },
placeholder = { Text(text = "Your email") },
onValueChange = {
text = it
}
)
OutlinedTextField(
value = text,
leadingIcon = { Icon(Icons.Default.Email, contentDescription = "Email") },
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
label = { Text(text = "Email address") },
placeholder = { Text(text = "Your email") },
onValueChange = {
text = it
}
)
OutlinedTextField(
value = text,
leadingIcon = { Icon(Icons.Default.Email, contentDescription = "Email") },
trailingIcon = { Icon(Icons.Default.Edit, contentDescription = "Edit") },
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
label = { Text(text = "Email address") },
placeholder = { Text(text = "Your email") },
onValueChange = {
text = it
}
)
var numberText by remember { mutableStateOf(TextFieldValue("")) }
OutlinedTextField(
value = numberText,
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
label = { Text(text = "Phone number") },
placeholder = { Text(text = "88888888") },
onValueChange = {
numberText = it
}
)
var numberText by remember { mutableStateOf(TextFieldValue("")) }
OutlinedTextField(
value = numberText,
modifier = Modifier.padding(8.dp).fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
label = { Text(text = "Phone number") },
placeholder = { Text(text = "88888888") },
onValueChange = {
numberText = it
}
)
}
}

5
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Texts.kt

@ -1,21 +1,22 @@
package org.jetbrains.compose.demo.widgets.ui.screens
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.platform.testTag
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.theme.typography
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
import org.jetbrains.compose.demo.widgets.ui.utils.SubtitleText
@Composable
fun TextViews() {
Column {
Column(Modifier.testTag(WidgetsType.TEXT_VIEWS.testTag)) {
val textModifier = Modifier.padding(horizontal = 8.dp)
SubtitleText(subtitle = "Font weights")

4
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/Toggles.kt

@ -9,11 +9,13 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
@Composable
fun Toggles() {
Column {
Column(Modifier.testTag(WidgetsType.TOGGLES.testTag)) {
var checked by remember { mutableStateOf(true) }
Checkbox(
checked = checked,

167
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/screens/UICards.kt

@ -9,96 +9,109 @@ import androidx.compose.material.icons.filled.ShoppingCart
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.demo.widgets.data.DemoDataProvider
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.demo.widgets.theme.typography
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.ImageResource
import widgets_gallery.shared.generated.resources.Res
@OptIn(ExperimentalMaterialApi::class, ExperimentalResourceApi::class)
@Composable
fun UICards() {
val item = remember { DemoDataProvider.item }
Column(Modifier.testTag(WidgetsType.UI_CARDS.testTag)) {
val item = remember { DemoDataProvider.item }
Text(
text = "Inbuilt box as container for any Clipping/Alignment controls",
style = typography.subtitle1,
modifier = Modifier.padding(8.dp)
)
Card(
modifier = Modifier.padding(8.dp).fillMaxWidth(),
backgroundColor = MaterialTheme.colors.primary,
shape = RoundedCornerShape(topStart = 16.dp, bottomEnd = 16.dp)
) {
Column {
Text(
text = item.title,
modifier = Modifier.padding(8.dp),
color = MaterialTheme.colors.onPrimary
)
Text(
text = item.subtitle,
modifier = Modifier.padding(8.dp),
color = MaterialTheme.colors.onPrimary
)
Text(
text = "Inbuilt box as container for any Clipping/Alignment controls",
style = typography.subtitle1,
modifier = Modifier.padding(8.dp)
)
Card(
modifier = Modifier.padding(8.dp).fillMaxWidth(),
backgroundColor = MaterialTheme.colors.primary,
shape = RoundedCornerShape(topStart = 16.dp, bottomEnd = 16.dp)
) {
Column {
Text(
text = item.title,
modifier = Modifier.padding(8.dp),
color = MaterialTheme.colors.onPrimary
)
Text(
text = item.subtitle,
modifier = Modifier.padding(8.dp),
color = MaterialTheme.colors.onPrimary
)
}
}
}
Divider()
Divider()
Text(text = "Inbuilt Card", style = typography.subtitle1, modifier = Modifier.padding(8.dp))
Card(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
shape = RoundedCornerShape(4.dp),
elevation = 4.dp
) {
Row {
Image(
painterResource(ImageResource("composeRes/images/p3.jpeg")),
contentDescription = null,
modifier = Modifier.requiredSize(60.dp)
)
Text(text = item.title, modifier = Modifier.padding(16.dp))
Text(text = "Inbuilt Card", style = typography.subtitle1, modifier = Modifier.padding(8.dp))
Card(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
shape = RoundedCornerShape(4.dp),
elevation = 4.dp
) {
Row {
Image(
painterResource(Res.drawable.p3),
contentDescription = null,
modifier = Modifier.requiredSize(60.dp)
)
Text(text = item.title, modifier = Modifier.padding(16.dp))
}
}
}
Divider()
Divider()
Text(
text = "In-built ListItems",
style = typography.subtitle1,
modifier = Modifier.padding(8.dp)
)
ListItem(text = { Text(item.title) }, secondaryText = { Text(item.subtitle) })
Divider(modifier = Modifier.padding(4.dp))
ListItem(
text = { Text(item.title) },
secondaryText = { Text(item.subtitle) },
singleLineSecondaryText = false
)
Divider(modifier = Modifier.padding(4.dp))
ListItem(text = { Text(item.title) }, secondaryText = { Text(item.subtitle) }, icon = {
Image(
painterResource(ImageResource("composeRes/images/p3.jpeg")),
contentDescription = null
Text(
text = "In-built ListItems",
style = typography.subtitle1,
modifier = Modifier.padding(8.dp)
)
})
Divider(modifier = Modifier.padding(4.dp))
//I am not sure why this is not going multiline for secondaryText...
ListItem(
text = { Text(item.title) },
secondaryText = { Text(item.subtitle) },
icon = { Image(painterResource(ImageResource("composeRes/images/p1.jpeg")), contentDescription = null) },
overlineText = { Text("Overline text") },
singleLineSecondaryText = false
)
Divider()
ListItem(
text = { Text(item.title) },
secondaryText = { Text(item.subtitle) },
icon = { Image(painterResource(ImageResource("composeRes/images/p2.jpeg")), contentDescription = null) },
trailing = { Icon(Icons.Default.ShoppingCart, contentDescription = null) },
singleLineSecondaryText = false
)
Divider()
ListItem(text = { Text(item.title) }, secondaryText = { Text(item.subtitle) })
Divider(modifier = Modifier.padding(4.dp))
ListItem(
text = { Text(item.title) },
secondaryText = { Text(item.subtitle) },
singleLineSecondaryText = false
)
Divider(modifier = Modifier.padding(4.dp))
ListItem(text = { Text(item.title) }, secondaryText = { Text(item.subtitle) }, icon = {
Image(
painterResource(Res.drawable.p3),
contentDescription = null
)
})
Divider(modifier = Modifier.padding(4.dp))
//I am not sure why this is not going multiline for secondaryText...
ListItem(
text = { Text(item.title) },
secondaryText = { Text(item.subtitle) },
icon = {
Image(
painterResource(Res.drawable.p1),
contentDescription = null
)
},
overlineText = { Text("Overline text") },
singleLineSecondaryText = false
)
Divider()
ListItem(
text = { Text(item.title) },
secondaryText = { Text(item.subtitle) },
icon = {
Image(
painterResource(Res.drawable.p2),
contentDescription = null
)
},
trailing = { Icon(Icons.Default.ShoppingCart, contentDescription = null) },
singleLineSecondaryText = false
)
Divider()
}
}

9
examples/widgets-gallery/shared/src/commonMain/kotlin/org/jetbrains/compose/demo/widgets/ui/utils/ResizablePanel.kt

@ -8,8 +8,8 @@ import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Text
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.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -60,7 +60,10 @@ fun ResizablePanel(
.clickable { state.isExpanded = !state.isExpanded }
) {
Icon(
if (state.isExpanded) Icons.Default.ArrowBack else Icons.Default.ArrowForward,
imageVector = if (state.isExpanded)
Icons.AutoMirrored.Default.ArrowBack
else
Icons.AutoMirrored.Default.ArrowForward,
contentDescription = if (state.isExpanded) "Collapse" else "Expand",
tint = LocalContentColor.current,
modifier = Modifier

34
examples/widgets-gallery/shared/src/commonTest/kotlin/ExampleTest.kt

@ -0,0 +1,34 @@
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.*
import kotlin.test.Test
/**
* This is a simple, sample test.
*/
class ExampleTest {
@OptIn(ExperimentalTestApi::class)
@Test
fun myTest() = runComposeUiTest {
setContent {
var text by remember { mutableStateOf("Hello") }
Text(
text = text,
modifier = Modifier.testTag("text")
)
Button(
onClick = { text = "Compose" },
modifier = Modifier.testTag("button")
){
Text("Click me")
}
}
onNodeWithTag("text").assertTextEquals("Hello")
onNodeWithTag("button").performClick()
onNodeWithTag("text").assertTextEquals("Compose")
}
}

28
examples/widgets-gallery/shared/src/commonTest/kotlin/WidgetsPanelTest.kt

@ -0,0 +1,28 @@
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.runComposeUiTest
import org.jetbrains.compose.demo.widgets.ui.WidgetsPanel
import org.jetbrains.compose.demo.widgets.ui.WidgetsType
import org.jetbrains.compose.demo.widgets.ui.listItemTestTag
import kotlin.test.Test
@OptIn(ExperimentalTestApi::class)
class WidgetsPanelTest {
/**
* Tests that clicking on each widget type in the list shows the corresponding widgets view.
*/
@OptIn(ExperimentalTestApi::class)
@Test
fun clickingOnWidgetListItemShowsCorrectWidgetUi() = runComposeUiTest {
setContent {
WidgetsPanel()
}
for (widgetsType in WidgetsType.entries) {
onNodeWithTag(widgetsType.listItemTestTag).performClick()
onNodeWithTag(widgetsType.testTag).assertExists()
}
}
}
Loading…
Cancel
Save