Skip to content

Commit f437d3a

Browse files
frettclaude
andcommitted
Introduce ToolCardEvent sealed interface for card-level UiEvents
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 33c022e commit f437d3a

21 files changed

Lines changed: 115 additions & 123 deletions

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ import org.cru.godtools.db.repository.ToolsRepository
3232
import org.cru.godtools.model.Tool
3333
import org.cru.godtools.ui.dashboard.home.AllFavoritesPresenter.UiState
3434
import org.cru.godtools.ui.tooldetails.ToolDetailsScreen
35-
import org.cru.godtools.ui.tools.ToolCard
3635
import org.cru.godtools.ui.tools.ToolCardPresenter
36+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
3737
import org.cru.godtools.util.createToolIntent
3838
import org.greenrobot.eventbus.EventBus
3939

@@ -69,8 +69,8 @@ class AllFavoritesPresenter @AssistedInject constructor(
6969
lateinit var state: ToolCardPresenter.UiState
7070
state = toolCardPresenter.present(tool) {
7171
when (it) {
72-
ToolCardPresenter.UiEvent.Click,
73-
ToolCardPresenter.UiEvent.OpenTool -> {
72+
ToolCardEvent.Click,
73+
ToolCardEvent.OpenTool -> {
7474
val intent = context.createToolIntent(
7575
tool = tool,
7676
languages = listOfNotNull(
@@ -88,16 +88,12 @@ class AllFavoritesPresenter @AssistedInject constructor(
8888
}
8989
}
9090

91-
ToolCardPresenter.UiEvent.OpenToolDetails -> {
91+
ToolCardEvent.OpenToolDetails -> {
9292
eventBus.post(
9393
OpenAnalyticsActionEvent(ACTION_OPEN_TOOL_DETAILS, toolCode, SOURCE_FAVORITE)
9494
)
9595
navigator.goTo(ToolDetailsScreen(toolCode))
9696
}
97-
98-
ToolCardPresenter.UiEvent.PinTool,
99-
ToolCardPresenter.UiEvent.UnpinTool ->
100-
error("$it should be handled by the ToolCardPresenter")
10197
}
10298
}
10399
state

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ import org.cru.godtools.ui.banner.BannerPresenter
3535
import org.cru.godtools.ui.banner.tutorial.TutorialFeaturesBannerPresenter
3636
import org.cru.godtools.ui.dashboard.home.HomePresenter.UiState
3737
import org.cru.godtools.ui.tooldetails.ToolDetailsScreen
38-
import org.cru.godtools.ui.tools.ToolCard
3938
import org.cru.godtools.ui.tools.ToolCardPresenter
39+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
4040
import org.cru.godtools.util.createToolIntent
4141
import org.greenrobot.eventbus.EventBus
4242

@@ -94,7 +94,7 @@ class HomePresenter @AssistedInject constructor(
9494
lateinit var lessonState: ToolCardPresenter.UiState
9595
lessonState = toolCardPresenter.present(lesson) {
9696
when (it) {
97-
ToolCardPresenter.UiEvent.Click -> {
97+
ToolCardEvent.Click -> {
9898
val intent = context.createToolIntent(
9999
tool = lesson,
100100
languages = listOfNotNull(lessonState.translation?.languageCode),
@@ -133,8 +133,8 @@ class HomePresenter @AssistedInject constructor(
133133
lateinit var state: ToolCardPresenter.UiState
134134
state = toolCardPresenter.present(tool) {
135135
when (it) {
136-
ToolCardPresenter.UiEvent.Click,
137-
ToolCardPresenter.UiEvent.OpenTool -> {
136+
ToolCardEvent.Click,
137+
ToolCardEvent.OpenTool -> {
138138
val intent = context.createToolIntent(
139139
tool = tool,
140140
languages = listOfNotNull(
@@ -152,15 +152,12 @@ class HomePresenter @AssistedInject constructor(
152152
}
153153
}
154154

155-
ToolCardPresenter.UiEvent.OpenToolDetails -> {
155+
ToolCardEvent.OpenToolDetails -> {
156156
eventBus.post(
157157
OpenAnalyticsActionEvent(ACTION_OPEN_TOOL_DETAILS, toolCode, SOURCE_FAVORITE)
158158
)
159159
navigator.goTo(ToolDetailsScreen(toolCode))
160160
}
161-
162-
ToolCardPresenter.UiEvent.PinTool,
163-
ToolCardPresenter.UiEvent.UnpinTool -> error("$it should be handled by the ToolCardPresenter")
164161
}
165162
}
166163
state

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ import org.cru.godtools.model.Language
4545
import org.cru.godtools.model.Language.Companion.filterByDisplayAndNativeName
4646
import org.cru.godtools.ui.dashboard.filters.FilterMenu
4747
import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState
48-
import org.cru.godtools.ui.tools.ToolCard
4948
import org.cru.godtools.ui.tools.ToolCardPresenter
49+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
5050
import org.cru.godtools.util.createToolIntent
5151
import org.greenrobot.eventbus.EventBus
5252

@@ -154,7 +154,7 @@ class LessonsPresenter @AssistedInject constructor(
154154
customLocale = locale,
155155
eventSink = {
156156
when (it) {
157-
ToolCardPresenter.UiEvent.Click -> {
157+
ToolCardEvent.Click, ToolCardEvent.OpenTool -> {
158158
eventBus.post(OpenAnalyticsActionEvent(ACTION_OPEN_LESSON, tool.code, SOURCE_LESSONS))
159159
navigator.goTo(
160160
IntentScreen(
@@ -167,10 +167,7 @@ class LessonsPresenter @AssistedInject constructor(
167167
)
168168
}
169169

170-
ToolCardPresenter.UiEvent.OpenTool,
171-
ToolCardPresenter.UiEvent.OpenToolDetails,
172-
ToolCardPresenter.UiEvent.PinTool,
173-
ToolCardPresenter.UiEvent.UnpinTool -> Unit
170+
ToolCardEvent.OpenToolDetails -> Unit
174171
}
175172
}
176173
)

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

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ import org.cru.godtools.ui.dashboard.tools.ToolFiltersStateProducer.Filters
4444
import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiState
4545
import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiState.Mode
4646
import org.cru.godtools.ui.tooldetails.ToolDetailsScreen
47-
import org.cru.godtools.ui.tools.ToolCard
4847
import org.cru.godtools.ui.tools.ToolCardPresenter
48+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
4949
import org.greenrobot.eventbus.EventBus
5050

5151
class ToolsPresenter @AssistedInject internal constructor(
@@ -166,13 +166,10 @@ class ToolsPresenter @AssistedInject internal constructor(
166166
secondLanguage = secondLanguage,
167167
eventSink = {
168168
when (it) {
169-
ToolCardPresenter.UiEvent.Click,
170-
ToolCardPresenter.UiEvent.OpenTool,
171-
ToolCardPresenter.UiEvent.OpenToolDetails ->
169+
ToolCardEvent.Click,
170+
ToolCardEvent.OpenTool,
171+
ToolCardEvent.OpenToolDetails ->
172172
toolCode?.let { eventSink(UiEvent.OpenToolDetails(it, SOURCE_SPOTLIGHT)) }
173-
174-
ToolCardPresenter.UiEvent.PinTool,
175-
ToolCardPresenter.UiEvent.UnpinTool -> error("$it should be handled by the ToolCardPresenter")
176173
}
177174
}
178175
)
@@ -199,14 +196,10 @@ class ToolsPresenter @AssistedInject internal constructor(
199196
secondLanguage = language,
200197
eventSink = {
201198
when (it) {
202-
ToolCardPresenter.UiEvent.Click,
203-
ToolCardPresenter.UiEvent.OpenTool,
204-
ToolCardPresenter.UiEvent.OpenToolDetails ->
199+
ToolCardEvent.Click,
200+
ToolCardEvent.OpenTool,
201+
ToolCardEvent.OpenToolDetails ->
205202
toolCode?.let { eventSink(UiEvent.OpenToolDetails(it, SOURCE_ALL_TOOLS)) }
206-
207-
ToolCardPresenter.UiEvent.PinTool,
208-
ToolCardPresenter.UiEvent.UnpinTool ->
209-
error("$it should be handled by the ToolCardPresenter")
210203
}
211204
}
212205
)

app/src/main/kotlin/org/cru/godtools/ui/tooldetails/ToolDetailsPresenter.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import org.cru.godtools.ui.tooldetails.ToolDetailsScreen.Page
7272
import org.cru.godtools.ui.tooldetails.ToolDetailsScreen.UiEvent
7373
import org.cru.godtools.ui.tooldetails.ToolDetailsScreen.UiState
7474
import org.cru.godtools.ui.tools.ToolCardPresenter
75+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
7576
import org.cru.godtools.util.createToolIntent
7677
import org.greenrobot.eventbus.EventBus
7778

@@ -236,7 +237,7 @@ class ToolDetailsPresenter @AssistedInject constructor(
236237
loadAvailableLanguages = true,
237238
eventSink = {
238239
when (it) {
239-
ToolCardPresenter.UiEvent.Click -> tool.code?.let { onVariantSelect(it) }
240+
ToolCardEvent.Click -> tool.code?.let { onVariantSelect(it) }
240241
else -> Unit
241242
}
242243
}

app/src/main/kotlin/org/cru/godtools/ui/tools/DefaultToolCardPresenter.kt

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.onEach
2525
import kotlinx.coroutines.flow.onStart
2626
import kotlinx.coroutines.flow.shareIn
2727
import kotlinx.coroutines.launch
28+
import kotlinx.coroutines.withContext
2829
import org.ccci.gto.android.common.compose.util.rememberStateFlow
2930
import org.cru.godtools.base.Settings
3031
import org.cru.godtools.base.ToolFileSystem
@@ -39,6 +40,8 @@ import org.cru.godtools.db.repository.rememberLanguage
3940
import org.cru.godtools.model.Language
4041
import org.cru.godtools.model.Tool
4142
import org.cru.godtools.shared.user.activity.UserCounterNames.LESSON_COMPLETION
43+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
44+
import org.cru.godtools.ui.tools.ToolCardPresenter.UiEvent
4245
import org.cru.godtools.ui.tools.ToolCardPresenter.UiState
4346

4447
@Singleton
@@ -59,7 +62,7 @@ internal class DefaultToolCardPresenter @Inject constructor(
5962
loadAppLanguage: Boolean,
6063
secondLanguage: Language?,
6164
loadAvailableLanguages: Boolean,
62-
eventSink: (ToolCardPresenter.UiEvent) -> Unit,
65+
eventSink: (ToolCardEvent) -> Unit,
6366
): UiState {
6467
val coroutineScope = rememberCoroutineScope()
6568
val toolCode by rememberUpdatedState(tool.code)
@@ -115,23 +118,6 @@ internal class DefaultToolCardPresenter @Inject constructor(
115118
val secondTranslation by translationsRepository.produceLatestTranslationState(toolCode, secondLanguage?.code)
116119
val secondLanguageAvailable by remember { derivedStateOf { secondTranslation != null } }
117120

118-
// eventSink
119-
val interceptingEventSink: (ToolCardPresenter.UiEvent) -> Unit = remember(eventSink) {
120-
{
121-
when (it) {
122-
ToolCardPresenter.UiEvent.PinTool -> coroutineScope.launch(NonCancellable) {
123-
toolCode?.let { toolsRepository.pinTool(it) }
124-
}
125-
126-
ToolCardPresenter.UiEvent.UnpinTool -> coroutineScope.launch(NonCancellable) {
127-
toolCode?.let { toolsRepository.unpinTool(it) }
128-
}
129-
130-
else -> eventSink(it)
131-
}
132-
}
133-
}
134-
135121
return UiState(
136122
toolCode = toolCode,
137123
tool = tool,
@@ -155,8 +141,19 @@ internal class DefaultToolCardPresenter @Inject constructor(
155141
!loadAvailableLanguages -> 0
156142
else -> toolCode?.let { rememberAvailableLanguages(it) } ?: 0
157143
},
158-
eventSink = interceptingEventSink,
159-
)
144+
) {
145+
when (it) {
146+
UiEvent.PinTool -> coroutineScope.launch {
147+
withContext(NonCancellable) { toolCode?.let { toolsRepository.pinTool(it) } }
148+
}
149+
150+
UiEvent.UnpinTool -> coroutineScope.launch {
151+
withContext(NonCancellable) { toolCode?.let { toolsRepository.unpinTool(it) } }
152+
}
153+
154+
is ToolCardEvent -> eventSink(it)
155+
}
156+
}
160157
}
161158

162159
@Composable

app/src/main/kotlin/org/cru/godtools/ui/tools/LessonToolCard.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import kotlin.math.roundToInt
2222
import org.ccci.gto.android.common.compose.ui.draw.invisibleIf
2323
import org.cru.godtools.R
2424
import org.cru.godtools.base.ui.util.ProvideLayoutDirectionFromLocale
25-
import org.cru.godtools.ui.tools.ToolCardPresenter.UiEvent
25+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
2626
import org.cru.godtools.ui.tools.ToolCardPresenter.UiState
2727
import org.cru.godtools.ui.tools.ToolCardPresenter.UiState.Progress
2828

@@ -39,7 +39,7 @@ fun LessonToolCard(
3939
val eventSink by rememberUpdatedState(state.eventSink)
4040

4141
ElevatedCard(
42-
onClick = { eventSink(UiEvent.Click) },
42+
onClick = { eventSink(ToolCardEvent.Click) },
4343
elevation = toolCardElevation,
4444
modifier = modifier.fillMaxWidth()
4545
) {

app/src/main/kotlin/org/cru/godtools/ui/tools/SquareToolCard.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import androidx.compose.ui.semantics.hideFromAccessibility
1919
import androidx.compose.ui.unit.dp
2020
import org.ccci.gto.android.common.compose.ui.draw.invisibleIf
2121
import org.cru.godtools.base.ui.util.ProvideLayoutDirectionFromLocale
22+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
2223
import org.cru.godtools.ui.tools.ToolCardPresenter.UiEvent
2324
import org.cru.godtools.ui.tools.ToolCardPresenter.UiState
2425

@@ -37,7 +38,7 @@ fun SquareToolCard(
3738

3839
ProvideLayoutDirectionFromLocale(locale = state.translation?.languageCode) {
3940
ElevatedCard(
40-
onClick = { eventSink(UiEvent.Click) },
41+
onClick = { eventSink(ToolCardEvent.Click) },
4142
elevation = toolCardElevation,
4243
modifier = modifier.width(189.dp)
4344
) {

app/src/main/kotlin/org/cru/godtools/ui/tools/ToolCard.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import androidx.compose.ui.Modifier
1919
import androidx.compose.ui.unit.dp
2020
import org.ccci.gto.android.common.androidx.compose.foundation.layout.widthIn
2121
import org.cru.godtools.base.ui.util.ProvideLayoutDirectionFromLocale
22-
import org.cru.godtools.ui.tools.ToolCardPresenter.UiEvent
22+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
2323
import org.cru.godtools.ui.tools.ToolCardPresenter.UiState
2424

2525
@Composable
@@ -36,7 +36,7 @@ fun ToolCard(
3636

3737
ProvideLayoutDirectionFromLocale(locale = state.translation?.languageCode) {
3838
ElevatedCard(
39-
onClick = { eventSink(UiEvent.Click) },
39+
onClick = { eventSink(ToolCardEvent.Click) },
4040
elevation = toolCardElevation,
4141
interactionSource = interactionSource,
4242
modifier = modifier

app/src/main/kotlin/org/cru/godtools/ui/tools/ToolCardActions.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ import androidx.compose.material3.OutlinedButton
1212
import androidx.compose.material3.Text
1313
import androidx.compose.runtime.Composable
1414
import androidx.compose.runtime.CompositionLocalProvider
15-
import androidx.compose.runtime.getValue
16-
import androidx.compose.runtime.rememberUpdatedState
1715
import androidx.compose.ui.Modifier
1816
import androidx.compose.ui.res.stringResource
1917
import androidx.compose.ui.unit.dp
2018
import org.cru.godtools.R
21-
import org.cru.godtools.ui.tools.ToolCardPresenter.UiEvent
19+
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
2220
import org.cru.godtools.ui.tools.ToolCardPresenter.UiState
2321

2422
@Composable
@@ -28,14 +26,12 @@ internal fun ToolCardActions(
2826
buttonModifier: Modifier = Modifier,
2927
buttonWeightFill: Boolean = true,
3028
) = Row(modifier = modifier) {
31-
val eventSink by rememberUpdatedState(state.eventSink)
32-
3329
val buttonContentPadding = PaddingValues(horizontal = 4.dp, vertical = 8.dp)
3430
val buttonMinHeight = 30.dp
3531

3632
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides buttonMinHeight) {
3733
OutlinedButton(
38-
onClick = { eventSink(UiEvent.OpenToolDetails) },
34+
onClick = { state.eventSink(ToolCardEvent.OpenToolDetails) },
3935
contentPadding = buttonContentPadding,
4036
modifier = buttonModifier
4137
.alignByBaseline()
@@ -47,9 +43,11 @@ internal fun ToolCardActions(
4743
style = MaterialTheme.typography.labelMedium
4844
)
4945
}
46+
5047
Spacer(Modifier.width(8.dp))
48+
5149
Button(
52-
onClick = { eventSink(UiEvent.OpenTool) },
50+
onClick = { state.eventSink(ToolCardEvent.OpenTool) },
5351
contentPadding = buttonContentPadding,
5452
modifier = buttonModifier
5553
.alignByBaseline()

0 commit comments

Comments
 (0)