diff --git a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt index a417515098..2dd3ab8ba4 100644 --- a/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt +++ b/app/app/src/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.kt @@ -13,9 +13,9 @@ import coil.ImageLoader import com.benasher44.uuid.Uuid import com.hedvig.android.app.ui.HedvigAppState import com.hedvig.android.core.buildconstants.HedvigBuildConstants -import com.hedvig.android.core.designsystem.material3.motion.MotionDefaults import com.hedvig.android.data.claimflow.ClaimFlowStep import com.hedvig.android.data.claimflow.toClaimFlowDestination +import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.change.tier.navigation.ChooseTierGraphDestination import com.hedvig.android.feature.change.tier.navigation.InsuranceCustomizationParameters import com.hedvig.android.feature.change.tier.navigation.StartTierFlowChooseInsuranceDestination diff --git a/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionDefaults.kt b/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionDefaults.kt index c53991d3a3..05d145258b 100644 --- a/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionDefaults.kt +++ b/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionDefaults.kt @@ -2,30 +2,8 @@ package com.hedvig.android.core.designsystem.material3.motion import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.dp object MotionDefaults { - fun sharedXAxisEnter(density: Density): EnterTransition { - val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } - return SharedAxisDefaults.sharedXAxisEnterTransition(offsetPixels) - } - - fun sharedXAxisExit(density: Density): ExitTransition { - val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } - return SharedAxisDefaults.sharedXAxisExitTransition(-offsetPixels) - } - - fun sharedXAxisPopEnter(density: Density): EnterTransition { - val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } - return SharedAxisDefaults.sharedXAxisEnterTransition(-offsetPixels) - } - - fun sharedXAxisPopExit(density: Density): ExitTransition { - val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } - return SharedAxisDefaults.sharedXAxisExitTransition(offsetPixels) - } - val fadeThroughEnter: EnterTransition = FadeThroughDefaults.fadeThroughEnterTransition val fadeThroughExit: ExitTransition = FadeThroughDefaults.fadeThroughExitTransition diff --git a/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionTokens.kt b/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionTokens.kt index f435475f4c..b2f81033ec 100644 --- a/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionTokens.kt +++ b/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/MotionTokens.kt @@ -2,10 +2,11 @@ package com.hedvig.android.core.designsystem.material3.motion import androidx.compose.animation.core.CubicBezierEasing +const val DurationExtraLong1 = 700.0 + // https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/MotionTokens.kt @Suppress("unused") object MotionTokens { - const val DurationExtraLong1 = 700.0 const val DurationExtraLong2 = 800.0 const val DurationExtraLong3 = 900.0 const val DurationExtraLong4 = 1000.0 diff --git a/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/RoundedCornerCheckBox.kt b/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/RoundedCornerCheckBox.kt deleted file mode 100644 index 1204319921..0000000000 --- a/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/RoundedCornerCheckBox.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.hedvig.android.core.ui - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -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.runtime.Composable -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.unit.dp -import com.hedvig.android.core.designsystem.material3.squircleExtraSmall -import com.hedvig.android.core.icons.Hedvig -import com.hedvig.android.core.icons.hedvig.small.hedvig.Checkmark -import com.hedvig.android.core.ui.animation.CheckItemAnimation - -@Composable -fun RoundedCornerCheckBox( - isChecked: Boolean, - onCheckedChange: ((Boolean) -> Unit)?, - checkMarkColor: Color = MaterialTheme.colorScheme.onPrimary, - checkColor: Color = MaterialTheme.colorScheme.primary, - uncheckedColor: Color = MaterialTheme.colorScheme.outlineVariant, -) { - CheckItemAnimation(selected = isChecked) { isSelected: Boolean -> - Box( - modifier = Modifier - .size(24.dp) - .background( - color = if (isSelected) checkColor else Color.Transparent, - shape = MaterialTheme.shapes.squircleExtraSmall, - ) - .border( - width = 2.dp, - color = if (isSelected) checkColor else uncheckedColor, - shape = MaterialTheme.shapes.squircleExtraSmall, - ) - .clip(MaterialTheme.shapes.squircleExtraSmall) - .clickable { - if (onCheckedChange != null) { - onCheckedChange(isSelected) - } - }, - contentAlignment = Alignment.Center, - ) { - if (isSelected) { - Icon(Icons.Hedvig.Checkmark, contentDescription = null, tint = checkMarkColor) - } - } - } -} diff --git a/app/design-system/design-system-api/build.gradle.kts b/app/design-system/design-system-api/build.gradle.kts new file mode 100644 index 0000000000..21b2fd0433 --- /dev/null +++ b/app/design-system/design-system-api/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("hedvig.gradle.plugin") + id("hedvig.kotlin.library") +} + +dependencies { + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.runtime) +} diff --git a/app/design-system/design-system-api/src/main/kotlin/com/hedvig/android/design/system/hedvig/api/HedvigDatePickerState.kt b/app/design-system/design-system-api/src/main/kotlin/com/hedvig/android/design/system/hedvig/api/HedvigDatePickerState.kt new file mode 100644 index 0000000000..d9da025cdc --- /dev/null +++ b/app/design-system/design-system-api/src/main/kotlin/com/hedvig/android/design/system/hedvig/api/HedvigDatePickerState.kt @@ -0,0 +1,44 @@ +package com.hedvig.android.design.system.hedvig.api + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.Stable + +@Stable +interface HedvigDatePickerState { + var selectedDateMillis: Long? + var displayedMonthMillis: Long + var displayMode: HedvigDisplayMode + val yearRange: IntRange + val selectableDates: HedvigSelectableDates +} + +@Stable +interface HedvigSelectableDates { + fun isSelectableDate(utcTimeMillis: Long) = true + + fun isSelectableYear(year: Int) = true +} + +@Immutable +@JvmInline +value class HedvigDisplayMode internal constructor(internal val value: Int) { + companion object { + /** Date picker mode */ + val Picker = HedvigDisplayMode(0) + + /** Date text input mode */ + val Input = HedvigDisplayMode(1) + } + + override fun toString() = when (this) { + Picker -> "Picker" + Input -> "Input" + else -> "Unknown" + } +} + +object HedvigDatePickerDefaults { + val displayMode = HedvigDisplayMode.Picker + val YearRange: IntRange = IntRange(1900, 2100) + val AllDates: HedvigSelectableDates = object : HedvigSelectableDates {} +} diff --git a/app/design-system/design-system-hedvig/build.gradle.kts b/app/design-system/design-system-hedvig/build.gradle.kts index f721d2bfe4..5f19c5366a 100644 --- a/app/design-system/design-system-hedvig/build.gradle.kts +++ b/app/design-system/design-system-hedvig/build.gradle.kts @@ -10,6 +10,7 @@ hedvig { dependencies { api(libs.androidx.compose.foundation) api(libs.coil.coil) + api(projects.designSystemApi) implementation(libs.androidx.activity.compose) implementation(libs.androidx.compose.foundationLayout) diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/EmptyState.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/EmptyState.kt index 7015dd0d7f..03a85c6ad1 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/EmptyState.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/EmptyState.kt @@ -89,6 +89,7 @@ fun EmptyState( } } +@Suppress("UnusedReceiverParameter") @Composable private fun ColumnScope.EmptyStateIcon(iconStyle: EmptyStateIconStyle) { val sizeModifier = Modifier.size(EmptyStateTokens.IconSize) diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/datepicker/DatePicker.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/datepicker/DatePicker.kt index e0b422f875..90ff39837e 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/datepicker/DatePicker.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/datepicker/DatePicker.kt @@ -9,19 +9,58 @@ import androidx.compose.ui.res.stringResource import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonSize.Medium import com.hedvig.android.design.system.hedvig.HedvigTextButton import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.api.HedvigDatePickerDefaults +import com.hedvig.android.design.system.hedvig.api.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.api.HedvigDisplayMode +import com.hedvig.android.design.system.hedvig.api.HedvigSelectableDates import com.hedvig.android.design.system.hedvig.fromToken import com.hedvig.android.design.system.hedvig.tokens.ColorSchemeKeyTokens import com.hedvig.android.design.system.hedvig.tokens.ColorSchemeKeyTokens.TextNegative import com.hedvig.android.design.system.hedvig.tokens.ColorSchemeKeyTokens.TextPrimary import com.hedvig.android.design.system.hedvig.tokens.ColorSchemeKeyTokens.TextTertiary +import com.hedvig.android.design.system.internals.HedvigDatePicker import com.hedvig.android.design.system.internals.HedvigDatePickerColors -import com.hedvig.android.design.system.internals.HedvigDatePickerInternal import hedvig.resources.R import java.util.Locale -data class HedvigDatePickerState( - var selectedDateMillis: Long?, - var displayedMonthMillis: Long?, +@Composable +fun rememberHedvigDatePickerState( + initialSelectedDateMillis: Long, + initialDisplayedMonthMillis: Long, + yearRange: IntRange, + initialDisplayMode: HedvigDisplayMode, + selectableDates: HedvigSelectableDates, +): HedvigDatePickerState { + return com.hedvig.android.design.system.internals.rememberHedvigDatePickerState( + initialSelectedDateMillis, + initialDisplayedMonthMillis, + yearRange, + initialDisplayMode, + selectableDates, + ) +} + +fun HedvigDatePickerState( + locale: Locale, + initialSelectedDateMillis: Long?, + initialDisplayedMonthMillis: Long?, + yearRange: IntRange = HedvigDatePickerDefaults.YearRange, + initialDisplayMode: HedvigDisplayMode = HedvigDatePickerDefaults.displayMode, + selectableDates: HedvigSelectableDates = HedvigDatePickerDefaults.AllDates, +): HedvigDatePickerState { + return com.hedvig.android.design.system.internals.HedvigDatePickerState( + locale, + initialSelectedDateMillis, + initialDisplayedMonthMillis, + yearRange, + initialDisplayMode, + selectableDates, + ) +} + +data class HedvigDatePickerImmutableState( + val selectedDateMillis: Long?, + val displayedMonthMillis: Long?, val yearRange: IntRange, val minDateInMillis: Long, val maxDateInMillis: Long, @@ -33,12 +72,39 @@ fun HedvigDatePicker( datePickerState: HedvigDatePickerState, onDismissRequest: () -> Unit, onConfirmRequest: () -> Unit, +) { + HedvigDatePicker( + state = datePickerState, + onDismissRequest = onDismissRequest, + hedvigDatePickerColors = hedvigDatePickerColors, + modifier = Modifier.background( + hedvigDatePickerColors.containerColor, + ), + confirmButton = { + HedvigTextButton( + text = stringResource(R.string.general_done_button), + onClick = onConfirmRequest, + buttonSize = Medium, + ) + }, + ) +} + +/** + * A version of [HedvigDatePicker] which does not offer internal mutability in the [datePickerState] parameter. Instead + * it takes in an immutable data class and it must be re-created again every time something changes + */ +@Composable +fun HedvigDatePicker( + datePickerState: HedvigDatePickerImmutableState, + onDismissRequest: () -> Unit, + onConfirmRequest: () -> Unit, onSelectedDateChanged: (Long?) -> Unit, isVisible: Boolean, ) { if (isVisible) { with(datePickerState) { - HedvigDatePickerInternal( + HedvigDatePicker( selectedDateMillis = selectedDateMillis, displayedMonthMillis = displayedMonthMillis, yearRange = yearRange, diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/MotionDefaults.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/FadeThroughDefaults.kt similarity index 69% rename from app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/MotionDefaults.kt rename to app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/FadeThroughDefaults.kt index ea76021e28..09ddc113b1 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/MotionDefaults.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/FadeThroughDefaults.kt @@ -1,4 +1,4 @@ -package com.hedvig.android.design.system.hedvig +package com.hedvig.android.design.system.hedvig.motion import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition @@ -7,24 +7,10 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import com.hedvig.android.design.system.hedvig.tokens.MotionTokens -object MotionDefaults { - val fadeThroughEnter: EnterTransition = FadeThroughDefaults.fadeThroughEnterTransition - - val fadeThroughExit: ExitTransition = FadeThroughDefaults.fadeThroughExitTransition -} - -private const val ProgressThreshold = 0.35f - -private val Int.ForOutgoing: Int - get() = (this * ProgressThreshold).toInt() - -private val Int.ForIncoming: Int - get() = this - this.ForOutgoing - -object FadeThroughDefaults { +internal object FadeThroughDefaults { private const val FadeThroughDuration = MotionTokens.DurationMedium1.toInt() - internal val fadeThroughEnterTransition: EnterTransition = fadeIn( + val fadeThroughEnterTransition: EnterTransition = fadeIn( animationSpec = tween( durationMillis = FadeThroughDuration.ForIncoming, delayMillis = FadeThroughDuration.ForOutgoing, @@ -32,7 +18,7 @@ object FadeThroughDefaults { ), ) - internal val fadeThroughExitTransition: ExitTransition = fadeOut( + val fadeThroughExitTransition: ExitTransition = fadeOut( animationSpec = tween( durationMillis = FadeThroughDuration.ForOutgoing, delayMillis = 0, @@ -40,3 +26,11 @@ object FadeThroughDefaults { ), ) } + +private const val ProgressThreshold = 0.35f + +private val Int.ForOutgoing: Int + get() = (this * ProgressThreshold).toInt() + +private val Int.ForIncoming: Int + get() = this - this.ForOutgoing diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/MotionDefaults.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/MotionDefaults.kt new file mode 100644 index 0000000000..6177a8483f --- /dev/null +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/MotionDefaults.kt @@ -0,0 +1,32 @@ +package com.hedvig.android.design.system.hedvig.motion + +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.dp + +object MotionDefaults { + fun sharedXAxisEnter(density: Density): EnterTransition { + val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } + return SharedAxisDefaults.sharedXAxisEnterTransition(offsetPixels) + } + + fun sharedXAxisExit(density: Density): ExitTransition { + val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } + return SharedAxisDefaults.sharedXAxisExitTransition(-offsetPixels) + } + + fun sharedXAxisPopEnter(density: Density): EnterTransition { + val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } + return SharedAxisDefaults.sharedXAxisEnterTransition(-offsetPixels) + } + + fun sharedXAxisPopExit(density: Density): ExitTransition { + val offsetPixels = with(density) { SharedAxisDefaults.SharedAxisOffset.dp.roundToPx() } + return SharedAxisDefaults.sharedXAxisExitTransition(offsetPixels) + } + + val fadeThroughEnter: EnterTransition = FadeThroughDefaults.fadeThroughEnterTransition + + val fadeThroughExit: ExitTransition = FadeThroughDefaults.fadeThroughExitTransition +} diff --git a/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/SharedAxisDefaults.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/SharedAxisDefaults.kt similarity index 93% rename from app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/SharedAxisDefaults.kt rename to app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/SharedAxisDefaults.kt index b3b4a9bc89..03d023dbff 100644 --- a/app/core/core-design-system/src/main/kotlin/com/hedvig/android/core/designsystem/material3/motion/SharedAxisDefaults.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/motion/SharedAxisDefaults.kt @@ -1,4 +1,4 @@ -package com.hedvig.android.core.designsystem.material3.motion +package com.hedvig.android.design.system.hedvig.motion import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition @@ -8,14 +8,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.ui.unit.IntOffset - -private const val ProgressThreshold = 0.3f - -private val Int.ForOutgoing: Int - get() = (this * ProgressThreshold).toInt() - -private val Int.ForIncoming: Int - get() = this - this.ForOutgoing +import com.hedvig.android.design.system.hedvig.tokens.MotionTokens object SharedAxisDefaults { const val SharedAxisOffset = 30.0 @@ -57,3 +50,11 @@ object SharedAxisDefaults { return slide + fade } } + +private const val ProgressThreshold = 0.3f + +private val Int.ForOutgoing: Int + get() = (this * ProgressThreshold).toInt() + +private val Int.ForIncoming: Int + get() = this - this.ForOutgoing diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/EmptyStateTokens.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/EmptyStateTokens.kt index 1fb066324a..96e0b69c25 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/EmptyStateTokens.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/EmptyStateTokens.kt @@ -10,5 +10,5 @@ internal object EmptyStateTokens { val ErrorIconColor = ColorSchemeKeyTokens.SignalAmberElement val InfoIconColor = ColorSchemeKeyTokens.SignalBlueElement val SuccessIconColor = ColorSchemeKeyTokens.SignalGreenElement - val IconSize = 40.dp + val IconSize = 32.dp } diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/MotionTokens.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/MotionTokens.kt index ca4cb1a542..6d9f828a2e 100644 --- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/MotionTokens.kt +++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/tokens/MotionTokens.kt @@ -2,8 +2,31 @@ package com.hedvig.android.design.system.hedvig.tokens import androidx.compose.animation.core.CubicBezierEasing +@Suppress("unused") internal object MotionTokens { + const val DurationExtraLong2 = 800.0 + const val DurationExtraLong3 = 900.0 + const val DurationExtraLong4 = 1000.0 + const val DurationLong1 = 450.0 + const val DurationLong2 = 500.0 + const val DurationLong3 = 550.0 + const val DurationLong4 = 600.0 const val DurationMedium1 = 250.0 + const val DurationMedium2 = 300.0 + const val DurationMedium3 = 350.0 + const val DurationMedium4 = 400.0 + const val DurationShort1 = 50.0 + const val DurationShort2 = 100.0 + const val DurationShort3 = 150.0 + const val DurationShort4 = 200.0 + val EasingEmphasizedCubicBezier = CubicBezierEasing(0.2f, 0.0f, 0.0f, 1.0f) + val EasingEmphasizedAccelerateCubicBezier = CubicBezierEasing(0.3f, 0.0f, 0.8f, 0.15f) + val EasingEmphasizedDecelerateCubicBezier = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1.0f) + val EasingLegacyCubicBezier = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f) + val EasingLegacyAccelerateCubicBezier = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f) + val EasingLegacyDecelerateCubicBezier = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f) + val EasingLinearCubicBezier = CubicBezierEasing(0.0f, 0.0f, 1.0f, 1.0f) val EasingStandardCubicBezier = CubicBezierEasing(0.2f, 0.0f, 0.0f, 1.0f) val EasingStandardAccelerateCubicBezier = CubicBezierEasing(0.3f, 0.0f, 1.0f, 1.0f) + val EasingStandardDecelerateCubicBezier = CubicBezierEasing(0.0f, 0.0f, 0.0f, 1.0f) } diff --git a/app/design-system/design-system-internals/build.gradle.kts b/app/design-system/design-system-internals/build.gradle.kts index 0ce2784e08..07a7d2db8d 100644 --- a/app/design-system/design-system-internals/build.gradle.kts +++ b/app/design-system/design-system-internals/build.gradle.kts @@ -14,4 +14,5 @@ dependencies { implementation(libs.androidx.compose.uiGraphics) implementation(projects.composeUi) implementation(projects.coreResources) + implementation(projects.designSystemApi) } diff --git a/app/design-system/design-system-internals/src/main/kotlin/com/hedvig/android/design/system/internals/DatePicker.kt b/app/design-system/design-system-internals/src/main/kotlin/com/hedvig/android/design/system/internals/DatePicker.kt index 675fb3971f..2f13342588 100644 --- a/app/design-system/design-system-internals/src/main/kotlin/com/hedvig/android/design/system/internals/DatePicker.kt +++ b/app/design-system/design-system-internals/src/main/kotlin/com/hedvig/android/design/system/internals/DatePicker.kt @@ -6,6 +6,7 @@ import androidx.compose.material3.DatePickerDefaults import androidx.compose.material3.DatePickerDialog import androidx.compose.material3.DatePickerFormatter import androidx.compose.material3.DatePickerState +import androidx.compose.material3.DisplayMode import androidx.compose.material3.SelectableDates import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.rememberDatePickerState @@ -16,10 +17,68 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import com.hedvig.android.design.system.hedvig.api.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.api.HedvigDisplayMode +import com.hedvig.android.design.system.hedvig.api.HedvigSelectableDates +import java.util.Locale import kotlinx.coroutines.flow.drop @Composable -fun HedvigDatePickerInternal( +fun rememberHedvigDatePickerState( + initialSelectedDateMillis: Long, + initialDisplayedMonthMillis: Long, + yearRange: IntRange, + initialDisplayMode: HedvigDisplayMode, + selectableDates: HedvigSelectableDates, +): HedvigDatePickerState { + val materialState = rememberDatePickerState( + initialSelectedDateMillis, + initialDisplayedMonthMillis, + yearRange, + initialDisplayMode.toMaterialDisplayMode(), + selectableDates.toMaterialSelectableDates(), + ) + return remember(materialState) { HedvigDatePickerStateImpl(materialState) } +} + +fun HedvigDatePickerState( + locale: Locale, + initialSelectedDateMillis: Long?, + initialDisplayedMonthMillis: Long?, + yearRange: IntRange, + initialDisplayMode: HedvigDisplayMode, + selectableDates: HedvigSelectableDates, +): HedvigDatePickerState { + val materialState = DatePickerState( + locale = locale, + initialSelectedDateMillis = initialSelectedDateMillis, + initialDisplayedMonthMillis = initialDisplayedMonthMillis, + yearRange = yearRange, + initialDisplayMode = initialDisplayMode.toMaterialDisplayMode(), + selectableDates = selectableDates.toMaterialSelectableDates(), + ) + return HedvigDatePickerStateImpl(materialState) +} + +@Composable +fun HedvigDatePicker( + state: HedvigDatePickerState, + onDismissRequest: () -> Unit, + hedvigDatePickerColors: HedvigDatePickerColors, + confirmButton: @Composable () -> Unit, + modifier: Modifier = Modifier, +) { + HedvigDatePicker( + state = MaterialDatePickerStateImpl(state), + onDismissRequest = onDismissRequest, + hedvigDatePickerColors = hedvigDatePickerColors, + confirmButton = confirmButton, + modifier = modifier, + ) +} + +@Composable +fun HedvigDatePicker( selectedDateMillis: Long?, displayedMonthMillis: Long?, yearRange: IntRange, @@ -30,6 +89,40 @@ fun HedvigDatePickerInternal( hedvigDatePickerColors: HedvigDatePickerColors, confirmButton: @Composable () -> Unit, modifier: Modifier = Modifier, +) { + val state = rememberDatePickerState( + initialSelectedDateMillis = selectedDateMillis, + initialDisplayedMonthMillis = displayedMonthMillis, + yearRange = yearRange, + selectableDates = SelectableDatesImmutableImpl( + minDateInMillis = minDateInMillis, + maxDateInMillis = maxDateInMillis, + yearRange = yearRange, + ), + ) + LaunchedEffect(state) { + snapshotFlow { state.selectedDateMillis } + .drop(1) + .collect { + onSelectedDateChanged(it) + } + } + HedvigDatePicker( + state = state, + onDismissRequest = onDismissRequest, + hedvigDatePickerColors = hedvigDatePickerColors, + confirmButton = confirmButton, + modifier = modifier, + ) +} + +@Composable +private fun HedvigDatePicker( + state: DatePickerState, + onDismissRequest: () -> Unit, + hedvigDatePickerColors: HedvigDatePickerColors, + confirmButton: @Composable () -> Unit, + modifier: Modifier = Modifier, ) { val hedvigColors = with(hedvigDatePickerColors) { DatePickerDefaults.colors( @@ -64,23 +157,6 @@ fun HedvigDatePickerInternal( ), ) } - val state = rememberDatePickerState( - initialSelectedDateMillis = selectedDateMillis, - initialDisplayedMonthMillis = displayedMonthMillis, - yearRange = yearRange, - selectableDates = SelectableDatesImpl( - minDateInMillis = minDateInMillis, - maxDateInMillis = maxDateInMillis, - yearRange = yearRange, - ), - ) - LaunchedEffect(state) { - snapshotFlow { state.selectedDateMillis } - .drop(1) - .collect { - onSelectedDateChanged(it) - } - } DatePickerDialog( onDismissRequest = onDismissRequest, colors = hedvigColors, @@ -95,7 +171,7 @@ fun HedvigDatePickerInternal( } @Composable -fun HedvigDatePicker( +private fun HedvigDatePicker( datePickerState: DatePickerState, colors: DatePickerColors, modifier: Modifier = Modifier, @@ -109,17 +185,6 @@ fun HedvigDatePicker( ) } -@Stable -data class SelectableDatesImpl( - val minDateInMillis: Long, - val maxDateInMillis: Long, - val yearRange: IntRange, -) : SelectableDates { - override fun isSelectableDate(utcTimeMillis: Long): Boolean = utcTimeMillis in minDateInMillis..maxDateInMillis - - override fun isSelectableYear(year: Int): Boolean = year in yearRange -} - data class HedvigDatePickerColors( val selectedDayContainerColor: Color, val selectedDayContentColor: Color, @@ -145,3 +210,101 @@ data class HedvigDatePickerColors( val dateTextColor: Color, val dateTextContainerColor: Color, ) + +@Stable +private data class SelectableDatesImmutableImpl( + val minDateInMillis: Long, + val maxDateInMillis: Long, + val yearRange: IntRange, +) : SelectableDates { + override fun isSelectableDate(utcTimeMillis: Long): Boolean = utcTimeMillis in minDateInMillis..maxDateInMillis + + override fun isSelectableYear(year: Int): Boolean = year in yearRange +} + +private class HedvigDatePickerStateImpl( + val materialState: DatePickerState, +) : HedvigDatePickerState { + override var selectedDateMillis: Long? + set(value) { + materialState.selectedDateMillis = value + } + get() = materialState.selectedDateMillis + + override var displayedMonthMillis: Long + get() = materialState.displayedMonthMillis + set(value) { + materialState.displayedMonthMillis = value + } + + override var displayMode: HedvigDisplayMode + get() = materialState.displayMode.toHedvigDisplayMode() + set(value) { + materialState.displayMode = value.toMaterialDisplayMode() + } + + override val yearRange: IntRange + get() = materialState.yearRange + + override val selectableDates: HedvigSelectableDates = materialState.selectableDates.toHedvigSelectableDates() +} + +private class MaterialDatePickerStateImpl( + val hedvigState: HedvigDatePickerState, +) : DatePickerState { + override var selectedDateMillis: Long? + get() = hedvigState.selectedDateMillis + set(value) { + hedvigState.selectedDateMillis = value + } + override var displayedMonthMillis: Long + get() = hedvigState.displayedMonthMillis + set(value) { + hedvigState.displayedMonthMillis = value + } + override var displayMode: DisplayMode + get() = hedvigState.displayMode.toMaterialDisplayMode() + set(value) { + hedvigState.displayMode = value.toHedvigDisplayMode() + } + override val yearRange: IntRange + get() = hedvigState.yearRange + override val selectableDates: SelectableDates + get() = hedvigState.selectableDates.toMaterialSelectableDates() +} + +private fun HedvigDisplayMode.toMaterialDisplayMode() = when (this) { + HedvigDisplayMode.Picker -> DisplayMode.Picker + HedvigDisplayMode.Input -> DisplayMode.Input + else -> DisplayMode.Picker +} + +private fun DisplayMode.toHedvigDisplayMode() = when (this) { + DisplayMode.Picker -> HedvigDisplayMode.Picker + DisplayMode.Input -> HedvigDisplayMode.Input + else -> HedvigDisplayMode.Picker +} + +private fun HedvigSelectableDates.toMaterialSelectableDates(): SelectableDates { + return object : SelectableDates { + override fun isSelectableDate(utcTimeMillis: Long): Boolean { + return this@toMaterialSelectableDates.isSelectableDate(utcTimeMillis) + } + + override fun isSelectableYear(year: Int): Boolean { + return this@toMaterialSelectableDates.isSelectableYear(year) + } + } +} + +private fun SelectableDates.toHedvigSelectableDates(): HedvigSelectableDates { + return object : HedvigSelectableDates { + override fun isSelectableDate(utcTimeMillis: Long): Boolean { + return this@toHedvigSelectableDates.isSelectableDate(utcTimeMillis) + } + + override fun isSelectableYear(year: Int): Boolean { + return this@toHedvigSelectableDates.isSelectableYear(year) + } + } +} diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt index 49845b0476..3483c927f3 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/navigation/HomeGraph.kt @@ -3,7 +3,7 @@ package com.hedvig.android.feature.home.home.navigation import androidx.navigation.NavBackStackEntry import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink -import com.hedvig.android.design.system.hedvig.MotionDefaults +import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.home.home.ui.FirstVetDestination import com.hedvig.android.feature.home.home.ui.HomeDestination import com.hedvig.android.feature.home.home.ui.HomeViewModel diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt index 1fda9376aa..d955b44a80 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/navigation/InsuranceGraph.kt @@ -4,7 +4,7 @@ import androidx.navigation.NavBackStackEntry import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink import coil.ImageLoader -import com.hedvig.android.design.system.hedvig.MotionDefaults +import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.insurances.data.CancelInsuranceData import com.hedvig.android.feature.insurances.insurance.InsuranceDestination import com.hedvig.android.feature.insurances.insurance.presentation.InsuranceViewModel diff --git a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressDestination.kt b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressDestination.kt index 86c438e2d8..db468fd500 100644 --- a/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressDestination.kt +++ b/app/feature/feature-movingflow/src/main/kotlin/com/hedvig/android/feature/movingflow/ui/enternewaddress/EnterNewAddressDestination.kt @@ -52,7 +52,7 @@ import com.hedvig.android.design.system.hedvig.ToggleDefaults.ToggleDefaultStyle import com.hedvig.android.design.system.hedvig.ToggleDefaults.ToggleStyle import com.hedvig.android.design.system.hedvig.clearFocusOnTap 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.HedvigDatePickerImmutableState import com.hedvig.android.design.system.hedvig.datepicker.HedvigDateTimeFormatterDefaults import com.hedvig.android.design.system.hedvig.datepicker.getLocale import com.hedvig.android.feature.movingflow.compose.ConstrainedNumberInput @@ -300,7 +300,7 @@ private fun DatePickerField( val selectedDateMillis = input.value?.atStartOfDayIn(TimeZone.UTC)?.toEpochMilliseconds() HedvigDatePicker( isVisible = showDatePicker, - datePickerState = HedvigDatePickerState( + datePickerState = HedvigDatePickerImmutableState( selectedDateMillis = selectedDateMillis, displayedMonthMillis = selectedDateMillis, yearRange = IntRange( diff --git a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt index 18876b74d1..7183f32609 100644 --- a/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt +++ b/app/feature/feature-payments/src/main/kotlin/com/hedvig/android/feature/payments/navigation/PaymentsGraph.kt @@ -3,7 +3,7 @@ package com.hedvig.android.feature.payments.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink import com.hedvig.android.core.buildconstants.HedvigBuildConstants -import com.hedvig.android.design.system.hedvig.MotionDefaults +import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.payments.ui.details.PaymentDetailsDestination import com.hedvig.android.feature.payments.ui.details.PaymentDetailsViewModel import com.hedvig.android.feature.payments.ui.discounts.DiscountsDestination diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt index 8a9f935258..2d8bd7becf 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileGraph.kt @@ -4,7 +4,7 @@ import androidx.navigation.NavBackStackEntry import androidx.navigation.NavGraphBuilder import androidx.navigation.navDeepLink import com.hedvig.android.core.buildconstants.HedvigBuildConstants -import com.hedvig.android.design.system.hedvig.MotionDefaults +import com.hedvig.android.design.system.hedvig.motion.MotionDefaults import com.hedvig.android.feature.profile.aboutapp.AboutAppDestination import com.hedvig.android.feature.profile.aboutapp.AboutAppViewModel import com.hedvig.android.feature.profile.aboutapp.LicensesDestination diff --git a/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateDestination.kt b/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateDestination.kt index 86771a304e..baa1e68837 100644 --- a/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateDestination.kt +++ b/app/feature/feature-terminate-insurance/src/main/kotlin/com/hedvig/android/feature/terminateinsurance/step/terminationdate/TerminationDateDestination.kt @@ -28,7 +28,7 @@ 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.design.system.hedvig.datepicker.HedvigDatePicker -import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerImmutableState import com.hedvig.android.feature.terminateinsurance.ui.TerminationInfoCardDate import com.hedvig.android.feature.terminateinsurance.ui.TerminationInfoCardInsurance import com.hedvig.android.feature.terminateinsurance.ui.TerminationScaffold @@ -164,7 +164,7 @@ private fun ImportantInfoCheckBox(isChecked: Boolean, onCheckedChange: () -> Uni @Composable private fun DateButton( - datePickerState: HedvigDatePickerState, + datePickerState: HedvigDatePickerImmutableState, onSelectedDateChange: (Long?) -> Unit, modifier: Modifier = Modifier, ) { @@ -193,7 +193,7 @@ private fun PreviewTerminationDateScreen() { Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TerminationDateScreen( TerminateInsuranceUiState( - HedvigDatePickerState( + HedvigDatePickerImmutableState( null, null, 2015..2023, 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 5688257e9e..8cd1d05231 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 @@ -3,7 +3,7 @@ package com.hedvig.android.feature.terminateinsurance.step.terminationdate import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.lifecycle.ViewModel -import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerImmutableState import com.hedvig.android.feature.terminateinsurance.navigation.TerminationDateParameters import com.hedvig.android.language.LanguageService import java.util.Locale @@ -53,7 +53,7 @@ private class DatePickerConfiguration(locale: Locale, minDate: LocalDate, maxDat private val maxDateInMillis = maxDate.atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds() private val yearRange = minDate.year..maxDate.year - val datePickerState = HedvigDatePickerState( + val datePickerState = HedvigDatePickerImmutableState( locale = locale, selectedDateMillis = null, displayedMonthMillis = null, @@ -64,7 +64,7 @@ private class DatePickerConfiguration(locale: Locale, minDate: LocalDate, maxDat } internal data class TerminateInsuranceUiState( - val datePickerState: HedvigDatePickerState, + val datePickerState: HedvigDatePickerImmutableState, val isLoading: Boolean, val exposureName: String, val displayName: String, diff --git a/app/feature/feature-travel-certificate/build.gradle.kts b/app/feature/feature-travel-certificate/build.gradle.kts index 7fd093eb5d..4c93396008 100644 --- a/app/feature/feature-travel-certificate/build.gradle.kts +++ b/app/feature/feature-travel-certificate/build.gradle.kts @@ -12,7 +12,6 @@ hedvig { dependencies { api(libs.androidx.navigation.common) - implementation(libs.androidx.compose.material3) implementation(libs.androidx.lifecycle.compose) implementation(libs.androidx.navigation.compose) implementation(libs.apollo.normalizedCache) @@ -27,11 +26,8 @@ dependencies { implementation(projects.apolloOctopusPublic) implementation(projects.coreCommonAndroidPublic) implementation(projects.coreCommonPublic) - implementation(projects.coreDesignSystem) implementation(projects.coreFileUpload) - implementation(projects.coreIcons) implementation(projects.coreResources) - implementation(projects.coreUi) implementation(projects.dataContractPublic) implementation(projects.designSystemHedvig) implementation(projects.languageCore) diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/navigation/TravelCertificateGraph.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/navigation/TravelCertificateGraph.kt index b2bec9ec4b..8824a2bd27 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/navigation/TravelCertificateGraph.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/navigation/TravelCertificateGraph.kt @@ -4,7 +4,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Density import androidx.navigation.NavGraphBuilder import com.hedvig.android.core.common.android.sharePDF -import com.hedvig.android.core.designsystem.material3.motion.MotionDefaults import com.hedvig.android.feature.travelcertificate.ui.choose.ChooseContractForCertificateDestination import com.hedvig.android.feature.travelcertificate.ui.choose.ChooseContractForCertificateViewModel import com.hedvig.android.feature.travelcertificate.ui.generatewhen.TravelCertificateDateInputDestination @@ -31,10 +30,6 @@ fun NavGraphBuilder.travelCertificateGraph( ) { navgraph( startDestination = TravelCertificateDestination.TravelCertificateHistory::class, - enterTransition = { MotionDefaults.sharedXAxisEnter(density) }, - exitTransition = { MotionDefaults.sharedXAxisExit(density) }, - popEnterTransition = { MotionDefaults.sharedXAxisPopEnter(density) }, - popExitTransition = { MotionDefaults.sharedXAxisPopExit(density) }, ) { navdestination { navBackStackEntry -> val viewModel: CertificateHistoryViewModel = koinViewModel() diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/TravelCertificateInfoBottomSheet.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/TravelCertificateInfoBottomSheet.kt index df1f9d0595..eede641a10 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/TravelCertificateInfoBottomSheet.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/TravelCertificateInfoBottomSheet.kt @@ -1,51 +1,62 @@ package com.hedvig.android.feature.travelcertificate.ui +import androidx.compose.foundation.layout.Column 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.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.SheetState -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.runtime.Composable 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.material3.squircleLargeTop +import com.hedvig.android.design.system.hedvig.HedvigBottomSheet +import com.hedvig.android.design.system.hedvig.HedvigBottomSheetState +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.Surface import hedvig.resources.R @Composable -internal fun TravelCertificateInfoBottomSheet(onDismiss: () -> Unit, sheetState: SheetState) { - ModalBottomSheet( - containerColor = MaterialTheme.colorScheme.background, - onDismissRequest = { - onDismiss() - }, - shape = MaterialTheme.shapes.squircleLargeTop, - sheetState = sheetState, - tonalElevation = 0.dp, - ) { - Text( - text = stringResource(id = R.string.travel_certificate_info_title), - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 24.dp), +internal fun TravelCertificateInfoBottomSheet(sheetState: HedvigBottomSheetState) { + HedvigBottomSheet(sheetState) { + TravelCertificateInfoBottomSheetContent(sheetState::dismiss) + } +} + +@Composable +private fun TravelCertificateInfoBottomSheetContent(onDismiss: () -> Unit) { + Column { + HedvigText( + text = stringResource(R.string.travel_certificate_info_title), + modifier = Modifier.fillMaxWidth(), ) Spacer(Modifier.height(8.dp)) - Text( - text = stringResource(id = R.string.travel_certificate_info_subtitle), - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 24.dp), + HedvigText( + text = stringResource(R.string.travel_certificate_info_subtitle), + color = HedvigTheme.colorScheme.textSecondary, + modifier = Modifier.fillMaxWidth(), ) - Spacer(Modifier.height(32.dp)) + Spacer(Modifier.height(16.dp)) HedvigTextButton( - text = stringResource(id = R.string.general_close_button), - onClick = { onDismiss() }, - modifier = Modifier.padding(start = 24.dp, end = 24.dp, bottom = 16.dp), + text = stringResource(R.string.general_close_button), + onClick = onDismiss, + modifier = Modifier.fillMaxWidth(), ) + Spacer(Modifier.height(8.dp)) + Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.safeDrawing)) + } +} + +@HedvigPreview +@Composable +private fun PreviewTravelCertificateInfoBottomSheetContent() { + HedvigTheme { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { + TravelCertificateInfoBottomSheetContent({}) + } } } diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/choose/ChooseContractForCertificate.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/choose/ChooseContractForCertificate.kt index 5181b6c476..d04e47f893 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/choose/ChooseContractForCertificate.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/choose/ChooseContractForCertificate.kt @@ -1,36 +1,36 @@ package com.hedvig.android.feature.travelcertificate.ui.choose -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.width -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -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.text.style.LineBreak 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.card.HedvigCard -import com.hedvig.android.core.designsystem.component.error.HedvigErrorSection -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgress -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.clearFocusOnTap -import com.hedvig.android.core.ui.scaffold.HedvigScaffold +import com.hedvig.android.design.system.hedvig.ChosenState.Chosen +import com.hedvig.android.design.system.hedvig.ChosenState.NotChosen +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.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.RadioGroup +import com.hedvig.android.design.system.hedvig.RadioGroupDefaults.RadioGroupStyle +import com.hedvig.android.design.system.hedvig.RadioOptionData +import com.hedvig.android.design.system.hedvig.RadioOptionGroupData.RadioOptionGroupDataSimple +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.clearFocusOnTap import com.hedvig.android.feature.travelcertificate.data.ContractEligibleWithAddress +import com.hedvig.android.feature.travelcertificate.ui.choose.ChooseContractUiState.Success import hedvig.resources.R @Composable @@ -55,9 +55,7 @@ private fun ChooseContractForCertificate( onContinue: (String) -> Unit, reload: () -> Unit, ) { - var selectedContractId by remember { - mutableStateOf(null) - } + var selectedContractId by remember { mutableStateOf(null) } when (uiState) { ChooseContractUiState.Failure -> { FailureScreen( @@ -75,54 +73,42 @@ private fun ChooseContractForCertificate( navigateUp = navigateUp, modifier = Modifier.clearFocusOnTap(), ) { - Spacer(Modifier.height(24.dp)) - Text( - text = stringResource(id = R.string.travel_certificate_select_contract_title), - style = MaterialTheme.typography.headlineMedium, - textAlign = TextAlign.Center, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + Spacer(Modifier.height(8.dp)) + HedvigText( + text = stringResource(R.string.travel_certificate_select_contract_title), + style = HedvigTheme.typography.headlineMedium.copy( + lineBreak = LineBreak.Heading, + ), + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), ) Spacer(Modifier.weight(1f)) - Spacer(Modifier.height(24.dp)) - for (contract in uiState.eligibleContracts) { - HedvigCard( - onClick = { selectedContractId = contract.contractId }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .heightIn(72.dp) - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 10.dp), - ) { - Text( - text = contract.address, - style = MaterialTheme.typography.headlineSmall, - modifier = Modifier.weight(1f), + Spacer(Modifier.height(16.dp)) + RadioGroup( + radioGroupStyle = RadioGroupStyle.Vertical.Default( + uiState.eligibleContracts.map { + RadioOptionGroupDataSimple( + radioOptionData = RadioOptionData( + id = it.contractId, + optionText = it.address, + chosenState = if (it.contractId == selectedContractId) Chosen else NotChosen, + ), ) - Spacer(Modifier.width(8.dp)) - SelectIndicationCircle(selectedContractId == contract.contractId) - } - } - Spacer(modifier = (Modifier.height(4.dp))) - } - Spacer(modifier = Modifier.height(12.dp)) - HedvigContainedButton( + }, + ), + onOptionClick = { contractId -> + selectedContractId = contractId + }, + modifier = Modifier.fillMaxWidth(), + ) + Spacer(modifier = Modifier.height(16.dp)) + HedvigButton( + text = stringResource(id = R.string.general_continue_button), onClick = { selectedContractId?.let { onContinue(it) } }, + enabled = selectedContractId != null, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), - ) { - Text( - text = stringResource(id = R.string.general_continue_button), - style = MaterialTheme.typography.bodyLarge, - ) - } + ) Spacer(Modifier.height(16.dp)) } } @@ -142,9 +128,9 @@ private fun FailureScreen(navigateUp: () -> Unit, reload: () -> Unit) { @Composable private fun PreviewChooseContractForCertificate() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { ChooseContractForCertificate( - ChooseContractUiState.Success( + Success( listOf( ContractEligibleWithAddress("Morbydalen 12", "keuwhwkjfhjkeharfj"), ContractEligibleWithAddress("Akerbyvagen 257", "sesjhfhakerfhlwkeija"), diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInput.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInput.kt index fa5eb549b7..578e464e82 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInput.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInput.kt @@ -1,19 +1,11 @@ package com.hedvig.android.feature.travelcertificate.ui.generatewhen -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.DatePickerDialog -import androidx.compose.material3.DatePickerState -import androidx.compose.material3.DisplayMode -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -21,29 +13,33 @@ 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.draw.clip import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign 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.card.HedvigCard -import com.hedvig.android.core.designsystem.component.datepicker.HedvigDatePicker -import com.hedvig.android.core.designsystem.component.error.HedvigErrorSection -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgress -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.scaffold.HedvigScaffold +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.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTextField +import com.hedvig.android.design.system.hedvig.HedvigTextFieldDefaults +import com.hedvig.android.design.system.hedvig.HedvigTextFieldDefaults.ErrorState +import com.hedvig.android.design.system.hedvig.HedvigTextFieldDefaults.TextFieldSize.Medium +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.api.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.api.HedvigDisplayMode +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePicker +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerState import com.hedvig.android.feature.travelcertificate.data.TravelCertificateUrl import com.hedvig.android.feature.travelcertificate.navigation.TravelCertificateDestination +import com.hedvig.android.feature.travelcertificate.ui.generatewhen.TravelCertificateDateInputUiState.Success import hedvig.resources.R import java.util.Locale -import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime @Composable internal fun TravelCertificateDateInputDestination( @@ -57,7 +53,6 @@ internal fun TravelCertificateDateInputDestination( val uiState by viewModel.uiState.collectAsStateWithLifecycle() TravelCertificateDateInput( uiState = uiState, - onDateChanged = { viewModel.emit(TravelCertificateDateInputEvent.ChangeDateInput(it)) }, reload = { viewModel.emit(TravelCertificateDateInputEvent.RetryLoadData) }, navigateUp = navigateUp, onNavigateToFellowTravellers = onNavigateToFellowTravellers, @@ -71,7 +66,6 @@ internal fun TravelCertificateDateInputDestination( @Composable private fun TravelCertificateDateInput( uiState: TravelCertificateDateInputUiState, - onDateChanged: (LocalDate) -> Unit, onEmailChanged: (String) -> Unit, reload: () -> Unit, navigateUp: () -> Unit, @@ -116,11 +110,10 @@ private fun TravelCertificateDateInput( HedvigScaffold( navigateUp = navigateUp, ) { - Spacer(Modifier.height(24.dp)) - Text( - text = stringResource(id = R.string.travel_certificate_when_is_your_trip), - style = MaterialTheme.typography.headlineMedium, - textAlign = TextAlign.Center, + Spacer(Modifier.height(8.dp)) + HedvigText( + text = stringResource(R.string.travel_certificate_when_is_your_trip), + style = HedvigTheme.typography.headlineMedium, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), @@ -128,7 +121,6 @@ private fun TravelCertificateDateInput( Spacer(Modifier.weight(1f)) Spacer(Modifier.height(24.dp)) MovingDateButton( - onDateSelected = onDateChanged, datePickerState = uiState.datePickerState, travelDate = uiState.travelDate, modifier = Modifier.padding(horizontal = 16.dp), @@ -144,17 +136,12 @@ private fun TravelCertificateDateInput( errorText = uiState.errorMessageRes?.let { stringResource(id = it) }, ) Spacer(Modifier.height(16.dp)) - HedvigContainedButton( + HedvigButton( + stringResource(id = R.string.general_continue_button), onClick = submitInput, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) { - Text( - text = stringResource(id = R.string.general_continue_button), - style = MaterialTheme.typography.bodyLarge, - ) - } + enabled = true, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + ) Spacer(Modifier.height(16.dp)) } } @@ -168,89 +155,55 @@ private fun EmailTextField( onEmailChanged: (String) -> Unit, modifier: Modifier = Modifier, ) { -// var errorMessage by remember { mutableStateOf(errorText)} HedvigTextField( - value = email, - errorText = errorText, - withNewDesign = true, + text = email, onValueChange = { onEmailChanged(it) }, - label = { - Text("Email") + errorState = if (errorText != null) { + ErrorState.Error.WithMessage(errorText) + } else { + ErrorState.NoError }, + textFieldSize = Medium, + labelText = stringResource(R.string.PROFILE_MY_INFO_EMAIL_LABEL), modifier = modifier.fillMaxWidth(), ) } @Composable private fun MovingDateButton( - onDateSelected: (LocalDate) -> Unit, - datePickerState: DatePickerState, + datePickerState: HedvigDatePickerState, travelDate: LocalDate, modifier: Modifier = Modifier, ) { var showDatePicker by rememberSaveable { mutableStateOf(false) } if (showDatePicker) { - DatePickerDialog( + HedvigDatePicker( + datePickerState = datePickerState, onDismissRequest = { showDatePicker = false }, - confirmButton = { - TextButton( - onClick = { - datePickerState.selectedDateMillis?.let { - val selectedDate = Instant.fromEpochMilliseconds(it) - .toLocalDateTime(TimeZone.UTC) - .date - onDateSelected(selectedDate) - } - showDatePicker = false - }, - shape = MaterialTheme.shapes.medium, - ) { - Text(stringResource(R.string.ALERT_OK)) - } - }, - dismissButton = { - TextButton( - onClick = { - showDatePicker = false - }, - shape = MaterialTheme.shapes.medium, - ) { - Text(stringResource(R.string.general_close_button)) - } - }, - ) { - HedvigDatePicker(datePickerState = datePickerState) - } + onConfirmRequest = { showDatePicker = false }, + ) } - Column(modifier) { - HedvigCard( - onClick = { showDatePicker = true }, - colors = CardDefaults.outlinedCardColors( - containerColor = MaterialTheme.colorScheme.surface, - contentColor = MaterialTheme.colorScheme.onSurface, - ), - modifier = Modifier.fillMaxWidth(), - ) { - Row( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Column(Modifier.weight(1f)) { - Text( - text = stringResource(id = R.string.travel_certificate_start_date_title), - style = MaterialTheme.typography.bodySmall, - ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = travelDate.toString(), - style = MaterialTheme.typography.headlineSmall, - ) - } - } - } + // Workaround to get the layout of the hedvigTextField, without the functionality of it. Perhaps room for another + // component here + Box(modifier) { + HedvigTextField( + text = travelDate.toString(), + onValueChange = {}, + readOnly = true, + enabled = true, + labelText = stringResource(R.string.travel_certificate_start_date_title), + textFieldSize = HedvigTextFieldDefaults.TextFieldSize.Medium, + trailingContent = {}, + ) + Box( + Modifier + .matchParentSize() + .clip(HedvigTheme.shapes.cornerLarge) + .clickable { showDatePicker = true }, + ) } } @@ -258,13 +211,13 @@ private fun MovingDateButton( @Composable private fun PreviewTravelCertificateDateInput() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateDateInput( - TravelCertificateDateInputUiState.Success( + Success( "id", "emaild", hasCoInsured = false, - datePickerState = DatePickerState(Locale.ENGLISH, null, null, 2020..2024, DisplayMode.Picker), + datePickerState = HedvigDatePickerState(Locale.ENGLISH, null, null, 2020..2024, HedvigDisplayMode.Picker), travelDate = LocalDate(2023, 1, 1), daysValid = 40, errorMessageRes = null, @@ -277,7 +230,6 @@ private fun PreviewTravelCertificateDateInput() { {}, {}, {}, - {}, ) } } diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInputViewModel.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInputViewModel.kt index 3a501db34b..03f7333406 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInputViewModel.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewhen/TravelCertificateDateInputViewModel.kt @@ -1,8 +1,5 @@ package com.hedvig.android.feature.travelcertificate.ui.generatewhen -import androidx.compose.material3.DatePickerState -import androidx.compose.material3.DisplayMode -import androidx.compose.material3.SelectableDates import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -11,6 +8,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import com.hedvig.android.core.common.android.validation.validateEmail +import com.hedvig.android.design.system.hedvig.api.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.api.HedvigSelectableDates +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerState import com.hedvig.android.feature.travelcertificate.data.CreateTravelCertificateUseCase import com.hedvig.android.feature.travelcertificate.data.GetTravelCertificateSpecificationsUseCase import com.hedvig.android.feature.travelcertificate.data.TravelCertificateUrl @@ -68,12 +68,12 @@ internal class TravelCertificateDateInputPresenter( DateInputScreenContent.Success.SpecificationsDetails( contractId = lastState.contractId, email = lastState.email, - travelDate = lastState.travelDate, datePickerState = lastState.datePickerState, daysValid = lastState.daysValid, hasCoInsured = lastState.hasCoInsured, ), ) + TravelCertificateDateInputUiState.Failure -> DateInputScreenContent.Failure TravelCertificateDateInputUiState.Loading -> DateInputScreenContent.Loading is TravelCertificateDateInputUiState.UrlFetched -> { @@ -135,15 +135,6 @@ internal class TravelCertificateDateInputPresenter( ) } - is TravelCertificateDateInputEvent.ChangeDateInput -> { - val successScreenContent = screenContent as? DateInputScreenContent.Success ?: return@CollectEvents - screenContent = successScreenContent.copy( - details = successScreenContent.details.copy( - travelDate = event.localDate, - ), - ) - } - TravelCertificateDateInputEvent.RetryLoadData -> { loadIteration++ } @@ -192,13 +183,12 @@ internal class TravelCertificateDateInputPresenter( ifRight = { travelCertificateData -> val travelSpecification = travelCertificateData.travelCertificateSpecification val yearRange = travelSpecification.dateRange.start.year..travelSpecification.dateRange.endInclusive.year - val datePickerState = DatePickerState( + val datePickerState = HedvigDatePickerState( locale = languageService.getLocale(), initialSelectedDateMillis = null, initialDisplayedMonthMillis = null, yearRange = yearRange, - initialDisplayMode = DisplayMode.Picker, - selectableDates = object : SelectableDates { + selectableDates = object : HedvigSelectableDates { override fun isSelectableDate(utcTimeMillis: Long): Boolean { val selectedDate = Instant.fromEpochMilliseconds(utcTimeMillis).toLocalDateTime(TimeZone.currentSystemDefault()).date @@ -215,7 +205,6 @@ internal class TravelCertificateDateInputPresenter( email = travelSpecification.email, contractId = travelSpecification.contractId, hasCoInsured = travelSpecification.numberOfCoInsured > 0, - travelDate = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date, ), ) }, @@ -253,11 +242,17 @@ private sealed interface DateInputScreenContent { data class SpecificationsDetails( val contractId: String, val email: String?, - val travelDate: LocalDate, - val datePickerState: DatePickerState, + val datePickerState: HedvigDatePickerState, val daysValid: Int, val hasCoInsured: Boolean, - ) + ) { + val travelDate: LocalDate + get() = datePickerState.selectedDateMillis?.let { + Instant.fromEpochMilliseconds(it) + .toLocalDateTime(TimeZone.UTC) + .date + } ?: Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date + } } data class UrlFetched(val travelCertificateUrl: TravelCertificateUrl) : DateInputScreenContent @@ -266,8 +261,6 @@ private sealed interface DateInputScreenContent { internal sealed interface TravelCertificateDateInputEvent { data object RetryLoadData : TravelCertificateDateInputEvent - data class ChangeDateInput(val localDate: LocalDate) : TravelCertificateDateInputEvent - data class ChangeEmailInput(val email: String) : TravelCertificateDateInputEvent data object Submit : TravelCertificateDateInputEvent @@ -287,7 +280,7 @@ internal sealed interface TravelCertificateDateInputUiState { val email: String?, val travelDate: LocalDate, val hasCoInsured: Boolean, - val datePickerState: DatePickerState, + val datePickerState: HedvigDatePickerState, val daysValid: Int, val primaryInput: TravelCertificateDestination.TravelCertificateTravellersInput.TravelCertificatePrimaryInput?, val errorMessageRes: Int?, diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewho/TravelCertificateTravellersInput.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewho/TravelCertificateTravellersInput.kt index fb7b78f439..cc47602f77 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewho/TravelCertificateTravellersInput.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/generatewho/TravelCertificateTravellersInput.kt @@ -1,43 +1,38 @@ package com.hedvig.android.feature.travelcertificate.ui.generatewho import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Button -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.runtime.LaunchedEffect import androidx.compose.runtime.getValue 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 androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed -import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton -import com.hedvig.android.core.designsystem.component.error.HedvigErrorSection -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgress -import com.hedvig.android.core.designsystem.material3.onSecondaryContainedButtonContainer -import com.hedvig.android.core.designsystem.material3.secondaryContainedButtonContainer -import com.hedvig.android.core.designsystem.material3.squircleMedium -import com.hedvig.android.core.designsystem.preview.HedvigPreview -import com.hedvig.android.core.designsystem.theme.HedvigTheme -import com.hedvig.android.core.ui.RoundedCornerCheckBox -import com.hedvig.android.core.ui.infocard.VectorInfoCard -import com.hedvig.android.core.ui.scaffold.HedvigScaffold import com.hedvig.android.design.system.hedvig.Checkbox import com.hedvig.android.design.system.hedvig.CheckboxDefaults.CheckboxSize.Large import com.hedvig.android.design.system.hedvig.CheckboxDefaults.CheckboxStyle import com.hedvig.android.design.system.hedvig.ChosenState.Chosen import com.hedvig.android.design.system.hedvig.ChosenState.NotChosen +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.HedvigNotificationCard +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.NotificationDefaults.InfoCardStyle +import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority +import com.hedvig.android.design.system.hedvig.Surface import com.hedvig.android.feature.travelcertificate.data.TravelCertificateUrl +import com.hedvig.android.feature.travelcertificate.ui.generatewho.TravelCertificateTravellersInputUiState.Failure +import com.hedvig.android.feature.travelcertificate.ui.generatewho.TravelCertificateTravellersInputUiState.Success import hedvig.resources.R @Composable @@ -93,14 +88,11 @@ private fun TravelCertificateTravellersInput( HedvigScaffold( navigateUp = navigateUp, ) { - Spacer(Modifier.height(24.dp)) - Text( + Spacer(Modifier.height(8.dp)) + HedvigText( text = stringResource(id = R.string.travel_certificate_who_is_traveling), - style = MaterialTheme.typography.headlineMedium, - textAlign = TextAlign.Center, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + style = HedvigTheme.typography.headlineMedium, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), ) Spacer(Modifier.weight(1f)) Spacer(Modifier.height(16.dp)) @@ -130,51 +122,29 @@ private fun TravelCertificateTravellersInput( } if (uiState.coInsuredHasMissingInfo) { Spacer(Modifier.height(16.dp)) - VectorInfoCard( - text = stringResource(id = R.string.travel_certificate_missing_coinsured_info), - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) { - Button( - onClick = dropUnlessResumed { - onNavigateToCoInsuredAddInfo() - }, - enabled = true, - modifier = Modifier.fillMaxWidth(), - shape = MaterialTheme.shapes.squircleMedium, - contentPadding = PaddingValues(6.dp), - colors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.secondaryContainedButtonContainer, - contentColor = MaterialTheme.colorScheme.onSecondaryContainedButtonContainer, - disabledContainerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.12f), - disabledContentColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38f), - ), - ) { - Text( - text = stringResource(id = R.string.travel_certificate_missing_coinsured_button), - style = MaterialTheme.typography.titleSmall, - ) - } - } + HedvigNotificationCard( + message = stringResource(R.string.travel_certificate_missing_coinsured_info), + priority = NotificationPriority.Info, + style = InfoCardStyle.Button( + buttonText = stringResource(R.string.travel_certificate_missing_coinsured_button), + onButtonClick = dropUnlessResumed { onNavigateToCoInsuredAddInfo() }, + ), + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + ) } - Spacer(Modifier.height(16.dp)) - HedvigContainedButton( + HedvigButton( + text = stringResource(R.string.GENERAL_SUBMIT), onClick = { if (uiState.hasAtLeastOneTraveler) { onGenerateTravelCertificate() } }, + enabled = uiState.hasAtLeastOneTraveler, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), - ) { - Text( - text = stringResource(id = R.string.GENERAL_SUBMIT), - style = MaterialTheme.typography.bodyLarge, - ) - } + ) Spacer(Modifier.height(16.dp)) } } @@ -182,33 +152,13 @@ private fun TravelCertificateTravellersInput( } } -@HedvigPreview -@Composable -private fun PreviewRoundedCornerCheckBoxChecked() { - HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { - RoundedCornerCheckBox(true, {}) - } - } -} - -@HedvigPreview -@Composable -private fun PreviewRoundedCornerCheckBoxUnChecked() { - HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { - RoundedCornerCheckBox(false, {}) - } - } -} - @HedvigPreview @Composable private fun PreviewTravelCertificateTravellersInput() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateTravellersInput( - TravelCertificateTravellersInputUiState.Success( + Success( true, listOf( CoInsured("id", "Co-insured Baby", null, null, false), @@ -233,9 +183,9 @@ private fun PreviewTravelCertificateTravellersInput() { @Composable private fun PreviewTravelCertificateTravellersInputWithEmailFailure() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateTravellersInput( - TravelCertificateTravellersInputUiState.Failure, + Failure, {}, {}, {}, diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/history/TravelCertificateHistory.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/history/TravelCertificateHistory.kt index 0456d98e1a..a6dbd0139d 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/history/TravelCertificateHistory.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/history/TravelCertificateHistory.kt @@ -9,20 +9,9 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material.icons.Icons -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -30,22 +19,36 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.hedvig.android.core.designsystem.component.button.HedvigSecondaryContainedButton -import com.hedvig.android.core.designsystem.component.error.HedvigErrorSection -import com.hedvig.android.core.designsystem.component.information.HedvigInformationSection -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgress -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.Info -import com.hedvig.android.core.ui.clearFocusOnTap -import com.hedvig.android.core.ui.dialog.ErrorDialog -import com.hedvig.android.core.ui.infocard.VectorInfoCard -import com.hedvig.android.core.ui.rememberHedvigMonthDateTimeFormatter -import com.hedvig.android.core.ui.scaffold.HedvigScaffold -import com.hedvig.android.core.ui.text.HorizontalItemsWithMaximumSpaceTaken +import androidx.lifecycle.compose.dropUnlessResumed +import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonStyle.Secondary +import com.hedvig.android.design.system.hedvig.EmptyState +import com.hedvig.android.design.system.hedvig.EmptyStateDefaults.EmptyStateIconStyle.INFO +import com.hedvig.android.design.system.hedvig.ErrorDialog +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.HedvigNotificationCard +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigText +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.HorizontalDivider +import com.hedvig.android.design.system.hedvig.HorizontalItemsWithMaximumSpaceTaken +import com.hedvig.android.design.system.hedvig.Icon +import com.hedvig.android.design.system.hedvig.IconButton +import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.clearFocusOnTap +import com.hedvig.android.design.system.hedvig.datepicker.rememberHedvigMonthDateTimeFormatter +import com.hedvig.android.design.system.hedvig.icon.HedvigIcons +import com.hedvig.android.design.system.hedvig.icon.InfoOutline +import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState +import com.hedvig.android.design.system.hedvig.show import com.hedvig.android.feature.travelcertificate.data.TravelCertificate import com.hedvig.android.feature.travelcertificate.ui.TravelCertificateInfoBottomSheet +import com.hedvig.android.feature.travelcertificate.ui.history.CertificateHistoryUiState.FailureDownloadingHistory +import com.hedvig.android.feature.travelcertificate.ui.history.CertificateHistoryUiState.Loading +import com.hedvig.android.feature.travelcertificate.ui.history.CertificateHistoryUiState.SuccessDownloadingHistory import hedvig.resources.R import java.io.File import kotlinx.datetime.LocalDate @@ -87,14 +90,8 @@ private fun TravelCertificateHistoryScreen( onShareTravelCertificate: (File) -> Unit, uiState: CertificateHistoryUiState, ) { - var showBottomSheet by remember { mutableStateOf(false) } - val explanationSheetState = rememberModalBottomSheetState(true) - if (showBottomSheet) { - TravelCertificateInfoBottomSheet( - onDismiss = { showBottomSheet = false }, - sheetState = explanationSheetState, - ) - } + val explanationSheetState = rememberHedvigBottomSheetState() + TravelCertificateInfoBottomSheet(explanationSheetState) when (uiState) { CertificateHistoryUiState.FailureDownloadingHistory -> { @@ -104,11 +101,11 @@ private fun TravelCertificateHistoryScreen( topAppBarText = stringResource(id = R.string.PROFILE_ROW_TRAVEL_CERTIFICATE), topAppBarActions = { IconButton( - onClick = { showBottomSheet = true }, + onClick = { explanationSheetState.show() }, modifier = Modifier.size(40.dp), ) { Icon( - imageVector = Icons.Hedvig.Info, + imageVector = HedvigIcons.InfoOutline, contentDescription = stringResource(R.string.REFERRALS_INFO_BUTTON_CONTENT_DESCRIPTION), modifier = Modifier.size(24.dp), ) @@ -133,7 +130,7 @@ private fun TravelCertificateHistoryScreen( HedvigFullScreenCenterAlignedProgress() } else { TravelCertificateSuccessScreen( - onIconClick = { showBottomSheet = true }, + onIconClick = { explanationSheetState.show() }, onCertificateClick = onCertificateClick, onStartGenerateTravelCertificateFlow = onStartGenerateTravelCertificateFlow, navigateUp = navigateUp, @@ -172,7 +169,7 @@ private fun TravelCertificateSuccessScreen( modifier = Modifier.size(40.dp), ) { Icon( - imageVector = Icons.Hedvig.Info, + imageVector = HedvigIcons.InfoOutline, contentDescription = stringResource(R.string.REFERRALS_INFO_BUTTON_CONTENT_DESCRIPTION), modifier = Modifier.size(24.dp), ) @@ -181,9 +178,9 @@ private fun TravelCertificateSuccessScreen( ) { if (historyList.isEmpty()) { Spacer(modifier = Modifier.weight(1f)) - ShowInitialInfo() + EmptyTravelCertificatesScreen() } else { - ShowNotEmptyList( + TravelCertificatesList( list = historyList, onCertificateClick = onCertificateClick, showErrorDialog = showErrorDialog, @@ -191,17 +188,21 @@ private fun TravelCertificateSuccessScreen( ) } Spacer(modifier = Modifier.weight(1f)) - VectorInfoCard( - text = String.format(stringResource(id = R.string.travel_certificate_start_date_info), 45), - modifier = Modifier - .fillMaxWidth() - .padding(16.dp, 16.dp, 16.dp, 8.dp), + HedvigNotificationCard( + message = stringResource(R.string.travel_certificate_start_date_info, 45), + priority = NotificationPriority.Info, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), ) if (showGenerationButton) { - HedvigSecondaryContainedButton( + Spacer(Modifier.height(8.dp)) + HedvigButton( text = stringResource(R.string.travel_certificate_get_travel_certificate_button), - onClick = if (hasChooseOption) onGoToChooseContract else onStartGenerateTravelCertificateFlow, - modifier = Modifier.padding(16.dp, 8.dp, 16.dp, 0.dp), + onClick = dropUnlessResumed { + if (hasChooseOption) onGoToChooseContract() else onStartGenerateTravelCertificateFlow() + }, + buttonStyle = Secondary, + enabled = true, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), ) } Spacer(Modifier.height(16.dp)) @@ -209,20 +210,22 @@ private fun TravelCertificateSuccessScreen( } @Composable -private fun ShowInitialInfo() { +private fun EmptyTravelCertificatesScreen() { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - HedvigInformationSection( - stringResource(id = R.string.travel_certificate_empty_list_message), + EmptyState( + text = stringResource(R.string.travel_certificate_empty_list_message), + description = null, + iconStyle = INFO, ) } } @Composable -private fun ShowNotEmptyList( +private fun TravelCertificatesList( list: List, onCertificateClick: (String) -> Unit, showErrorDialog: Boolean, @@ -244,12 +247,12 @@ private fun ShowNotEmptyList( val year = it.key val travelCertificates = it.value - Text(text = year.toString(), modifier = Modifier.padding(horizontal = 16.dp)) + HedvigText(text = year.toString(), modifier = Modifier.padding(horizontal = 16.dp)) Spacer(Modifier.height(4.dp)) travelCertificates.forEachIndexed { index, certificate -> val isExpired = certificate.isExpiredNow - val color = if (isExpired) MaterialTheme.colorScheme.error else Color.Unspecified + val color = if (isExpired) HedvigTheme.colorScheme.signalRedElement else Color.Unspecified val endText = if (isExpired) { stringResource(id = R.string.travel_certificate_expired) } else { @@ -258,13 +261,13 @@ private fun ShowNotEmptyList( HorizontalItemsWithMaximumSpaceTaken( startSlot = { - Text( + HedvigText( text = dateTimeFormatter.format(certificate.startDate.toJavaLocalDate()), color = color, ) }, endSlot = { - Text( + HedvigText( text = endText, color = color, textAlign = TextAlign.End, @@ -291,7 +294,7 @@ private fun ShowNotEmptyList( @Composable private fun PreviewTravelCertificateHistoryScreenWithEmptyList() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -300,7 +303,7 @@ private fun PreviewTravelCertificateHistoryScreenWithEmptyList() { {}, {}, {}, - CertificateHistoryUiState.SuccessDownloadingHistory( + SuccessDownloadingHistory( listOf(), false, true, @@ -317,7 +320,7 @@ private fun PreviewTravelCertificateHistoryScreenWithEmptyList() { @Composable private fun PreviewTravelCertificateHistoryScreenWithExpiredEarlier() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -326,7 +329,7 @@ private fun PreviewTravelCertificateHistoryScreenWithExpiredEarlier() { {}, {}, {}, - CertificateHistoryUiState.SuccessDownloadingHistory( + SuccessDownloadingHistory( listOf( TravelCertificate( startDate = LocalDate(2024, 6, 2), @@ -372,7 +375,7 @@ private fun PreviewTravelCertificateHistoryScreenWithExpiredEarlier() { @Composable private fun PreviewErrorWithDownloadingCertificate() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -381,7 +384,7 @@ private fun PreviewErrorWithDownloadingCertificate() { {}, {}, {}, - CertificateHistoryUiState.SuccessDownloadingHistory( + SuccessDownloadingHistory( listOf( TravelCertificate( startDate = LocalDate(2024, 6, 2), @@ -427,7 +430,7 @@ private fun PreviewErrorWithDownloadingCertificate() { @Composable private fun PreviewTravelCertificateHistoryScreenWithExpiredToday() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -436,7 +439,7 @@ private fun PreviewTravelCertificateHistoryScreenWithExpiredToday() { {}, {}, {}, - CertificateHistoryUiState.SuccessDownloadingHistory( + SuccessDownloadingHistory( listOf( TravelCertificate( startDate = LocalDate(2024, 1, 6), @@ -472,7 +475,7 @@ private fun PreviewTravelCertificateHistoryScreenWithExpiredToday() { @Composable private fun PreviewTravelCertificateHistoryScreenWithExpiredTodayNoGenerateButton() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -481,7 +484,7 @@ private fun PreviewTravelCertificateHistoryScreenWithExpiredTodayNoGenerateButto {}, {}, {}, - CertificateHistoryUiState.SuccessDownloadingHistory( + SuccessDownloadingHistory( listOf( TravelCertificate( startDate = LocalDate(2024, 1, 6), @@ -517,7 +520,7 @@ private fun PreviewTravelCertificateHistoryScreenWithExpiredTodayNoGenerateButto @Composable private fun PreviewCertificateHistoryLoading() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -526,7 +529,7 @@ private fun PreviewCertificateHistoryLoading() { {}, {}, {}, - CertificateHistoryUiState.Loading, + Loading, ) } } @@ -536,7 +539,7 @@ private fun PreviewCertificateHistoryLoading() { @Composable private fun PreviewErrorWithHistory() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -545,7 +548,7 @@ private fun PreviewErrorWithHistory() { {}, {}, {}, - CertificateHistoryUiState.FailureDownloadingHistory, + FailureDownloadingHistory, ) } } @@ -555,7 +558,7 @@ private fun PreviewErrorWithHistory() { @Composable private fun PreviewLoadingCertificate() { HedvigTheme { - Surface(color = MaterialTheme.colorScheme.background) { + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { TravelCertificateHistoryScreen( {}, {}, @@ -564,7 +567,7 @@ private fun PreviewLoadingCertificate() { {}, {}, {}, - CertificateHistoryUiState.SuccessDownloadingHistory( + SuccessDownloadingHistory( listOf( TravelCertificate( startDate = LocalDate(2024, 6, 2), diff --git a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/overview/TravelCertificateOverview.kt b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/overview/TravelCertificateOverview.kt index 9843fd8c8c..66ebc7350c 100644 --- a/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/overview/TravelCertificateOverview.kt +++ b/app/feature/feature-travel-certificate/src/main/kotlin/com/hedvig/android/feature/travelcertificate/ui/overview/TravelCertificateOverview.kt @@ -5,35 +5,29 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.LineBreak -import androidx.compose.ui.text.style.TextAlign 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.error.HedvigErrorSection -import com.hedvig.android.core.designsystem.component.progress.HedvigFullScreenCenterAlignedProgress -import com.hedvig.android.core.designsystem.material3.typeElement -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.small.hedvig.Checkmark -import com.hedvig.android.core.ui.appbar.m3.TopAppBarActionType -import com.hedvig.android.core.ui.infocard.VectorInfoCard -import com.hedvig.android.core.ui.scaffold.HedvigScaffold +import com.hedvig.android.design.system.hedvig.EmptyState +import com.hedvig.android.design.system.hedvig.EmptyStateDefaults.EmptyStateIconStyle.SUCCESS +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.HedvigNotificationCard +import com.hedvig.android.design.system.hedvig.HedvigPreview +import com.hedvig.android.design.system.hedvig.HedvigScaffold +import com.hedvig.android.design.system.hedvig.HedvigTextButton +import com.hedvig.android.design.system.hedvig.HedvigTheme +import com.hedvig.android.design.system.hedvig.NotificationDefaults.NotificationPriority +import com.hedvig.android.design.system.hedvig.Surface +import com.hedvig.android.design.system.hedvig.TopAppBarActionType import com.hedvig.android.feature.travelcertificate.data.TravelCertificateUrl +import com.hedvig.android.feature.travelcertificate.ui.overview.TravelCertificateOverviewUiState.Success import hedvig.resources.R import java.io.File @@ -89,41 +83,22 @@ internal fun TravelCertificateOverview( navigateUp, itemsColumnHorizontalAlignment = Alignment.CenterHorizontally, ) { - Spacer(Modifier.height(32.dp)) - Spacer(modifier = Modifier.weight(1f)) - Icon( - imageVector = Icons.Hedvig.Checkmark, - contentDescription = null, - tint = MaterialTheme.colorScheme.typeElement, - ) Spacer(Modifier.height(16.dp)) - Text( - text = stringResource(id = R.string.travel_certificate_travel_certificate_ready), - textAlign = TextAlign.Center, - style = LocalTextStyle.current.copy( - lineBreak = LineBreak.Heading, - ), - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + Spacer(Modifier.weight(1f)) + EmptyState( + text = stringResource(R.string.travel_certificate_travel_certificate_ready), + description = stringResource(R.string.travel_certificate_travel_certificate_ready_description), + iconStyle = SUCCESS, ) - Spacer(Modifier.height(2.dp)) - Text( - text = stringResource(id = R.string.travel_certificate_travel_certificate_ready_description), - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - ) - Spacer(Modifier.height(32.dp)) - Spacer(modifier = Modifier.weight(1f)) - VectorInfoCard( - text = stringResource(id = R.string.travel_certificate_download_recommendation), - modifier = Modifier.padding(horizontal = 16.dp), + Spacer(Modifier.weight(1f)) + Spacer(Modifier.height(16.dp)) + HedvigNotificationCard( + message = stringResource(R.string.travel_certificate_download_recommendation), + priority = NotificationPriority.Info, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), ) Spacer(modifier = Modifier.height(16.dp)) - HedvigContainedButton( + HedvigButton( text = if (uiState.travelCertificateUri != null) { stringResource(R.string.travel_certificate_share_travel_certificate) } else { @@ -136,19 +111,16 @@ internal fun TravelCertificateOverview( onDownloadCertificate(travelCertificateUrl) } }, + enabled = true, modifier = Modifier + .fillMaxWidth() .padding(horizontal = 16.dp), ) Spacer(modifier = Modifier.height(8.dp)) - HedvigSecondaryContainedButton( + HedvigTextButton( text = stringResource(id = R.string.general_done_button), onClick = navigateUp, - modifier = Modifier - .padding(horizontal = 16.dp), - colors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.onPrimary, - contentColor = MaterialTheme.colorScheme.primary, - ), + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), ) Spacer(modifier = Modifier.height(16.dp)) } @@ -160,12 +132,14 @@ internal fun TravelCertificateOverview( @Composable private fun PreviewTravelCertificateOverview() { HedvigTheme { - TravelCertificateOverview( - travelCertificateUrl = TravelCertificateUrl(""), - onDownloadCertificate = {}, - navigateUp = {}, - onShareTravelCertificate = {}, - uiState = TravelCertificateOverviewUiState.Success(null), - ) + Surface(color = HedvigTheme.colorScheme.backgroundPrimary) { + TravelCertificateOverview( + travelCertificateUrl = TravelCertificateUrl(""), + onDownloadCertificate = {}, + navigateUp = {}, + onShareTravelCertificate = {}, + uiState = Success(null), + ) + } } } diff --git a/hedvig-lint/lint-baseline/lint-baseline-design-system-api.xml b/hedvig-lint/lint-baseline/lint-baseline-design-system-api.xml new file mode 100644 index 0000000000..696b88b8cf --- /dev/null +++ b/hedvig-lint/lint-baseline/lint-baseline-design-system-api.xml @@ -0,0 +1,4 @@ + + + + diff --git a/micro-apps/design-showcase/src/main/kotlin/com/hedvig/android/sample/design/showcase/datepicker/DatePickerShowcase.kt b/micro-apps/design-showcase/src/main/kotlin/com/hedvig/android/sample/design/showcase/datepicker/DatePickerShowcase.kt index 7b7e50a40f..7f60388f6b 100644 --- a/micro-apps/design-showcase/src/main/kotlin/com/hedvig/android/sample/design/showcase/datepicker/DatePickerShowcase.kt +++ b/micro-apps/design-showcase/src/main/kotlin/com/hedvig/android/sample/design/showcase/datepicker/DatePickerShowcase.kt @@ -23,7 +23,7 @@ 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.design.system.hedvig.datepicker.HedvigDatePicker -import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerState +import com.hedvig.android.design.system.hedvig.datepicker.HedvigDatePickerImmutableState import java.util.Locale import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate @@ -36,7 +36,7 @@ fun DatePickerShowcase() { val locale = getLocale() var state by remember { mutableStateOf( - HedvigDatePickerState( + HedvigDatePickerImmutableState( selectedDateMillis = null, displayedMonthMillis = null, yearRange = 2024..2025,