diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarConfig.kt b/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarConfig.kt index 65b9fd23de..0334daefc7 100644 --- a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarConfig.kt +++ b/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarConfig.kt @@ -13,11 +13,29 @@ data class NavBarConfig( fun deserialize(value: String): NavBarConfig { if (value.isBlank()) return Default val parts = value.split("|") - val order = parts.getOrNull(0) + val stored = parts.getOrNull(0) ?.split(",") ?.mapNotNull { runCatching { NavBarButton.valueOf(it) }.getOrNull() } ?.ifEmpty { NavBarButton.defaultOrder } ?: NavBarButton.defaultOrder + // Back-fill any buttons added after this order was persisted (e.g. Tips), + // inserting each at its position in defaultOrder so it lands where intended + // rather than getting appended. Without this, a persisted order that predates + // a new button would never surface it, even when its feature flag is enabled. + val order = if (stored.containsAll(NavBarButton.defaultOrder)) { + stored + } else { + NavBarButton.defaultOrder.fold(stored) { acc, button -> + if (button in acc) { + acc + } else { + val insertAt = NavBarButton.defaultOrder + .subList(0, NavBarButton.defaultOrder.indexOf(button)) + .let { preceding -> acc.indexOfLast { it in preceding } + 1 } + acc.toMutableList().apply { add(insertAt, button) } + } + } + } val label = parts.getOrNull(1) ?.let { runCatching { GiveButtonLabel.valueOf(it) }.getOrNull() } ?: GiveButtonLabel.Give diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/NavBarConfigTest.kt b/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/NavBarConfigTest.kt new file mode 100644 index 0000000000..751b9835f2 --- /dev/null +++ b/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/NavBarConfigTest.kt @@ -0,0 +1,65 @@ +package com.flipcash.app.core.navigation + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class NavBarConfigTest { + + @Test + fun `blank string yields the default config`() { + assertEquals(NavBarConfig.Default, NavBarConfig.deserialize("")) + } + + @Test + fun `round-trips a full, current order`() { + val config = NavBarConfig( + order = listOf(NavBarButton.Wallet, NavBarButton.Give, NavBarButton.Discover, NavBarButton.Send, NavBarButton.Tips), + giveButtonLabel = GiveButtonLabel.Cash, + ) + assertEquals(config, NavBarConfig.deserialize(config.serialize())) + } + + @Test + fun `back-fills a button added after the order was persisted, at its default position`() { + // A nav bar order persisted before Tips was added to the enum/defaultOrder. + val legacy = "Discover,Give,Send,Wallet|Cash" + + val order = NavBarConfig.deserialize(legacy).order + + assertTrue(NavBarButton.Tips in order, "Tips should be back-filled into a legacy order") + // Inserted at its defaultOrder position (between Send and Wallet), not appended. + assertEquals( + listOf(NavBarButton.Discover, NavBarButton.Give, NavBarButton.Send, NavBarButton.Tips, NavBarButton.Wallet), + order, + ) + } + + @Test + fun `back-fill preserves a user's custom ordering of existing buttons`() { + val legacy = "Wallet,Send,Give,Discover|Cash" + + val order = NavBarConfig.deserialize(legacy).order + + assertTrue(NavBarButton.Tips in order) + // Existing buttons keep the user's reversed order; only the missing one is added. + assertEquals( + listOf(NavBarButton.Wallet, NavBarButton.Send, NavBarButton.Give, NavBarButton.Discover), + order.filterNot { it == NavBarButton.Tips }, + ) + } + + @Test + fun `unknown button names are dropped and missing known ones back-filled`() { + val order = NavBarConfig.deserialize("Discover,Bogus,Give,Send,Wallet|Cash").order + + assertEquals(NavBarButton.defaultOrder, order) + } + + @Test + fun `empty order falls back to the default order`() { + val order = NavBarConfig.deserialize("|Cash").order + + assertEquals(NavBarButton.defaultOrder, order) + } +}