Skip to content

Commit

Permalink
"Non scrollable" dialog (#2244)
Browse files Browse the repository at this point in the history
  • Loading branch information
yschimke authored May 29, 2024
1 parent ab0e3c5 commit 635fd3b
Show file tree
Hide file tree
Showing 102 changed files with 560 additions and 4 deletions.
1 change: 1 addition & 0 deletions compose-material/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ package com.google.android.horologist.compose.material {

public final class ResponsiveDialogKt {
method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void ResponsiveDialogContent(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? message, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onOk, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onCancel, optional String okButtonContentDescription, optional String cancelButtonContentDescription, optional com.google.android.horologist.compose.layout.ScalingLazyColumnState state, optional boolean showPositionIndicator, optional kotlin.jvm.functions.Function1<? super androidx.wear.compose.foundation.lazy.ScalingLazyListScope,kotlin.Unit>? content);
method @androidx.compose.runtime.Composable public static com.google.android.horologist.compose.layout.ScalingLazyColumnState centeredDialogColumnState();
}

public final class ResponsiveListHeaderKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.google.android.horologist.compose.material

import android.R
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
Expand All @@ -42,6 +41,7 @@ import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.AutoCenteringParams
import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
import androidx.wear.compose.material.ButtonDefaults
import androidx.wear.compose.material.ChipColors
Expand All @@ -50,6 +50,7 @@ import androidx.wear.compose.material.LocalTextStyle
import androidx.wear.compose.material.MaterialTheme
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.layout.ScalingLazyColumn
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.responsive
import com.google.android.horologist.compose.layout.ScalingLazyColumnState
import com.google.android.horologist.compose.layout.ScreenScaffold
Expand All @@ -65,8 +66,8 @@ public fun ResponsiveDialogContent(
message: @Composable (() -> Unit)? = null,
onOk: (() -> Unit)? = null,
onCancel: (() -> Unit)? = null,
okButtonContentDescription: String = stringResource(R.string.ok),
cancelButtonContentDescription: String = stringResource(R.string.cancel),
okButtonContentDescription: String = stringResource(android.R.string.ok),
cancelButtonContentDescription: String = stringResource(android.R.string.cancel),
state: ScalingLazyColumnState =
rememberColumnState(
responsive(
Expand Down Expand Up @@ -224,3 +225,13 @@ internal val titleMaxWidthFraction = 1f - 2f * calculatePaddingFraction(
// Calculate total padding given global padding and additional padding required inside that.
internal fun calculatePaddingFraction(extraPadding: Float) =
extraPadding / (100f - 2f * globalHorizontalPadding)

@Composable
public fun centeredDialogColumnState(): ScalingLazyColumnState = rememberColumnState(
ScalingLazyColumnDefaults.scalingLazyColumnDefaults(
initialCenterIndex = 0,
initialCenterOffset = 50,
verticalArrangement = spacedBy(4.dp, Alignment.CenterVertically),
autoCentering = AutoCenteringParams(itemIndex = 0, itemOffset = 50),
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.google.android.horologist.compose.layout.ScalingLazyColumnState
import com.google.android.horologist.compose.material.AlertDialog
import com.google.android.horologist.compose.material.ToggleChip
import com.google.android.horologist.compose.material.ToggleChipToggleControl
import com.google.android.horologist.compose.material.centeredDialogColumnState

@Composable
internal fun SampleAlertDialog(
Expand All @@ -44,6 +45,7 @@ internal fun SampleAlertDialog(
var showSimpleDialog by remember { mutableStateOf(false) }
var showBedtimeModeDialog by remember { mutableStateOf(false) }
var showAllowDebuggingDialog by remember { mutableStateOf(false) }
var showCenteredDialog by remember { mutableStateOf(false) }
ScalingLazyColumn(
columnState = columnState,
modifier = modifier,
Expand All @@ -61,6 +63,14 @@ internal fun SampleAlertDialog(
modifier = Modifier.fillMaxWidth(),
)
}
item {
Chip(
onClick = { showCenteredDialog = true },
label = { Text("Centered alert") },
colors = ChipDefaults.secondaryChipColors(),
modifier = Modifier.fillMaxWidth(),
)
}
item {
Chip(
onClick = { showBedtimeModeDialog = true },
Expand All @@ -79,7 +89,7 @@ internal fun SampleAlertDialog(
}
}

// Simple AlertDialog sample with icon, title and Ok/Cancel buttons.
// Simple AlertDialog sample with icon, title, message and Ok/Cancel buttons.
AlertDialog(
showDialog = showSimpleDialog,
onCancel = { showSimpleDialog = false },
Expand All @@ -94,6 +104,15 @@ internal fun SampleAlertDialog(
message = "Icon and Text dialog use up to 2 lines.",
)

// Centered AlertDialog sample with title and Ok/Cancel buttons.
AlertDialog(
showDialog = showCenteredDialog,
onCancel = { showCenteredDialog = false },
onOk = { showCenteredDialog = false },
title = "A Centered Dialog",
state = centeredDialogColumnState(),
)

// "Bedtime mode" AlertDialog sample, with Ok/Cancel buttons and extra content.
var bedtimeMode by remember { mutableStateOf(false) }
AlertDialog(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.google.android.horologist.dialog

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.compose.material.AlertContent
import com.google.android.horologist.compose.material.centeredDialogColumnState

@ExperimentalHorologistApi
@Composable
public fun NonScrollableAlertContent(
onCancel: (() -> Unit)? = null,
onOk: (() -> Unit)? = null,
icon: @Composable (() -> Unit)? = null,
title: String? = null,
message: String? = null,
okButtonContentDescription: String = stringResource(android.R.string.ok),
cancelButtonContentDescription: String = stringResource(android.R.string.cancel),
showPositionIndicator: Boolean = true,
content: (ScalingLazyListScope.() -> Unit)? = null,
) {
val columnState = centeredDialogColumnState()

AlertContent(
onCancel,
onOk,
icon,
title,
message,
okButtonContentDescription,
cancelButtonContentDescription,
columnState,
showPositionIndicator,
content,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2022 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.google.android.horologist.dialog

import androidx.compose.ui.res.stringResource
import com.google.android.horologist.audio.ui.R.string.horologist_volume_screen_change_audio_output
import com.google.android.horologist.compose.material.AlertContent
import com.google.android.horologist.screenshots.rng.WearDevice
import com.google.android.horologist.screenshots.rng.WearDeviceScreenshotTest
import org.junit.Test
import org.robolectric.annotation.Config

class NonScrollableAlertDialogTest(device: WearDevice) : WearDeviceScreenshotTest(device = device) {
public override val tolerance: Float = 0.01f

override fun testName(suffix: String): String =
"src/test/screenshots/${this.javaClass.simpleName}_${testInfo.methodName.substringBefore('[')}_${device.id}$suffix.png"

// Not actually non scrolling - but should only be used when developer is confident that
// content won't scroll

@Test
fun turnOnBluetoothScrollable() = runTest {
AlertContent(
title = "Turn on Bluetooth?",
onOk = {},
onCancel = {},
)
}

@Test
fun turnOnBluetooth() = runTest {
NonScrollableAlertContent(
title = "Turn on Bluetooth?",
onOk = {},
onCancel = {},
)
}

@Test
fun changeAudioOutputEn() = runTest {
NonScrollableAlertContent(
title = stringResource(horologist_volume_screen_change_audio_output),
onOk = {},
onCancel = {},
)
}

@Test
@Config(qualifiers = "+ka")
fun changeAudioOutputKa() = runTest {
NonScrollableAlertContent(
title = stringResource(horologist_volume_screen_change_audio_output),
onOk = {},
onCancel = {},
)
}

@Test
@Config(qualifiers = "+ta")
fun changeAudioOutputTa() = runTest {
NonScrollableAlertContent(
title = stringResource(horologist_volume_screen_change_audio_output),
onOk = {},
onCancel = {},
)
}

@Test
@Config(qualifiers = "+ru")
fun changeAudioOutputRu() = runTest {
NonScrollableAlertContent(
title = stringResource(horologist_volume_screen_change_audio_output),
onOk = {},
onCancel = {},
)
}

@Test
fun tooLong() = runTest {
NonScrollableAlertContent(
title = "Phone app is required",
onCancel = {},
onOk = {},
message = "Tap the button below to install it on your phone.",
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2022 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.google.android.horologist.dialog

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Error
import androidx.compose.ui.res.stringResource
import androidx.wear.compose.material.Icon
import com.google.android.horologist.auth.composables.R.string.horologist_auth_error_message
import com.google.android.horologist.compose.material.ConfirmationContent
import com.google.android.horologist.compose.material.util.DECORATIVE_ELEMENT_CONTENT_DESCRIPTION
import com.google.android.horologist.screenshots.rng.WearDevice
import com.google.android.horologist.screenshots.rng.WearDeviceScreenshotTest
import org.junit.Test
import org.robolectric.annotation.Config

class NonScrollableConfirmationTest(device: WearDevice) : WearDeviceScreenshotTest(device = device) {
public override val tolerance: Float = 0.01f

override fun testName(suffix: String): String =
"src/test/screenshots/${this.javaClass.simpleName}_${testInfo.methodName.substringBefore('[')}_${device.id}$suffix.png"

// Not actually non scrolling - but demonstrating content that won't scroll

@Test
fun confirmationContentEn() = runTest {
ConfirmationContent(
title = stringResource(horologist_auth_error_message),
)
}

@Test
@Config(qualifiers = "+ka")
fun confirmationContentKa() = runTest {
ConfirmationContent(
title = stringResource(horologist_auth_error_message),
)
}

@Test
@Config(qualifiers = "+ta")
fun confirmationContentTa() = runTest {
ConfirmationContent(
title = stringResource(horologist_auth_error_message),
)
}

@Test
@Config(qualifiers = "+ru")
fun confirmationContentRu() = runTest {
ConfirmationContent(
title = stringResource(horologist_auth_error_message),
)
}

@Test
fun confirmationContentWithIcon() = runTest {
ConfirmationContent(
title = stringResource(horologist_auth_error_message),
icon = {
Icon(
imageVector = Icons.Filled.Error,
contentDescription = DECORATIVE_ELEMENT_CONTENT_DESCRIPTION,
)
},
)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 635fd3b

Please sign in to comment.