Skip to content

Commit fead793

Browse files
committed
feat(flipcash): render list of pools when non-zero
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent 141c54e commit fead793

File tree

7 files changed

+159
-16
lines changed

7 files changed

+159
-16
lines changed

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/pools/Pool.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ data class Pool(
1515
val isOpen: Boolean = true,
1616
val resolution: PoolResolution = PoolResolution.NotSet,
1717
val createdAt: Instant,
18+
val didWin: Boolean,
1819
)
1920

2021
data class PoolWithBets(

apps/flipcash/core/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,7 @@
188188
<string name="error_description_bidLimitReached">Bids are capped at %1$s</string>
189189
<string name="error_title_createPoolFailed">Create Pool Failed</string>
190190
<string name="error_description_createPoolFailed">Something went wrong</string>
191+
<string name="subtitle_amountInPool">%1$s in Pool</string>
192+
<string name="subtitle_lostInPool">Lost %1$s</string>
193+
<string name="subtitle_wonInPool">Won %1$s</string>
191194
</resources>

apps/flipcash/features/pools/src/main/kotlin/com/flipcash/app/pools/internal/list/PoolListScreenContent.kt

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,47 @@ package com.flipcash.app.pools.internal.list
33
import androidx.compose.foundation.Image
44
import androidx.compose.foundation.background
55
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.BoxScope
67
import androidx.compose.foundation.layout.Column
78
import androidx.compose.foundation.layout.Spacer
89
import androidx.compose.foundation.layout.WindowInsets
910
import androidx.compose.foundation.layout.fillMaxSize
1011
import androidx.compose.foundation.layout.fillMaxWidth
1112
import androidx.compose.foundation.layout.navigationBars
13+
import androidx.compose.foundation.layout.navigationBarsPadding
1214
import androidx.compose.foundation.layout.padding
1315
import androidx.compose.foundation.layout.windowInsetsPadding
16+
import androidx.compose.foundation.lazy.LazyColumn
1417
import androidx.compose.material.Text
1518
import androidx.compose.runtime.Composable
1619
import androidx.compose.runtime.LaunchedEffect
17-
import androidx.lifecycle.compose.collectAsStateWithLifecycle
1820
import androidx.compose.runtime.getValue
1921
import androidx.compose.ui.Alignment
2022
import androidx.compose.ui.Modifier
2123
import androidx.compose.ui.res.painterResource
2224
import androidx.compose.ui.res.stringResource
2325
import androidx.compose.ui.text.style.TextAlign
2426
import androidx.compose.ui.tooling.preview.Preview
27+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
28+
import androidx.paging.LoadState
29+
import androidx.paging.PagingData
30+
import androidx.paging.compose.LazyPagingItems
31+
import androidx.paging.compose.collectAsLazyPagingItems
2532
import cafe.adriel.voyager.core.registry.ScreenRegistry
2633
import com.flipcash.app.core.NavScreenProvider
34+
import com.flipcash.app.core.pools.Pool
35+
import com.flipcash.app.pools.internal.list.components.PoolSummaryRow
2736
import com.flipcash.app.theme.FlipcashDesignSystem
2837
import com.flipcash.features.pools.R
2938
import com.getcode.navigation.core.LocalCodeNavigator
3039
import com.getcode.theme.CodeTheme
3140
import com.getcode.ui.theme.ButtonState
3241
import com.getcode.ui.theme.CodeButton
42+
import com.getcode.ui.theme.CodeScaffold
3343
import kotlinx.coroutines.flow.filterIsInstance
44+
import kotlinx.coroutines.flow.flowOf
3445
import kotlinx.coroutines.flow.launchIn
46+
import kotlinx.coroutines.flow.map
3547
import kotlinx.coroutines.flow.onEach
3648

3749
@Composable
@@ -40,14 +52,20 @@ internal fun PoolListScreen(
4052
) {
4153
val navigator = LocalCodeNavigator.current
4254
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
55+
val pools = viewModel.pools.collectAsLazyPagingItems()
4356

44-
PoolListScreenContent(state, viewModel::dispatchEvent)
57+
PoolListScreenContent(state, pools, viewModel::dispatchEvent)
4558

4659
LaunchedEffect(viewModel) {
4760
viewModel.eventFlow
4861
.filterIsInstance<PoolListViewModel.Event.OnPoolClicked>()
62+
.map { it.pool }
4963
.onEach {
50-
64+
navigator.push(
65+
ScreenRegistry.get(
66+
NavScreenProvider.HomeScreen.Pools.ChoiceSelection(it.id)
67+
)
68+
)
5169
}.launchIn(this)
5270
}
5371

@@ -63,11 +81,55 @@ internal fun PoolListScreen(
6381
@Composable
6482
private fun PoolListScreenContent(
6583
state: PoolListViewModel.State,
84+
pools: LazyPagingItems<Pool>,
85+
dispatch: (PoolListViewModel.Event) -> Unit
86+
) {
87+
if (pools.itemCount == 0 && pools.loadState.append is LoadState.NotLoading) {
88+
Box(
89+
modifier = Modifier.fillMaxSize(),
90+
contentAlignment = Alignment.Center
91+
) {
92+
EmptyState(dispatch)
93+
}
94+
} else {
95+
CodeScaffold(
96+
bottomBar = {
97+
CodeButton(
98+
onClick = { dispatch(PoolListViewModel.Event.OnCreatePool) },
99+
text = stringResource(R.string.action_createNewPool),
100+
buttonState = ButtonState.Filled,
101+
modifier = Modifier
102+
.fillMaxWidth()
103+
.navigationBarsPadding()
104+
.padding(horizontal = CodeTheme.dimens.inset)
105+
.padding(
106+
top = CodeTheme.dimens.grid.x2,
107+
bottom = CodeTheme.dimens.grid.x2
108+
),
109+
)
110+
}
111+
) { innerPadding ->
112+
LazyColumn(modifier = Modifier.padding(innerPadding)) {
113+
items(pools.itemCount) { index ->
114+
pools[index]?.let {
115+
PoolSummaryRow(
116+
pool = it,
117+
onClick = { dispatch(PoolListViewModel.Event.OnPoolClicked(it)) }
118+
)
119+
}
120+
}
121+
}
122+
}
123+
}
124+
}
125+
126+
@Composable
127+
private fun BoxScope.EmptyState(
66128
dispatch: (PoolListViewModel.Event) -> Unit
67129
) {
68130
Box(
69131
modifier = Modifier
70-
.fillMaxSize()
132+
.matchParentSize()
71133
.windowInsetsPadding(WindowInsets.navigationBars),
72134
) {
73135
Column(
@@ -93,7 +155,7 @@ private fun PoolListScreenContent(
93155
)
94156
Spacer(Modifier.weight(1f))
95157
CodeButton(
96-
onClick = { dispatch(PoolListViewModel.Event.OnCreatePool) },
158+
onClick = { dispatch(PoolListViewModel.Event.OnCreatePool) },
97159
text = stringResource(R.string.action_createNewPool),
98160
buttonState = ButtonState.Filled,
99161
modifier = Modifier
@@ -112,6 +174,7 @@ private fun Preview_EmptyState() {
112174
Box(modifier = Modifier.background(CodeTheme.colors.background)) {
113175
PoolListScreenContent(
114176
state = PoolListViewModel.State(),
177+
pools = flowOf(PagingData.empty<Pool>()).collectAsLazyPagingItems(),
115178
dispatch = {}
116179
)
117180
}

apps/flipcash/features/pools/src/main/kotlin/com/flipcash/app/pools/internal/list/PoolListViewModel.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,45 @@
11
package com.flipcash.app.pools.internal.list
22

3+
import androidx.lifecycle.viewModelScope
4+
import androidx.paging.cachedIn
5+
import androidx.paging.insertSeparators
6+
import com.flipcash.app.core.pools.Pool
7+
import com.flipcash.app.pools.PoolsCoordinator
38
import com.flipcash.services.controllers.PoolController
49
import com.flipcash.services.models.PoolMetadata
10+
import com.getcode.vendor.Base58
511
import com.getcode.view.BaseViewModel2
612
import dagger.hilt.android.lifecycle.HiltViewModel
13+
import kotlinx.coroutines.flow.map
14+
import kotlinx.coroutines.launch
715
import javax.inject.Inject
816

917
@HiltViewModel
1018
internal class PoolListViewModel @Inject constructor(
11-
private val poolsController: PoolController,
12-
): BaseViewModel2<PoolListViewModel.State, PoolListViewModel.Event>(
19+
poolsCoordinator: PoolsCoordinator,
20+
) : BaseViewModel2<PoolListViewModel.State, PoolListViewModel.Event>(
1321
initialState = State(),
1422
updateStateForEvent = updateStateForEvent,
1523
) {
1624
data class State(
17-
val pools: List<PoolMetadata> = emptyList()
25+
val stub: String = "",
1826
)
1927

2028
sealed interface Event {
21-
data class OnPoolsUpdated(val pools: List<PoolMetadata>) : Event
22-
data class OnPoolClicked(val pool: PoolMetadata) : Event
23-
data object OnCreatePool: Event
29+
data class OnPoolClicked(val pool: Pool) : Event
30+
data object OnCreatePool : Event
2431
}
2532

26-
init {
27-
28-
}
33+
val pools = poolsCoordinator.pools
34+
.map { pagingData ->
35+
pagingData.insertSeparators { before, after ->
36+
return@insertSeparators null
37+
}
38+
}.cachedIn(viewModelScope)
2939

3040
internal companion object {
3141
val updateStateForEvent: (Event) -> ((State) -> State) = { event ->
3242
when (event) {
33-
is Event.OnPoolsUpdated -> { state -> state.copy(pools = event.pools) }
3443
is Event.OnPoolClicked -> { state -> state }
3544
is Event.OnCreatePool -> { state -> state }
3645
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.flipcash.app.pools.internal.list.components
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.material.Icon
8+
import androidx.compose.material.Text
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.remember
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.res.painterResource
14+
import androidx.compose.ui.res.stringResource
15+
import com.flipcash.app.core.pools.Pool
16+
import com.flipcash.app.core.pools.PoolResolution
17+
import com.flipcash.features.pools.R
18+
import com.getcode.theme.CodeTheme
19+
20+
@Composable
21+
internal fun PoolSummaryRow(
22+
pool: Pool,
23+
modifier: Modifier = Modifier,
24+
onClick: () -> Unit,
25+
) {
26+
val isCompleted = remember(pool) { pool.resolution != PoolResolution.NotSet }
27+
val didWin = remember(pool) { pool.didWin }
28+
29+
Row(
30+
modifier = modifier
31+
.clickable(onClick = onClick)
32+
.padding(
33+
horizontal = CodeTheme.dimens.grid.x2,
34+
vertical = CodeTheme.dimens.grid.x2,
35+
),
36+
verticalAlignment = Alignment.CenterVertically,
37+
) {
38+
Column(
39+
modifier = Modifier
40+
.weight(1f)
41+
.padding(start = CodeTheme.dimens.grid.x2),
42+
) {
43+
Text(
44+
text = pool.name,
45+
style = CodeTheme.typography.textMedium,
46+
color = CodeTheme.colors.textMain,
47+
)
48+
Text(
49+
text = when {
50+
isCompleted && didWin -> stringResource(R.string.subtitle_wonInPool, pool.buyIn.formatted())
51+
isCompleted -> stringResource(R.string.subtitle_lostInPool, pool.buyIn.formatted())
52+
else -> stringResource(R.string.subtitle_amountInPool, pool.buyIn.formatted())
53+
},
54+
style = CodeTheme.typography.textSmall,
55+
color = CodeTheme.colors.textSecondary,
56+
)
57+
}
58+
59+
Icon(
60+
painter = painterResource(id = R.drawable.ic_chevron_right),
61+
contentDescription = null,
62+
tint = CodeTheme.colors.secondary,
63+
)
64+
65+
}
66+
}

apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/pools/PoolEntityToPoolMapper.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class PoolEntityToPoolMapper @Inject constructor() : Mapper<PoolEntity, Pool> {
2222
isOpen = from.isOpen,
2323
resolution = PoolResolutionConverter.toPoolResolution(from.resolution),
2424
createdAt = from.createdAt,
25+
didWin = from.didWin
2526
)
2627
}
2728
}

apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/FlipcashDesignSystem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ private val colors = with(FlipcashColorSpec) {
3939
brandDark = BrandDark,
4040
brandOverlay = BrandOverlay,
4141
brandContainer = primary,
42-
secondary = BrandAccent,
42+
secondary = secondaryText,
4343
tertiary = BrandAccent,
4444
indicator = BrandIndicator,
4545
action = Gray50,

0 commit comments

Comments
 (0)