diff --git a/CLAUDE.md b/CLAUDE.md
index b811a101c2..5390fe7ada 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -628,6 +628,13 @@ Example:
Text("This is some text for feature X")
```
+**Verifying whether a string key is "real" (already in Lokalise):** if you find a key in a
+`strings.xml` and are unsure whether it actually exists in Lokalise or was hand-added, run
+`./gradlew downloadStrings` and re-check the file. Because `downloadStrings` regenerates every
+`strings.xml` from Lokalise, a key that **survives** the run exists in Lokalise; a key that
+**disappears** was only added locally and would break the build once someone else syncs. Use this
+before relying on (or committing code that references) a key you didn't personally add to Lokalise.
+
## Debugging
### Common Issues
diff --git a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls
index 9b640dcbe3..98edc25fe0 100644
--- a/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls
+++ b/app/apollo/apollo-octopus-public/src/commonMain/graphql/com/hedvig/android/apollo/octopus/schema.graphqls
@@ -971,6 +971,11 @@ type ClaimIntent {
"""
displayName: String
"""
+ Whether this draft is resumable by the member. A draft that has been deleted (see `claimIntentDeleteDraft`)
+ is no longer resumable.
+ """
+ resumable: Boolean!
+ """
The created claim of this intent.
Once this value is returned, the intent is effectively over, and no steps
can be produced or interacted with.
@@ -3713,6 +3718,10 @@ type Mutation {
"""
claimIntentRegretStep(stepId: ID!): ClaimIntentMutationOutput!
"""
+ Delete a draft claim intent from the member's perspective (a soft delete) so it is no longer returned by `resumableClaimIntent`.
+ """
+ claimIntentDeleteDraft(id: ID!): Boolean!
+ """
Submit a step containing a `ClaimIntentStepContentForm`.
"""
claimIntentSubmitForm(input: ClaimIntentSubmitFormInput!): ClaimIntentMutationOutput!
diff --git a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml
index 75a8dca92c..671a6ac4bf 100644
--- a/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml
+++ b/app/core/core-resources/src/androidMain/res/values-sv-rSE/strings.xml
@@ -503,8 +503,8 @@
Inga konversationer än. Starta en genom att skriva ett meddelande
Din inkorg är tom
Nytt
- Anmäl något som har hänt med dig eller dina saker
- Frågor om din försäkring, betalningar och annat
+ Anmäl något som hänt dig eller dina saker
+ Frågor om din försäkring, betalningar eller annat
Erbjudanden
Du har ingen aktiv försäkring
Tillägg
@@ -986,6 +986,7 @@
Välj den försäkring du vill uppdatera
Visa ditt skydd
Välj din skyddsnivå och självrisk
+ Välj din skyddsnivå
Godkänn ändringar
Skyddet
Dokument
diff --git a/app/core/core-resources/src/androidMain/res/values/strings.xml b/app/core/core-resources/src/androidMain/res/values/strings.xml
index 0d194724d5..6657ce11d1 100644
--- a/app/core/core-resources/src/androidMain/res/values/strings.xml
+++ b/app/core/core-resources/src/androidMain/res/values/strings.xml
@@ -986,6 +986,7 @@
Select the insurance you want to edit
Show coverage
Set your coverage level and deductible
+ Set your coverage level
Confirm changes
Coverage
Documents
diff --git a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml
index 2d75e502d1..42758c2870 100644
--- a/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml
+++ b/app/core/core-resources/src/commonMain/composeResources/values-sv-rSE/strings.xml
@@ -502,8 +502,8 @@
Inga konversationer än. Starta en genom att skriva ett meddelande
Din inkorg är tom
Nytt
- Anmäl något som har hänt med dig eller dina saker
- Frågor om din försäkring, betalningar och annat
+ Anmäl något som hänt dig eller dina saker
+ Frågor om din försäkring, betalningar eller annat
Erbjudanden
Du har ingen aktiv försäkring
Tillägg
@@ -985,6 +985,7 @@
Välj den försäkring du vill uppdatera
Visa ditt skydd
Välj din skyddsnivå och självrisk
+ Välj din skyddsnivå
Godkänn ändringar
Skyddet
Dokument
diff --git a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml
index 0061307317..6428d4a37d 100644
--- a/app/core/core-resources/src/commonMain/composeResources/values/strings.xml
+++ b/app/core/core-resources/src/commonMain/composeResources/values/strings.xml
@@ -985,6 +985,7 @@
Select the insurance you want to edit
Show coverage
Set your coverage level and deductible
+ Set your coverage level
Confirm changes
Coverage
Documents
diff --git a/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql b/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql
index 1de9f27fb4..0c21535700 100644
--- a/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql
+++ b/app/data/data-changetier/src/main/graphql/MutationChangeTierDeductible.graphql
@@ -19,6 +19,7 @@ $addonsFlagOn: Boolean!) {
}
tierLevel
tierName
+ tierDescription
}
quotes {
currentTotalCost {
@@ -48,6 +49,7 @@ $addonsFlagOn: Boolean!) {
}
tierLevel
tierName
+ tierDescription
addons @include(if: $addonsFlagOn) {
addonVariant {
...AddonVariantFragment
diff --git a/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt b/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt
index 709901bcde..91e34383cb 100644
--- a/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt
+++ b/app/data/data-changetier/src/main/kotlin/com/hedvig/android/data/changetier/data/CreateChangeTierDeductibleIntentUseCase.kt
@@ -100,7 +100,7 @@ internal class CreateChangeTierDeductibleIntentUseCaseImpl(
tier = Tier(
tierName = tierName,
tierLevel = tierLevel,
- tierDescription = productVariant.tierDescription,
+ tierDescription = tierDescription ?: productVariant.tierDescription,
tierDisplayName = productVariant.displayNameTier,
),
displayItems = displayItems.toDisplayItems(),
@@ -126,7 +126,7 @@ internal class CreateChangeTierDeductibleIntentUseCaseImpl(
tier = Tier(
tierName = it.tierName,
tierLevel = it.tierLevel,
- tierDescription = it.productVariant.tierDescription,
+ tierDescription = it.tierDescription ?: it.productVariant.tierDescription,
tierDisplayName = it.productVariant.displayNameTier,
),
addons = it.addons?.map { addon ->
diff --git a/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ContractGroup.kt b/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ContractGroup.kt
index b1d9e29413..2617e07546 100644
--- a/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ContractGroup.kt
+++ b/app/data/data-contract/src/commonMain/kotlin/com/hedvig/android/data/contract/ContractGroup.kt
@@ -8,6 +8,7 @@ import hedvigandroid.data_contract.generated.resources.dog
import hedvigandroid.data_contract.generated.resources.home
import hedvigandroid.data_contract.generated.resources.homeowner
import hedvigandroid.data_contract.generated.resources.rental
+import hedvigandroid.data_contract.generated.resources.safety
import hedvigandroid.data_contract.generated.resources.student
import hedvigandroid.data_contract.generated.resources.vacation
import hedvigandroid.data_contract.generated.resources.villa
@@ -25,6 +26,7 @@ enum class ContractGroup {
STUDENT,
COUNTRY_HOME,
QASA_LANDLORD,
+ PAYMENT_PROTECTION,
UNKNOWN,
}
@@ -41,6 +43,7 @@ fun ContractGroup.gradientResource(): DrawableResource = when (this) {
ContractGroup.COUNTRY_HOME -> Res.drawable.vacation
ContractGroup.UNKNOWN -> Res.drawable.home
ContractGroup.QASA_LANDLORD -> Res.drawable.home
+ ContractGroup.PAYMENT_PROTECTION -> Res.drawable.safety
}
fun ContractGroup.pillowResource(): DrawableResource = when (this) {
@@ -56,6 +59,7 @@ fun ContractGroup.pillowResource(): DrawableResource = when (this) {
ContractGroup.COUNTRY_HOME -> Res.drawable.vacation
ContractGroup.UNKNOWN -> Res.drawable.home
ContractGroup.QASA_LANDLORD -> Res.drawable.home
+ ContractGroup.PAYMENT_PROTECTION -> Res.drawable.safety
}
fun String.toContractGroup(): ContractGroup = when (this) {
@@ -132,5 +136,7 @@ fun String.toContractGroup(): ContractGroup = when (this) {
"SE_QASA_LANDLORD" -> ContractGroup.QASA_LANDLORD
+ "SE_PAYMENT_PROTECTION" -> ContractGroup.PAYMENT_PROTECTION
+
else -> ContractGroup.UNKNOWN
}
diff --git a/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectCoverageViewModel.kt b/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectCoverageViewModel.kt
index cd86130499..0e4cad32f0 100644
--- a/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectCoverageViewModel.kt
+++ b/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectCoverageViewModel.kt
@@ -219,6 +219,8 @@ internal class SelectCoveragePresenter(
),
quotesForChosenTier = currentPartialStateValue.map[chosenTier]!!,
isTierChoiceEnabled = currentPartialStateValue.map.keys.size > 1,
+ isPaymentProtection =
+ currentPartialStateValue.contractData.contractGroup == ContractGroup.PAYMENT_PROTECTION,
contractData = currentPartialStateValue.contractData,
chosenInDialogQuote = chosenQuoteInDialog,
chosenInDialogTier = chosenTierInDialog,
@@ -326,6 +328,9 @@ internal data class SelectCoverageSuccessUiState(
val chosenInDialogQuote: TierDeductibleQuote?,
val isCurrentChosen: Boolean,
val isTierChoiceEnabled: Boolean,
+ // Payment protection has no real tiers nor comparable coverage: it reuses the tier flow only to pick an
+ // insured amount. Used to hide the compare/show-coverage button and to swap the deductible-mentioning subtitle.
+ val isPaymentProtection: Boolean,
// sorted list of tiers with corresponding premiums (depending on selected deductible)
val tiers: List>,
val quotesForChosenTier: List,
diff --git a/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectTierDestination.kt b/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectTierDestination.kt
index b054469c73..c9d9b3d58d 100644
--- a/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectTierDestination.kt
+++ b/app/feature/feature-choose-tier/src/main/kotlin/com/hedvig/android/feature/change/tier/ui/stepcustomize/SelectTierDestination.kt
@@ -95,7 +95,9 @@ import hedvig.resources.TIER_FLOW_SELECT_COVERAGE_SUBTITLE
import hedvig.resources.TIER_FLOW_SELECT_COVERAGE_TITLE
import hedvig.resources.TIER_FLOW_SELECT_DEDUCTIBLE_SUBTITLE
import hedvig.resources.TIER_FLOW_SELECT_DEDUCTIBLE_TITLE
+import hedvig.resources.TIER_FLOW_SHOW_COVERAGE_BUTTON
import hedvig.resources.TIER_FLOW_SUBTITLE
+import hedvig.resources.TIER_FLOW_SUBTITLE_WITHOUT_DEDUCTIBLE
import hedvig.resources.TIER_FLOW_TITLE
import hedvig.resources.TIER_FLOW_TOTAL
import hedvig.resources.general_cancel_button
@@ -234,7 +236,12 @@ private fun SelectTierScreen(
lineBreak = LineBreak.Heading,
color = HedvigTheme.colorScheme.textSecondary,
),
- text = stringResource(Res.string.TIER_FLOW_SUBTITLE),
+ // Payment protection has no deductible, so the standard "…level and deductible" subtitle over-promises.
+ text = if (uiState.isPaymentProtection) {
+ stringResource(Res.string.TIER_FLOW_SUBTITLE_WITHOUT_DEDUCTIBLE)
+ } else {
+ stringResource(Res.string.TIER_FLOW_SUBTITLE)
+ },
modifier = Modifier.padding(horizontal = 16.dp),
)
Spacer(Modifier.weight(1f))
@@ -270,14 +277,20 @@ private fun SelectTierScreen(
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
- if (uiState.tiers.size > 1) {
+ if (!uiState.isPaymentProtection) {
Spacer(Modifier.height(8.dp))
HedvigTextButton(
buttonSize = Large,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
- text = stringResource(Res.string.TIER_FLOW_COMPARE_BUTTON),
+ text = stringResource(
+ if (uiState.tiers.size == 1) {
+ Res.string.TIER_FLOW_SHOW_COVERAGE_BUTTON
+ } else {
+ Res.string.TIER_FLOW_COMPARE_BUTTON
+ },
+ ),
onClick = {
onCompareClick()
},
@@ -327,7 +340,7 @@ private fun CustomizationCard(
Spacer(Modifier.height(16.dp))
val tierSimpleItems = buildList {
for (tier in tiers) {
- add(SimpleDropdownItem(tier.first.tierDisplayName ?: "-"))
+ add(SimpleDropdownItem(tier.first.tierDisplayName ?: tier.first.tierName))
}
}
val hintText = stringResource(Res.string.TIER_FLOW_COVERAGE_PLACEHOLDER)
@@ -543,7 +556,7 @@ private fun TierCoverageRadioGroup(
options = tiers.map { pair ->
RadioOption(
id = RadioOptionId(pair.first.tierName),
- text = pair.first.tierDisplayName ?: "-",
+ text = pair.first.tierDisplayName ?: pair.first.tierName,
label = pair.first.tierDescription,
)
},
@@ -753,6 +766,7 @@ private fun SelectTierScreenPreview() {
),
quotesForChosenTier = listOf(quotesForPreview[0]),
isTierChoiceEnabled = true,
+ isPaymentProtection = false,
chosenTier = Tier(
"BAS",
tierLevel = 0,
diff --git a/app/feature/feature-choose-tier/src/test/kotlin/ui/stepcustomize/SelectCoveragePresenterTest.kt b/app/feature/feature-choose-tier/src/test/kotlin/ui/stepcustomize/SelectCoveragePresenterTest.kt
index 922dad5b95..682dfa6619 100644
--- a/app/feature/feature-choose-tier/src/test/kotlin/ui/stepcustomize/SelectCoveragePresenterTest.kt
+++ b/app/feature/feature-choose-tier/src/test/kotlin/ui/stepcustomize/SelectCoveragePresenterTest.kt
@@ -12,6 +12,7 @@ import assertk.assertions.isNull
import assertk.assertions.prop
import basTier
import com.hedvig.android.core.common.ErrorMessage
+import com.hedvig.android.data.contract.ContractGroup
import com.hedvig.android.feature.change.tier.data.CurrentContractData
import com.hedvig.android.feature.change.tier.data.GetCurrentContractDataUseCase
import com.hedvig.android.feature.change.tier.navigation.ComparisonKey
@@ -264,8 +265,56 @@ class SelectCoveragePresenterTest {
.isNull()
}
}
+
+ @Test
+ fun `when the contract is payment protection isPaymentProtection is true`() = runTest {
+ val tierRepo = FakeChangeTierRepository()
+ val presenter = SelectCoveragePresenter(
+ params = params,
+ tierRepository = tierRepo,
+ getCurrentContractDataUseCase = FakeGetCurrentContractDataUseCase(),
+ backstack = TestBackstack(),
+ )
+ presenter.test(SelectCoverageState.Loading) {
+ tierRepo.quoteListTurbine.add(listOf(paymentProtectionQuote))
+ skipItems(1)
+ assertThat(awaitItem())
+ .isInstanceOf(SelectCoverageState.Success::class)
+ .prop(SelectCoverageState.Success::uiState)
+ .isInstanceOf(SelectCoverageSuccessUiState::class.java)
+ .prop(SelectCoverageSuccessUiState::isPaymentProtection)
+ .isEqualTo(true)
+ }
+ }
+
+ @Test
+ fun `when the contract is not payment protection isPaymentProtection is false`() = runTest {
+ val tierRepo = FakeChangeTierRepository()
+ val presenter = SelectCoveragePresenter(
+ params = params,
+ tierRepository = tierRepo,
+ getCurrentContractDataUseCase = FakeGetCurrentContractDataUseCase(),
+ backstack = TestBackstack(),
+ )
+ presenter.test(SelectCoverageState.Loading) {
+ tierRepo.quoteListTurbine.add(listOf(testQuote, testQuote2, currentQuote))
+ skipItems(1)
+ assertThat(awaitItem())
+ .isInstanceOf(SelectCoverageState.Success::class)
+ .prop(SelectCoverageState.Success::uiState)
+ .isInstanceOf(SelectCoverageSuccessUiState::class.java)
+ .prop(SelectCoverageSuccessUiState::isPaymentProtection)
+ .isEqualTo(false)
+ }
+ }
}
+// A current quote whose contract group is payment protection, which reuses the tier flow only to pick an
+// insured amount. Its id must match FakeChangeTierRepository.getCurrentQuoteId() so it is treated as current.
+private val paymentProtectionQuote = currentQuote.copy(
+ productVariant = currentQuote.productVariant.copy(contractGroup = ContractGroup.PAYMENT_PROTECTION),
+)
+
private class FakeGetCurrentContractDataUseCase() : GetCurrentContractDataUseCase {
override suspend fun invoke(insuranceId: String): Either {
return either { CurrentContractData("exposure name") }