diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Button.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Button.kt index f58a547600..bcb92b37e9 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Button.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Button.kt @@ -39,6 +39,7 @@ import com.hedvig.android.design.system.hedvig.tokens.MediumSizeButtonTokens import com.hedvig.android.design.system.hedvig.tokens.MiniSizeButtonTokens import com.hedvig.android.design.system.hedvig.tokens.PrimaryAltStyleButtonTokens import com.hedvig.android.design.system.hedvig.tokens.PrimaryStyleButtonTokens +import com.hedvig.android.design.system.hedvig.tokens.RedStyleButtonTokens import com.hedvig.android.design.system.hedvig.tokens.SecondaryAltStyleButtonTokens import com.hedvig.android.design.system.hedvig.tokens.SecondaryStyleButtonTokens import com.hedvig.android.design.system.hedvig.tokens.SmallSizeButtonTokens @@ -181,6 +182,7 @@ object ButtonDefaults { Secondary, SecondaryAlt, Ghost, + Red, } enum class ButtonSize { @@ -198,6 +200,7 @@ private val ButtonDefaults.ButtonStyle.style: Style ButtonDefaults.ButtonStyle.Secondary -> Style.Secondary ButtonDefaults.ButtonStyle.SecondaryAlt -> Style.SecondaryAlt ButtonDefaults.ButtonStyle.Ghost -> Style.Ghost + ButtonDefaults.ButtonStyle.Red -> Style.Red } private val ButtonDefaults.ButtonSize.size: Size @@ -427,4 +430,24 @@ private sealed interface Style { } } } + + data object Red : Style { + override val buttonColors: ButtonColors + @Composable + get() = with(HedvigTheme.colorScheme) { + remember(this) { + ButtonColors( + containerColor = fromToken(RedStyleButtonTokens.ContainerColor), + contentColor = fromToken(RedStyleButtonTokens.ContentColor), + disabledContainerColor = fromToken(RedStyleButtonTokens.DisabledContainerColor), + disabledContentColor = fromToken(RedStyleButtonTokens.DisabledContentColor), + hoverContainerColor = fromToken(RedStyleButtonTokens.HoverContainerColor), + hoverContentColor = fromToken(RedStyleButtonTokens.HoverContentColor), + activeLoadingIndicatorColor = fromToken(RedStyleButtonTokens.ActiveLoadingIndicatorColor), + inactiveLoadingIndicatorColor = fromToken(RedStyleButtonTokens.InactiveLoadingIndicatorColor), + redTextColor = fromToken(RedStyleButtonTokens.RedContentColor), + ) + } + } + } } diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Dialog.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Dialog.kt index af8afbcf68..520015b897 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Dialog.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/Dialog.kt @@ -53,6 +53,7 @@ fun ErrorDialog( text = title, description = message, iconStyle = ERROR, + modifier = Modifier.fillMaxWidth(), buttonStyle = EmptyStateButtonStyle.Button( buttonText = buttonText, onButtonClick = onButtonClick ?: onDismiss, diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/HedvigCard.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/HedvigCard.kt index 1e37671063..9ec8ba35a9 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/HedvigCard.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/HedvigCard.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale @@ -46,11 +47,12 @@ fun HedvigCard( onClick: (() -> Unit)? = null, interactionSource: MutableInteractionSource? = null, indication: Indication? = null, + shape: Shape = HedvigTheme.shapes.cornerXLarge, content: @Composable () -> Unit, ) { if (onClick != null) { Surface( - shape = HedvigTheme.shapes.cornerXLarge, + shape = shape, onClick = onClick, interactionSource = interactionSource, indication = indication, @@ -60,7 +62,7 @@ fun HedvigCard( } } else { Surface( - shape = HedvigTheme.shapes.cornerXLarge, + shape = shape, modifier = modifier, ) { content() diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/ButtonTokens.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/ButtonTokens.kt index 894125d352..14740f3b12 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/ButtonTokens.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/ButtonTokens.kt @@ -58,6 +58,18 @@ internal object GhostStyleButtonTokens { val InactiveLoadingIndicatorColor = ColorSchemeKeyTokens.SurfaceSecondaryTransparent } +internal object RedStyleButtonTokens { + val ContainerColor = ColorSchemeKeyTokens.SignalRedElement + val ContentColor = ColorSchemeKeyTokens.TextWhite + val HoverContainerColor = ColorSchemeKeyTokens.ButtonPrimaryHover + val HoverContentColor = ColorSchemeKeyTokens.TextWhite + val DisabledContainerColor = ColorSchemeKeyTokens.ButtonPrimaryDisabled + val DisabledContentColor = ColorSchemeKeyTokens.TextTertiary + val ActiveLoadingIndicatorColor = ColorSchemeKeyTokens.TextWhite + val InactiveLoadingIndicatorColor = ColorSchemeKeyTokens.SignalRedText + val RedContentColor = ColorSchemeKeyTokens.SignalRedElement // should not be used ever +} + internal object LargeSizeButtonTokens { val HorizontalPadding = 32.dp val TopPadding = 15.dp diff --git a/app/feature/feature-delete-account/src/main/kotlin/com/hedvig/android/feature/deleteaccount/DeleteAccountDestination.kt b/app/feature/feature-delete-account/src/main/kotlin/com/hedvig/android/feature/deleteaccount/DeleteAccountDestination.kt index bdf074f943..d0689dd6c6 100644 --- a/app/feature/feature-delete-account/src/main/kotlin/com/hedvig/android/feature/deleteaccount/DeleteAccountDestination.kt +++ b/app/feature/feature-delete-account/src/main/kotlin/com/hedvig/android/feature/deleteaccount/DeleteAccountDestination.kt @@ -15,11 +15,11 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.halilibo.richtext.commonmark.Markdown +import com.hedvig.android.design.system.hedvig.ButtonDefaults import com.hedvig.android.design.system.hedvig.HedvigButton import com.hedvig.android.design.system.hedvig.HedvigErrorSection import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgress import com.hedvig.android.design.system.hedvig.HedvigPreview -import com.hedvig.android.design.system.hedvig.HedvigRedTextButton import com.hedvig.android.design.system.hedvig.HedvigScaffold import com.hedvig.android.design.system.hedvig.HedvigText import com.hedvig.android.design.system.hedvig.HedvigTheme @@ -124,26 +124,21 @@ private fun DeleteScreenContents( Spacer(Modifier.height(16.dp)) Spacer(Modifier.weight(1f)) Spacer(Modifier.height(8.dp)) - if (isButtonRed) { - HedvigRedTextButton( - text = buttonText, - onClick = onButtonClick, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) + val buttonStyle = if (isButtonRed) { + ButtonDefaults.ButtonStyle.Red } else { - HedvigButton( - text = buttonText, - onClick = onButtonClick, - enabled = true, - isLoading = isButtonLoading, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) + ButtonDefaults.ButtonStyle.Primary } - + HedvigButton( + text = buttonText, + onClick = onButtonClick, + enabled = true, + buttonStyle = buttonStyle, + isLoading = isButtonLoading, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) Spacer(Modifier.height(16.dp)) } } diff --git a/app/feature/feature-edit-coinsured/build.gradle.kts b/app/feature/feature-edit-coinsured/build.gradle.kts index bfa52a9ab5..9b2f8d7240 100644 --- a/app/feature/feature-edit-coinsured/build.gradle.kts +++ b/app/feature/feature-edit-coinsured/build.gradle.kts @@ -15,8 +15,7 @@ android { dependencies { api(libs.androidx.navigation.common) - - implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.foundation) implementation(libs.androidx.lifecycle.compose) implementation(libs.androidx.navigation.compose) implementation(libs.arrow.core) @@ -31,10 +30,7 @@ dependencies { implementation(projects.coreAppReview) implementation(projects.coreCommonPublic) implementation(projects.coreDemoMode) - implementation(projects.coreDesignSystem) - implementation(projects.coreIcons) implementation(projects.coreResources) - implementation(projects.coreUi) implementation(projects.coreUiData) implementation(projects.designSystemHedvig) implementation(projects.moleculeAndroid) diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt index 4487328bdc..28be0a9708 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/AddCoInsuredBottomSheetContent.kt @@ -10,28 +10,19 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.windowInsetsBottomHeight -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.DatePickerDialog -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.rememberDatePickerState import androidx.compose.runtime.Composable 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.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource @@ -47,35 +38,44 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp -import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton -import com.hedvig.android.core.designsystem.component.button.HedvigTextButton -import com.hedvig.android.core.designsystem.component.card.HedvigCard -import com.hedvig.android.core.designsystem.component.datepicker.HedvigDatePicker -import com.hedvig.android.core.designsystem.component.textfield.HedvigTextField -import com.hedvig.android.core.designsystem.preview.HedvigPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme -import com.hedvig.android.core.ui.SelectIndicationCircle -import com.hedvig.android.core.ui.getLocale -import com.hedvig.android.core.ui.infocard.VectorWarningCard -import com.hedvig.android.core.ui.rememberHedvigDateTimeFormatter -import com.hedvig.android.core.ui.text.HorizontalItemsWithMaximumSpaceTaken -import com.hedvig.android.core.ui.text.WarningTextWithIconForInput import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonStyle.Ghost +import com.hedvig.android.design.system.hedvig.ChosenState import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigCard +import com.hedvig.android.design.system.hedvig.HedvigNotificationCard +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTextButton +import com.hedvig.android.design.system.hedvig.HedvigTextField +import com.hedvig.android.design.system.hedvig.HedvigTextFieldDefaults +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.HedvigToggle +import com.hedvig.android.design.system.hedvig.NotificationDefaults +import com.hedvig.android.design.system.hedvig.RadioOption +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.ToggleDefaults.ToggleDefaultStyleSize.Small +import com.hedvig.android.design.system.hedvig.ToggleDefaults.ToggleStyle +import com.hedvig.android.design.system.hedvig.api.HedvigSelectableDates +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePicker +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDateTimeFormatterDefaults +import com.hedvig.android.design.system.hedvig.datepicker.getLocale import com.hedvig.android.feature.editcoinsured.data.CoInsured -import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.AddBottomSheetState +import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.AddBottomSheetContentState import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.InfoFromSsn import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.ManualInfo import hedvig.resources.R +import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone +import kotlinx.datetime.atStartOfDayIn import kotlinx.datetime.toJavaLocalDate import kotlinx.datetime.toLocalDateTime @Composable internal fun AddCoInsuredBottomSheetContent( - bottomSheetState: AddBottomSheetState, + bottomSheetState: AddBottomSheetContentState, onSsnChanged: (String) -> Unit, onContinue: () -> Unit, onDismiss: () -> Unit, @@ -88,7 +88,7 @@ internal fun AddCoInsuredBottomSheetContent( ) { Column { Spacer(Modifier.height(16.dp)) - Text( + HedvigText( text = stringResource(id = R.string.CONTRACT_ADD_COINSURED), textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), @@ -124,52 +124,35 @@ internal fun AddCoInsuredBottomSheetContent( ) } Spacer(Modifier.height(4.dp)) - - HedvigCard( + HedvigToggle( + turnedOn = bottomSheetState.showManualInput, onClick = { - onManualInputSwitchChanged(!bottomSheetState.showManualInput) + onManualInputSwitchChanged(it) }, modifier = Modifier.fillMaxWidth(), - ) { - HorizontalItemsWithMaximumSpaceTaken( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), - startSlot = { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(id = R.string.CONTRACT_ADD_COINSURED_NO_SSN), - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - }, - endSlot = { - Switch( - checked = bottomSheetState.showManualInput, - onCheckedChange = onManualInputSwitchChanged, - modifier = Modifier.wrapContentSize(Alignment.CenterEnd), - ) - }, - spaceBetween = 4.dp, - ) - } + toggleStyle = ToggleStyle.Default(Small), + labelText = stringResource(id = R.string.CONTRACT_ADD_COINSURED_NO_SSN), + enabled = true, + ) AnimatedVisibility(bottomSheetState.showUnderAgedInfo) { Column { Spacer(Modifier.height(4.dp)) - VectorWarningCard( - text = stringResource( + HedvigNotificationCard( + message = stringResource( id = R.string.COINSURED_WITHOUT_SSN_INFO, ), + priority = NotificationDefaults.NotificationPriority.Attention, ) } } } Spacer(Modifier.height(16.dp)) - HedvigContainedButton( + HedvigButton( text = stringResource(id = bottomSheetState.getSaveLabel().stringRes()), enabled = bottomSheetState.canContinue(), onClick = onContinue, isLoading = bottomSheetState.isLoading, + modifier = Modifier.fillMaxWidth(), ) Spacer(Modifier.height(8.dp)) HedvigButton( @@ -201,32 +184,29 @@ internal fun SelectableCoInsuredList( Spacer(Modifier.height(4.dp)) } AnimatedVisibility(visible = errorMessage != null) { - WarningTextWithIconForInput(text = errorMessage ?: "") + HedvigNotificationCard( + message = errorMessage ?: "", + modifier = Modifier.fillMaxWidth(), + priority = NotificationDefaults.NotificationPriority.Attention, + ) } HedvigTextButton( text = stringResource(id = R.string.GENERAL_ADD_NEW), onClick = { onAddNewCoInsured() }, + modifier = Modifier.fillMaxWidth(), ) } @Composable private fun SelectableHedvigCard(text: String, isSelected: Boolean, onClick: () -> Unit) { - HedvigCard(onClick = onClick) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .heightIn(72.dp) - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 10.dp), - ) { - Text( - text = text, - style = MaterialTheme.typography.headlineSmall, - modifier = Modifier.weight(1f), - ) - Spacer(Modifier.width(8.dp)) - SelectIndicationCircle(isSelected) - } + RadioOption( + chosenState = if (isSelected) ChosenState.Chosen else ChosenState.NotChosen, + onClick = onClick, + modifier = Modifier.fillMaxWidth(), + ) { + HedvigText( + text = text, + ) } } @@ -240,20 +220,23 @@ private fun FetchFromSsnFields( ) { var ssnInput by remember { mutableStateOf(ssn ?: "") } val mask = stringResource(id = R.string.edit_coinsured_ssn_placeholder) - val maskColor = MaterialTheme.colorScheme.onSurfaceVariant + val maskColor = HedvigTheme.colorScheme.textSecondary Column { HedvigTextField( - value = ssnInput, - label = { - Text(stringResource(id = R.string.CONTRACT_PERSONAL_IDENTITY)) - }, - onValueChange = { - if (it.length <= 12) { - onSsnChanged(it) - ssnInput = it + text = ssnInput, + labelText = stringResource(id = R.string.CONTRACT_PERSONAL_IDENTITY), + onValueChange = { value -> + if (value.length <= 12) { + onSsnChanged(value) + ssnInput = value } }, - errorText = errorMessage, + textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, + errorState = if (errorMessage != null) { + HedvigTextFieldDefaults.ErrorState.Error.WithMessage(stringResource(R.string.something_went_wrong)) + } else { + HedvigTextFieldDefaults.ErrorState.NoError + }, visualTransformation = PersonalNumberVisualTransformation(mask, maskColor), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, @@ -271,11 +254,10 @@ private fun FetchFromSsnFields( modifier = Modifier.padding(top = 4.dp), ) { HedvigTextField( - value = displayName, + text = displayName, onValueChange = {}, - label = { - Text(stringResource(id = R.string.FULL_NAME_TEXT)) - }, + labelText = stringResource(id = R.string.FULL_NAME_TEXT), + textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, enabled = false, modifier = Modifier.fillMaxWidth(), ) @@ -342,133 +324,126 @@ private fun ManualInputFields( modifier = Modifier.fillMaxWidth(), ) Spacer(Modifier.height(4.dp)) - HorizontalItemsWithMaximumSpaceTaken( - startSlot = { - HedvigTextField( - value = firstNameInput, - label = { - Text(stringResource(id = R.string.CONTRACT_FIRST_NAME)) - }, - onValueChange = { - onFirstNameChanged(it) - firstNameInput = it - }, - keyboardOptions = KeyboardOptions( - capitalization = KeyboardCapitalization.Words, - keyboardType = KeyboardType.Text, - ), - modifier = Modifier.fillMaxWidth(), - ) - }, - endSlot = { - HedvigTextField( - value = lastNameInput, - label = { - Text(stringResource(id = R.string.CONTRACT_LAST_NAME)) - }, - onValueChange = { - onLastNameChanged(it) - lastNameInput = it - }, - keyboardOptions = KeyboardOptions( - capitalization = KeyboardCapitalization.Words, - keyboardType = KeyboardType.Text, - ), - modifier = Modifier.fillMaxWidth(), - ) - }, - spaceBetween = 4.dp, - ) - - Spacer(Modifier.height(4.dp)) + Row { + HedvigTextField( + text = firstNameInput, + labelText = stringResource(id = R.string.CONTRACT_FIRST_NAME), + textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, + onValueChange = { + onFirstNameChanged(it) + firstNameInput = it + }, + keyboardOptions = KeyboardOptions( + capitalization = KeyboardCapitalization.Words, + keyboardType = KeyboardType.Text, + ), + modifier = Modifier.weight(1f).requiredHeight(64.dp), + ) + Spacer(Modifier.width(4.dp)) + HedvigTextField( + text = lastNameInput, + textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, + labelText = stringResource(id = R.string.CONTRACT_LAST_NAME), + onValueChange = { + onLastNameChanged(it) + lastNameInput = it + }, + keyboardOptions = KeyboardOptions( + capitalization = KeyboardCapitalization.Words, + keyboardType = KeyboardType.Text, + ), + modifier = Modifier.weight(1f).requiredHeight(64.dp), + ) + } AnimatedVisibility( visible = errorMessage != null, enter = fadeIn(), exit = fadeOut(), ) { - WarningTextWithIconForInput(text = errorMessage ?: "") + Column { + Spacer(Modifier.height(4.dp)) + HedvigNotificationCard( + message = stringResource(R.string.something_went_wrong), + priority = NotificationDefaults.NotificationPriority.Attention, + modifier = Modifier.fillMaxWidth(), + ) + } } } } @Composable internal fun DatePickerWithDialog(birthDate: LocalDate?, onSave: (LocalDate) -> Unit, modifier: Modifier = Modifier) { - val datePickerState = rememberDatePickerState() - - val selectedDateMillis: Long? = datePickerState.selectedDateMillis + val selectedDateMillis = birthDate?.atStartOfDayIn(TimeZone.UTC)?.toEpochMilliseconds() + ?: Clock.System.now().toEpochMilliseconds() val locale = getLocale() - val hedvigDateTimeFormatter = rememberHedvigDateTimeFormatter() - val selectedDate = remember(locale, selectedDateMillis) { - if (selectedDateMillis == null) { - null - } else { - Instant.fromEpochMilliseconds(selectedDateMillis) - .toLocalDateTime(TimeZone.UTC) - .date - } + var showDatePicker by rememberSaveable { mutableStateOf(false) } + val rememberHedvigDateTimeFormatter = remember(locale) { + HedvigDateTimeFormatterDefaults.dateMonthAndYear(locale) } + val datePickerState by remember { + mutableStateOf( + HedvigDatePickerState( + locale = locale, + initialSelectedDateMillis = selectedDateMillis, + initialDisplayedMonthMillis = selectedDateMillis, + selectableDates = object : HedvigSelectableDates { + override fun isSelectableDate(utcTimeMillis: Long): Boolean { + return utcTimeMillis <= Clock.System.now().toEpochMilliseconds() // todo: check here pls + } - var showDatePicker by rememberSaveable { mutableStateOf(false) } + override fun isSelectableYear(year: Int): Boolean = + year <= Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).year + }, + ), + ) + } if (showDatePicker) { - DatePickerDialog( + HedvigDatePicker( + datePickerState = datePickerState, onDismissRequest = { showDatePicker = false }, - confirmButton = { - TextButton( - onClick = { - showDatePicker = false - selectedDate?.let { - onSave(selectedDate) - } - }, - shape = MaterialTheme.shapes.medium, - ) { - Text(stringResource(R.string.general_save_button)) - } - }, - dismissButton = { - TextButton( - onClick = { - showDatePicker = false - }, - shape = MaterialTheme.shapes.medium, - ) { - Text(stringResource(R.string.general_cancel_button)) + onConfirmRequest = { + val selected = datePickerState.selectedDateMillis + if (selected != null) { + val date = Instant.fromEpochMilliseconds(selected) + .toLocalDateTime(TimeZone.currentSystemDefault()).date + onSave(date) } + showDatePicker = false }, - ) { - HedvigDatePicker(datePickerState = datePickerState) - } + ) } HedvigCard( onClick = { showDatePicker = true }, modifier = modifier, + shape = HedvigTheme.shapes.cornerLarge, ) { Column(Modifier.padding(top = 4.dp, bottom = 8.dp)) { val paddingForBirthDate = if (birthDate == null) { - PaddingValues(start = 16.dp, end = 16.dp, top = 12.dp, bottom = 8.dp) + PaddingValues(start = 16.dp, end = 16.dp, top = 15.dp, bottom = 13.dp) } else { PaddingValues(horizontal = 16.dp) } if (birthDate != null) { - Text( + HedvigText( text = stringResource(id = R.string.CONTRACT_BIRTH_DATE), - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = MaterialTheme.typography.labelMedium.fontSize, + color = HedvigTheme.colorScheme.textSecondary, + fontSize = HedvigTheme.typography.label.fontSize, modifier = Modifier.padding( horizontal = 16.dp, ), ) } - Text( + HedvigText( text = if (birthDate != null) { - hedvigDateTimeFormatter.format(birthDate.toJavaLocalDate()) + rememberHedvigDateTimeFormatter.format(birthDate.toJavaLocalDate()) } else { stringResource(id = R.string.CONTRACT_BIRTH_DATE) }, color = if (birthDate != null) { Color.Unspecified } else { - MaterialTheme.colorScheme.onSurfaceVariant + HedvigTheme.colorScheme.textSecondaryTranslucent }, modifier = Modifier.padding( paddingForBirthDate, @@ -478,18 +453,18 @@ internal fun DatePickerWithDialog(birthDate: LocalDate?, onSave: (LocalDate) -> } } -private fun AddBottomSheetState.SaveButtonLabel.stringRes() = when (this) { - AddBottomSheetState.SaveButtonLabel.FETCH_INFO -> R.string.CONTRACT_SSN_FETCH_INFO - AddBottomSheetState.SaveButtonLabel.ADD -> R.string.CONTRACT_ADD_COINSURED +private fun AddBottomSheetContentState.SaveButtonLabel.stringRes() = when (this) { + AddBottomSheetContentState.SaveButtonLabel.FETCH_INFO -> R.string.CONTRACT_SSN_FETCH_INFO + AddBottomSheetContentState.SaveButtonLabel.ADD -> R.string.CONTRACT_ADD_COINSURED } @Composable @HedvigPreview private fun AddCoInsuredBottomSheetContentPreview() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { AddCoInsuredBottomSheetContent( - bottomSheetState = AddBottomSheetState( + bottomSheetState = AddBottomSheetContentState( errorMessage = "Error", manualInfo = ManualInfo(), infoFromSsn = InfoFromSsn(), @@ -528,15 +503,16 @@ private fun AddCoInsuredBottomSheetContentPreview() { @HedvigPreview private fun AddCoInsuredBottomSheetContentWithCoInsuredPreview() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { AddCoInsuredBottomSheetContent( - bottomSheetState = AddBottomSheetState( + bottomSheetState = AddBottomSheetContentState( errorMessage = "errorMessage", showUnderAgedInfo = true, showManualInput = true, infoFromSsn = InfoFromSsn(), manualInfo = ManualInfo( - birthDate = LocalDate(2016, 7, 28), + birthDate = null, + // birthDate = LocalDate(2016, 7, 28), ), ), onSsnChanged = {}, diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/CoInsuredList.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/CoInsuredList.kt index 0042adf975..2f6f52d067 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/CoInsuredList.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/CoInsuredList.kt @@ -1,11 +1,11 @@ package com.hedvig.android.feature.editcoinsured.ui import androidx.compose.foundation.layout.Column -import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import com.hedvig.android.core.ui.rememberHedvigBirthDateDateTimeFormatter +import com.hedvig.android.design.system.hedvig.HorizontalDivider +import com.hedvig.android.design.system.hedvig.datepicker.rememberHedvigBirthDateDateTimeFormatter import com.hedvig.android.feature.editcoinsured.data.CoInsured import hedvig.resources.R diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt index f3e7a0589a..a64deb7d87 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddMissingInfoDestination.kt @@ -14,31 +14,38 @@ import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton -import com.hedvig.android.core.designsystem.component.button.HedvigTextButton -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgressDebounced -import com.hedvig.android.core.designsystem.preview.HedvigMultiScreenPreview -import com.hedvig.android.core.designsystem.preview.HedvigPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme -import com.hedvig.android.core.ui.appbar.m3.TopAppBarWithBack -import com.hedvig.android.core.ui.dialog.ErrorDialog -import com.hedvig.android.core.ui.infocard.VectorWarningCard import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.design.system.hedvig.ErrorDialog import com.hedvig.android.design.system.hedvig.HedvigBottomSheet +import com.hedvig.android.design.system.hedvig.HedvigBottomSheetState +import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgressDebounced +import com.hedvig.android.design.system.hedvig.HedvigMultiScreenPreview +import com.hedvig.android.design.system.hedvig.HedvigNotificationCard +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigTextButton +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.NotificationDefaults +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.TopAppBar +import com.hedvig.android.design.system.hedvig.TopAppBarActionType +import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.feature.editcoinsured.data.CoInsured import com.hedvig.android.feature.editcoinsured.data.Member import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.InfoFromSsn import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.ManualInfo import hedvig.resources.R +import kotlinx.coroutines.flow.drop import kotlinx.datetime.LocalDate @Composable @@ -113,9 +120,10 @@ private fun EditCoInsuredScreen( onCoInsuredSelected: (CoInsured) -> Unit, ) { Column(Modifier.fillMaxSize()) { - TopAppBarWithBack( + TopAppBar( title = stringResource(id = R.string.COINSURED_EDIT_TITLE), - onClick = navigateUp, + actionType = TopAppBarActionType.BACK, + onActionClick = navigateUp, ) when (uiState) { @@ -133,18 +141,18 @@ private fun EditCoInsuredScreen( onCompleted(uiState.contractUpdateDate) } } + val hedvigBottomSheetState = rememberHedvigBottomSheetState() + DismissSheetOnSuccessfulInfoChangeEffect(hedvigBottomSheetState, uiState.finishedAdding) + ClearBottomSheetContentStateOnSheetDismissedEffect(hedvigBottomSheetState, onResetAddBottomSheetState) HedvigBottomSheet( - isVisible = uiState.addBottomSheetState.show, - onVisibleChange = { isVisible -> - if (!isVisible) { - onResetAddBottomSheetState() - } - }, + hedvigBottomSheetState = hedvigBottomSheetState, ) { AddCoInsuredBottomSheetContent( - bottomSheetState = uiState.addBottomSheetState, + bottomSheetState = uiState.addBottomSheetContentState, onContinue = onBottomSheetContinue, - onDismiss = onResetAddBottomSheetState, + onDismiss = { + hedvigBottomSheetState.dismiss() + }, onSsnChanged = onSsnChanged, onFirstNameChanged = onFirstNameChanged, onLastNameChanged = onLastNameChanged, @@ -167,17 +175,21 @@ private fun EditCoInsuredScreen( CoInsuredList( uiState = uiState.listState, onRemove = {}, - onEdit = onCoInsuredClicked, + onEdit = { insured -> + hedvigBottomSheetState.show(uiState.addBottomSheetContentState) + onCoInsuredClicked(insured) + }, allowEdit = true, modifier = Modifier.padding(horizontal = 16.dp), ) Spacer(Modifier.height(8.dp)) if (uiState.listState.priceInfo != null && uiState.listState.hasMadeChanges()) { - VectorWarningCard( - text = stringResource( + HedvigNotificationCard( + message = stringResource( id = R.string.CONTRACT_ADD_COINSURED_REVIEW_INFO, ), + priority = NotificationDefaults.NotificationPriority.Attention, modifier = Modifier.padding(horizontal = 16.dp).fillMaxWidth(), ) } @@ -186,12 +198,12 @@ private fun EditCoInsuredScreen( Column { if (uiState.listState.priceInfo != null && uiState.listState.hasMadeChanges()) { Spacer(Modifier.height(8.dp)) - HedvigContainedButton( + HedvigButton( text = stringResource(id = R.string.GENERAL_SAVE_CHANGES_BUTTON), onClick = onCommitChanges, enabled = true, isLoading = uiState.listState.isCommittingUpdate, - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier.padding(horizontal = 16.dp).fillMaxWidth(), ) } } @@ -199,7 +211,7 @@ private fun EditCoInsuredScreen( HedvigTextButton( onClick = navigateUp, text = stringResource(R.string.general_cancel_button), - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier.padding(horizontal = 16.dp).fillMaxWidth(), ) Spacer(Modifier.height(16.dp)) Spacer(Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom))) @@ -211,6 +223,100 @@ private fun EditCoInsuredScreen( } } +@Composable +internal fun DismissSheetOnSuccessfulInfoChangeEffect( + sheetState: HedvigBottomSheetState, + infoSuccessfullyChanged: Boolean, +) { + val updatedInfoSuccessfullyChanged by rememberUpdatedState(infoSuccessfullyChanged) + LaunchedEffect(sheetState) { + snapshotFlow { updatedInfoSuccessfullyChanged } + .drop(1) + .collect { + if (it) { + sheetState.dismiss() + } + } + } +} + +@Composable +internal fun DismissRemoveCoinsuredSheetOnSuccessfulRemoveEffect( + sheetState: HedvigBottomSheetState, + coInsuredSuccessfullyRemoved: Boolean, +) { + val updatedCoInsuredSuccessfullyRemoved by rememberUpdatedState(coInsuredSuccessfullyRemoved) + LaunchedEffect(sheetState) { + snapshotFlow { updatedCoInsuredSuccessfullyRemoved } + .drop(1) + .collect { + if (it) { + sheetState.dismiss() + } + } + } +} + +@Composable +internal fun ClearRemoveBottomSheetContentStateOnSheetDismissedEffect( + sheetState: HedvigBottomSheetState, + clearBottomSheetState: () -> Unit, +) { + val updatedClearBottomSheetState by rememberUpdatedState(clearBottomSheetState) + LaunchedEffect(sheetState) { + snapshotFlow { sheetState.isVisible } + .drop(1) + .collect { + if (!it) { + updatedClearBottomSheetState() + } + } + } +} + +@Composable +internal fun ClearBottomSheetContentStateOnSheetDismissedEffect( + sheetState: HedvigBottomSheetState, + clearBottomSheetState: () -> Unit, +) { + val updatedClearBottomSheetState by rememberUpdatedState(clearBottomSheetState) + LaunchedEffect(sheetState) { + snapshotFlow { sheetState.isVisible } + .drop(1) + .collect { + if (!it) { + updatedClearBottomSheetState() + } + } + } +} + +@Composable +@HedvigPreview +private fun EditCoInsuredScreenErrorPreview() { + HedvigTheme { + Surface { + EditCoInsuredScreen( + navigateUp = { }, + uiState = EditCoInsuredState.Error("Something"), + onCoInsuredClicked = {}, + onSsnChanged = {}, + onBottomSheetContinue = {}, + onCommitChanges = {}, + onCompleted = {}, + onDismissError = {}, + onResetAddBottomSheetState = {}, + onFirstNameChanged = {}, + onLastNameChanged = {}, + onBirthDateChanged = {}, + onManualInputSwitchChanged = {}, + onAddNewCoInsured = {}, + onCoInsuredSelected = {}, + ) + } + } +} + @Composable @HedvigMultiScreenPreview private fun EditCoInsuredScreenEditablePreview() { @@ -271,12 +377,12 @@ private fun EditCoInsuredScreenEditablePreview() { ), allCoInsured = listOf(), ), - addBottomSheetState = EditCoInsuredState.Loaded.AddBottomSheetState( + addBottomSheetContentState = EditCoInsuredState.Loaded.AddBottomSheetContentState( isLoading = false, manualInfo = ManualInfo(), infoFromSsn = InfoFromSsn(), ), - removeBottomSheetState = EditCoInsuredState.Loaded.RemoveBottomSheetState(), + removeBottomSheetContentState = EditCoInsuredState.Loaded.RemoveBottomSheetContentState(), ), onCoInsuredClicked = {}, onSsnChanged = {}, @@ -328,12 +434,12 @@ private fun EditCoInsuredScreenNonEditablePreview() { ), allCoInsured = listOf(), ), - addBottomSheetState = EditCoInsuredState.Loaded.AddBottomSheetState( + addBottomSheetContentState = EditCoInsuredState.Loaded.AddBottomSheetContentState( isLoading = false, infoFromSsn = InfoFromSsn(), manualInfo = ManualInfo(), ), - removeBottomSheetState = EditCoInsuredState.Loaded.RemoveBottomSheetState(), + removeBottomSheetContentState = EditCoInsuredState.Loaded.RemoveBottomSheetContentState(), ), onCoInsuredClicked = {}, onSsnChanged = {}, diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddOrRemoveDestination.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddOrRemoveDestination.kt index fe6acedc9b..4bb0f1979c 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddOrRemoveDestination.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredAddOrRemoveDestination.kt @@ -16,10 +16,6 @@ import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -32,24 +28,29 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton -import com.hedvig.android.core.designsystem.component.button.HedvigSecondaryContainedButton -import com.hedvig.android.core.designsystem.component.button.HedvigTextButton -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgressDebounced -import com.hedvig.android.core.designsystem.preview.HedvigMultiScreenPreview -import com.hedvig.android.core.designsystem.preview.HedvigPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme -import com.hedvig.android.core.ui.appbar.m3.TopAppBarWithBack -import com.hedvig.android.core.ui.dialog.ErrorDialog -import com.hedvig.android.core.ui.rememberHedvigDateTimeFormatter -import com.hedvig.android.core.ui.text.HorizontalItemsWithMaximumSpaceTaken import com.hedvig.android.core.uidata.UiCurrencyCode import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.design.system.hedvig.ButtonDefaults +import com.hedvig.android.design.system.hedvig.ErrorDialog import com.hedvig.android.design.system.hedvig.HedvigBottomSheet +import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigFullScreenCenterAlignedProgressDebounced +import com.hedvig.android.design.system.hedvig.HedvigMultiScreenPreview +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTextButton +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.HorizontalItemsWithMaximumSpaceTaken +import com.hedvig.android.design.system.hedvig.LocalTextStyle +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.TopAppBarWithBack +import com.hedvig.android.design.system.hedvig.datepicker.rememberHedvigDateTimeFormatter +import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.feature.editcoinsured.data.CoInsured import com.hedvig.android.feature.editcoinsured.data.Member import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.InfoFromSsn import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.ManualInfo +import com.hedvig.android.feature.editcoinsured.ui.EditCoInsuredState.Loaded.RemoveBottomSheetContentState import hedvig.resources.R import kotlinx.datetime.LocalDate import kotlinx.datetime.toJavaLocalDate @@ -149,6 +150,7 @@ private fun EditCoInsuredScreen( title = stringResource(id = R.string.general_error), message = uiState.message, onDismiss = onDismissError, + modifier = Modifier.fillMaxWidth(), ) } @@ -158,7 +160,9 @@ private fun EditCoInsuredScreen( .fillMaxSize() .padding( WindowInsets - .safeDrawing.only(WindowInsetsSides.Horizontal).asPaddingValues(), + .safeDrawing + .only(WindowInsetsSides.Horizontal) + .asPaddingValues(), ) .nestedScroll(remember { object : NestedScrollConnection {} }) .verticalScroll(state = rememberScrollState()), @@ -168,18 +172,26 @@ private fun EditCoInsuredScreen( onCompleted(uiState.contractUpdateDate) } } + val addHedvigBottomSheetState = + rememberHedvigBottomSheetState() + DismissSheetOnSuccessfulInfoChangeEffect( + sheetState = addHedvigBottomSheetState, + infoSuccessfullyChanged = uiState.finishedAdding, + ) + ClearBottomSheetContentStateOnSheetDismissedEffect( + sheetState = addHedvigBottomSheetState, + clearBottomSheetState = onResetAddBottomSheetState, + ) HedvigBottomSheet( - isVisible = uiState.addBottomSheetState.show, - onVisibleChange = { isVisible -> - if (!isVisible) { - onResetAddBottomSheetState() - } - }, + hedvigBottomSheetState = addHedvigBottomSheetState, ) { AddCoInsuredBottomSheetContent( - bottomSheetState = uiState.addBottomSheetState, + bottomSheetState = uiState.addBottomSheetContentState, onContinue = onSave, - onDismiss = onResetAddBottomSheetState, + onDismiss = { + addHedvigBottomSheetState.dismiss() + onResetAddBottomSheetState() + }, onSsnChanged = onSsnChanged, onFirstNameChanged = onFirstNameChanged, onLastNameChanged = onLastNameChanged, @@ -189,28 +201,34 @@ private fun EditCoInsuredScreen( onCoInsuredSelected = onCoInsuredSelected, ) } - + val removeHedvigBottomSheetState = rememberHedvigBottomSheetState() + DismissRemoveCoinsuredSheetOnSuccessfulRemoveEffect(removeHedvigBottomSheetState, uiState.finishedRemoving) + ClearRemoveBottomSheetContentStateOnSheetDismissedEffect( + removeHedvigBottomSheetState, + onResetRemoveBottomSheetState, + ) HedvigBottomSheet( - isVisible = uiState.removeBottomSheetState.show && uiState.removeBottomSheetState.coInsured != null, - onVisibleChange = { isVisible -> - if (!isVisible) { - onResetRemoveBottomSheetState() - } - }, + removeHedvigBottomSheetState, ) { - if (uiState.removeBottomSheetState.coInsured != null) { + if (uiState.removeBottomSheetContentState.coInsured != null) { RemoveCoInsuredBottomSheetContent( - onDismiss = onResetRemoveBottomSheetState, + onDismiss = { + removeHedvigBottomSheetState.dismiss() + onResetRemoveBottomSheetState() + }, onRemove = { onRemoveCoInsured(it) }, - isLoading = uiState.removeBottomSheetState.isLoading, - coInsured = uiState.removeBottomSheetState.coInsured, - errorMessage = uiState.removeBottomSheetState.errorMessage, + isLoading = uiState.removeBottomSheetContentState.isLoading, + coInsured = uiState.removeBottomSheetContentState.coInsured, + errorMessage = uiState.removeBottomSheetContentState.errorMessage, ) } } CoInsuredList( uiState = uiState.listState, - onRemove = onRemoveCoInsuredClicked, + onRemove = { insured -> + onRemoveCoInsuredClicked(insured) + removeHedvigBottomSheetState.show(uiState.removeBottomSheetContentState) + }, onEdit = {}, allowEdit = false, modifier = Modifier.padding(horizontal = 16.dp), @@ -218,10 +236,17 @@ private fun EditCoInsuredScreen( Spacer(Modifier.height(8.dp)) if (uiState.listState.noCoInsuredHaveMissingInfo()) { - HedvigSecondaryContainedButton( + HedvigButton( text = stringResource(id = R.string.CONTRACT_ADD_COINSURED), - onClick = onAddCoInsuredClicked, - modifier = Modifier.padding(horizontal = 16.dp), + onClick = { + addHedvigBottomSheetState.show(uiState.addBottomSheetContentState) + onAddCoInsuredClicked() + }, + enabled = true, + buttonStyle = ButtonDefaults.ButtonStyle.Secondary, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), ) } @@ -230,11 +255,14 @@ private fun EditCoInsuredScreen( if (uiState.listState.priceInfo != null && uiState.listState.hasMadeChanges()) { Spacer(Modifier.height(8.dp)) PriceInfo(uiState.listState.priceInfo) - HedvigContainedButton( + HedvigButton( text = stringResource(id = R.string.CONTRACT_ADD_COINSURED_CONFIRM_CHANGES), onClick = onCommitChanges, + enabled = true, isLoading = uiState.listState.isCommittingUpdate, - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), ) } @@ -272,36 +300,67 @@ private fun PriceInfo(priceInfo: EditCoInsuredState.Loaded.PriceInfo) { .fillMaxWidth(), ) { HorizontalItemsWithMaximumSpaceTaken( - startSlot = { Text(text = stringResource(id = R.string.CONTRACT_ADD_COINSURED_TOTAL)) }, + startSlot = { HedvigText(text = stringResource(id = R.string.CONTRACT_ADD_COINSURED_TOTAL)) }, endSlot = { Row(horizontalArrangement = Arrangement.End) { - Text( + HedvigText( text = stringResource( id = R.string.CHANGE_ADDRESS_PRICE_PER_MONTH_LABEL, priceInfo.previousPrice.toString(), ), - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = HedvigTheme.colorScheme.textSecondary, style = LocalTextStyle.current.copy(textDecoration = TextDecoration.LineThrough), ) Spacer(modifier = Modifier.width(8.dp)) - Text(text = stringResource(id = R.string.CHANGE_ADDRESS_PRICE_PER_MONTH_LABEL, priceInfo.newPrice.toString())) + HedvigText( + text = stringResource(id = R.string.CHANGE_ADDRESS_PRICE_PER_MONTH_LABEL, priceInfo.newPrice.toString()), + ) } }, spaceBetween = 8.dp, ) - Text( + HedvigText( text = stringResource( id = R.string.CONTRACT_ADD_COINSURED_STARTS_FROM, dateTimeFormatter.format(priceInfo.validFrom.toJavaLocalDate()), ), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurfaceVariant, + style = HedvigTheme.typography.label, + color = HedvigTheme.colorScheme.textSecondary, textAlign = TextAlign.End, modifier = Modifier.fillMaxWidth(), ) } } +@Composable +@HedvigPreview +private fun EditCoInsuredScreenErrorPreview() { + HedvigTheme { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { + EditCoInsuredScreen( + navigateUp = { }, + uiState = EditCoInsuredState.Error("Something happened"), + onSave = {}, + onSsnChanged = {}, + onRemoveCoInsured = {}, + onRemoveCoInsuredClicked = {}, + onAddCoInsuredClicked = {}, + onCommitChanges = {}, + onCompleted = {}, + onDismissError = {}, + onResetAddBottomSheetState = {}, + onResetRemoveBottomSheetState = {}, + onFirstNameChanged = {}, + onLastNameChanged = {}, + onBirthDateChanged = {}, + onManualInputSwitchChanged = {}, + onCoInsuredSelected = {}, + onAddNewCoInsured = {}, + ) + } + } +} + @Composable @HedvigPreview private fun EditCoInsuredScreenEditablePreview() { @@ -348,12 +407,12 @@ private fun EditCoInsuredScreenEditablePreview() { ), allCoInsured = listOf(), ), - addBottomSheetState = EditCoInsuredState.Loaded.AddBottomSheetState( + addBottomSheetContentState = EditCoInsuredState.Loaded.AddBottomSheetContentState( isLoading = false, manualInfo = ManualInfo(), infoFromSsn = InfoFromSsn(), ), - removeBottomSheetState = EditCoInsuredState.Loaded.RemoveBottomSheetState(), + removeBottomSheetContentState = EditCoInsuredState.Loaded.RemoveBottomSheetContentState(), ), onSave = {}, onSsnChanged = {}, @@ -380,7 +439,7 @@ private fun EditCoInsuredScreenEditablePreview() { @HedvigMultiScreenPreview private fun EditCoInsuredScreenNonEditablePreview() { HedvigTheme { - Surface { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { EditCoInsuredScreen( navigateUp = { }, uiState = EditCoInsuredState.Loaded( @@ -408,12 +467,12 @@ private fun EditCoInsuredScreenNonEditablePreview() { ), allCoInsured = listOf(), ), - addBottomSheetState = EditCoInsuredState.Loaded.AddBottomSheetState( + addBottomSheetContentState = EditCoInsuredState.Loaded.AddBottomSheetContentState( isLoading = false, manualInfo = ManualInfo(), infoFromSsn = InfoFromSsn(), ), - removeBottomSheetState = EditCoInsuredState.Loaded.RemoveBottomSheetState(), + removeBottomSheetContentState = EditCoInsuredState.Loaded.RemoveBottomSheetContentState(), ), onSave = {}, onSsnChanged = {}, diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt index 470fee3160..5c4f9863b7 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenter.kt @@ -47,20 +47,23 @@ internal class EditCoInsuredPresenter( val lastListState = lastState.safeCast()?.listState mutableStateOf(lastListState ?: Loaded.CoInsuredListState()) } - var addBottomSheetState by remember { - val lastBottomSheetState = lastState.safeCast()?.addBottomSheetState + var addBottomSheetContentState by remember { + val lastBottomSheetState = lastState.safeCast()?.addBottomSheetContentState mutableStateOf( - lastBottomSheetState ?: Loaded.AddBottomSheetState( + lastBottomSheetState ?: Loaded.AddBottomSheetContentState( manualInfo = ManualInfo(), infoFromSsn = InfoFromSsn(), ), ) } - var removeBottomSheetState by remember { - val lastBottomSheetState = lastState.safeCast()?.removeBottomSheetState - mutableStateOf(lastBottomSheetState ?: Loaded.RemoveBottomSheetState()) + var removeBottomSheetContentState by remember { + val lastBottomSheetState = lastState.safeCast()?.removeBottomSheetContentState + mutableStateOf(lastBottomSheetState ?: Loaded.RemoveBottomSheetContentState()) } + var finishedAdding by remember { mutableStateOf(false) } + var finishedRemoving by remember { mutableStateOf(false) } + var errorMessage by remember { mutableStateOf(null) } var isLoading by remember { mutableStateOf(true) } var fetchInfoFromSsn by remember { mutableIntStateOf(0) } @@ -100,18 +103,19 @@ internal class EditCoInsuredPresenter( CollectEvents { event -> when (event) { EditCoInsuredEvent.OnBottomSheetContinue -> { - val selectedCoInsured = addBottomSheetState.selectedCoInsured + val selectedCoInsured = addBottomSheetContentState.selectedCoInsured if (selectedCoInsured != null) { editedCoInsuredList = addCoInsured(selectedCoInsuredId, selectedCoInsured, listState) - } else if (addBottomSheetState.shouldFetchInfo()) { + } else if (addBottomSheetContentState.shouldFetchInfo()) { fetchInfoFromSsn++ } else { - editedCoInsuredList = addCoInsuredFromBottomSheet(selectedCoInsuredId, addBottomSheetState, listState) + editedCoInsuredList = + addCoInsuredFromBottomSheet(selectedCoInsuredId, addBottomSheetContentState, listState) } } is EditCoInsuredEvent.OnCoInsuredSelected -> - addBottomSheetState = addBottomSheetState.copy( + addBottomSheetContentState = addBottomSheetContentState.copy( selectedCoInsured = event.coInsured, errorMessage = null, ) @@ -122,7 +126,7 @@ internal class EditCoInsuredPresenter( is EditCoInsuredEvent.OnSsnChanged -> if (event.ssn.length <= 12) { - addBottomSheetState = addBottomSheetState.copy( + addBottomSheetContentState = addBottomSheetContentState.copy( manualInfo = ManualInfo(), infoFromSsn = InfoFromSsn( ssn = event.ssn, @@ -134,37 +138,38 @@ internal class EditCoInsuredPresenter( } is EditCoInsuredEvent.OnBirthDateChanged -> - addBottomSheetState = - addBottomSheetState.copy( - manualInfo = addBottomSheetState.manualInfo.copy(birthDate = event.birthDate), + addBottomSheetContentState = + addBottomSheetContentState.copy( + manualInfo = addBottomSheetContentState.manualInfo.copy(birthDate = event.birthDate), errorMessage = null, ) is EditCoInsuredEvent.OnFirstNameChanged -> - addBottomSheetState = - addBottomSheetState.copy( - manualInfo = addBottomSheetState.manualInfo.copy(firstName = event.firstName), + addBottomSheetContentState = + addBottomSheetContentState.copy( + manualInfo = addBottomSheetContentState.manualInfo.copy(firstName = event.firstName), errorMessage = null, ) is EditCoInsuredEvent.OnLastNameChanged -> - addBottomSheetState = - addBottomSheetState.copy( - manualInfo = addBottomSheetState.manualInfo.copy(lastName = event.lastName), + addBottomSheetContentState = + addBottomSheetContentState.copy( + manualInfo = addBottomSheetContentState.manualInfo.copy(lastName = event.lastName), errorMessage = null, ) is EditCoInsuredEvent.OnManualInputSwitchChanged -> { - addBottomSheetState = addBottomSheetState.copy( + addBottomSheetContentState = addBottomSheetContentState.copy( showManualInput = event.show, errorMessage = null, - showUnderAgedInfo = false, + showUnderAgedInfo = if (!event.show) false else addBottomSheetContentState.showUnderAgedInfo, ) } is EditCoInsuredEvent.OnEditCoInsuredClicked -> { + finishedAdding = false selectedCoInsuredId = event.coInsured.internalId - addBottomSheetState = Loaded.AddBottomSheetState( + addBottomSheetContentState = Loaded.AddBottomSheetContentState( manualInfo = ManualInfo( firstName = event.coInsured.firstName, lastName = event.coInsured.lastName, @@ -176,52 +181,55 @@ internal class EditCoInsuredPresenter( ssn = event.coInsured.ssn, ), selectableCoInsured = listState.allCoInsured, - show = true, ) } - is OnRemoveCoInsuredClicked -> removeBottomSheetState = Loaded.RemoveBottomSheetState( - coInsured = event.coInsured, - show = true, - ) + is OnRemoveCoInsuredClicked -> { + finishedRemoving = false + removeBottomSheetContentState = Loaded.RemoveBottomSheetContentState( + coInsured = event.coInsured, + ) + } - OnAddCoInsuredClicked -> addBottomSheetState = Loaded.AddBottomSheetState( - show = true, - selectableCoInsured = listState.allCoInsured, - manualInfo = ManualInfo(), - infoFromSsn = InfoFromSsn(), - ) + OnAddCoInsuredClicked -> { + finishedAdding = false + addBottomSheetContentState = Loaded.AddBottomSheetContentState( + selectableCoInsured = listState.allCoInsured, + manualInfo = ManualInfo(), + infoFromSsn = InfoFromSsn(), + ) + } EditCoInsuredEvent.OnAddNewCoInsured -> - addBottomSheetState = - addBottomSheetState.copy( + addBottomSheetContentState = + addBottomSheetContentState.copy( selectableCoInsured = null, selectedCoInsured = null, errorMessage = null, ) ResetAddBottomSheetState -> { - addBottomSheetState = Loaded.AddBottomSheetState( + addBottomSheetContentState = Loaded.AddBottomSheetContentState( infoFromSsn = InfoFromSsn(), manualInfo = ManualInfo(), ) } - ResetRemoveBottomSheetState -> removeBottomSheetState = Loaded.RemoveBottomSheetState() + ResetRemoveBottomSheetState -> removeBottomSheetContentState = Loaded.RemoveBottomSheetContentState() OnDismissError -> errorMessage = null EditCoInsuredEvent.OnCommitChanges -> commit = true } } LaunchedEffect(fetchInfoFromSsn) { - addBottomSheetState = addBottomSheetState.copy(errorMessage = null) - val ssn = addBottomSheetState.infoFromSsn.ssn - if (ssn != null && !addBottomSheetState.showManualInput) { + addBottomSheetContentState = addBottomSheetContentState.copy(errorMessage = null) + val ssn = addBottomSheetContentState.infoFromSsn.ssn + if (ssn != null && !addBottomSheetContentState.showManualInput) { either { val result = fetchCoInsuredPersonalInformationUseCase.invoke(ssn).bind() when (result) { is CoInsuredPersonalInformation.FullInfo -> { - addBottomSheetState = addBottomSheetState.copy( + addBottomSheetContentState = addBottomSheetContentState.copy( infoFromSsn = InfoFromSsn( firstName = result.firstName, lastName = result.lastName, @@ -232,10 +240,9 @@ internal class EditCoInsuredPresenter( } is CoInsuredPersonalInformation.EmptyInfo -> { - addBottomSheetState = - Loaded.AddBottomSheetState( + addBottomSheetContentState = + Loaded.AddBottomSheetContentState( showManualInput = true, - show = true, manualInfo = ManualInfo(null, null, birthDate = result.dateOfBirth), infoFromSsn = InfoFromSsn(), showUnderAgedInfo = true, @@ -243,7 +250,7 @@ internal class EditCoInsuredPresenter( } } }.onLeft { - addBottomSheetState = addBottomSheetState.copy(errorMessage = it.message) + addBottomSheetContentState = addBottomSheetContentState.copy(errorMessage = it.message) } } } @@ -251,8 +258,8 @@ internal class EditCoInsuredPresenter( LaunchedEffect(editedCoInsuredList) { editedCoInsuredList?.let { list -> Snapshot.withMutableSnapshot { - addBottomSheetState = addBottomSheetState.copy(isLoading = true) - removeBottomSheetState = removeBottomSheetState.copy(isLoading = true) + addBottomSheetContentState = addBottomSheetContentState.copy(isLoading = true) + removeBottomSheetContentState = removeBottomSheetContentState.copy(isLoading = true) } createMidtermChangeUseCase @@ -260,11 +267,11 @@ internal class EditCoInsuredPresenter( .fold( ifLeft = { Snapshot.withMutableSnapshot { - removeBottomSheetState = removeBottomSheetState.copy( + removeBottomSheetContentState = removeBottomSheetContentState.copy( errorMessage = it.message, isLoading = false, ) - addBottomSheetState = addBottomSheetState.copy( + addBottomSheetContentState = addBottomSheetContentState.copy( errorMessage = it.message, isLoading = false, ) @@ -282,13 +289,14 @@ internal class EditCoInsuredPresenter( ), ) selectedCoInsuredId = null - addBottomSheetState = Loaded.AddBottomSheetState( - show = false, - manualInfo = ManualInfo(null, null, birthDate = null), - infoFromSsn = InfoFromSsn(null, null, null), + addBottomSheetContentState = Loaded.AddBottomSheetContentState( + manualInfo = ManualInfo(), + infoFromSsn = InfoFromSsn(), ) - removeBottomSheetState = Loaded.RemoveBottomSheetState(show = false) + removeBottomSheetContentState = Loaded.RemoveBottomSheetContentState() editedCoInsuredList = null + finishedAdding = true + finishedRemoving = true } }, ) @@ -325,9 +333,11 @@ internal class EditCoInsuredPresenter( } else if (listState.member != null) { Loaded( listState = listState, - addBottomSheetState = addBottomSheetState, - removeBottomSheetState = removeBottomSheetState, + addBottomSheetContentState = addBottomSheetContentState, + removeBottomSheetContentState = removeBottomSheetContentState, contractUpdateDate = contractUpdateDate, + finishedAdding = finishedAdding, + finishedRemoving = finishedRemoving, ) } else if (isLoading) { Loading @@ -338,10 +348,10 @@ internal class EditCoInsuredPresenter( private fun addCoInsuredFromBottomSheet( selectedCoInsuredId: String?, - addBottomSheetState: Loaded.AddBottomSheetState, + addBottomSheetContentState: Loaded.AddBottomSheetContentState, listState: Loaded.CoInsuredListState, ): List { - with(addBottomSheetState) { + with(addBottomSheetContentState) { val firstName = if (showManualInput) manualInfo.firstName else infoFromSsn.firstName val lastName = if (showManualInput) manualInfo.lastName else infoFromSsn.lastName val ssn = if (showManualInput) null else infoFromSsn.ssn @@ -420,9 +430,11 @@ internal sealed interface EditCoInsuredState { data class Loaded( val listState: CoInsuredListState, - val addBottomSheetState: AddBottomSheetState, - val removeBottomSheetState: RemoveBottomSheetState, + val addBottomSheetContentState: AddBottomSheetContentState, + val removeBottomSheetContentState: RemoveBottomSheetContentState, val contractUpdateDate: LocalDate? = null, + val finishedAdding: Boolean = false, + val finishedRemoving: Boolean = false, ) : EditCoInsuredState { data class CoInsuredListState( val originalCoInsured: List? = null, @@ -460,7 +472,7 @@ internal sealed interface EditCoInsuredState { val ssn: String? = null, ) - data class AddBottomSheetState( + data class AddBottomSheetContentState( val infoFromSsn: InfoFromSsn, val manualInfo: ManualInfo, val showManualInput: Boolean = false, @@ -468,7 +480,6 @@ internal sealed interface EditCoInsuredState { val selectedCoInsured: CoInsured? = null, val errorMessage: String? = null, val isLoading: Boolean = false, - val show: Boolean = false, val showUnderAgedInfo: Boolean = false, ) { fun canPickExistingCoInsured() = !selectableCoInsured.isNullOrEmpty() @@ -507,11 +518,10 @@ internal sealed interface EditCoInsuredState { } } - data class RemoveBottomSheetState( + data class RemoveBottomSheetContentState( val coInsured: CoInsured? = null, val errorMessage: String? = null, val isLoading: Boolean = false, - val show: Boolean = false, ) } } diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt index acfeec02dc..b0bfcbb43a 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoinsuredSuccessDestination.kt @@ -6,21 +6,23 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.hedvig.android.core.designsystem.component.button.HedvigTextButton -import com.hedvig.android.core.designsystem.component.success.HedvigSuccessSection -import com.hedvig.android.core.designsystem.preview.HedvigMultiScreenPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme -import com.hedvig.android.core.ui.getLocale -import com.hedvig.android.core.ui.hedvigDateTimeFormatter +import com.hedvig.android.design.system.hedvig.EmptyState +import com.hedvig.android.design.system.hedvig.EmptyStateDefaults +import com.hedvig.android.design.system.hedvig.HedvigMultiScreenPreview +import com.hedvig.android.design.system.hedvig.HedvigTextButton +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.datepicker.getLocale +import com.hedvig.android.design.system.hedvig.datepicker.hedvigDateTimeFormatter import kotlinx.datetime.LocalDate import kotlinx.datetime.toJavaLocalDate @@ -31,14 +33,15 @@ internal fun EditCoInsuredSuccessDestination(date: LocalDate?, popBackstack: () ) { Spacer(Modifier.height(8.dp)) Box( - modifier = Modifier.weight(1f), + modifier = Modifier.weight(1f).fillMaxWidth(), ) { - HedvigSuccessSection( - title = stringResource(id = hedvig.resources.R.string.CONTRACT_ADD_COINSURED_UPDATED_TITLE), - subTitle = stringResource( + EmptyState( + text = stringResource(id = hedvig.resources.R.string.CONTRACT_ADD_COINSURED_UPDATED_TITLE), + description = stringResource( id = hedvig.resources.R.string.CONTRACT_ADD_COINSURED_UPDATED_LABEL, date?.toJavaLocalDate()?.format(hedvigDateTimeFormatter(getLocale())) ?: "-", ), + iconStyle = EmptyStateDefaults.EmptyStateIconStyle.SUCCESS, modifier = Modifier.align(Alignment.Center), ) } @@ -48,7 +51,7 @@ internal fun EditCoInsuredSuccessDestination(date: LocalDate?, popBackstack: () text = stringResource(id = hedvig.resources.R.string.general_done_button), onClick = popBackstack, modifier = Modifier - .padding(padding), + .padding(padding).fillMaxWidth(), ) Spacer(Modifier.height(16.dp)) } diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/InsuredRow.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/InsuredRow.kt index b120ca5fc1..dcbb89a2f0 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/InsuredRow.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/InsuredRow.kt @@ -6,23 +6,21 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material.icons.Icons -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.hedvig.android.core.designsystem.preview.HedvigPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme -import com.hedvig.android.core.icons.Hedvig -import com.hedvig.android.core.icons.hedvig.normal.X -import com.hedvig.android.core.icons.hedvig.small.hedvig.Lock -import com.hedvig.android.core.ui.text.HorizontalItemsWithMaximumSpaceTaken +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.HorizontalItemsWithMaximumSpaceTaken +import com.hedvig.android.design.system.hedvig.Icon +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.icon.Close +import com.hedvig.android.design.system.hedvig.icon.HedvigIcons +import com.hedvig.android.design.system.hedvig.icon.Lock import hedvig.resources.R @Composable @@ -42,18 +40,18 @@ internal fun InsuredRow( modifier = Modifier.padding(vertical = 16.dp), ) { Column { - Text( + HedvigText( text = displayName, color = if (isMember) { - MaterialTheme.colorScheme.onSurfaceVariant + HedvigTheme.colorScheme.textSecondary } else { Color.Unspecified }, ) - Text( + HedvigText( text = identifier, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = HedvigTheme.colorScheme.textSecondary, ) } } @@ -67,19 +65,19 @@ internal fun InsuredRow( when { isMember -> { Icon( - imageVector = Icons.Hedvig.Lock, + imageVector = HedvigIcons.Lock, contentDescription = "Locked", - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = HedvigTheme.colorScheme.fillSecondary, modifier = Modifier.size(16.dp), ) } allowEdit && hasMissingInfo -> { - Text(stringResource(id = R.string.CONTRACT_EDIT_INFO)) + HedvigText(stringResource(id = R.string.CONTRACT_EDIT_INFO)) } !allowEdit -> Icon( - imageVector = Icons.Hedvig.X, + imageVector = HedvigIcons.Close, contentDescription = "Remove", modifier = Modifier.size(16.dp), ) @@ -140,7 +138,7 @@ private fun InsuredRowPreviewMissingInfo() { @HedvigPreview private fun InsuredRowPreviewMember() { HedvigTheme { - Surface { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { InsuredRow( displayName = "Test testersson", identifier = "182312041933", diff --git a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/RemoveCoInsuredBottomSheetContent.kt b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/RemoveCoInsuredBottomSheetContent.kt index 783cf869f3..a0ad445a01 100644 --- a/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/RemoveCoInsuredBottomSheetContent.kt +++ b/app/feature/feature-edit-coinsured/src/main/kotlin/com/hedvig/android/feature/editcoinsured/ui/RemoveCoInsuredBottomSheetContent.kt @@ -1,5 +1,8 @@ package com.hedvig.android.feature.editcoinsured.ui +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets @@ -7,20 +10,21 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.windowInsetsBottomHeight -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton -import com.hedvig.android.core.designsystem.preview.HedvigPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme +import com.hedvig.android.design.system.hedvig.ButtonDefaults import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonStyle.Ghost +import com.hedvig.android.design.system.hedvig.EmptyState +import com.hedvig.android.design.system.hedvig.EmptyStateDefaults import com.hedvig.android.design.system.hedvig.HedvigButton +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.feature.editcoinsured.data.CoInsured import hedvig.resources.R @@ -36,24 +40,35 @@ internal fun RemoveCoInsuredBottomSheetContent( horizontalAlignment = Alignment.CenterHorizontally, ) { Spacer(Modifier.height(16.dp)) - Text(stringResource(id = R.string.CONTRACT_REMOVE_COINSURED_CONFIRMATION)) + HedvigText( + stringResource(id = R.string.CONTRACT_REMOVE_COINSURED_CONFIRMATION), + textAlign = TextAlign.Center, + ) + AnimatedVisibility( + visible = errorMessage != null, + enter = fadeIn(), + exit = fadeOut(), + ) { + Column { + Spacer(Modifier.height(16.dp)) + EmptyState( + text = stringResource(R.string.something_went_wrong), + modifier = Modifier.fillMaxWidth(), + iconStyle = EmptyStateDefaults.EmptyStateIconStyle.ERROR, + description = null, + ) + } + } Spacer(Modifier.height(24.dp)) - HedvigContainedButton( + HedvigButton( text = stringResource(id = R.string.REMOVE_CONFIRMATION_BUTTON), - colors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.error, - contentColor = MaterialTheme.colorScheme.onError, - disabledContainerColor = MaterialTheme.colorScheme.error.copy( - alpha = 0.12f, - ), - disabledContentColor = MaterialTheme.colorScheme.onError.copy( - alpha = 0.38f, - ), - ), onClick = { onRemove(coInsured) }, + enabled = true, + buttonStyle = ButtonDefaults.ButtonStyle.Red, isLoading = isLoading, + modifier = Modifier.fillMaxWidth(), ) Spacer(Modifier.height(8.dp)) HedvigButton( @@ -72,7 +87,7 @@ internal fun RemoveCoInsuredBottomSheetContent( @HedvigPreview private fun RemoveCoInsuredBottomSheetContentPreview() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { RemoveCoInsuredBottomSheetContent( onDismiss = {}, onRemove = {}, @@ -94,7 +109,7 @@ private fun RemoveCoInsuredBottomSheetContentPreview() { @HedvigPreview private fun RemoveCoInsuredBottomSheetContentWithCoInsuredPreview() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { RemoveCoInsuredBottomSheetContent( onDismiss = {}, onRemove = {}, diff --git a/app/feature/feature-edit-coinsured/src/test/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenterTest.kt b/app/feature/feature-edit-coinsured/src/test/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenterTest.kt index 398ef3fbbc..a57433c9bd 100644 --- a/app/feature/feature-edit-coinsured/src/test/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenterTest.kt +++ b/app/feature/feature-edit-coinsured/src/test/kotlin/com/hedvig/android/feature/editcoinsured/ui/EditCoInsuredPresenterTest.kt @@ -78,11 +78,11 @@ internal class EditCoInsuredPresenterTest { member = testMember, allCoInsured = listOf(), ), - addBottomSheetState = EditCoInsuredState.Loaded.AddBottomSheetState( + addBottomSheetContentState = EditCoInsuredState.Loaded.AddBottomSheetContentState( infoFromSsn = InfoFromSsn(), manualInfo = ManualInfo(), ), - removeBottomSheetState = EditCoInsuredState.Loaded.RemoveBottomSheetState(), + removeBottomSheetContentState = EditCoInsuredState.Loaded.RemoveBottomSheetContentState(), ), ) { skipItems(1) @@ -93,11 +93,10 @@ internal class EditCoInsuredPresenterTest { assertThat(item).isInstanceOf() val uiState = item as EditCoInsuredState.Loaded - assertThat(uiState.addBottomSheetState.manualInfo.firstName).isEqualTo(coInsuredTestList[0].firstName) - assertThat(uiState.addBottomSheetState.manualInfo.lastName).isEqualTo(coInsuredTestList[0].lastName) - assertThat(uiState.addBottomSheetState.infoFromSsn.ssn).isEqualTo(coInsuredTestList[0].ssn) - assertThat(uiState.addBottomSheetState.manualInfo.birthDate).isEqualTo(coInsuredTestList[0].birthDate) - assertThat(uiState.addBottomSheetState.show).isEqualTo(true) + assertThat(uiState.addBottomSheetContentState.manualInfo.firstName).isEqualTo(coInsuredTestList[0].firstName) + assertThat(uiState.addBottomSheetContentState.manualInfo.lastName).isEqualTo(coInsuredTestList[0].lastName) + assertThat(uiState.addBottomSheetContentState.infoFromSsn.ssn).isEqualTo(coInsuredTestList[0].ssn) + assertThat(uiState.addBottomSheetContentState.manualInfo.birthDate).isEqualTo(coInsuredTestList[0].birthDate) } } @@ -123,12 +122,12 @@ internal class EditCoInsuredPresenterTest { member = testMember, allCoInsured = listOf(), ), - addBottomSheetState = EditCoInsuredState.Loaded.AddBottomSheetState( + addBottomSheetContentState = EditCoInsuredState.Loaded.AddBottomSheetContentState( showManualInput = false, infoFromSsn = InfoFromSsn(), manualInfo = ManualInfo(), ), - removeBottomSheetState = EditCoInsuredState.Loaded.RemoveBottomSheetState(), + removeBottomSheetContentState = EditCoInsuredState.Loaded.RemoveBottomSheetContentState(), ), ) { skipItems(1) @@ -141,7 +140,7 @@ internal class EditCoInsuredPresenterTest { sendEvent(EditCoInsuredEvent.OnLastNameChanged("New last name manual")) val state2 = awaitItem() assertThat( - (state2 as EditCoInsuredState.Loaded).addBottomSheetState.manualInfo.lastName, + (state2 as EditCoInsuredState.Loaded).addBottomSheetContentState.manualInfo.lastName, ).isEqualTo("New last name manual") sendEvent(EditCoInsuredEvent.OnBottomSheetContinue) skipItems(1) @@ -154,7 +153,7 @@ internal class EditCoInsuredPresenterTest { val item = awaitItem() assertThat(item).isInstanceOf() val uiState = item as EditCoInsuredState.Loaded - assertThat(uiState.addBottomSheetState.manualInfo).isEqualTo(ManualInfo()) + assertThat(uiState.addBottomSheetContentState.manualInfo).isEqualTo(ManualInfo()) assertThat(uiState.listState.coInsured[2].ssn).isEqualTo(null) assertThat(uiState.listState.coInsured[2].lastName).isEqualTo("New last name manual") } diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index e010e2fce1..1f74f25e71 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -129,6 +129,7 @@ internal fun YourInfoTab( daysUntil(upcomingChangesInsuranceAgreement.activeFrom) } HedvigNotificationCard( + modifier = Modifier.padding(horizontal = 16.dp), message = stringResource(R.string.DASHBOARD_RENEWAL_PROMPTER_BODY, daysUntilRenewal), priority = Info, style = Button( @@ -138,6 +139,7 @@ internal fun YourInfoTab( ) } else { HedvigNotificationCard( + modifier = Modifier.padding(horizontal = 16.dp), message = stringResource( R.string.insurances_tab_your_insurance_will_be_updated, dateTimeFormatter.format(upcomingChangesInsuranceAgreement.activeFrom.toJavaLocalDate()), diff --git a/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateViewModel.kt b/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateViewModel.kt index 8cd1d05231..59cea9f4c5 100644 --- a/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateViewModel.kt +++ b/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateViewModel.kt @@ -47,7 +47,6 @@ internal class TerminationDateViewModel( } } -// todo change with generic DatePickerUiState private class DatePickerConfiguration(locale: Locale, minDate: LocalDate, maxDate: LocalDate) { private val minDateInMillis = minDate.atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds() private val maxDateInMillis = maxDate.atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds()