Skip to content

Commit be78ced

Browse files
committed
feat: add unread indicator support to HomeBottom
cleanup in process, removing ConstraintLayout and hoisting some state Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 2b67062 commit be78ced

6 files changed

Lines changed: 136 additions & 92 deletions

File tree

app/src/main/java/com/getcode/view/components/Badge.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.getcode.view.components
22

3+
import androidx.compose.animation.AnimatedVisibility
34
import androidx.compose.material.Text
45
import androidx.compose.runtime.Composable
56
import androidx.compose.ui.Modifier
@@ -16,7 +17,7 @@ fun Badge(
1617
color: Color = CodeTheme.colors.brand,
1718
contentColor: Color = Color.White,
1819
) {
19-
if (count > 0) {
20+
AnimatedVisibility(visible = count > 0) {
2021
val text = when {
2122
count in 1..99 -> "$count"
2223
else -> "99+"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.getcode.view.components
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.PaddingValues
6+
import androidx.compose.foundation.layout.RowScope
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.layout.requiredWidth
11+
import androidx.compose.runtime.Composable
12+
import androidx.compose.ui.Alignment
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.unit.dp
15+
import com.getcode.util.calculateEndPadding
16+
import com.getcode.util.calculateStartPadding
17+
import com.getcode.util.calculateVerticalPadding
18+
19+
@Composable
20+
inline fun Row(
21+
modifier: Modifier = Modifier,
22+
contentPadding: PaddingValues = PaddingValues(0.dp),
23+
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
24+
verticalAlignment: Alignment.Vertical = Alignment.Top,
25+
content: @Composable RowScope.() -> Unit,
26+
) {
27+
Box(modifier = modifier) {
28+
androidx.compose.foundation.layout.Row(
29+
modifier = Modifier
30+
.fillMaxWidth()
31+
.padding(vertical = contentPadding.calculateVerticalPadding()),
32+
horizontalArrangement = horizontalArrangement,
33+
verticalAlignment = verticalAlignment,
34+
) {
35+
Spacer(modifier = Modifier.requiredWidth(contentPadding.calculateStartPadding()))
36+
content()
37+
Spacer(modifier = Modifier.requiredWidth(contentPadding.calculateEndPadding()))
38+
}
39+
}
40+
}

app/src/main/java/com/getcode/view/components/chat/ChatNode.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,10 @@ fun ChatNode(
9090
tint = BrandLight
9191
)
9292
} else {
93-
AnimatedVisibility(visible = hasUnreadMessages) {
94-
Badge(
95-
count = chat.unreadCount,
96-
color = ChatNodeDefaults.UnreadIndicator
97-
)
98-
}
93+
Badge(
94+
count = chat.unreadCount,
95+
color = ChatNodeDefaults.UnreadIndicator
96+
)
9997
}
10098
}
10199
}

app/src/main/java/com/getcode/view/main/home/DecorView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ internal fun DecorView(
146146

147147
HomeBottom(
148148
modifier = Modifier
149-
.fillMaxWidth()
150149
.windowInsetsPadding(WindowInsets.navigationBars)
151150
.padding(bottom = CodeTheme.dimens.grid.x3),
151+
state = dataState,
152152
onPress = {
153153
showBottomSheet(it)
154154
},

app/src/main/java/com/getcode/view/main/home/HomeViewModel.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import com.getcode.models.PaymentState
3939
import com.getcode.models.Valuation
4040
import com.getcode.models.amountFloored
4141
import com.getcode.network.BalanceController
42+
import com.getcode.network.HistoryController
4243
import com.getcode.network.client.Client
4344
import com.getcode.network.client.RemoteSendException
4445
import com.getcode.network.client.awaitEstablishRelationship
@@ -92,10 +93,12 @@ import kotlinx.coroutines.flow.SharedFlow
9293
import kotlinx.coroutines.flow.asSharedFlow
9394
import kotlinx.coroutines.flow.collectLatest
9495
import kotlinx.coroutines.flow.combine
96+
import kotlinx.coroutines.flow.distinctUntilChanged
9597
import kotlinx.coroutines.flow.distinctUntilChangedBy
9698
import kotlinx.coroutines.flow.filter
9799
import kotlinx.coroutines.flow.flowOn
98100
import kotlinx.coroutines.flow.launchIn
101+
import kotlinx.coroutines.flow.map
99102
import kotlinx.coroutines.flow.onEach
100103
import kotlinx.coroutines.flow.update
101104
import kotlinx.coroutines.launch
@@ -130,6 +133,7 @@ data class HomeUiModel(
130133
val billState: BillState = BillState.Default,
131134
val restrictionType: RestrictionType? = null,
132135
val isRemoteSendLoading: Boolean = false,
136+
val chatUnreadCount: Int = 0,
133137
)
134138

135139
sealed interface HomeEvent {
@@ -150,6 +154,7 @@ class HomeViewModel @Inject constructor(
150154
private val receiveTransactionRepository: ReceiveTransactionRepository,
151155
private val paymentRepository: PaymentRepository,
152156
private val balanceController: BalanceController,
157+
private val historyController: HistoryController,
153158
private val prefRepository: PrefRepository,
154159
private val analytics: AnalyticsService,
155160
private val authManager: AuthManager,
@@ -194,6 +199,13 @@ class HomeViewModel @Inject constructor(
194199
}
195200
}.launchIn(viewModelScope)
196201

202+
historyController.unreadCount
203+
.distinctUntilChanged()
204+
.map { it }
205+
.onEach { count ->
206+
uiFlow.update { it.copy(chatUnreadCount = count) }
207+
}.launchIn(viewModelScope)
208+
197209
prefRepository.observeOrDefault(PrefsBool.LOG_SCAN_TIMES, false)
198210
.flowOn(Dispatchers.IO)
199211
.onEach { log ->
Lines changed: 77 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,115 @@
11
package com.getcode.view.main.home.components
22

33
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.Box
45
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.PaddingValues
7+
import androidx.compose.foundation.layout.Spacer
58
import androidx.compose.foundation.layout.fillMaxWidth
6-
import androidx.compose.foundation.layout.height
79
import androidx.compose.foundation.layout.padding
8-
import androidx.compose.foundation.layout.width
9-
import androidx.compose.foundation.shape.RoundedCornerShape
10-
import androidx.compose.material.MaterialTheme
10+
import androidx.compose.foundation.layout.size
1111
import androidx.compose.material.Text
1212
import androidx.compose.runtime.Composable
1313
import androidx.compose.ui.Alignment
1414
import androidx.compose.ui.Modifier
1515
import androidx.compose.ui.draw.clip
16+
import androidx.compose.ui.graphics.painter.Painter
1617
import androidx.compose.ui.res.painterResource
1718
import androidx.compose.ui.res.stringResource
1819
import androidx.compose.ui.tooling.preview.Preview
19-
import androidx.compose.ui.unit.dp
20-
import androidx.constraintlayout.compose.ConstraintLayout
20+
import androidx.compose.ui.unit.Dp
2121
import com.getcode.R
2222
import com.getcode.theme.CodeTheme
2323
import com.getcode.util.rememberedClickable
24+
import com.getcode.view.components.Badge
25+
import com.getcode.view.components.Row
26+
import com.getcode.view.components.chat.ChatNodeDefaults
2427
import com.getcode.view.main.home.HomeBottomSheet
28+
import com.getcode.view.main.home.HomeUiModel
2529

2630
@Preview
2731
@Composable
2832
internal fun HomeBottom(
2933
modifier: Modifier = Modifier,
34+
state: HomeUiModel = HomeUiModel(),
3035
onPress: (homeBottomSheet: HomeBottomSheet) -> Unit = {},
3136
) {
32-
ConstraintLayout(modifier = modifier.fillMaxWidth()) {
33-
val (button1, button2, button3) = createRefs()
34-
35-
Column(modifier = Modifier
36-
.constrainAs(button2) {
37-
centerHorizontallyTo(parent)
38-
bottom.linkTo(parent.bottom)
39-
}
40-
.clip(
41-
RoundedCornerShape(10.dp)
42-
)
43-
.rememberedClickable { onPress(HomeBottomSheet.GIVE_KIN) },
44-
horizontalAlignment = Alignment.CenterHorizontally
45-
) {
46-
Image(
47-
modifier = Modifier
48-
.padding(horizontal = 15.dp)
49-
.padding(vertical = 11.dp)
50-
.height(51.dp)
51-
.width(51.dp),
52-
painter = painterResource(
53-
R.drawable.ic_kin_white
54-
),
55-
contentDescription = stringResource(R.string.action_giveKin),
56-
)
57-
Text(
58-
text = stringResource(R.string.action_giveKin),
59-
style = CodeTheme.typography.body2
60-
)
61-
}
37+
Row(
38+
modifier = Modifier
39+
.fillMaxWidth()
40+
.then(modifier),
41+
verticalAlignment = Alignment.Bottom,
42+
contentPadding = PaddingValues(horizontal = CodeTheme.dimens.grid.x3),
43+
) {
44+
BottomBarAction(
45+
label = stringResource(R.string.title_getKin),
46+
contentPadding = PaddingValues(
47+
start = CodeTheme.dimens.grid.x3,
48+
end = CodeTheme.dimens.grid.x3,
49+
top = CodeTheme.dimens.grid.x1,
50+
bottom = CodeTheme.dimens.grid.x2,
51+
),
52+
imageSize = CodeTheme.dimens.grid.x6,
53+
painter = painterResource(R.drawable.ic_wallet),
54+
onClick = { onPress(HomeBottomSheet.GET_KIN) }
55+
)
56+
Spacer(modifier = Modifier.weight(1f))
57+
BottomBarAction(
58+
label = stringResource(R.string.action_giveKin),
59+
contentPadding = PaddingValues(
60+
horizontal = CodeTheme.dimens.grid.x3,
61+
vertical = CodeTheme.dimens.grid.x2
62+
),
63+
imageSize = CodeTheme.dimens.grid.x10,
64+
painter = painterResource(R.drawable.ic_kin_white),
65+
onClick = { onPress(HomeBottomSheet.GIVE_KIN) }
66+
)
67+
Spacer(modifier = Modifier.weight(1f))
68+
BottomBarAction(
69+
label = stringResource(R.string.action_balance),
70+
contentPadding = PaddingValues(
71+
horizontal = CodeTheme.dimens.grid.x2,
72+
),
73+
imageSize = CodeTheme.dimens.grid.x9,
74+
painter = painterResource(R.drawable.ic_history),
75+
onClick = { onPress(HomeBottomSheet.BALANCE) },
76+
badge = { Badge(count = state.chatUnreadCount, color = ChatNodeDefaults.UnreadIndicator) }
77+
)
78+
}
79+
}
6280

63-
Column(modifier = Modifier
64-
.constrainAs(button1) {
65-
start.linkTo(parent.start)
66-
bottom.linkTo(parent.bottom)
67-
}
68-
.padding(start = 15.dp)
69-
.clip(
70-
RoundedCornerShape(10.dp, 10.dp, 10.dp, 10.dp)
71-
)
72-
.rememberedClickable {
73-
onPress(HomeBottomSheet.GET_KIN)
74-
},
81+
@Composable
82+
private fun BottomBarAction(
83+
modifier: Modifier = Modifier,
84+
label: String,
85+
contentPadding: PaddingValues = PaddingValues(),
86+
painter: Painter,
87+
imageSize: Dp,
88+
badge: @Composable () -> Unit = { },
89+
onClick: () -> Unit,
90+
) {
91+
Box(modifier = modifier) {
92+
Column(
93+
modifier = Modifier
94+
.align(Alignment.Center)
95+
.clip(CodeTheme.shapes.medium)
96+
.rememberedClickable { onClick() },
7597
horizontalAlignment = Alignment.CenterHorizontally
7698
) {
7799
Image(
78100
modifier = Modifier
79-
.padding(horizontal = 15.dp)
80-
.padding(bottom = 8.dp, top = 5.dp)
81-
.height(32.dp)
82-
.width(32.dp),
83-
painter = painterResource(
84-
R.drawable.ic_wallet
85-
),
86-
contentDescription = stringResource(R.string.title_getKin),
101+
.padding(contentPadding)
102+
.size(imageSize),
103+
painter = painter,
104+
contentDescription = null,
87105
)
88106
Text(
89-
text = stringResource(R.string.title_getKin),
107+
text = label,
90108
style = CodeTheme.typography.body2
91109
)
92110
}
93-
94-
Column(modifier = Modifier
95-
.constrainAs(button3) {
96-
end.linkTo(parent.end)
97-
bottom.linkTo(parent.bottom)
98-
}
99-
.padding(end = 15.dp)
100-
.clip(
101-
RoundedCornerShape(10.dp, 10.dp, 10.dp, 10.dp)
102-
)
103-
.rememberedClickable { onPress(HomeBottomSheet.BALANCE) },
104-
horizontalAlignment = Alignment.CenterHorizontally
105-
) {
106-
Image(
107-
modifier = Modifier
108-
.padding(horizontal = 10.dp)
109-
.height(44.dp)
110-
.width(44.dp),
111-
painter = painterResource(
112-
R.drawable.ic_history
113-
),
114-
contentDescription = stringResource(R.string.action_balance),
115-
)
116-
Text(
117-
text = stringResource(R.string.action_balance),
118-
style = CodeTheme.typography.body2
119-
)
111+
Box(modifier = Modifier.align(Alignment.TopEnd)) {
112+
badge()
120113
}
121114
}
122115
}

0 commit comments

Comments
 (0)