diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 760f9a7626..54c68e7196 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -24,6 +24,7 @@ jobs: # Only write to the cache for builds on the 'develop' branch cache-read-only: ${{ github.ref != 'refs/heads/develop' }} gradle-home-cache-cleanup: true + cache-disabled: true - name: Prebuild run: ./scripts/ci-prebuild.sh env: diff --git a/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/FragmentClaimFlowStepFragment.graphql b/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/FragmentClaimFlowStepFragment.graphql index 57b9c9785f..a59cd25eba 100644 --- a/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/FragmentClaimFlowStepFragment.graphql +++ b/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/FragmentClaimFlowStepFragment.graphql @@ -12,6 +12,10 @@ fragment ClaimFlowStepFragment on Flow { ...FlowClaimFailedStepFragment ...FlowClaimSuccessStepFragment ...FlowClaimContractSelectStepFragment + ...FlowClaimDeflectGlassDamageStepFragment + ...FlowClaimConfirmEmergencyStepFragment + ...FlowClaimDeflectEmergencyStepFragment + ...FlowClaimDeflectPestsStepFragment } } @@ -129,3 +133,41 @@ fragment FlowClaimContractSelectStepFragment on FlowClaimContractSelectStep { displayName } } + +fragment FlowClaimDeflectGlassDamageStepFragment on FlowClaimDeflectGlassDamageStep { + id + partners { + ...FlowClaimDeflectPartnerFragment + } +} + +fragment FlowClaimConfirmEmergencyStepFragment on FlowClaimConfirmEmergencyStep { + id + text + confirmEmergency + options { + displayName + displayValue: value + } +} + +fragment FlowClaimDeflectEmergencyStepFragment on FlowClaimDeflectEmergencyStep { + id + partners { + ...FlowClaimDeflectPartnerFragment + } +} + +fragment FlowClaimDeflectPestsStepFragment on FlowClaimDeflectPestsStep { + id + partners { + ...FlowClaimDeflectPartnerFragment + } +} + +fragment FlowClaimDeflectPartnerFragment on FlowClaimDeflectPartner { + id + imageUrl + url + phoneNumber +} diff --git a/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/MutationFlowClaimConfirmEmergency.graphql b/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/MutationFlowClaimConfirmEmergency.graphql new file mode 100644 index 0000000000..28db87843a --- /dev/null +++ b/app/apollo/apollo-octopus-public/src/main/graphql/com/hedvig/android/apollo/octopus/graphql/claimflow/MutationFlowClaimConfirmEmergency.graphql @@ -0,0 +1,7 @@ +mutation FlowClaimConfirmEmergency($isUrgentEmergency: Boolean!, $context: FlowContext!) { + flowClaimConfirmEmergencyNext(input: { confirmEmergency: $isUrgentEmergency }, context: $context) { + id + context + ...ClaimFlowStepFragment + } +} diff --git a/app/app/build.gradle.kts b/app/app/build.gradle.kts index c3d889cbf7..22a0d04034 100644 --- a/app/app/build.gradle.kts +++ b/app/app/build.gradle.kts @@ -95,7 +95,7 @@ android { signingConfigs { named("debug") { - storeFile = file("../../debug.keystore").also { println("Stelios file : ${it.absolutePath}") } + storeFile = file("../../debug.keystore") } } 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 469cc12536..54b73cf9fc 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 @@ -131,6 +131,7 @@ internal fun HedvigNavHost( navigator = navigator, shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale, activityNavigator = activityNavigator, + imageLoader = imageLoader, ) }, navigator = navigator, @@ -238,6 +239,7 @@ private fun NavGraphBuilder.nestedHomeGraphs( navigator: Navigator, shouldShowRequestPermissionRationale: (String) -> Boolean, activityNavigator: ActivityNavigator, + imageLoader: ImageLoader, ) { changeAddressGraph( navController = hedvigAppState.navController, @@ -281,6 +283,13 @@ private fun NavGraphBuilder.nestedHomeGraphs( }, ) }, + openUrl = { activityNavigator.openWebsite(context, Uri.parse(it)) }, + openChat = { backStackEntry -> + with(navigator) { + backStackEntry.navigate(AppDestination.Chat) + } + }, + imageLoader = imageLoader, ) terminalClaimFlowStepDestinations( navigator = navigator, diff --git a/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/HedvigChip.kt b/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/HedvigChip.kt new file mode 100644 index 0000000000..19da691e52 --- /dev/null +++ b/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/HedvigChip.kt @@ -0,0 +1,119 @@ +package com.hedvig.android.core.ui + +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.PressInteraction +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.compositeOver +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.hedvig.android.core.designsystem.material3.motion.MotionTokens +import com.hedvig.android.core.designsystem.material3.onTypeContainer +import com.hedvig.android.core.designsystem.material3.squircleMedium +import com.hedvig.android.core.designsystem.material3.typeContainer +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.filterIsInstance + +@Composable +fun <T> HedvigChip( + item: T, + itemDisplayName: (T) -> String, + isSelected: Boolean, + onItemClick: (T) -> Unit, + modifier: Modifier = Modifier, + showChipAnimatable: Animatable<Float, AnimationVector1D>, +) { + Box( + // TODO replace with space on the flow row itself https://kotlinlang.slack.com/archives/CJLTWPH7S/p1687442185827989?thread_ts=1679515354.462029&cid=CJLTWPH7S + modifier = modifier + .padding(bottom = 8.dp) + .graphicsLayer { + scaleX = showChipAnimatable.value + scaleY = showChipAnimatable.value + }, + contentAlignment = Alignment.Center, + ) { + val surfaceColor by animateColorAsState( + if (isSelected) { + MaterialTheme.colorScheme.typeContainer.compositeOver(MaterialTheme.colorScheme.background) + } else { + MaterialTheme.colorScheme.surface + }, + ) + val contentColor by animateColorAsState( + if (isSelected) { + MaterialTheme.colorScheme.onTypeContainer.compositeOver(surfaceColor) + } else { + MaterialTheme.colorScheme.onSurface + }, + ) + val backgroundScale = remember { Animatable(1f) } + val interactionSource = remember { MutableInteractionSource() } + LaunchedEffect(interactionSource) { + interactionSource + .interactions + .filterIsInstance<PressInteraction.Release>() + .collectLatest { + backgroundScale.animateTo( + targetValue = 1.05f, + animationSpec = tween( + durationMillis = MotionTokens.DurationShort3.toInt(), + easing = MotionTokens.EasingStandardCubicBezier, + ), + ) + backgroundScale.animateTo( + targetValue = 1f, + animationSpec = tween( + durationMillis = MotionTokens.DurationShort3.toInt(), + easing = MotionTokens.EasingStandardCubicBezier, + ), + ) + } + } + Box( + modifier = Modifier + .matchParentSize() + .graphicsLayer { + scaleX = backgroundScale.value + scaleY = backgroundScale.value + } + .clip(MaterialTheme.shapes.squircleMedium) + .background(surfaceColor, MaterialTheme.shapes.squircleMedium) + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = { onItemClick(item) }, + ), + ) + CompositionLocalProvider(LocalContentColor provides contentColor) { + Text( + text = itemDisplayName(item), + style = MaterialTheme.typography.bodyLarge.copy( + fontSize = 18.sp, + ), + maxLines = 1, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + ) + } + } +} diff --git a/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/infocard/WarningCard.kt b/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/infocard/WarningCard.kt new file mode 100644 index 0000000000..733643cac7 --- /dev/null +++ b/app/core/core-ui/src/main/kotlin/com/hedvig/android/core/ui/infocard/WarningCard.kt @@ -0,0 +1,106 @@ +package com.hedvig.android.core.ui.infocard + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material3.CardColors +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.dp +import com.hedvig.android.core.designsystem.component.card.HedvigInfoCard +import com.hedvig.android.core.designsystem.material3.onWarningContainer +import com.hedvig.android.core.designsystem.material3.warningContainer +import com.hedvig.android.core.designsystem.material3.warningElement +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.WarningFilled + +@Composable +fun VectorWarningCard( + text: String, + modifier: Modifier = Modifier, + icon: ImageVector = Icons.Hedvig.WarningFilled, + iconColor: Color = MaterialTheme.colorScheme.warningElement, + colors: CardColors = CardDefaults.outlinedCardColors( + containerColor = MaterialTheme.colorScheme.warningContainer, + contentColor = MaterialTheme.colorScheme.onWarningContainer, + ), +) { + VectorWarningCard( + text = text, + modifier = modifier, + icon = icon, + iconColor = iconColor, + colors = colors, + underTextContent = null, + ) +} + +@Composable +fun VectorWarningCard( + text: String, + modifier: Modifier = Modifier, + icon: ImageVector = Icons.Hedvig.WarningFilled, + iconColor: Color = MaterialTheme.colorScheme.warningElement, + colors: CardColors = CardDefaults.outlinedCardColors( + containerColor = MaterialTheme.colorScheme.warningContainer, + contentColor = MaterialTheme.colorScheme.onWarningContainer, + ), + underTextContent: @Composable (ColumnScope.() -> Unit)?, +) { + HedvigInfoCard( + modifier = modifier, + contentPadding = PaddingValues( + start = 12.dp, + top = 12.dp, + end = 16.dp, + bottom = 12.dp, + ), + colors = colors, + ) { + Icon( + imageVector = icon, + contentDescription = "info", + modifier = Modifier + .padding(top = 2.dp) + .size(16.dp), + tint = iconColor, + ) + Spacer(Modifier.width(8.dp)) + Column { + Text( + text = text, + style = MaterialTheme.typography.bodyMedium, + ) + if (underTextContent != null) { + Spacer(Modifier.height(12.dp)) + underTextContent() + Spacer(Modifier.height(4.dp)) + } + } + } +} + +@HedvigPreview +@Composable +private fun PreviewVectorInfoCard() { + HedvigTheme { + Surface(color = MaterialTheme.colorScheme.background) { + VectorInfoCard("Lorem ipsum") + } + } +} diff --git a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowDestination.kt b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowDestination.kt index 6f911500ee..a114018073 100644 --- a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowDestination.kt +++ b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowDestination.kt @@ -69,6 +69,28 @@ sealed interface ClaimFlowDestination : Destination { val selectedItemProblems: List<String>?, ) : ClaimFlowDestination + @Serializable + data class DeflectGlassDamage( + val partners: List<DeflectPartner>, + ) : ClaimFlowDestination + + @Serializable + data class ConfirmEmergency( + val text: String, + val confirmEmergency: Boolean?, + val options: List<EmergencyOption>, + ) : ClaimFlowDestination + + @Serializable + data class DeflectEmergency( + val partners: List<DeflectPartner>, + ) : ClaimFlowDestination + + @Serializable + data class DeflectPests( + val partners: List<DeflectPartner>, + ) : ClaimFlowDestination + @Serializable data class Summary( val claimTypeTitle: String, @@ -213,3 +235,14 @@ data class AudioContent( */ val audioUrl: AudioUrl, ) + +@Serializable +data class DeflectPartner( + val id: String, + val imageUrl: String, + val phoneNumber: String?, + val url: String?, +) + +@Serializable +data class EmergencyOption(val displayName: String, val value: Boolean) diff --git a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowRepository.kt b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowRepository.kt index 173a8a5b63..a9efa6f92b 100644 --- a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowRepository.kt +++ b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowRepository.kt @@ -18,6 +18,7 @@ import com.hedvig.android.logger.LogPriority import com.hedvig.android.logger.logcat import kotlinx.datetime.LocalDate import octopus.FlowClaimAudioRecordingNextMutation +import octopus.FlowClaimConfirmEmergencyMutation import octopus.FlowClaimContractNextMutation import octopus.FlowClaimDateOfOccurrenceNextMutation import octopus.FlowClaimDateOfOccurrencePlusLocationNextMutation @@ -77,6 +78,8 @@ interface ClaimFlowRepository { purchaseDate: LocalDate?, purchasePrice: Double?, ): Either<ErrorMessage, ClaimFlowStep> + + suspend fun submitUrgentEmergency(isUrgentEmergency: Boolean): Either<ErrorMessage, ClaimFlowStep> } internal class ClaimFlowRepositoryImpl( @@ -244,7 +247,6 @@ internal class ClaimFlowRepositoryImpl( .bind() .flowClaimSingleItemCheckoutNext claimFlowContextStorage.saveContext(result.context) - Unit } } @@ -283,6 +285,22 @@ internal class ClaimFlowRepositoryImpl( } } + override suspend fun submitUrgentEmergency(isUrgentEmergency: Boolean): Either<ErrorMessage, ClaimFlowStep> { + return either { + val result = apolloClient + .mutation( + FlowClaimConfirmEmergencyMutation(isUrgentEmergency = isUrgentEmergency, claimFlowContextStorage.getContext()), + ) + .safeExecute() + .toEither(::ErrorMessage) + .bind() + .flowClaimConfirmEmergencyNext + + claimFlowContextStorage.saveContext(result.context) + result.currentStep.toClaimFlowStep(FlowId(result.id)) + } + } + private suspend fun Raise<ErrorMessage>.uploadAudioFile(flowId: String, file: File): AudioUrl { val result = odysseyService .uploadAudioRecordingFile( diff --git a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStep.kt b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStep.kt index 4b2c2ecd01..124a27215f 100644 --- a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStep.kt +++ b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStep.kt @@ -6,6 +6,7 @@ import octopus.fragment.AudioContentFragment import octopus.fragment.CheckoutMethodFragment import octopus.fragment.ClaimFlowStepFragment import octopus.fragment.FlowClaimContractSelectStepFragment +import octopus.fragment.FlowClaimDeflectPartnerFragment import octopus.fragment.FlowClaimLocationStepFragment import octopus.fragment.FlowClaimSingleItemStepFragment import octopus.fragment.MoneyFragment @@ -93,6 +94,28 @@ sealed interface ClaimFlowStep { val selectedItemProblems: List<String>?, ) : ClaimFlowStep + data class ClaimDeflectGlassDamageStep( + override val flowId: FlowId, + val partners: List<FlowClaimDeflectPartnerFragment>, + ) : ClaimFlowStep + + data class ClaimConfirmEmergencyStep( + override val flowId: FlowId, + val text: String, + val confirmEmergency: Boolean?, + val options: List<ClaimFlowStepFragment.FlowClaimConfirmEmergencyStepCurrentStep.Option>, + ) : ClaimFlowStep + + data class ClaimDeflectEmergencyStep( + override val flowId: FlowId, + val partners: List<FlowClaimDeflectPartnerFragment>, + ) : ClaimFlowStep + + data class ClaimDeflectPestsStep( + override val flowId: FlowId, + val partners: List<FlowClaimDeflectPartnerFragment>, + ) : ClaimFlowStep + data class ClaimFailedStep(override val flowId: FlowId) : ClaimFlowStep data class ClaimSuccessStep(override val flowId: FlowId) : ClaimFlowStep @@ -175,6 +198,24 @@ internal fun ClaimFlowStepFragment.CurrentStep.toClaimFlowStep(flowId: FlowId): flowId, options, ) + is ClaimFlowStepFragment.FlowClaimDeflectGlassDamageStepCurrentStep -> ClaimFlowStep.ClaimDeflectGlassDamageStep( + flowId, + partners, + ) + is ClaimFlowStepFragment.FlowClaimConfirmEmergencyStepCurrentStep -> ClaimFlowStep.ClaimConfirmEmergencyStep( + flowId, + text, + confirmEmergency, + options, + ) + is ClaimFlowStepFragment.FlowClaimDeflectEmergencyStepCurrentStep -> ClaimFlowStep.ClaimDeflectEmergencyStep( + flowId, + partners, + ) + is ClaimFlowStepFragment.FlowClaimDeflectPestsStepCurrentStep -> ClaimFlowStep.ClaimDeflectPestsStep( + flowId, + partners, + ) else -> ClaimFlowStep.UnknownStep(flowId) } } diff --git a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStepExt.kt b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStepExt.kt index 211442c020..ae1eea4a3e 100644 --- a/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStepExt.kt +++ b/app/data/data-claim-flow/src/main/kotlin/com/hedvig/android/data/claimflow/ClaimFlowStepExt.kt @@ -6,7 +6,9 @@ import com.hedvig.android.data.claimflow.model.AudioUrl import octopus.fragment.AudioContentFragment import octopus.fragment.AutomaticAutogiroPayoutFragment import octopus.fragment.CheckoutMethodFragment +import octopus.fragment.ClaimFlowStepFragment import octopus.fragment.FlowClaimContractSelectStepFragment +import octopus.fragment.FlowClaimDeflectPartnerFragment import octopus.fragment.FlowClaimLocationStepFragment import octopus.fragment.FlowClaimSingleItemStepFragment @@ -15,15 +17,18 @@ fun ClaimFlowStep.toClaimFlowDestination(): ClaimFlowDestination { is ClaimFlowStep.ClaimAudioRecordingStep -> { ClaimFlowDestination.AudioRecording(flowId, questions, audioContent?.toAudioContent()) } + is ClaimFlowStep.ClaimDateOfOccurrenceStep -> { ClaimFlowDestination.DateOfOccurrence(dateOfOccurrence, maxDate) } + is ClaimFlowStep.ClaimLocationStep -> { ClaimFlowDestination.Location( selectedLocation = location, locationOptions = options.map { it.toLocationOption() }, ) } + is ClaimFlowStep.ClaimDateOfOccurrencePlusLocationStep -> { ClaimFlowDestination.DateOfOccurrencePlusLocation( dateOfOccurrence = dateOfOccurrence, @@ -32,6 +37,7 @@ fun ClaimFlowStep.toClaimFlowDestination(): ClaimFlowDestination { locationOptions = options.map { it.toLocationOption() }, ) } + is ClaimFlowStep.ClaimPhoneNumberStep -> ClaimFlowDestination.PhoneNumber(phoneNumber) is ClaimFlowStep.ClaimSingleItemStep -> { ClaimFlowDestination.SingleItem( @@ -46,6 +52,7 @@ fun ClaimFlowStep.toClaimFlowDestination(): ClaimFlowDestination { selectedItemProblems = selectedItemProblems, ) } + is ClaimFlowStep.ClaimSummaryStep -> { ClaimFlowDestination.Summary( claimTypeTitle = claimTypeTitle, @@ -64,6 +71,7 @@ fun ClaimFlowStep.toClaimFlowDestination(): ClaimFlowDestination { selectedItemProblems = selectedItemProblems, ) } + is ClaimFlowStep.ClaimResolutionSingleItemStep -> { ClaimFlowDestination.SingleItemCheckout( UiMoney.fromMoneyFragment(price), @@ -73,12 +81,31 @@ fun ClaimFlowStep.toClaimFlowDestination(): ClaimFlowDestination { availableCheckoutMethods.map(CheckoutMethodFragment::toCheckoutMethod).filterIsInstance<CheckoutMethod.Known>(), ) } + is ClaimFlowStep.ClaimSuccessStep -> ClaimFlowDestination.ClaimSuccess is ClaimFlowStep.ClaimFailedStep -> ClaimFlowDestination.Failure is ClaimFlowStep.UnknownStep -> ClaimFlowDestination.UpdateApp is ClaimFlowStep.ClaimSelectContractStep -> ClaimFlowDestination.SelectContract( options = options.map { it.toLocalOptions() }, ) + + is ClaimFlowStep.ClaimDeflectGlassDamageStep -> ClaimFlowDestination.DeflectGlassDamage( + partners.map { it.toLocalPartner() }, + ) + + is ClaimFlowStep.ClaimConfirmEmergencyStep -> ClaimFlowDestination.ConfirmEmergency( + text, + confirmEmergency, + options.map { it.toLocalOption() }, + ) + + is ClaimFlowStep.ClaimDeflectEmergencyStep -> ClaimFlowDestination.DeflectEmergency( + partners.map { it.toLocalPartner() }, + ) + + is ClaimFlowStep.ClaimDeflectPestsStep -> ClaimFlowDestination.DeflectPests( + partners.map { it.toLocalPartner() }, + ) } } @@ -107,6 +134,7 @@ private fun CheckoutMethodFragment.toCheckoutMethod(): CheckoutMethod { is AutomaticAutogiroPayoutFragment -> { CheckoutMethod.Known.AutomaticAutogiro(id, displayName, UiMoney.fromMoneyFragment(amount)) } + else -> CheckoutMethod.Unknown } } @@ -114,3 +142,19 @@ private fun CheckoutMethodFragment.toCheckoutMethod(): CheckoutMethod { private fun AudioContentFragment.toAudioContent(): AudioContent { return AudioContent(AudioUrl(signedUrl), AudioUrl(audioUrl)) } + +private fun FlowClaimDeflectPartnerFragment.toLocalPartner(): DeflectPartner { + return DeflectPartner( + id = id, + imageUrl = imageUrl, + phoneNumber = phoneNumber, + url = url, + ) +} + +private fun ClaimFlowStepFragment.FlowClaimConfirmEmergencyStepCurrentStep.Option.toLocalOption(): EmergencyOption { + return EmergencyOption( + displayName = displayName, + value = displayValue, + ) +} diff --git a/app/feature/feature-chat/src/main/kotlin/com/hedvig/android/feature/chat/ui/ChatFragment.kt b/app/feature/feature-chat/src/main/kotlin/com/hedvig/android/feature/chat/ui/ChatFragment.kt index 7e650dfafd..3a984eca5c 100644 --- a/app/feature/feature-chat/src/main/kotlin/com/hedvig/android/feature/chat/ui/ChatFragment.kt +++ b/app/feature/feature-chat/src/main/kotlin/com/hedvig/android/feature/chat/ui/ChatFragment.kt @@ -143,7 +143,7 @@ class ChatFragment : Fragment(R.layout.fragment_chat) { setNegativeButton( resources.getString(android.R.string.cancel), ) { _, _ -> - requireActivity().onBackPressedDispatcher.onBackPressed() + this@ChatFragment.activity?.onBackPressedDispatcher?.onBackPressed() } setMessage(hedvig.resources.R.string.NETWORK_ERROR_ALERT_MESSAGE) setCancelable(false) diff --git a/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/OptionChipsFlowRow.kt b/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/OptionChipsFlowRow.kt index 26e1749bc6..deb163c12c 100644 --- a/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/OptionChipsFlowRow.kt +++ b/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/OptionChipsFlowRow.kt @@ -1,14 +1,8 @@ package com.hedvig.android.feature.claimtriaging -import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring -import androidx.compose.animation.core.tween -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.interaction.PressInteraction import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ExperimentalLayoutApi @@ -16,30 +10,20 @@ import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.padding 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.runtime.key import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.compositeOver -import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.dp import arrow.core.identity -import com.hedvig.android.core.designsystem.material3.motion.MotionTokens -import com.hedvig.android.core.designsystem.material3.onTypeContainer -import com.hedvig.android.core.designsystem.material3.squircleMedium -import com.hedvig.android.core.designsystem.material3.typeContainer import com.hedvig.android.core.designsystem.preview.HedvigPreview import com.hedvig.android.core.designsystem.theme.HedvigTheme +import com.hedvig.android.core.ui.HedvigChip import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.filterIsInstance import kotlin.random.Random import kotlin.time.Duration.Companion.seconds @@ -72,73 +56,13 @@ internal fun <T> OptionChipsFlowRow( ), ) } - Box( - // TODO replace with space on the flow row itself https://kotlinlang.slack.com/archives/CJLTWPH7S/p1687442185827989?thread_ts=1679515354.462029&cid=CJLTWPH7S - modifier = Modifier.padding(bottom = 8.dp) - .graphicsLayer { - scaleX = showChipAnimatable.value - scaleY = showChipAnimatable.value - }, - ) { - val surfaceColor by animateColorAsState( - if (selectedItem == item) { - MaterialTheme.colorScheme.typeContainer.compositeOver(MaterialTheme.colorScheme.background) - } else { - MaterialTheme.colorScheme.surface - }, - ) - val contentColor by animateColorAsState( - if (selectedItem == item) { - MaterialTheme.colorScheme.onTypeContainer.compositeOver(surfaceColor) - } else { - MaterialTheme.colorScheme.onSurface - }, - ) - val backgroundScale = remember { Animatable(1f) } - val interactionSource = remember { MutableInteractionSource() } - LaunchedEffect(interactionSource) { - interactionSource - .interactions - .filterIsInstance<PressInteraction.Release>() - .collectLatest { - backgroundScale.animateTo( - targetValue = 1.05f, - animationSpec = tween( - durationMillis = MotionTokens.DurationShort3.toInt(), - easing = MotionTokens.EasingStandardCubicBezier, - ), - ) - backgroundScale.animateTo( - targetValue = 1f, - animationSpec = tween( - durationMillis = MotionTokens.DurationShort3.toInt(), - easing = MotionTokens.EasingStandardCubicBezier, - ), - ) - } - } - Box( - modifier = Modifier - .matchParentSize() - .graphicsLayer { - scaleX = backgroundScale.value - scaleY = backgroundScale.value - } - .clip(MaterialTheme.shapes.squircleMedium) - .background(surfaceColor, MaterialTheme.shapes.squircleMedium) - .clickable( - interactionSource = interactionSource, - indication = null, - onClick = { onItemClick(item) }, - ), - ) - Text( - text = itemDisplayName(item), - style = MaterialTheme.typography.bodyLarge.copy(color = contentColor), - maxLines = 1, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), - ) - } + HedvigChip( + item = item, + showChipAnimatable = showChipAnimatable, + itemDisplayName = itemDisplayName, + isSelected = item == selectedItem, + onItemClick = onItemClick, + ) } } } diff --git a/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/claimentrypoints/ClaimEntryPointsDestination.kt b/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/claimentrypoints/ClaimEntryPointsDestination.kt index 79ed8221a0..064f105290 100644 --- a/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/claimentrypoints/ClaimEntryPointsDestination.kt +++ b/app/feature/feature-claim-triaging/src/main/kotlin/com/hedvig/android/feature/claimtriaging/claimentrypoints/ClaimEntryPointsDestination.kt @@ -135,7 +135,7 @@ private fun ClaimEntryPointsScreen( itemDisplayName = EntryPoint::displayName, selectedItem = uiState.selectedEntryPoint, onItemClick = { entryPoint -> onSelectEntryPoint(entryPoint) }, - modifier = Modifier.padding(horizontal = 16.dp), + modifier = Modifier.padding(horizontal = 16.dp).fillMaxWidth(), ) Spacer(Modifier.height(8.dp)) HedvigContainedButton( diff --git a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt index f9d8624ecd..300a0b2dd0 100644 --- a/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt +++ b/app/feature/feature-insurances/src/main/kotlin/com/hedvig/android/feature/insurances/insurancedetail/yourinfo/YourInfoTab.kt @@ -127,7 +127,7 @@ internal fun YourInfoTab( ) { UpcomingChangesBottomSheetContent( infoText = stringResource( - id = R.string.insurances_tab_your_insurance_will_be_updated, + id = R.string.insurances_tab_your_insurance_will_be_updated_with_info, upcomingChangesAgreement.activeFrom, ), sections = upcomingChangesAgreement.displayItems diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/di/OdysseyModule.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/di/OdysseyModule.kt index d9f93c560c..53a43580b2 100644 --- a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/di/OdysseyModule.kt +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/di/OdysseyModule.kt @@ -8,6 +8,7 @@ import com.hedvig.android.data.claimflow.model.FlowId import com.hedvig.android.feature.odyssey.step.audiorecording.AudioRecordingViewModel import com.hedvig.android.feature.odyssey.step.dateofoccurrence.DateOfOccurrenceViewModel import com.hedvig.android.feature.odyssey.step.dateofoccurrencepluslocation.DateOfOccurrencePlusLocationViewModel +import com.hedvig.android.feature.odyssey.step.informdeflect.ConfirmEmergencyViewModel import com.hedvig.android.feature.odyssey.step.location.LocationViewModel import com.hedvig.android.feature.odyssey.step.phonenumber.PhoneNumberViewModel import com.hedvig.android.feature.odyssey.step.selectcontract.SelectContractViewModel @@ -61,4 +62,7 @@ val odysseyModule = module { viewModel<SelectContractViewModel> { (selectContract: ClaimFlowDestination.SelectContract) -> SelectContractViewModel(selectContract, get<ClaimFlowRepository>()) } + viewModel<ConfirmEmergencyViewModel> { (confirmEmergency: ClaimFlowDestination.ConfirmEmergency) -> + ConfirmEmergencyViewModel(confirmEmergency, get<ClaimFlowRepository>()) + } } diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/navigation/ClaimFlowGraph.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/navigation/ClaimFlowGraph.kt index 86b76c3802..1c25ccc0a9 100644 --- a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/navigation/ClaimFlowGraph.kt +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/navigation/ClaimFlowGraph.kt @@ -4,6 +4,7 @@ import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.navigation.NavBackStackEntry import androidx.navigation.NavGraphBuilder import androidx.navigation.navOptions +import coil.ImageLoader import com.hedvig.android.core.designsystem.material3.motion.MotionDefaults import com.hedvig.android.data.claimflow.ClaimFlowDestination import com.hedvig.android.data.claimflow.ClaimFlowStep @@ -15,6 +16,11 @@ import com.hedvig.android.feature.odyssey.step.dateofoccurrence.DateOfOccurrence import com.hedvig.android.feature.odyssey.step.dateofoccurrencepluslocation.DateOfOccurrencePlusLocationDestination import com.hedvig.android.feature.odyssey.step.dateofoccurrencepluslocation.DateOfOccurrencePlusLocationViewModel import com.hedvig.android.feature.odyssey.step.honestypledge.HonestyPledgeDestination +import com.hedvig.android.feature.odyssey.step.informdeflect.ConfirmEmergencyDestination +import com.hedvig.android.feature.odyssey.step.informdeflect.ConfirmEmergencyViewModel +import com.hedvig.android.feature.odyssey.step.informdeflect.DeflectEmergencyDestination +import com.hedvig.android.feature.odyssey.step.informdeflect.DeflectGlassDamageDestination +import com.hedvig.android.feature.odyssey.step.informdeflect.DeflectPestsDestination import com.hedvig.android.feature.odyssey.step.location.LocationDestination import com.hedvig.android.feature.odyssey.step.location.LocationViewModel import com.hedvig.android.feature.odyssey.step.notificationpermission.NotificationPermissionDestination @@ -49,6 +55,9 @@ fun NavGraphBuilder.claimFlowGraph( navigateToTriaging: (NavBackStackEntry?) -> Unit, openAppSettings: () -> Unit, closeClaimFlow: () -> Unit, + openChat: (NavBackStackEntry) -> Unit, + openUrl: (String) -> Unit, + imageLoader: ImageLoader, nestedGraphs: NavGraphBuilder.() -> Unit, ) { navigation<AppDestination.ClaimsFlow>( @@ -216,6 +225,57 @@ fun NavGraphBuilder.claimFlowGraph( closeClaimFlow = closeClaimFlow, ) } + composable<ClaimFlowDestination.ConfirmEmergency> { backStackEntry -> + val viewModel: ConfirmEmergencyViewModel = koinViewModel { parametersOf(this) } + ConfirmEmergencyDestination( + viewModel = viewModel, + navigateToNextStep = { claimFlowStep -> + viewModel.handledNextStepNavigation() + navigator.navigateToClaimFlowDestination(backStackEntry, claimFlowStep.toClaimFlowDestination()) + }, + windowSizeClass = windowSizeClass, + navigateUp = navigator::navigateUp, + closeClaimFlow = closeClaimFlow, + ) + } + composable<ClaimFlowDestination.DeflectGlassDamage> { navBackStackEntry -> + DeflectGlassDamageDestination( + parameter = this, + openChat = { + openChat(navBackStackEntry) + }, + windowSizeClass = windowSizeClass, + navigateUp = navigator::navigateUp, + openUrl = openUrl, + closeClaimFlow = closeClaimFlow, + imageLoader = imageLoader, + ) + } + composable<ClaimFlowDestination.DeflectEmergency> { navBackStackEntry -> + DeflectEmergencyDestination( + parameter = this, + openChat = { + openChat(navBackStackEntry) + }, + navigateUp = navigator::navigateUp, + windowSizeClass = windowSizeClass, + closeClaimFlow = closeClaimFlow, + imageLoader = imageLoader, + ) + } + composable<ClaimFlowDestination.DeflectPests> { navBackStackEntry -> + DeflectPestsDestination( + parameter = this, + openChat = { + openChat(navBackStackEntry) + }, + navigateUp = navigator::navigateUp, + openUrl = openUrl, + windowSizeClass = windowSizeClass, + closeClaimFlow = closeClaimFlow, + imageLoader = imageLoader, + ) + } } } @@ -266,15 +326,17 @@ fun <T : ClaimFlowDestination> Navigator.navigateToClaimFlowDestination( destination: T, ) { val navOptions = navOptions { - when { - destination is ClaimFlowDestination.ClaimSuccess || - destination is ClaimFlowDestination.UpdateApp || - destination is ClaimFlowDestination.Failure || - destination is ClaimFlowDestination.SingleItemPayout -> { + when (destination) { + is ClaimFlowDestination.ClaimSuccess, + is ClaimFlowDestination.UpdateApp, + is ClaimFlowDestination.Failure, + is ClaimFlowDestination.SingleItemPayout, + -> { popUpTo<AppDestination.ClaimsFlow> { inclusive = true } } + else -> {} } } diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/ConfirmEmergencyDestination.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/ConfirmEmergencyDestination.kt new file mode 100644 index 0000000000..8433c69d54 --- /dev/null +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/ConfirmEmergencyDestination.kt @@ -0,0 +1,191 @@ +package com.hedvig.android.feature.odyssey.step.informdeflect + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton +import com.hedvig.android.core.designsystem.preview.HedvigPreview +import com.hedvig.android.core.designsystem.theme.HedvigTheme +import com.hedvig.android.core.ui.HedvigChip +import com.hedvig.android.core.ui.preview.calculateForPreview +import com.hedvig.android.core.ui.text.WarningTextWithIcon +import com.hedvig.android.data.claimflow.ClaimFlowStep +import com.hedvig.android.data.claimflow.EmergencyOption +import com.hedvig.android.feature.odyssey.ui.ClaimFlowScaffold +import hedvig.resources.R +import kotlinx.coroutines.delay +import kotlin.random.Random +import kotlin.time.Duration.Companion.seconds + +@Composable +internal fun ConfirmEmergencyDestination( + viewModel: ConfirmEmergencyViewModel, + navigateToNextStep: (ClaimFlowStep) -> Unit, + windowSizeClass: WindowSizeClass, + navigateUp: () -> Unit, + closeClaimFlow: () -> Unit, +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val nextStep = uiState.nextStep + LaunchedEffect(nextStep) { + if (nextStep != null) { + navigateToNextStep(nextStep) + } + } + ConfirmEmergencyScreen( + uiState = uiState, + windowSizeClass = windowSizeClass, + onSubmit = viewModel::submitIsUrgentEmergency, + navigateUp = navigateUp, + onSelectOption = viewModel::selectOption, + closeClaimFlow = closeClaimFlow, + ) +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun ConfirmEmergencyScreen( + uiState: ConfirmEmergencyUiState, + windowSizeClass: WindowSizeClass, + navigateUp: () -> Unit, + onSelectOption: (EmergencyOption) -> Unit, + closeClaimFlow: () -> Unit, + onSubmit: () -> Unit, +) { + ClaimFlowScaffold( + windowSizeClass = windowSizeClass, + navigateUp = navigateUp, + closeClaimFlow = closeClaimFlow, + ) { sideSpacingModifier -> + Spacer(Modifier.height(16.dp)) + Text( + text = uiState.title, + style = MaterialTheme.typography.headlineMedium, + modifier = sideSpacingModifier.fillMaxWidth(), + ) + Spacer(Modifier.height(32.dp)) + Spacer(Modifier.weight(1f)) + AnimatedVisibility( + visible = uiState.haveTriedContinuingWithoutSelection, + enter = fadeIn(), + exit = fadeOut(), + ) { + Column { + WarningTextWithIcon( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth() + .wrapContentWidth(), + text = stringResource(R.string.CLAIMS_SELECT_CATEGORY), + ) + Spacer(Modifier.height(16.dp)) + } + } + FlowRow( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), + maxItemsInEachRow = 2, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) { + for (item in uiState.options) { + key(item) { + val isPreview = LocalInspectionMode.current + val showChipAnimatable = remember { + Animatable(if (isPreview) 1.0f else 0.0f) + } + LaunchedEffect(Unit) { + delay(Random.nextDouble(0.3, 0.6).seconds) + showChipAnimatable.animateTo( + 1.0f, + animationSpec = spring( + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessLow, + ), + ) + } + HedvigChip( + item = item, + itemDisplayName = EmergencyOption::displayName, + isSelected = item == uiState.selectedOption, + onItemClick = onSelectOption, + showChipAnimatable = showChipAnimatable, + modifier = Modifier.weight(1f), + ) + } + } + } + Spacer(Modifier.height(8.dp)) + HedvigContainedButton( + text = stringResource(id = R.string.general_continue_button), + isLoading = uiState.isLoading, + onClick = onSubmit, + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Spacer(Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom))) + } +} + +@Composable +@HedvigPreview +private fun ConfirmEmergencyScreenPreview() { + HedvigTheme { + Surface { + ConfirmEmergencyScreen( + uiState = ConfirmEmergencyUiState( + "Är du på en resa och behöver akut vård eller assistans?", + options = listOf( + EmergencyOption( + displayName = "Yes", + value = false, + ), + EmergencyOption( + displayName = "No", + value = true, + ), + ), + selectedOption = null, + isLoading = false, + ), + windowSizeClass = WindowSizeClass.calculateForPreview(), + navigateUp = {}, + closeClaimFlow = {}, + onSubmit = {}, + onSelectOption = {}, + ) + } + } +} diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/ConfirmEmergencyViewModel.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/ConfirmEmergencyViewModel.kt new file mode 100644 index 0000000000..b9440af90b --- /dev/null +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/ConfirmEmergencyViewModel.kt @@ -0,0 +1,85 @@ +package com.hedvig.android.feature.odyssey.step.informdeflect + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hedvig.android.data.claimflow.ClaimFlowDestination +import com.hedvig.android.data.claimflow.ClaimFlowRepository +import com.hedvig.android.data.claimflow.ClaimFlowStep +import com.hedvig.android.data.claimflow.EmergencyOption +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +internal class ConfirmEmergencyViewModel( + confirmEmergency: ClaimFlowDestination.ConfirmEmergency, + private val claimFlowRepository: ClaimFlowRepository, +) : ViewModel() { + + private val _uiState = MutableStateFlow( + ConfirmEmergencyUiState( + title = confirmEmergency.text, + options = confirmEmergency.options, + selectedOption = null, + isLoading = false, + error = false, + nextStep = null, + ), + ) + val uiState: StateFlow<ConfirmEmergencyUiState> = _uiState.asStateFlow() + + fun submitIsUrgentEmergency() { + val selectedOption = uiState.value.selectedOption + if (selectedOption == null) { + _uiState.update { it.copy(haveTriedContinuingWithoutSelection = true) } + } else { + viewModelScope.launch { + _uiState.update { it.copy(isLoading = false) } + claimFlowRepository.submitUrgentEmergency(selectedOption.value).fold( + ifLeft = { + _uiState.update { + it.copy( + error = true, + isLoading = false, + ) + } + }, + ifRight = { nextStep -> + _uiState.update { + it.copy( + nextStep = nextStep, + isLoading = false, + ) + } + }, + ) + } + } + } + + fun selectOption(emergencyOption: EmergencyOption) { + _uiState.update { + it.copy( + selectedOption = emergencyOption, + haveTriedContinuingWithoutSelection = false, + ) + } + } + + fun handledNextStepNavigation() { + _uiState.update { it.copy(nextStep = null) } + } +} + +internal data class ConfirmEmergencyUiState( + val title: String, + val options: List<EmergencyOption>, + val selectedOption: EmergencyOption?, + val haveTriedContinuingWithoutSelection: Boolean = false, + val isLoading: Boolean = false, + val error: Boolean = false, + val nextStep: ClaimFlowStep? = null, +) { + val canSubmit: Boolean = !isLoading && !error && nextStep == null +} diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectEmergencyDestination.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectEmergencyDestination.kt new file mode 100644 index 0000000000..0fe535526a --- /dev/null +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectEmergencyDestination.kt @@ -0,0 +1,196 @@ +package com.hedvig.android.feature.odyssey.step.informdeflect + +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +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.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.content.ContextCompat.startActivity +import coil.ImageLoader +import coil.compose.AsyncImage +import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton +import com.hedvig.android.core.designsystem.component.button.HedvigContainedSmallButton +import com.hedvig.android.core.designsystem.component.card.HedvigCard +import com.hedvig.android.core.designsystem.preview.HedvigPreview +import com.hedvig.android.core.ui.infocard.VectorWarningCard +import com.hedvig.android.core.ui.preview.calculateForPreview +import com.hedvig.android.core.ui.preview.rememberPreviewImageLoader +import com.hedvig.android.data.claimflow.ClaimFlowDestination +import com.hedvig.android.data.claimflow.DeflectPartner +import com.hedvig.android.feature.odyssey.ui.ClaimFlowScaffold +import com.hedvig.android.logger.LogPriority +import com.hedvig.android.logger.logcat +import hedvig.resources.R + +@Composable +internal fun DeflectEmergencyDestination( + parameter: ClaimFlowDestination.DeflectEmergency, + openChat: () -> Unit, + closeClaimFlow: () -> Unit, + windowSizeClass: WindowSizeClass, + navigateUp: () -> Unit, + imageLoader: ImageLoader, +) { + val context = LocalContext.current + ClaimFlowScaffold( + windowSizeClass = windowSizeClass, + navigateUp = navigateUp, + closeClaimFlow = closeClaimFlow, + ) { + Spacer(modifier = Modifier.height(8.dp)) + VectorWarningCard( + text = stringResource(id = R.string.SUBMIT_CLAIM_EMERGENCY_INFO_LABEL), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(8.dp)) + parameter.partners.forEach { partner -> + HedvigCard( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.primary), + ) { + Column { + Spacer(modifier = Modifier.height(24.dp)) + AsyncImage( + model = partner.imageUrl, + contentDescription = "Partner image", + imageLoader = imageLoader, + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + .height(80.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_EMERGENCY_GLOBAL_ASSISTANCE_TITLE), + color = MaterialTheme.colorScheme.onPrimary, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_EMERGENCY_GLOBAL_ASSISTANCE_LABEL), + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp), + ) + Spacer(modifier = Modifier.height(24.dp)) + partner.phoneNumber?.let { + HedvigContainedButton( + text = stringResource(id = R.string.SUBMIT_CLAIM_GLOBAL_ASSISTANCE_CALL_LABEL, it), + onClick = { + try { + val intent = Intent(Intent.ACTION_DIAL) + intent.data = Uri.parse(it) + startActivity(context, intent, null) + } catch (exception: Throwable) { + logcat(LogPriority.ERROR) { "Could not open dial activity in deflect emergency destination" } + } + }, + modifier = Modifier.padding(horizontal = 16.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.onPrimary, + contentColor = MaterialTheme.colorScheme.primary, + disabledContainerColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.12f), + disabledContentColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.38f), + ), + ) + } + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_GLOBAL_ASSISTANCE_FOOTNOTE), + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f), + textAlign = TextAlign.Center, + fontSize = 12.sp, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(24.dp)) + } + } + Spacer(modifier = Modifier.height(24.dp)) + } + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_EMERGENCY_INSURANCE_COVER_TITLE), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_EMERGENCY_INSURANCE_COVER_LABEL), + modifier = Modifier.padding(horizontal = 16.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + Spacer(modifier = Modifier.height(56.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_NEED_HELP_TITLE), + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_NEED_HELP_LABEL), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + Spacer(modifier = Modifier.height(24.dp)) + Box( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + HedvigContainedSmallButton( + text = stringResource(id = R.string.open_chat), + onClick = openChat, + ) + } + Spacer(modifier = Modifier.height(56.dp)) + } +} + +@HedvigPreview +@Composable +private fun DeflectEmergencyDestinationPreview() { + DeflectEmergencyDestination( + parameter = ClaimFlowDestination.DeflectEmergency( + partners = listOf( + DeflectPartner( + id = "1", + imageUrl = "test", + phoneNumber = "1234", + url = "test", + ), + ), + ), + openChat = {}, + closeClaimFlow = {}, + windowSizeClass = WindowSizeClass.calculateForPreview(), + navigateUp = {}, + imageLoader = rememberPreviewImageLoader(), + ) +} diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectGlassDamageDestination.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectGlassDamageDestination.kt new file mode 100644 index 0000000000..b298fdbbac --- /dev/null +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectGlassDamageDestination.kt @@ -0,0 +1,176 @@ +package com.hedvig.android.feature.odyssey.step.informdeflect + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +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.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import coil.ImageLoader +import coil.compose.AsyncImage +import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton +import com.hedvig.android.core.designsystem.component.button.HedvigContainedSmallButton +import com.hedvig.android.core.designsystem.component.card.HedvigCard +import com.hedvig.android.core.designsystem.preview.HedvigPreview +import com.hedvig.android.core.ui.infocard.VectorInfoCard +import com.hedvig.android.core.ui.preview.calculateForPreview +import com.hedvig.android.core.ui.preview.rememberPreviewImageLoader +import com.hedvig.android.data.claimflow.ClaimFlowDestination +import com.hedvig.android.data.claimflow.DeflectPartner +import com.hedvig.android.feature.odyssey.ui.ClaimFlowScaffold +import hedvig.resources.R + +@Composable +internal fun DeflectGlassDamageDestination( + parameter: ClaimFlowDestination.DeflectGlassDamage, + openChat: () -> Unit, + closeClaimFlow: () -> Unit, + windowSizeClass: WindowSizeClass, + navigateUp: () -> Unit, + openUrl: (String) -> Unit, + imageLoader: ImageLoader, +) { + ClaimFlowScaffold( + windowSizeClass = windowSizeClass, + navigateUp = navigateUp, + closeClaimFlow = closeClaimFlow, + ) { + Spacer(modifier = Modifier.height(8.dp)) + VectorInfoCard( + text = stringResource(id = R.string.SUBMIT_CLAIM_GLASS_DAMAGE_INFO_LABEL), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_PARTNER_TITLE), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + parameter.partners.forEach { partner -> + HedvigCard( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.primary), + ) { + Column { + Spacer(modifier = Modifier.height(24.dp)) + AsyncImage( + model = partner.imageUrl, + contentDescription = "Partner image", + imageLoader = imageLoader, + modifier = Modifier.padding(16.dp).fillMaxWidth().height(40.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_GLASS_DAMAGE_ONLINE_BOOKING_LABEL), + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + HedvigContainedButton( + text = stringResource(id = R.string.SUBMIT_CLAIM_GLASS_DAMAGE_ONLINE_BOOKING_BUTTON), + onClick = { + val url = partner.url + if (url != null) { + openUrl(url) + } + }, + modifier = Modifier.padding(horizontal = 16.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.onPrimary, + contentColor = MaterialTheme.colorScheme.primary, + disabledContainerColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.12f), + disabledContentColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.38f), + ), + ) + Spacer(modifier = Modifier.height(16.dp)) + } + } + Spacer(modifier = Modifier.height(8.dp)) + } + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_HOW_IT_WORKS_TITLE), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_GLASS_DAMAGE_HOW_IT_WORKS_LABEL), + modifier = Modifier.padding(horizontal = 16.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + Spacer(modifier = Modifier.height(56.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_NEED_HELP_TITLE), + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_NEED_HELP_LABEL), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + Spacer(modifier = Modifier.height(24.dp)) + Box( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + HedvigContainedSmallButton( + text = stringResource(id = R.string.open_chat), + onClick = openChat, + ) + } + Spacer(modifier = Modifier.height(56.dp)) + } +} + +@HedvigPreview +@Composable +private fun DeflectGlassDamageDestinationPreview() { + DeflectGlassDamageDestination( + parameter = ClaimFlowDestination.DeflectGlassDamage( + partners = listOf( + DeflectPartner( + id = "1", + imageUrl = "test", + phoneNumber = "1234", + url = "test", + ), + DeflectPartner( + id = "2", + imageUrl = "test2", + phoneNumber = "4321", + url = "test2", + ), + ), + ), + openChat = {}, + closeClaimFlow = {}, + windowSizeClass = WindowSizeClass.calculateForPreview(), + navigateUp = {}, + imageLoader = rememberPreviewImageLoader(), + openUrl = {}, + ) +} diff --git a/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectPestsDestination.kt b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectPestsDestination.kt new file mode 100644 index 0000000000..8ff39cf4dd --- /dev/null +++ b/app/feature/feature-odyssey/src/main/kotlin/com/hedvig/android/feature/odyssey/step/informdeflect/DeflectPestsDestination.kt @@ -0,0 +1,169 @@ +package com.hedvig.android.feature.odyssey.step.informdeflect + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +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.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import coil.ImageLoader +import coil.compose.AsyncImage +import com.hedvig.android.core.designsystem.component.button.HedvigContainedButton +import com.hedvig.android.core.designsystem.component.button.HedvigContainedSmallButton +import com.hedvig.android.core.designsystem.component.card.HedvigCard +import com.hedvig.android.core.designsystem.preview.HedvigPreview +import com.hedvig.android.core.ui.infocard.VectorInfoCard +import com.hedvig.android.core.ui.preview.calculateForPreview +import com.hedvig.android.core.ui.preview.rememberPreviewImageLoader +import com.hedvig.android.data.claimflow.ClaimFlowDestination +import com.hedvig.android.data.claimflow.DeflectPartner +import com.hedvig.android.feature.odyssey.ui.ClaimFlowScaffold +import hedvig.resources.R + +@Composable +internal fun DeflectPestsDestination( + parameter: ClaimFlowDestination.DeflectPests, + openChat: () -> Unit, + closeClaimFlow: () -> Unit, + windowSizeClass: WindowSizeClass, + navigateUp: () -> Unit, + imageLoader: ImageLoader, + openUrl: (String) -> Unit, +) { + ClaimFlowScaffold( + windowSizeClass = windowSizeClass, + navigateUp = navigateUp, + closeClaimFlow = closeClaimFlow, + ) { + Spacer(modifier = Modifier.height(8.dp)) + VectorInfoCard( + text = stringResource(id = R.string.SUBMIT_CLAIM_PESTS_INFO_LABEL), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_PARTNER_TITLE), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + parameter.partners.forEach { partner -> + HedvigCard( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.primary), + ) { + Column { + Spacer(modifier = Modifier.height(24.dp)) + AsyncImage( + model = partner.imageUrl, + contentDescription = "Partner image", + imageLoader = imageLoader, + modifier = Modifier.padding(16.dp).fillMaxWidth().height(40.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_PESTS_CUSTOMER_SERVICE_LABEL), + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + HedvigContainedButton( + text = stringResource(id = R.string.SUBMIT_CLAIM_PESTS_CUSTOMER_SERVICE_BUTTON), + onClick = { + val url = partner.url + if (url != null) { + openUrl(url) + } + }, + modifier = Modifier.padding(horizontal = 16.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.onPrimary, + contentColor = MaterialTheme.colorScheme.primary, + disabledContainerColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.12f), + disabledContentColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.38f), + ), + ) + Spacer(modifier = Modifier.height(16.dp)) + } + } + Spacer(modifier = Modifier.height(24.dp)) + } + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_EMERGENCY_INSURANCE_COVER_TITLE), + modifier = Modifier.padding(horizontal = 16.dp), + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_PESTS_HOW_IT_WORKS_LABEL), + modifier = Modifier.padding(horizontal = 16.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + Spacer(modifier = Modifier.height(56.dp)) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_NEED_HELP_TITLE), + textAlign = TextAlign.Center, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + Text( + text = stringResource(id = R.string.SUBMIT_CLAIM_NEED_HELP_LABEL), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + ) + Spacer(modifier = Modifier.height(24.dp)) + Box( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + HedvigContainedSmallButton( + text = stringResource(id = R.string.open_chat), + onClick = openChat, + ) + } + Spacer(modifier = Modifier.height(56.dp)) + } +} + +@HedvigPreview +@Composable +private fun DeflectPestsDestinationPreview() { + DeflectPestsDestination( + parameter = ClaimFlowDestination.DeflectPests( + partners = listOf( + DeflectPartner( + id = "1", + imageUrl = "test", + phoneNumber = "1234", + url = "test", + ), + ), + ), + openChat = {}, + closeClaimFlow = {}, + windowSizeClass = WindowSizeClass.calculateForPreview(), + navigateUp = {}, + imageLoader = rememberPreviewImageLoader(), + openUrl = {}, + ) +} diff --git a/app/feature/feature-odyssey/src/test/kotlin/com/hedvig/android/feature/odyssey/data/TestClaimFlowRepository.kt b/app/feature/feature-odyssey/src/test/kotlin/com/hedvig/android/feature/odyssey/data/TestClaimFlowRepository.kt index 3253223a65..462e026ffa 100644 --- a/app/feature/feature-odyssey/src/test/kotlin/com/hedvig/android/feature/odyssey/data/TestClaimFlowRepository.kt +++ b/app/feature/feature-odyssey/src/test/kotlin/com/hedvig/android/feature/odyssey/data/TestClaimFlowRepository.kt @@ -86,4 +86,8 @@ internal class TestClaimFlowRepository : ClaimFlowRepository { ): Either<ErrorMessage, ClaimFlowStep> { error("Not implemented") } + + override suspend fun submitUrgentEmergency(isUrgentEmergency: Boolean): Either<ErrorMessage, ClaimFlowStep> { + error("Not implemented") + } } diff --git a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt index 61a78ed06d..3381afe2d0 100644 --- a/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt +++ b/app/member-reminders/member-reminders-ui/src/main/kotlin/com/hedvig/android/memberreminders/ui/MemberReminderCards.kt @@ -12,9 +12,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width -import androidx.compose.material.icons.Icons import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -26,14 +24,10 @@ import androidx.compose.ui.unit.dp import com.hedvig.android.core.designsystem.component.button.HedvigContainedSmallButton import com.hedvig.android.core.designsystem.material3.containedButtonContainer import com.hedvig.android.core.designsystem.material3.onContainedButtonContainer -import com.hedvig.android.core.designsystem.material3.onWarningContainer -import com.hedvig.android.core.designsystem.material3.warningContainer -import com.hedvig.android.core.designsystem.material3.warningElement 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.WarningFilled import com.hedvig.android.core.ui.infocard.VectorInfoCard +import com.hedvig.android.core.ui.infocard.VectorWarningCard import com.hedvig.android.memberreminders.ApplicableMemberReminders import com.hedvig.android.memberreminders.UpcomingRenewal import com.hedvig.android.notification.permission.NotificationPermissionState @@ -181,14 +175,8 @@ private fun ReminderCardConnectPayment( navigateToConnectPayment: () -> Unit, modifier: Modifier = Modifier, ) { - VectorInfoCard( + VectorWarningCard( text = stringResource(R.string.info_card_missing_payment_body), - icon = Icons.Hedvig.WarningFilled, - iconColor = MaterialTheme.colorScheme.warningElement, - colors = CardDefaults.outlinedCardColors( - containerColor = MaterialTheme.colorScheme.warningContainer, - contentColor = MaterialTheme.colorScheme.onWarningContainer, - ), modifier = modifier, ) { InfoCardTextButton(