diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt index 2e9ec6e6ad..8517f57552 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt @@ -2939,7 +2939,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { .performClick() composeTestRule - .onNodeWithTag(testTag = "ClearButton") + .onNodeWithText(text = "Clear") .performClick() verify { @@ -2976,7 +2976,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { .performClick() composeTestRule - .onNodeWithTag(testTag = "ClearButton") + .onNodeWithText(text = "Clear") .performClick() verify { @@ -3014,7 +3014,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { .performClick() composeTestRule - .onNodeWithTag(testTag = "ClearButton") + .onNodeWithText(text = "Clear") .performClick() verify { @@ -3218,7 +3218,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { .performClick() composeTestRule - .onNodeWithTag(testTag = "ClearButton") + .onNodeWithText(text = "Clear") .performClick() verify { @@ -3256,7 +3256,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { .performClick() composeTestRule - .onNodeWithTag(testTag = "ClearButton") + .onNodeWithText(text = "Clear") .performClick() verify { @@ -3294,7 +3294,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { .performClick() composeTestRule - .onNodeWithTag(testTag = "ClearButton") + .onNodeWithText(text = "Clear") .performClick() verify { diff --git a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/dialog/BitwardenDatePickerDialog.kt b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/dialog/BitwardenDatePickerDialog.kt index 24af126d8c..33209ffa20 100644 --- a/ui/src/main/kotlin/com/bitwarden/ui/platform/components/dialog/BitwardenDatePickerDialog.kt +++ b/ui/src/main/kotlin/com/bitwarden/ui/platform/components/dialog/BitwardenDatePickerDialog.kt @@ -1,8 +1,22 @@ package com.bitwarden.ui.platform.components.dialog +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.DatePicker import androidx.compose.material3.DatePickerColors -import androidx.compose.material3.DatePickerDialog +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Surface import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -12,6 +26,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTag import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import com.bitwarden.ui.platform.components.button.BitwardenTextButton import com.bitwarden.ui.platform.components.field.color.bitwardenTextFieldColors import com.bitwarden.ui.platform.resource.BitwardenString @@ -27,6 +42,8 @@ import java.time.ZoneOffset * @param onDateSelect The callback invoked with the selected [LocalDate] when the user confirms. * @param onDismissRequest The callback invoked when the dialog is dismissed. */ +@Suppress("LongMethod") +@OptIn(ExperimentalMaterial3Api::class) @Composable fun BitwardenDatePickerDialog( initialDate: LocalDate?, @@ -39,49 +56,71 @@ fun BitwardenDatePickerDialog( ?.toInstant() ?.toEpochMilli(), ) - DatePickerDialog( + BasicAlertDialog( onDismissRequest = onDismissRequest, - confirmButton = { - BitwardenTextButton( - label = stringResource(id = BitwardenString.okay), - onClick = { - datePickerState - .selectedDateMillis - ?.let { millis -> - Instant - .ofEpochMilli(millis) - .atZone(ZoneOffset.UTC) - .toLocalDate() - } - .let(onDateSelect) - }, - modifier = Modifier.testTag(tag = "AcceptAlertButton"), - ) - }, - dismissButton = { - BitwardenTextButton( - label = stringResource(id = BitwardenString.clear), - onClick = { onDateSelect(null) }, - contentColor = BitwardenTheme.colorScheme.status.error, - modifier = Modifier.testTag(tag = "ClearButton"), - ) - BitwardenTextButton( - label = stringResource(id = BitwardenString.cancel), - onClick = onDismissRequest, - modifier = Modifier.testTag(tag = "DismissAlertButton"), - ) - }, - shape = BitwardenTheme.shapes.dialog, - colors = bitwardenDatePickerColors(), - modifier = Modifier.semantics { - testTagsAsResourceId = true - testTag = "DatePickerDialog" - }, + modifier = Modifier + .semantics { + testTagsAsResourceId = true + testTag = "DatePickerDialog" + } + .wrapContentHeight(), ) { - DatePicker( - state = datePickerState, - colors = bitwardenDatePickerColors(), - ) + val colors = bitwardenDatePickerColors() + Surface( + modifier = Modifier + // The Date picker has specific requirements in order to look correct. + // It does not follow the normal dialog size rules. + .requiredWidth(width = 360.dp) + .heightIn(max = 568.0.dp), + shape = BitwardenTheme.shapes.dialog, + color = colors.containerColor, + ) { + Column { + // Wrap the content in a Box with a weight of 1f to ensure that any buttons + // are not pushed out of view when running on small screens. Fill is false to + // support collapsing the dialog's height when switching to input mode. + Box(modifier = Modifier.weight(weight = 1f, fill = false)) { + DatePicker( + modifier = Modifier.verticalScroll(state = rememberScrollState()), + state = datePickerState, + colors = colors, + ) + } + Row(modifier = Modifier.padding(bottom = 8.dp, start = 12.dp)) { + BitwardenTextButton( + label = stringResource(id = BitwardenString.clear), + onClick = { onDateSelect(null) }, + modifier = Modifier.testTag(tag = "ClearAlertButton"), + ) + Spacer(modifier = Modifier.weight(weight = 1f)) + FlowRow( + horizontalArrangement = Arrangement.End, + modifier = Modifier.padding(horizontal = 8.dp), + ) { + BitwardenTextButton( + label = stringResource(id = BitwardenString.cancel), + onClick = onDismissRequest, + modifier = Modifier.testTag(tag = "DismissAlertButton"), + ) + BitwardenTextButton( + label = stringResource(id = BitwardenString.okay), + onClick = { + datePickerState + .selectedDateMillis + ?.let { millis -> + Instant + .ofEpochMilli(millis) + .atZone(ZoneOffset.UTC) + .toLocalDate() + } + .let(onDateSelect) + }, + modifier = Modifier.testTag(tag = "AcceptAlertButton"), + ) + } + } + } + } } }