Skip to content

Commit 28fc773

Browse files
frettclaude
andcommitted
Use FeaturedToolsFlowProducer in ToolsPresenter for spotlight tools
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8bc1c76 commit 28fc773

2 files changed

Lines changed: 35 additions & 61 deletions

File tree

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

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import dagger.assisted.AssistedInject
2323
import dagger.hilt.components.SingletonComponent
2424
import java.util.Locale
2525
import kotlinx.coroutines.flow.first
26-
import kotlinx.coroutines.flow.map
2726
import org.ccci.gto.android.common.sync.SyncTracker
2827
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent
2928
import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.ACTION_OPEN_TOOL_DETAILS
@@ -32,9 +31,7 @@ import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.SOURC
3231
import org.cru.godtools.base.CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED
3332
import org.cru.godtools.base.Settings
3433
import org.cru.godtools.base.ui.circuit.screen.dashboard.page.ToolsScreen
35-
import org.cru.godtools.db.repository.ToolsRepository
3634
import org.cru.godtools.model.Language
37-
import org.cru.godtools.model.Tool
3835
import org.cru.godtools.sync.GodToolsSyncService
3936
import org.cru.godtools.ui.banner.Banner
4037
import org.cru.godtools.ui.banner.BannerPresenter
@@ -53,8 +50,8 @@ class ToolsPresenter @AssistedInject internal constructor(
5350
private val remoteConfig: FirebaseRemoteConfig,
5451
private val settings: Settings,
5552
private val toolCardPresenter: ToolCardPresenter,
56-
private val toolsRepository: ToolsRepository,
5753
private val favoriteToolsBannerPresenter: BannerPresenter<FavoriteToolsBannerPresenter.UiState>,
54+
private val featuredToolsFlowProducer: FeaturedToolsFlowProducer,
5855
private val filteredToolsFlowProducer: FilteredToolsFlowProducer,
5956
private val toolFiltersStateProducer: ToolFiltersStateProducer,
6057
private val syncService: GodToolsSyncService,
@@ -95,8 +92,9 @@ class ToolsPresenter @AssistedInject internal constructor(
9592

9693
RegisterSyncTask(selectedLocale)
9794

98-
val spotlightTools = rememberSpotlightTools(
99-
secondLanguage = filters.languageFilter.selectedItem
95+
val featuredTools = rememberFeaturedTools(
96+
mode = mode,
97+
language = filters.languageFilter.selectedItem
10098
) { openToolDetails(it, selectedLocale, SOURCE_SPOTLIGHT) }
10199

102100
val tools = rememberTools(
@@ -108,10 +106,10 @@ class ToolsPresenter @AssistedInject internal constructor(
108106
return UiState(
109107
mode = mode,
110108
banner = favoriteToolsBannerPresenter.present(),
111-
dataLoaded = spotlightTools != null && tools != null,
109+
dataLoaded = featuredTools != null && tools != null,
112110
spotlightTools = when {
113111
isPersonalizationEnabled && mode == Mode.ALL_TOOLS -> emptyList()
114-
else -> spotlightTools.orEmpty()
112+
else -> featuredTools.orEmpty()
115113
},
116114
filters = filters,
117115
tools = tools.orEmpty(),
@@ -134,21 +132,22 @@ class ToolsPresenter @AssistedInject internal constructor(
134132
}
135133

136134
@Composable
137-
private fun rememberSpotlightTools(
138-
secondLanguage: Language?,
135+
private fun rememberFeaturedTools(
136+
mode: Mode,
137+
language: Language?,
139138
onOpenToolDetails: (String) -> Unit,
140139
): List<ToolCardPresenter.UiState>? {
141-
val tools by remember {
142-
toolsRepository.getNormalToolsFlow()
143-
.map { it.filter { !it.isHidden && it.isSpotlight }.sortedWith(Tool.COMPARATOR_DEFAULT_ORDER) }
140+
val locale = language?.code
141+
val tools by remember(mode, locale) {
142+
featuredToolsFlowProducer.getFlow(mode, locale)
144143
}.collectAsState(null)
145144

146145
return tools?.map { tool ->
147146
val toolCode by rememberUpdatedState(tool.code)
148147

149148
toolCardPresenter.present(
150149
tool = tool,
151-
secondLanguage = secondLanguage,
150+
secondLanguage = language,
152151
eventSink = {
153152
when (it) {
154153
ToolCardEvent.Click,

app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/tools/ToolsPresenterTest.kt

Lines changed: 22 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import org.ccci.gto.support.turbine.awaitItemMatching
3333
import org.cru.godtools.base.CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED
3434
import org.cru.godtools.base.Settings
3535
import org.cru.godtools.base.ui.circuit.screen.dashboard.page.ToolsScreen
36-
import org.cru.godtools.db.repository.ToolsRepository
3736
import org.cru.godtools.model.Language
3837
import org.cru.godtools.model.Tool
3938
import org.cru.godtools.model.randomTool
@@ -59,7 +58,7 @@ import org.robolectric.annotation.Config
5958
class ToolsPresenterTest {
6059
private var isPersonalizationEnabled = false
6160
private val countryFlow = MutableStateFlow<String?>("US")
62-
private val toolsFlow = MutableStateFlow(emptyList<Tool>())
61+
private val featuredToolsFlow = MutableStateFlow(emptyList<Tool>())
6362
private val filteredToolsFlow = MutableStateFlow(emptyList<Tool>())
6463
private val toolOrderSync = Channel<Boolean>()
6564

@@ -76,16 +75,16 @@ class ToolsPresenterTest {
7675
coEvery { syncToolOrder(any(), any(), any()) } coAnswers { toolOrderSync.receive() }
7776
}
7877
private val favoriteToolsBannerPresenter = FakeBannerPresenter<FavoriteToolsBannerPresenter.UiState>(null)
78+
private val featuredToolsFlowProducer: FeaturedToolsFlowProducer = mockk {
79+
every { getFlow(any(), any()) } returns featuredToolsFlow
80+
}
7981
private val filteredToolsFlowProducer: FilteredToolsFlowProducer = mockk {
8082
every { getFlow(any(), any(), any()) } returns filteredToolsFlow
8183
}
8284
private val navigator = FakeNavigator(ToolsScreen)
8385
private val remoteConfig: FirebaseRemoteConfig = mockk {
8486
every { getBoolean(CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED) } answers { isPersonalizationEnabled }
8587
}
86-
private val toolsRepository: ToolsRepository = mockk {
87-
every { getNormalToolsFlow() } returns toolsFlow
88-
}
8988
private val toolFiltersStateProducer = FakeToolFiltersStateProducer()
9089
private val toolCardPresenter = FakeToolCardPresenter()
9190

@@ -94,8 +93,8 @@ class ToolsPresenterTest {
9493
remoteConfig = remoteConfig,
9594
settings = settings,
9695
toolCardPresenter = toolCardPresenter,
97-
toolsRepository = toolsRepository,
9896
favoriteToolsBannerPresenter = favoriteToolsBannerPresenter,
97+
featuredToolsFlowProducer = featuredToolsFlowProducer,
9998
filteredToolsFlowProducer = filteredToolsFlowProducer,
10099
toolFiltersStateProducer = toolFiltersStateProducer,
101100
syncService = syncService,
@@ -185,54 +184,30 @@ class ToolsPresenterTest {
185184

186185
// region State.spotlightTools
187186
@Test
188-
fun `Property spotlightTools`() = testScope.runTest {
189-
val normalTool = randomTool("normal", isHidden = false, isSpotlight = false)
190-
val spotlightTool = randomTool("spotlight", isHidden = false, isSpotlight = true)
191-
192-
presenter.test {
193-
toolsFlow.value = listOf(normalTool, spotlightTool)
194-
assertEquals(listOf(spotlightTool), expectMostRecentItem().spotlightTools.map { it.tool })
195-
}
196-
}
197-
198-
@Test
199-
fun `Property spotlightTools - Don't show hidden tools`() = testScope.runTest {
200-
val hiddenTool = randomTool("normal", isHidden = true, isSpotlight = true)
201-
val spotlightTool = randomTool("spotlight", isHidden = false, isSpotlight = true)
202-
203-
presenter.test {
204-
toolsFlow.value = listOf(hiddenTool, spotlightTool)
205-
assertEquals(listOf(spotlightTool), expectMostRecentItem().spotlightTools.map { it.tool })
206-
}
207-
}
208-
209-
@Test
210-
fun `Property spotlightTools - Sorted by default order`() = testScope.runTest {
211-
val tools = List(10) {
212-
randomTool("tool$it", Tool.Type.TRACT, defaultOrder = it, isHidden = false, isSpotlight = true)
213-
}
187+
fun `State - spotlightTools - shows tools from featuredToolsFlowProducer`() = testScope.runTest {
188+
val tool = randomTool(isHidden = false, isSpotlight = true)
214189

215190
presenter.test {
216-
toolsFlow.value = tools.shuffled()
217-
assertEquals(tools, expectMostRecentItem().spotlightTools.map { it.tool })
191+
featuredToolsFlow.value = listOf(tool)
192+
assertEquals(listOf(tool), expectMostRecentItem().spotlightTools.map { it.tool })
218193
}
219194
}
220195

221196
@Test
222-
fun `Property spotlightTools - Don't show spotlight tools for ALL_TOOLS`() = testScope.runTest {
223-
isPersonalizationEnabled = true
224-
val normalTool = randomTool("normal", isHidden = false, isSpotlight = false)
225-
val spotlightTool = randomTool("spotlight", isHidden = false, isSpotlight = true)
226-
toolsFlow.value = listOf(normalTool, spotlightTool)
227-
228-
presenter.test {
229-
val initialState = awaitInitialItem()
230-
assertEquals(listOf(spotlightTool), initialState.spotlightTools.map { it.tool })
231-
232-
initialState.eventSink(UiEvent.ChangeMode(Mode.ALL_TOOLS))
233-
assertEquals(emptyList(), expectMostRecentItem().spotlightTools)
197+
fun `State - spotlightTools - Don't show spotlight tools for ALL_TOOLS when personalization enabled`() =
198+
testScope.runTest {
199+
isPersonalizationEnabled = true
200+
val spotlightTool = randomTool(isHidden = false, isSpotlight = true)
201+
featuredToolsFlow.value = listOf(spotlightTool)
202+
203+
presenter.test {
204+
val initialState = awaitInitialItem()
205+
assertEquals(listOf(spotlightTool), initialState.spotlightTools.map { it.tool })
206+
207+
initialState.eventSink(UiEvent.ChangeMode(Mode.ALL_TOOLS))
208+
assertEquals(emptyList(), expectMostRecentItem().spotlightTools)
209+
}
234210
}
235-
}
236211
// endregion State.spotlightTools
237212

238213
// region State.filters

0 commit comments

Comments
 (0)