Skip to content

Commit 5d79459

Browse files
authored
Merge pull request #3790 from CruGlobal/circuitDashboardHome
GT-2314 use Circuit to render the Dashboard Home
2 parents 1ed32f3 + b2ca1c8 commit 5d79459

29 files changed

Lines changed: 674 additions & 225 deletions

File tree

app/src/main/kotlin/org/cru/godtools/ui/dashboard/DashboardLayout.kt

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ import org.cru.godtools.base.ui.theme.GodToolsTheme
5757
import org.cru.godtools.model.Tool
5858
import org.cru.godtools.shared.analytics.AnalyticsScreenNames
5959
import org.cru.godtools.ui.dashboard.home.AllFavoritesScreen
60-
import org.cru.godtools.ui.dashboard.home.DashboardHomeEvent
61-
import org.cru.godtools.ui.dashboard.home.HomeContent
60+
import org.cru.godtools.ui.dashboard.home.HomeScreen
6261
import org.cru.godtools.ui.dashboard.lessons.DashboardLessonsEvent
6362
import org.cru.godtools.ui.dashboard.lessons.LessonsLayout
6463
import org.cru.godtools.ui.dashboard.tools.ToolsScreen
@@ -130,33 +129,23 @@ internal fun DashboardLayout(onEvent: (DashboardEvent) -> Unit, viewModel: Dashb
130129
},
131130
)
132131

133-
Page.HOME -> HomeContent(
134-
onEvent = {
135-
when (it) {
136-
DashboardHomeEvent.ViewAllFavorites -> {
137-
saveableStateHolder.removeState(Page.FAVORITE_TOOLS)
138-
viewModel.updateCurrentPage(Page.FAVORITE_TOOLS, false)
139-
}
140-
DashboardHomeEvent.ViewAllTools -> viewModel.updateCurrentPage(Page.ALL_TOOLS)
141-
is DashboardHomeEvent.OpenTool ->
142-
onEvent(DashboardEvent.OpenTool(it.tool, it.type, it.lang1, it.lang2))
143-
is DashboardHomeEvent.OpenToolDetails ->
144-
onEvent(DashboardEvent.OpenToolDetails(it.tool))
145-
}
146-
}
147-
)
148-
132+
Page.HOME,
149133
Page.FAVORITE_TOOLS,
150134
Page.ALL_TOOLS -> {
151135
CircuitContent(
152136
screen = when (page) {
137+
Page.HOME -> HomeScreen
153138
Page.FAVORITE_TOOLS -> AllFavoritesScreen
154139
Page.ALL_TOOLS -> ToolsScreen
155140
else -> error("Page $page is not converted to Circuit yet")
156141
},
157142
onNavEvent = {
158143
when (it) {
159144
is NavEvent.GoTo -> when (val screen = it.screen) {
145+
AllFavoritesScreen -> {
146+
saveableStateHolder.removeState(Page.FAVORITE_TOOLS)
147+
viewModel.updateCurrentPage(Page.FAVORITE_TOOLS, false)
148+
}
160149
is IntentScreen -> onEvent(DashboardEvent.OpenIntent(screen.intent))
161150
is ToolDetailsScreen -> onEvent(
162151
DashboardEvent.OpenToolDetails(
@@ -165,6 +154,9 @@ internal fun DashboardLayout(onEvent: (DashboardEvent) -> Unit, viewModel: Dashb
165154
)
166155
)
167156
}
157+
is NavEvent.ResetRoot -> when (it.newRoot) {
158+
ToolsScreen -> viewModel.updateCurrentPage(Page.ALL_TOOLS)
159+
}
168160
else -> Unit
169161
}
170162
},

app/src/main/kotlin/org/cru/godtools/ui/dashboard/home/HomeLayout.kt

Lines changed: 44 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -21,60 +21,37 @@ import androidx.compose.material3.Surface
2121
import androidx.compose.material3.Text
2222
import androidx.compose.runtime.Composable
2323
import androidx.compose.runtime.LaunchedEffect
24-
import androidx.compose.runtime.collectAsState
25-
import androidx.compose.runtime.derivedStateOf
2624
import androidx.compose.runtime.getValue
27-
import androidx.compose.runtime.remember
25+
import androidx.compose.runtime.rememberUpdatedState
2826
import androidx.compose.ui.Alignment
2927
import androidx.compose.ui.Modifier
3028
import androidx.compose.ui.graphics.RectangleShape
3129
import androidx.compose.ui.res.stringResource
3230
import androidx.compose.ui.text.style.TextAlign
33-
import androidx.compose.ui.tooling.preview.Preview
3431
import androidx.compose.ui.unit.dp
35-
import androidx.lifecycle.viewmodel.compose.viewModel
36-
import java.util.Locale
37-
import org.cru.godtools.BuildConfig
32+
import com.slack.circuit.codegen.annotations.CircuitInject
33+
import dagger.hilt.components.SingletonComponent
3834
import org.cru.godtools.R
39-
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.ACTION_OPEN_LESSON
40-
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.ACTION_OPEN_TOOL
41-
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.ACTION_OPEN_TOOL_DETAILS
42-
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.SOURCE_FAVORITE
43-
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.SOURCE_FEATURED
44-
import org.cru.godtools.model.Tool
4535
import org.cru.godtools.ui.banner.Banners
36+
import org.cru.godtools.ui.dashboard.home.HomeScreen.UiEvent
37+
import org.cru.godtools.ui.dashboard.home.HomeScreen.UiState
4638
import org.cru.godtools.ui.tools.LessonToolCard
47-
import org.cru.godtools.ui.tools.PreloadTool
4839
import org.cru.godtools.ui.tools.SquareToolCard
49-
import org.cru.godtools.ui.tools.ToolCardEvent
5040

5141
private val PADDING_HORIZONTAL = 16.dp
5242

53-
internal sealed interface DashboardHomeEvent {
54-
open class OpenTool(val tool: String?, val type: Tool.Type?, val lang1: Locale?, val lang2: Locale? = null) :
55-
DashboardHomeEvent {
56-
constructor(event: ToolCardEvent) : this(event.tool, event.toolType, event.lang1, event.lang2)
57-
}
58-
open class OpenToolDetails(val tool: String?) : DashboardHomeEvent {
59-
constructor(event: ToolCardEvent.OpenToolDetails) : this(event.tool)
60-
}
61-
class OpenLesson(event: ToolCardEvent) : OpenTool(event.tool, Tool.Type.LESSON, event.lang1)
62-
data object ViewAllFavorites : DashboardHomeEvent
63-
data object ViewAllTools : DashboardHomeEvent
64-
}
65-
6643
@Composable
67-
internal fun HomeContent(onEvent: (DashboardHomeEvent) -> Unit, viewModel: HomeViewModel = viewModel()) {
68-
val favoriteTools by viewModel.favoriteTools.collectAsState()
69-
val spotlightLessons by viewModel.spotlightLessons.collectAsState()
70-
val favoriteToolsLoaded by remember { derivedStateOf { favoriteTools != null } }
71-
val hasFavoriteTools by remember { derivedStateOf { !favoriteTools.isNullOrEmpty() } }
44+
@CircuitInject(HomeScreen::class, SingletonComponent::class)
45+
internal fun HomeLayout(state: UiState, modifier: Modifier = Modifier) {
46+
val banner by rememberUpdatedState(state.banner)
47+
val favoriteToolsLoaded by rememberUpdatedState(state.favoriteToolsLoaded)
48+
49+
val hasFavoriteTools by rememberUpdatedState(state.favoriteTools.isNotEmpty())
7250

7351
val columnState = rememberLazyListState()
74-
val banner by viewModel.banner.collectAsState()
7552
LaunchedEffect(banner) { if (banner != null) columnState.animateScrollToItem(0) }
7653

77-
LazyColumn(state = columnState, contentPadding = PaddingValues(bottom = 16.dp)) {
54+
LazyColumn(state = columnState, contentPadding = PaddingValues(bottom = 16.dp), modifier = modifier) {
7855
item("banners", "banners") {
7956
Banners(
8057
{ banner },
@@ -94,7 +71,7 @@ internal fun HomeContent(onEvent: (DashboardHomeEvent) -> Unit, viewModel: HomeV
9471
}
9572

9673
// featured lessons
97-
if (spotlightLessons.isNotEmpty()) {
74+
if (state.spotlightLessons.isNotEmpty()) {
9875
item("lesson-header", "lesson-header") {
9976
FeaturedLessonsHeader(
10077
modifier = Modifier
@@ -104,20 +81,13 @@ internal fun HomeContent(onEvent: (DashboardHomeEvent) -> Unit, viewModel: HomeV
10481
)
10582
}
10683

107-
items(spotlightLessons, key = { it }, contentType = { "lesson-tool-card" }) { lesson ->
84+
items(
85+
state.spotlightLessons,
86+
key = { it.toolCode.orEmpty() },
87+
contentType = { "lesson-tool-card" }
88+
) { lessonState ->
10889
LessonToolCard(
109-
lesson,
110-
onEvent = {
111-
when (it) {
112-
is ToolCardEvent.Click, is ToolCardEvent.OpenTool -> {
113-
viewModel.recordOpenClickInAnalytics(ACTION_OPEN_LESSON, it.tool, SOURCE_FEATURED)
114-
onEvent(DashboardHomeEvent.OpenLesson(it))
115-
}
116-
is ToolCardEvent.OpenToolDetails -> {
117-
if (BuildConfig.DEBUG) error("$it is currently unsupported for Lesson Cards")
118-
}
119-
}
120-
},
90+
lessonState,
12191
modifier = Modifier
12292
.animateItem()
12393
.padding(horizontal = PADDING_HORIZONTAL)
@@ -130,8 +100,7 @@ internal fun HomeContent(onEvent: (DashboardHomeEvent) -> Unit, viewModel: HomeV
130100
if (favoriteToolsLoaded) {
131101
item("favorites-header") {
132102
FavoritesHeader(
133-
showViewAll = { hasFavoriteTools },
134-
onEvent = onEvent,
103+
state = state,
135104
modifier = Modifier
136105
.animateItem()
137106
.padding(horizontal = PADDING_HORIZONTAL)
@@ -142,22 +111,7 @@ internal fun HomeContent(onEvent: (DashboardHomeEvent) -> Unit, viewModel: HomeV
142111
if (hasFavoriteTools) {
143112
item("favorites", "favorites") {
144113
HorizontalFavoriteTools(
145-
{ favoriteTools.orEmpty().take(5) },
146-
onEvent = {
147-
when {
148-
it is DashboardHomeEvent.OpenTool -> viewModel.recordOpenClickInAnalytics(
149-
ACTION_OPEN_TOOL,
150-
it.tool,
151-
SOURCE_FAVORITE
152-
)
153-
it is DashboardHomeEvent.OpenToolDetails -> viewModel.recordOpenClickInAnalytics(
154-
ACTION_OPEN_TOOL_DETAILS,
155-
it.tool,
156-
SOURCE_FAVORITE
157-
)
158-
}
159-
onEvent(it)
160-
},
114+
state,
161115
modifier = Modifier
162116
.animateItem()
163117
.fillMaxWidth()
@@ -166,7 +120,7 @@ internal fun HomeContent(onEvent: (DashboardHomeEvent) -> Unit, viewModel: HomeV
166120
} else {
167121
item("favorites-empty", "favorites-empty") {
168122
NoFavoriteTools(
169-
onEvent = onEvent,
123+
state = state,
170124
modifier = Modifier
171125
.animateItem()
172126
.padding(horizontal = PADDING_HORIZONTAL)
@@ -192,11 +146,9 @@ private fun FeaturedLessonsHeader(modifier: Modifier = Modifier) = Text(
192146
)
193147

194148
@Composable
195-
private fun FavoritesHeader(
196-
showViewAll: () -> Boolean,
197-
onEvent: (DashboardHomeEvent) -> Unit,
198-
modifier: Modifier = Modifier,
199-
) = Row(modifier = modifier.fillMaxWidth()) {
149+
private fun FavoritesHeader(state: UiState, modifier: Modifier = Modifier) = Row(modifier = modifier.fillMaxWidth()) {
150+
val eventSink by rememberUpdatedState(state.eventSink)
151+
200152
Text(
201153
stringResource(R.string.dashboard_home_section_favorites_title),
202154
style = MaterialTheme.typography.titleLarge,
@@ -206,7 +158,7 @@ private fun FavoritesHeader(
206158
)
207159

208160
AnimatedVisibility(
209-
showViewAll(),
161+
state.favoriteTools.isNotEmpty(),
210162
enter = fadeIn(),
211163
exit = fadeOut(),
212164
modifier = Modifier.alignByBaseline()
@@ -215,47 +167,38 @@ private fun FavoritesHeader(
215167
stringResource(R.string.dashboard_home_section_favorites_action_view_all),
216168
style = MaterialTheme.typography.bodySmall,
217169
color = MaterialTheme.colorScheme.primary,
218-
modifier = Modifier.clickable { onEvent(DashboardHomeEvent.ViewAllFavorites) }
170+
modifier = Modifier.clickable { eventSink(UiEvent.ViewAllFavorites) }
219171
)
220172
}
221173
}
222174

223175
@Composable
224-
private fun HorizontalFavoriteTools(
225-
tools: () -> List<Tool>,
226-
onEvent: (DashboardHomeEvent) -> Unit,
227-
modifier: Modifier = Modifier,
228-
) = LazyRow(
229-
contentPadding = PaddingValues(horizontal = 16.dp),
230-
horizontalArrangement = Arrangement.spacedBy(16.dp),
231-
modifier = modifier
232-
) {
233-
items(tools(), key = { it.code.orEmpty() }) {
234-
PreloadTool(it)
235-
236-
SquareToolCard(
237-
toolCode = it.code.orEmpty(),
238-
confirmRemovalFromFavorites = true,
239-
onEvent = {
240-
when (it) {
241-
is ToolCardEvent.Click, is ToolCardEvent.OpenTool -> onEvent(DashboardHomeEvent.OpenTool(it))
242-
is ToolCardEvent.OpenToolDetails -> onEvent(DashboardHomeEvent.OpenToolDetails(it))
243-
}
244-
},
245-
modifier = Modifier.animateItem()
246-
)
176+
private fun HorizontalFavoriteTools(state: UiState, modifier: Modifier = Modifier) {
177+
LazyRow(
178+
contentPadding = PaddingValues(horizontal = 16.dp),
179+
horizontalArrangement = Arrangement.spacedBy(16.dp),
180+
modifier = modifier
181+
) {
182+
items(state.favoriteTools, key = { it.toolCode.orEmpty() }) { toolState ->
183+
SquareToolCard(
184+
state = toolState,
185+
confirmRemovalFromFavorites = true,
186+
modifier = Modifier.animateItem()
187+
)
188+
}
247189
}
248190
}
249191

250-
@Preview
251192
@Composable
252-
private fun NoFavoriteTools(modifier: Modifier = Modifier, onEvent: (DashboardHomeEvent) -> Unit = {}) = Surface(
193+
private fun NoFavoriteTools(state: UiState, modifier: Modifier = Modifier) = Surface(
253194
color = MaterialTheme.colorScheme.surfaceVariant,
254195
shape = RectangleShape,
255196
modifier = modifier
256197
.fillMaxWidth()
257198
.heightIn(min = 215.dp)
258199
) {
200+
val eventSink by rememberUpdatedState(state.eventSink)
201+
259202
Column(verticalArrangement = Arrangement.Center, modifier = Modifier.padding(16.dp)) {
260203
Text(
261204
stringResource(R.string.dashboard_home_section_favorites_no_tools_title),
@@ -270,7 +213,7 @@ private fun NoFavoriteTools(modifier: Modifier = Modifier, onEvent: (DashboardHo
270213
modifier = Modifier.fillMaxWidth()
271214
)
272215
Button(
273-
onClick = { onEvent(DashboardHomeEvent.ViewAllTools) },
216+
onClick = { eventSink(UiEvent.ViewAllTools) },
274217
modifier = Modifier
275218
.padding(top = 8.dp)
276219
.align(Alignment.CenterHorizontally)

0 commit comments

Comments
 (0)