Skip to content

Commit 996fe2e

Browse files
committed
refactor(bill-customization): encapsulate controller and expose BillPlayground
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent cedf854 commit 996fe2e

6 files changed

Lines changed: 114 additions & 102 deletions

File tree

apps/flipcash/features/bill-customization/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ dependencies {
1212
implementation(libs.compose.activities)
1313

1414
implementation(project(":apps:flipcash:shared:bills"))
15-
implementation(project(":apps:flipcash:shared:bill-customization"))
15+
api(project(":apps:flipcash:shared:bill-customization"))
1616
implementation(project(":apps:flipcash:shared:tokens"))
1717
implementation(project(":libs:datetime"))
1818
implementation(project(":libs:messaging"))

apps/flipcash/features/bill-customization/src/main/kotlin/com/flipcash/app/bill/customization/BillCustomizationScaffold.kt

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import com.flipcash.app.bill.customization.components.BillPlayground
4242
import com.flipcash.app.bills.AnimatedBill
4343
import com.flipcash.app.core.bill.Bill
4444
import com.flipcash.features.bill.playground.R
45-
import com.getcode.opencode.model.ui.TokenBillCustomizations
4645
import com.getcode.theme.CodeTheme
4746
import com.getcode.ui.components.AppBarDefaults
4847
import com.getcode.ui.core.measured
@@ -64,20 +63,7 @@ fun BillPlaygroundScaffold(content: @Composable () -> Unit) {
6463
)
6564
}
6665

67-
val customizationsOptions by remember(
68-
playgroundState.backgroundState.selectedColors,
69-
playgroundState.textureState.selectedOption,
70-
playgroundState.textureState.selectedBlendMode,
71-
playgroundState.bill?.token?.billCustomizations
72-
) {
73-
derivedStateOf {
74-
return@derivedStateOf TokenBillCustomizations(
75-
background = playgroundState.background,
76-
texture = playgroundState.texture,
77-
icon = null,
78-
)
79-
}
80-
}
66+
val customizationsOptions = playgroundState.customizations
8167

8268
val augmentedBill by remember(playgroundState.bill, customizationsOptions) {
8369
derivedStateOf {

apps/flipcash/features/bill-customization/src/main/kotlin/com/flipcash/app/bill/customization/components/BillPlayground.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ import com.getcode.ui.core.rememberedClickable
5454

5555
@OptIn(ExperimentalSharedTransitionApi::class)
5656
@Composable
57-
internal fun BillPlayground(
57+
fun BillPlayground(
58+
modifier: Modifier = Modifier,
5859
state: PlaygroundState,
5960
dispatchEvent: (Event) -> Unit,
6061
) {
61-
BoxWithConstraints {
62+
Box(modifier = modifier) {
6263
val screenWidth = CodeTheme.dimens.screenWidth
6364
var firstFeatureWidth by remember { mutableStateOf(0.dp) }
6465
var lastFeatureWidth by remember { mutableStateOf(0.dp) }

apps/flipcash/features/scanner/src/main/kotlin/com/flipcash/app/scanner/internal/ui/components/DecorView.kt

Lines changed: 74 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -55,96 +55,92 @@ internal fun DecorView(
5555
modifier: Modifier = Modifier,
5656
onAction: (ScannerDecorItem) -> Unit,
5757
) {
58-
val billPlayground = LocalBillPlaygroundController.current
59-
val playgroundState by billPlayground.state.collectAsStateWithLifecycle()
60-
AnimatedVisibility(!playgroundState.isCustomizing) {
61-
Box(
58+
Box(
59+
modifier = Modifier
60+
.fillMaxSize()
61+
.then(modifier)
62+
) {
63+
Image(
6264
modifier = Modifier
63-
.fillMaxSize()
64-
.then(modifier)
65+
.statusBarsPadding()
66+
.padding(vertical = CodeTheme.dimens.grid.x3)
67+
.padding(horizontal = CodeTheme.dimens.grid.x3)
68+
.align(Alignment.TopStart)
69+
.width(CodeTheme.dimens.staticGrid.x18)
70+
.rememberedClickable(
71+
interactionSource = remember { MutableInteractionSource() },
72+
indication = null
73+
) {
74+
onAction(ScannerDecorItem.Logo)
75+
}.testTag("flipcash_logo"),
76+
painter = painterResource(R.drawable.ic_flipcash_logo_w_name),
77+
contentDescription = "Tap to share the app",
78+
)
79+
80+
Column(
81+
modifier = Modifier
82+
.statusBarsPadding()
83+
.padding(vertical = CodeTheme.dimens.grid.x2)
84+
.padding(horizontal = CodeTheme.dimens.grid.x3)
85+
.align(Alignment.TopEnd),
86+
horizontalAlignment = Alignment.End,
87+
verticalArrangement = Arrangement.spacedBy(CodeTheme.dimens.inset)
6588
) {
6689
Image(
6790
modifier = Modifier
68-
.statusBarsPadding()
69-
.padding(vertical = CodeTheme.dimens.grid.x3)
70-
.padding(horizontal = CodeTheme.dimens.grid.x3)
71-
.align(Alignment.TopStart)
72-
.width(CodeTheme.dimens.staticGrid.x18)
73-
.rememberedClickable(
74-
interactionSource = remember { MutableInteractionSource() },
75-
indication = null
76-
) {
77-
onAction(ScannerDecorItem.Logo)
78-
}.testTag("flipcash_logo"),
79-
painter = painterResource(R.drawable.ic_flipcash_logo_w_name),
80-
contentDescription = "Tap to share the app",
91+
.clip(CircleShape)
92+
.unboundedClickable {
93+
onAction(ScannerDecorItem.Menu)
94+
}.testTag("menu_button"),
95+
painter = painterResource(R.drawable.ic_home_options),
96+
contentDescription = "",
8197
)
98+
}
8299

83-
Column(
100+
Column(modifier = Modifier.align(Alignment.BottomCenter)) {
101+
val networkState by LocalNetworkObserver.current.state.collectAsState()
102+
103+
AnimatedVisibility(
84104
modifier = Modifier
85-
.statusBarsPadding()
86-
.padding(vertical = CodeTheme.dimens.grid.x2)
87-
.padding(horizontal = CodeTheme.dimens.grid.x3)
88-
.align(Alignment.TopEnd),
89-
horizontalAlignment = Alignment.End,
90-
verticalArrangement = Arrangement.spacedBy(CodeTheme.dimens.inset)
105+
.align(Alignment.CenterHorizontally),
106+
visible = state.showNetworkOffline && !networkState.connected,
107+
enter = fadeIn(animationSpec = tween(500, 100)),
108+
exit = fadeOut(animationSpec = tween(500, 100)),
91109
) {
92-
Image(
93-
modifier = Modifier
94-
.clip(CircleShape)
95-
.unboundedClickable {
96-
onAction(ScannerDecorItem.Menu)
97-
}.testTag("menu_button"),
98-
painter = painterResource(R.drawable.ic_home_options),
99-
contentDescription = "",
100-
)
101-
}
102-
103-
Column(modifier = Modifier.align(Alignment.BottomCenter)) {
104-
val networkState by LocalNetworkObserver.current.state.collectAsState()
105-
106-
AnimatedVisibility(
110+
Row(
107111
modifier = Modifier
108-
.align(Alignment.CenterHorizontally),
109-
visible = state.showNetworkOffline && !networkState.connected,
110-
enter = fadeIn(animationSpec = tween(500, 100)),
111-
exit = fadeOut(animationSpec = tween(500, 100)),
112+
.wrapContentSize()
113+
.clip(CodeTheme.shapes.xxl)
114+
.background(CodeTheme.colors.error)
115+
.padding(
116+
horizontal = CodeTheme.dimens.grid.x2,
117+
vertical = CodeTheme.dimens.grid.x1
118+
),
119+
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.staticGrid.x1),
120+
verticalAlignment = Alignment.CenterVertically
112121
) {
113-
Row(
114-
modifier = Modifier
115-
.wrapContentSize()
116-
.clip(CodeTheme.shapes.xxl)
117-
.background(CodeTheme.colors.error)
118-
.padding(
119-
horizontal = CodeTheme.dimens.grid.x2,
120-
vertical = CodeTheme.dimens.grid.x1
121-
),
122-
horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.staticGrid.x1),
123-
verticalAlignment = Alignment.CenterVertically
124-
) {
125-
Icon(
126-
modifier = Modifier.size(16.dp),
127-
painter = painterResource(id = R.drawable.ic_wifi_slash),
128-
contentDescription = null
129-
)
130-
Text(
131-
text = stringResource(id = R.string.title_badge_no_connection),
132-
color = Color.White,
133-
style = CodeTheme.typography.caption
134-
)
135-
}
122+
Icon(
123+
modifier = Modifier.size(16.dp),
124+
painter = painterResource(id = R.drawable.ic_wifi_slash),
125+
contentDescription = null
126+
)
127+
Text(
128+
text = stringResource(id = R.string.title_badge_no_connection),
129+
color = Color.White,
130+
style = CodeTheme.typography.caption
131+
)
136132
}
137-
138-
ScannerNavigationBar(
139-
modifier = Modifier
140-
.windowInsetsPadding(WindowInsets.navigationBars)
141-
.padding(bottom = CodeTheme.dimens.grid.x3),
142-
state = state,
143-
billState = billState,
144-
isPaused = isPaused,
145-
onAction = onAction
146-
)
147133
}
134+
135+
ScannerNavigationBar(
136+
modifier = Modifier
137+
.windowInsetsPadding(WindowInsets.navigationBars)
138+
.padding(bottom = CodeTheme.dimens.grid.x3),
139+
state = state,
140+
billState = billState,
141+
isPaused = isPaused,
142+
onAction = onAction
143+
)
148144
}
149145
}
150146
}

apps/flipcash/shared/bill-customization/src/main/kotlin/com/flipcash/app/bill/customization/BillPlaygroundController.kt

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import com.flipcash.app.bill.customization.internal.features.ColorState
77
import com.flipcash.app.bill.customization.internal.features.GraphicState
88
import com.flipcash.app.bill.customization.models.PlaygroundFeature
99
import com.flipcash.app.core.bill.Bill
10+
import com.getcode.opencode.model.financial.Fiat
1011
import com.getcode.opencode.model.financial.Token
12+
import com.getcode.opencode.model.financial.toFiat
1113
import com.getcode.opencode.model.ui.BillBackground
1214
import com.getcode.opencode.model.ui.BillTexture
15+
import com.getcode.opencode.model.ui.TokenBillCustomizations
1316
import com.getcode.ui.utils.Hsv
1417
import com.getcode.ui.utils.toAGColor
1518
import kotlinx.coroutines.flow.MutableStateFlow
@@ -19,7 +22,6 @@ interface BillPlaygroundController {
1922
val state: StateFlow<PlaygroundState>
2023
val canUndo: Boolean
2124
val canCopy: Boolean
22-
fun customizeFor(token: Token)
2325

2426
fun dispatchEvent(event: Event)
2527
fun cancel()
@@ -67,6 +69,24 @@ data class PlaygroundState(
6769
}
6870
}
6971

72+
val customizations: TokenBillCustomizations
73+
get() = TokenBillCustomizations(
74+
background = background,
75+
texture = texture,
76+
icon = null,
77+
)
78+
79+
val customizedBill: Bill?
80+
get() {
81+
if (bill == null) return null
82+
if (bill !is Bill.Cash) return null
83+
return bill.copy(
84+
token = bill.token.copy(
85+
billCustomizations = customizations
86+
)
87+
)
88+
}
89+
7090
val backgroundBrush: Brush
7191
get() {
7292
with (backgroundState) {
@@ -80,6 +100,10 @@ data class PlaygroundState(
80100
}
81101

82102
sealed interface Event {
103+
data class Load(
104+
val customizations: TokenBillCustomizations?,
105+
val amount: Fiat = 5.toFiat(),
106+
): Event
83107
data class SelectFeature(val feature: PlaygroundFeature): Event
84108
sealed interface Colors: Event {
85109
data object AddSlot : Colors
@@ -105,7 +129,6 @@ internal object StubPlaygroundController : BillPlaygroundController {
105129
override val state: StateFlow<PlaygroundState> = MutableStateFlow(PlaygroundState())
106130
override val canUndo: Boolean = false
107131
override val canCopy: Boolean = false
108-
override fun customizeFor(token: Token) = Unit
109132
override fun dispatchEvent(event: Event) = Unit
110133
override fun cancel() = Unit
111134
}

apps/flipcash/shared/bill-customization/src/main/kotlin/com/flipcash/app/bill/customization/internal/InternalBillPlaygroundController.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ import com.flipcash.app.bill.customization.models.PlaygroundFeature
1515
import com.flipcash.app.core.bill.Bill
1616
import com.getcode.opencode.model.core.OpenCodePayload
1717
import com.getcode.opencode.model.core.PayloadKind
18+
import com.getcode.opencode.model.financial.Fiat
1819
import com.getcode.opencode.model.financial.LocalFiat
1920
import com.getcode.opencode.model.financial.Token
2021
import com.getcode.opencode.model.financial.toFiat
22+
import com.getcode.opencode.model.financial.usdf
2123
import com.getcode.opencode.model.ui.BillBackground
24+
import com.getcode.opencode.model.ui.TokenBillCustomizations
2225
import com.getcode.opencode.utils.nonce
2326
import com.getcode.ui.utils.Hsv
2427
import com.getcode.ui.utils.toHex
@@ -77,12 +80,12 @@ class InternalBillPlaygroundController(
7780
get() = !undoStack.isEmpty()
7881

7982
override val canCopy: Boolean
80-
get() = true
83+
get() = false
8184

82-
override fun customizeFor(token: Token) {
85+
private fun customizeFor(token: Token, amount: Fiat, customizations: TokenBillCustomizations?) {
8386
// create amount for the bill
8487
val demoAmount = LocalFiat(
85-
usdf = 5.toFiat(),
88+
usdf = amount,
8689
)
8790

8891
// provide bill "data" to render the scan code
@@ -93,7 +96,7 @@ class InternalBillPlaygroundController(
9396
)
9497
// create bill for token
9598
val bill = Bill.Cash(
96-
token = token.copy(billCustomizations = null),
99+
token = token.copy(billCustomizations = customizations),
97100
amount = demoAmount,
98101
disableGestures = true,
99102
data = payloadInfo.codeData.toList()
@@ -105,6 +108,9 @@ class InternalBillPlaygroundController(
105108
override fun dispatchEvent(event: Event) {
106109
when (event) {
107110
// high level actions
111+
is Event.Load -> {
112+
customizeFor(Token.usdf, event.amount, event.customizations)
113+
}
108114

109115
// selecting feature from tab row
110116
is Event.SelectFeature -> selectFeature(event.feature)

0 commit comments

Comments
 (0)