From 1104d106d44ce83e6624384f5aa2d573a0d000c1 Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Wed, 21 May 2025 12:40:43 -0400 Subject: [PATCH 1/9] add search to playground --- .../PaymentSheetPlaygroundActivity.kt | 101 +++++++++++++++++- .../example/playground/settings/SettingsUI.kt | 35 ++++-- 2 files changed, 129 insertions(+), 7 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index 342486f255e..02a942c924d 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -14,17 +14,35 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button +import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Search 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.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.CustomerSheetResult @@ -204,7 +222,17 @@ internal class PaymentSheetPlaygroundActivity : ) } + var settingsSearchQuery by rememberSaveable { mutableStateOf("") } PlaygroundTheme( + topBarContent = { + SearchSettingsField( + modifier = Modifier + .statusBarsPadding() + .padding(horizontal = 16.dp), + query = settingsSearchQuery, + onQueryChanged = { settingsSearchQuery = it } + ) + }, content = { playgroundState?.asPaymentState()?.endpoint?.let { customEndpoint -> Text( @@ -222,7 +250,10 @@ internal class PaymentSheetPlaygroundActivity : ) } - SettingsUi(playgroundSettings = localPlaygroundSettings) + SettingsUi( + searchQuery = settingsSearchQuery, + playgroundSettings = localPlaygroundSettings, + ) AppearanceButton() @@ -261,6 +292,74 @@ internal class PaymentSheetPlaygroundActivity : } } + @Composable + private fun SearchSettingsField( + query: String, + onQueryChanged: (String) -> Unit, + modifier: Modifier = Modifier, + ) { + var hasFocus by remember { mutableStateOf(false) } + val keyboardController = LocalSoftwareKeyboardController.current + TextField( + modifier = modifier + .onFocusChanged { hasFocus = it.isFocused } + .onKeyEvent { + if (it.key == Key.Enter) { + keyboardController?.hide() + true + } else { + false + } + } + .fillMaxWidth(), + value = query, + placeholder = if (hasFocus) { + null + } else { + @Composable { + Text(text = "Search") + } + }, + singleLine = true, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { keyboardController?.show() } + ), + leadingIcon = { + Icon( + imageVector = Icons.Default.Search, + contentDescription = null, + ) + }, + trailingIcon = if (query.isEmpty()) { + null + } else { + @Composable { + IconButton(onClick = { onQueryChanged("") }) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = null, + ) + } + } + }, + onValueChange = onQueryChanged, + ) + } + + @Preview(showBackground = true) + @Composable + private fun SearchSettingsFieldPreview() { + var query by remember { mutableStateOf("") } + SearchSettingsField( + query = query, + onQueryChanged = { query = it }, + ) + } + @Composable private fun AppearanceButton() { Button( diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index 0f1bec501ef..d2a1f24b438 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -22,13 +22,23 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.stripe.android.paymentsheet.example.playground.PlaygroundTheme import kotlinx.coroutines.flow.StateFlow @Composable -internal fun SettingsUi(playgroundSettings: PlaygroundSettings) { +internal fun SettingsUi( + playgroundSettings: PlaygroundSettings, + searchQuery: String, +) { val configurationData by playgroundSettings.configurationData.collectAsState() val displayableDefinitions by playgroundSettings.displayableDefinitions.collectAsState() + val filteredDefinitions = remember(displayableDefinitions, searchQuery) { + displayableDefinitions.filter { + it.displayName.contains(searchQuery, ignoreCase = true) + } + } Column( modifier = Modifier.padding(bottom = 16.dp), @@ -41,14 +51,27 @@ internal fun SettingsUi(playgroundSettings: PlaygroundSettings) { ) } - for (settingDefinition in displayableDefinitions) { - Row { - Setting(settingDefinition, playgroundSettings) - } + for (settingDefinition in filteredDefinitions) { + Setting(settingDefinition, playgroundSettings) } } } +@Preview +@Composable +private fun SettingsUiPreview() { + PlaygroundTheme( + content = { + SettingsUi( + playgroundSettings = PlaygroundSettings.createFromDefaults(), + searchQuery = "", + ) + }, + bottomBarContent = {}, + topBarContent = {} + ) +} + @Composable private fun Setting( settingDefinition: PlaygroundSettingDefinition.Displayable, @@ -56,7 +79,7 @@ private fun Setting( ) { val configurationData by playgroundSettings.configurationData.collectAsState() - val options = remember(configurationData) { + val options = remember(settingDefinition, configurationData) { settingDefinition.createOptions(configurationData) } From 1297f148e5c0539ae06f378f3b449fb47409ec0b Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Wed, 21 May 2025 12:58:22 -0400 Subject: [PATCH 2/9] always show reload; hide keyboard; better results --- .../PaymentSheetPlaygroundActivity.kt | 15 +++++++++++++++ .../example/playground/settings/SettingsUI.kt | 17 ++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index 02a942c924d..faf049569df 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -11,8 +11,14 @@ import androidx.appcompat.app.AppCompatActivity import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.exclude import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.text.KeyboardActions @@ -278,6 +284,13 @@ internal class PaymentSheetPlaygroundActivity : ) } } + + Spacer( + Modifier.padding( + WindowInsets.ime.exclude(WindowInsets.navigationBars) + .asPaddingValues() + ) + ) }, ) @@ -425,8 +438,10 @@ internal class PaymentSheetPlaygroundActivity : @Composable private fun ReloadButton(playgroundSettings: PlaygroundSettings) { + val keyboardController = LocalSoftwareKeyboardController.current Button( onClick = { + keyboardController?.hide() viewModel.prepare( playgroundSettings = playgroundSettings, ) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index d2a1f24b438..9c97a0535ef 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -34,9 +34,10 @@ internal fun SettingsUi( ) { val configurationData by playgroundSettings.configurationData.collectAsState() val displayableDefinitions by playgroundSettings.displayableDefinitions.collectAsState() - val filteredDefinitions = remember(displayableDefinitions, searchQuery) { + val trimmedSearchQuery = searchQuery.trim() + val filteredDefinitions = remember(displayableDefinitions, trimmedSearchQuery) { displayableDefinitions.filter { - it.displayName.contains(searchQuery, ignoreCase = true) + it.displayName.contains(trimmedSearchQuery, ignoreCase = true) } } @@ -44,11 +45,13 @@ internal fun SettingsUi( modifier = Modifier.padding(bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - Row { - IntegrationTypeConfigurableSetting( - configurationData, - playgroundSettings::updateConfigurationData - ) + if (searchQuery.isBlank()) { + Row { + IntegrationTypeConfigurableSetting( + configurationData, + playgroundSettings::updateConfigurationData + ) + } } for (settingDefinition in filteredDefinitions) { From 618c7dec9464508a698fdcd84e7ecee8b89d3c55 Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Fri, 30 May 2025 17:26:55 -0400 Subject: [PATCH 3/9] move composables outside Activity class --- .../PaymentSheetPlaygroundActivity.kt | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index faf049569df..1b512c3b726 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -305,74 +305,6 @@ internal class PaymentSheetPlaygroundActivity : } } - @Composable - private fun SearchSettingsField( - query: String, - onQueryChanged: (String) -> Unit, - modifier: Modifier = Modifier, - ) { - var hasFocus by remember { mutableStateOf(false) } - val keyboardController = LocalSoftwareKeyboardController.current - TextField( - modifier = modifier - .onFocusChanged { hasFocus = it.isFocused } - .onKeyEvent { - if (it.key == Key.Enter) { - keyboardController?.hide() - true - } else { - false - } - } - .fillMaxWidth(), - value = query, - placeholder = if (hasFocus) { - null - } else { - @Composable { - Text(text = "Search") - } - }, - singleLine = true, - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, - imeAction = ImeAction.Done - ), - keyboardActions = KeyboardActions( - onDone = { keyboardController?.show() } - ), - leadingIcon = { - Icon( - imageVector = Icons.Default.Search, - contentDescription = null, - ) - }, - trailingIcon = if (query.isEmpty()) { - null - } else { - @Composable { - IconButton(onClick = { onQueryChanged("") }) { - Icon( - imageVector = Icons.Default.Close, - contentDescription = null, - ) - } - } - }, - onValueChange = onQueryChanged, - ) - } - - @Preview(showBackground = true) - @Composable - private fun SearchSettingsFieldPreview() { - var query by remember { mutableStateOf("") } - SearchSettingsField( - query = query, - onQueryChanged = { query = it }, - ) - } - @Composable private fun AppearanceButton() { Button( @@ -806,5 +738,73 @@ internal class PaymentSheetPlaygroundActivity : } } +@Composable +private fun SearchSettingsField( + query: String, + onQueryChanged: (String) -> Unit, + modifier: Modifier = Modifier, +) { + var hasFocus by remember { mutableStateOf(false) } + val keyboardController = LocalSoftwareKeyboardController.current + TextField( + modifier = modifier + .onFocusChanged { hasFocus = it.isFocused } + .onKeyEvent { + if (it.key == Key.Enter) { + keyboardController?.hide() + true + } else { + false + } + } + .fillMaxWidth(), + value = query, + placeholder = if (hasFocus) { + null + } else { + @Composable { + Text(text = "Search") + } + }, + singleLine = true, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { keyboardController?.show() } + ), + leadingIcon = { + Icon( + imageVector = Icons.Default.Search, + contentDescription = null, + ) + }, + trailingIcon = if (query.isEmpty()) { + null + } else { + @Composable { + IconButton(onClick = { onQueryChanged("") }) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = null, + ) + } + } + }, + onValueChange = onQueryChanged, + ) +} + +@Preview(showBackground = true) +@Composable +private fun SearchSettingsFieldPreview() { + var query by remember { mutableStateOf("") } + SearchSettingsField( + query = query, + onQueryChanged = { query = it }, + ) +} + const val RELOAD_TEST_TAG = "RELOAD" private const val PLAYGROUND_BOTTOM_BAR_LABEL = "PlaygroundBottomBar" From 221a2c65d00cc4d09631224d88929c2c5c29c03c Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Fri, 30 May 2025 17:27:20 -0400 Subject: [PATCH 4/9] filter "Integration Type" --- .../example/playground/settings/SettingsUI.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index 9c97a0535ef..bfeb80805bd 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -36,16 +36,14 @@ internal fun SettingsUi( val displayableDefinitions by playgroundSettings.displayableDefinitions.collectAsState() val trimmedSearchQuery = searchQuery.trim() val filteredDefinitions = remember(displayableDefinitions, trimmedSearchQuery) { - displayableDefinitions.filter { - it.displayName.contains(trimmedSearchQuery, ignoreCase = true) - } + displayableDefinitions.filter { it.displayName.matchesQuery(trimmedSearchQuery) } } Column( modifier = Modifier.padding(bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - if (searchQuery.isBlank()) { + if (IntegrationTypeSettingName.matchesQuery(trimmedSearchQuery)) { Row { IntegrationTypeConfigurableSetting( configurationData, @@ -60,6 +58,10 @@ internal fun SettingsUi( } } +private fun String.matchesQuery(query: String): Boolean { + return this.contains(query, ignoreCase = true) +} + @Preview @Composable private fun SettingsUiPreview() { @@ -127,13 +129,15 @@ private fun Setting( } } +private const val IntegrationTypeSettingName = "Integration Type" + @Composable private fun IntegrationTypeConfigurableSetting( configurationData: PlaygroundConfigurationData, updateConfigurationData: (updater: (PlaygroundConfigurationData) -> PlaygroundConfigurationData) -> Unit ) { DropdownSetting( - name = "Integration Type", + name = IntegrationTypeSettingName, options = listOf( PlaygroundSettingDefinition.Displayable.Option( name = "Payment Sheet", From 3581222eeadd6cc069b3fcd4e2f7e51a6200c509 Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Fri, 30 May 2025 20:48:23 -0400 Subject: [PATCH 5/9] better search algorithm --- .../example/playground/settings/SettingsUI.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index bfeb80805bd..c7f4d95ce92 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -58,8 +58,21 @@ internal fun SettingsUi( } } +private val WordBoundaryRegex by lazy(LazyThreadSafetyMode.NONE) { "\\s+".toRegex() } + +/** + * Returns true if the string matches the query. + */ private fun String.matchesQuery(query: String): Boolean { - return this.contains(query, ignoreCase = true) + if (query.isBlank()) { + return true + } + + val words = this.trim().split(WordBoundaryRegex) + val queryWords = query.trim().split(WordBoundaryRegex) + return queryWords.all { queryWord -> + words.any { word -> word.startsWith(queryWord, ignoreCase = true) } + } } @Preview From edc01b057a10beeaebc3747dca67259ef143e211 Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Mon, 2 Jun 2025 14:34:03 -0400 Subject: [PATCH 6/9] tweaks --- .../example/playground/PaymentSheetPlaygroundActivity.kt | 2 +- .../paymentsheet/example/playground/settings/SettingsUI.kt | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index 1b512c3b726..28512e321c2 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -763,7 +763,7 @@ private fun SearchSettingsField( null } else { @Composable { - Text(text = "Search") + Text(text = "Search settings") } }, singleLine = true, diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index c7f4d95ce92..ca6a2e7b321 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -34,16 +34,15 @@ internal fun SettingsUi( ) { val configurationData by playgroundSettings.configurationData.collectAsState() val displayableDefinitions by playgroundSettings.displayableDefinitions.collectAsState() - val trimmedSearchQuery = searchQuery.trim() - val filteredDefinitions = remember(displayableDefinitions, trimmedSearchQuery) { - displayableDefinitions.filter { it.displayName.matchesQuery(trimmedSearchQuery) } + val filteredDefinitions = remember(displayableDefinitions, searchQuery) { + displayableDefinitions.filter { it.displayName.matchesQuery(searchQuery) } } Column( modifier = Modifier.padding(bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - if (IntegrationTypeSettingName.matchesQuery(trimmedSearchQuery)) { + if (IntegrationTypeSettingName.matchesQuery(searchQuery)) { Row { IntegrationTypeConfigurableSetting( configurationData, From ea3664311fb20b4382731b85e4d41b17683af845 Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Mon, 2 Jun 2025 15:21:16 -0400 Subject: [PATCH 7/9] fix settings composables --- .../example/playground/settings/SettingsUI.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index ca6a2e7b321..440ab489791 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -217,7 +217,9 @@ private fun RadioButtonSetting( ) } - val selectedOption = remember(value) { options.firstOrNull { it.value == value } } + val selectedOption = remember(options, value) { + options.firstOrNull { it.value == value } + } Row { options.forEach { option -> @@ -262,7 +264,9 @@ internal fun DropdownSetting( onOptionChanged: (T) -> Unit, ) { var expanded by remember { mutableStateOf(false) } - val selectedOption = remember(value) { options.firstOrNull { it.value == value } } + val selectedOption = remember(options, value) { + options.firstOrNull { it.value == value } + } ExposedDropdownMenuBox( expanded = expanded, From 049bb0ca21aea5c9f8fbc5a9f25400a58a7a413a Mon Sep 17 00:00:00 2001 From: Larry Ng Date: Mon, 2 Jun 2025 15:39:45 -0400 Subject: [PATCH 8/9] more precise padding --- .../example/playground/PaymentSheetPlaygroundActivity.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index 28512e321c2..d68a646375a 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -16,11 +16,12 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.exclude import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button @@ -286,9 +287,10 @@ internal class PaymentSheetPlaygroundActivity : } Spacer( - Modifier.padding( - WindowInsets.ime.exclude(WindowInsets.navigationBars) + Modifier.height( + WindowInsets.ime.exclude(WindowInsets.systemBars) .asPaddingValues() + .calculateBottomPadding() ) ) }, From 75ec847f3f5fbd1c7137c8d2a60667322da24367 Mon Sep 17 00:00:00 2001 From: tianzhao-stripe Date: Tue, 29 Jul 2025 12:26:28 -0700 Subject: [PATCH 9/9] add empty text --- .../example/playground/settings/SettingsUI.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt index 440ab489791..e01262f1c69 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/settings/SettingsUI.kt @@ -51,8 +51,12 @@ internal fun SettingsUi( } } - for (settingDefinition in filteredDefinitions) { - Setting(settingDefinition, playgroundSettings) + if (filteredDefinitions.isEmpty()) { + Text("No matching settings found") + } else { + for (settingDefinition in filteredDefinitions) { + Setting(settingDefinition, playgroundSettings) + } } } }