From 27aaca6b118c6187df20fb9913130c5ee3864ad8 Mon Sep 17 00:00:00 2001 From: jakeroseman Date: Fri, 11 Oct 2024 11:37:08 +0100 Subject: [PATCH 1/6] Tooltip component examples --- .../compose/snippets/SnippetsActivity.kt | 2 + .../compose/snippets/components/Tooltips.kt | 162 ++++++++++++++++++ .../snippets/navigation/Destination.kt | 3 +- 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/SnippetsActivity.kt b/compose/snippets/src/main/java/com/example/compose/snippets/SnippetsActivity.kt index 645cd9e54..023d81140 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/SnippetsActivity.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/SnippetsActivity.kt @@ -48,6 +48,7 @@ import com.example.compose.snippets.components.ScaffoldExample import com.example.compose.snippets.components.SliderExamples import com.example.compose.snippets.components.SwitchExamples import com.example.compose.snippets.components.TimePickerExamples +import com.example.compose.snippets.components.TooltipExamples import com.example.compose.snippets.graphics.ApplyPolygonAsClipImage import com.example.compose.snippets.graphics.BitmapFromComposableFullSnippet import com.example.compose.snippets.graphics.BrushExamplesScreen @@ -113,6 +114,7 @@ class SnippetsActivity : ComponentActivity() { TopComponentsDestination.DatePickerExamples -> DatePickerExamples() TopComponentsDestination.CarouselExamples -> CarouselExamples() TopComponentsDestination.MenusExample -> MenusExamples() + TopComponentsDestination.TooltipExamples -> TooltipExamples() } } } diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt new file mode 100644 index 000000000..dc9063753 --- /dev/null +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt @@ -0,0 +1,162 @@ +package com.example.compose.snippets.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Camera +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.Info +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.PlainTooltip +import androidx.compose.material3.RichTooltip +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.rememberTooltipState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp + +@Composable +fun TooltipExamples(){ + Text( + "Long press an icon to see the tooltip.", + modifier = Modifier.fillMaxWidth().padding(16.dp), + textAlign = TextAlign.Center + ) + Row( + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxSize() + ) { + PlainTooltipExample() + RichTooltipExample() + AdvancedRichTooltipExample() + } +} + +@OptIn(ExperimentalMaterial3Api::class) +// [START android_compose_components_plaintooltipexample] +@Composable +fun PlainTooltipExample( + modifier: Modifier = Modifier, + plainTooltipText: String = "Add to favorites" +) { + TooltipBox( + modifier = modifier, + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { Text(plainTooltipText) } + }, + state = rememberTooltipState() + ) { + IconButton(onClick = { /* Icon button's click event */ }) { + Icon( + imageVector = Icons.Filled.Favorite, + contentDescription = "Localized Description" + ) + } + } +} +// [END android_compose_components_plaintooltipexample] + +@Preview +@Composable +private fun PlainTooltipSamplePreview() { + PlainTooltipExample() +} + +@OptIn(ExperimentalMaterial3Api::class) +// [START android_compose_components_richtooltipexample] +@Composable +fun RichTooltipExample( + modifier: Modifier = Modifier, + richTooltipSubheadText: String = "Rich Tooltip", + richTooltipText: String = "Rich tooltips supports multiple lines of informational text." +) { + val tooltipState = rememberTooltipState(isPersistent = true) + + TooltipBox( + modifier = modifier, + positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(), + tooltip = { + RichTooltip( + title = { Text(richTooltipSubheadText) } + ) { + Text(richTooltipText) + } + }, state = tooltipState + ) { + IconButton(onClick = { /* Icon button's click event */ }) { + Icon( + imageVector = Icons.Filled.Info, + contentDescription = "Localized Description" + ) + } + } +} +// [END android_compose_components_richtooltipexample] + +@Preview +@Composable +private fun RichTooltipSamplePreview() { + RichTooltipExample() +} + +@OptIn(ExperimentalMaterial3Api::class) +// [START android_compose_components_advancedrichtooltipexample] +@Composable +fun AdvancedRichTooltipExample( + modifier: Modifier = Modifier, + richTooltipSubheadText: String = "Custom Rich Tooltip", + richTooltipText: String = "Rich tooltips supports multiple lines of informational text.", + richTooltipActionText: String = "Dismiss" +) { + val tooltipState = rememberTooltipState(isPersistent = true) + + TooltipBox( + modifier = modifier, + positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(), + tooltip = { + RichTooltip( + title = { Text(richTooltipSubheadText) }, + action = { + Row { + TextButton(onClick = { /* Do something... */ }) { + Text(richTooltipActionText) + } + TextButton(onClick = { /* Do something... */ }) { + Text("Learn more") + } + } + }, + caretSize = DpSize(32.dp, 16.dp) + ) { + Text(richTooltipText) + } + }, + state = tooltipState + ) { + IconButton(onClick = { /* Icon button's click event */ }) { + Icon(imageVector = Icons.Filled.Camera, contentDescription = "Localized Description") + } + } +} +// [END android_compose_components_advancedrichtooltipexample] + +@Preview +@Composable +private fun RichTooltipWithCustomCaretSamplePreview() { + AdvancedRichTooltipExample() +} + diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/navigation/Destination.kt b/compose/snippets/src/main/java/com/example/compose/snippets/navigation/Destination.kt index 0bce08f0d..9e3a64f0f 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/navigation/Destination.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/navigation/Destination.kt @@ -45,5 +45,6 @@ enum class TopComponentsDestination(val route: String, val title: String) { TimePickerExamples("timePickerExamples", "Time Pickers"), DatePickerExamples("datePickerExamples", "Date Pickers"), CarouselExamples("carouselExamples", "Carousel"), - MenusExample("menusExamples", "Menus") + MenusExample("menusExamples", "Menus"), + TooltipExamples("tooltipExamples", "Tooltips") } From c076771c908aeb98aa025c0e505a62a5a17903da Mon Sep 17 00:00:00 2001 From: jakeroseman Date: Fri, 11 Oct 2024 10:40:36 +0000 Subject: [PATCH 2/6] Apply Spotless --- .../compose/snippets/components/Tooltips.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt index dc9063753..40367477b 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 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 + * + * https://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 com.example.compose.snippets.components import androidx.compose.foundation.layout.Arrangement @@ -28,7 +44,7 @@ import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp @Composable -fun TooltipExamples(){ +fun TooltipExamples() { Text( "Long press an icon to see the tooltip.", modifier = Modifier.fillMaxWidth().padding(16.dp), @@ -159,4 +175,3 @@ fun AdvancedRichTooltipExample( private fun RichTooltipWithCustomCaretSamplePreview() { AdvancedRichTooltipExample() } - From b2ebc5a1eda8487472f16bf08382b9f1712ba572 Mon Sep 17 00:00:00 2001 From: jakeroseman Date: Fri, 11 Oct 2024 12:04:31 +0100 Subject: [PATCH 3/6] Addressing PR comments --- .../example/compose/snippets/components/Tooltips.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt index dc9063753..9284b4397 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt @@ -63,7 +63,7 @@ fun PlainTooltipExample( IconButton(onClick = { /* Icon button's click event */ }) { Icon( imageVector = Icons.Filled.Favorite, - contentDescription = "Localized Description" + contentDescription = "Add to favorites" ) } } @@ -100,7 +100,7 @@ fun RichTooltipExample( IconButton(onClick = { /* Icon button's click event */ }) { Icon( imageVector = Icons.Filled.Info, - contentDescription = "Localized Description" + contentDescription = "Show more information" ) } } @@ -132,12 +132,9 @@ fun AdvancedRichTooltipExample( title = { Text(richTooltipSubheadText) }, action = { Row { - TextButton(onClick = { /* Do something... */ }) { + TextButton(onClick = { tooltipState.dismiss() }) { Text(richTooltipActionText) } - TextButton(onClick = { /* Do something... */ }) { - Text("Learn more") - } } }, caretSize = DpSize(32.dp, 16.dp) @@ -147,7 +144,7 @@ fun AdvancedRichTooltipExample( }, state = tooltipState ) { - IconButton(onClick = { /* Icon button's click event */ }) { + IconButton(onClick = { tooltipState.dismiss() }) { Icon(imageVector = Icons.Filled.Camera, contentDescription = "Localized Description") } } From 39e44bdb8130d4792cdd103de0c03a0fd7d37e61 Mon Sep 17 00:00:00 2001 From: jakeroseman Date: Fri, 11 Oct 2024 15:13:01 +0100 Subject: [PATCH 4/6] use LaunchedEffect to fix tooltip bug --- .../compose/snippets/components/Tooltips.kt | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt index 9284b4397..1b43a34f9 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt @@ -1,6 +1,7 @@ package com.example.compose.snippets.components import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -18,14 +19,21 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults -import androidx.compose.material3.rememberTooltipState +import androidx.compose.material3.TooltipState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch @Composable fun TooltipExamples(){ @@ -45,6 +53,12 @@ fun TooltipExamples(){ } } +@Preview +@Composable +private fun TooltipExamplesPreview() { + TooltipExamples() +} + @OptIn(ExperimentalMaterial3Api::class) // [START android_compose_components_plaintooltipexample] @Composable @@ -52,22 +66,31 @@ fun PlainTooltipExample( modifier: Modifier = Modifier, plainTooltipText: String = "Add to favorites" ) { + var tooltipState by remember { mutableStateOf(TooltipState()) } TooltipBox( modifier = modifier, positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), tooltip = { PlainTooltip { Text(plainTooltipText) } }, - state = rememberTooltipState() + state = tooltipState ) { - IconButton(onClick = { /* Icon button's click event */ }) { + IconButton(onClick = { /* Do something... */ }) { Icon( imageVector = Icons.Filled.Favorite, - contentDescription = "Add to favorites" + contentDescription = "Localized Description" ) } } + + // Reset tooltipState after closing the tooltip. + LaunchedEffect(tooltipState.isVisible) { + if (!tooltipState.isVisible) { + tooltipState = TooltipState() + } + } } + // [END android_compose_components_plaintooltipexample] @Preview @@ -82,9 +105,9 @@ private fun PlainTooltipSamplePreview() { fun RichTooltipExample( modifier: Modifier = Modifier, richTooltipSubheadText: String = "Rich Tooltip", - richTooltipText: String = "Rich tooltips supports multiple lines of informational text." + richTooltipText: String = "Rich tooltips support multiple lines of informational text." ) { - val tooltipState = rememberTooltipState(isPersistent = true) + var tooltipState by remember { mutableStateOf(TooltipState(isPersistent = true)) } TooltipBox( modifier = modifier, @@ -95,7 +118,8 @@ fun RichTooltipExample( ) { Text(richTooltipText) } - }, state = tooltipState + }, + state = tooltipState ) { IconButton(onClick = { /* Icon button's click event */ }) { Icon( @@ -104,6 +128,13 @@ fun RichTooltipExample( ) } } + + // Reset tooltipState after closing the tooltip. + LaunchedEffect(tooltipState.isVisible) { + if (!tooltipState.isVisible) { + tooltipState = TooltipState(isPersistent = true) + } + } } // [END android_compose_components_richtooltipexample] @@ -119,10 +150,10 @@ private fun RichTooltipSamplePreview() { fun AdvancedRichTooltipExample( modifier: Modifier = Modifier, richTooltipSubheadText: String = "Custom Rich Tooltip", - richTooltipText: String = "Rich tooltips supports multiple lines of informational text.", + richTooltipText: String = "Rich tooltips support multiple lines of informational text.", richTooltipActionText: String = "Dismiss" ) { - val tooltipState = rememberTooltipState(isPersistent = true) + var tooltipState by remember { mutableStateOf(TooltipState(isPersistent = true)) } TooltipBox( modifier = modifier, @@ -145,7 +176,17 @@ fun AdvancedRichTooltipExample( state = tooltipState ) { IconButton(onClick = { tooltipState.dismiss() }) { - Icon(imageVector = Icons.Filled.Camera, contentDescription = "Localized Description") + Icon( + imageVector = Icons.Filled.Camera, + contentDescription = "Localized Description" + ) + } + } + + // Reset tooltipState after closing the tooltip. + LaunchedEffect(tooltipState.isVisible) { + if (!tooltipState.isVisible) { + tooltipState = TooltipState(isPersistent = true) } } } From 80be6565a5d75cafc3dfe53ed682cf24fb30a8a4 Mon Sep 17 00:00:00 2001 From: jakeroseman Date: Fri, 11 Oct 2024 14:15:11 +0000 Subject: [PATCH 5/6] Apply Spotless --- .../java/com/example/compose/snippets/components/Tooltips.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt index c562307f6..7b2e40288 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt @@ -17,7 +17,6 @@ package com.example.compose.snippets.components import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -41,7 +40,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -49,7 +47,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import kotlinx.coroutines.launch @Composable fun TooltipExamples() { From 3d4a520b972a79b69dc6ebc9262023286af2c1ef Mon Sep 17 00:00:00 2001 From: jakeroseman Date: Fri, 11 Oct 2024 15:21:34 +0100 Subject: [PATCH 6/6] Updated content descriptions --- .../java/com/example/compose/snippets/components/Tooltips.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt index c562307f6..6440ba523 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/Tooltips.kt @@ -94,7 +94,7 @@ fun PlainTooltipExample( IconButton(onClick = { /* Do something... */ }) { Icon( imageVector = Icons.Filled.Favorite, - contentDescription = "Localized Description" + contentDescription = "Add to favorites" ) } } @@ -194,7 +194,7 @@ fun AdvancedRichTooltipExample( IconButton(onClick = { tooltipState.dismiss() }) { Icon( imageVector = Icons.Filled.Camera, - contentDescription = "Localized Description" + contentDescription = "Open camera" ) } }