Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
}
Loading