Add dashboard tools personalization mode#4392
Conversation
e0d27cd to
bf86a48
Compare
bf86a48 to
73b73e0
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces a Mode enum (PERSONALIZATION / ALL_TOOLS) to ToolsPresenter, driven by the CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED remote config flag. Spotlight tools are hidden when personalization is enabled and mode is ALL_TOOLS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cuit presenters Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lOrder API call Merges the two-endpoint pattern (featured + default_order) into a single default_order endpoint with an optional country parameter, and renames syncPersonalizedTools → syncToolOrder throughout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…yncTaskRegistry DashboardPresenter now registers its syncData task with the SyncTaskRegistry and exposes the registry on CircuitContext so nested presenters can participate. ToolsPresenter registers a syncToolOrder task against that registry, replacing the previous direct rememberSyncTracker usage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
f7e25a1 to
42ee3b7
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #4392 +/- ##
===========================================
+ Coverage 50.20% 51.02% +0.81%
===========================================
Files 447 449 +2
Lines 11996 12082 +86
Branches 2081 2094 +13
===========================================
+ Hits 6023 6165 +142
+ Misses 5370 5305 -65
- Partials 603 612 +9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
42ee3b7 to
6632a9d
Compare
| import org.cru.godtools.base.ui.circuit.screen.dashboard.page.LessonsScreen | ||
| import org.cru.godtools.base.ui.circuit.screen.dashboard.page.ToolsScreen | ||
| import org.cru.godtools.base.ui.compose.LocalEventBus | ||
| import org.cru.godtools.base.ui.theme.GodToolsTheme |
There was a problem hiding this comment.
This was to remove the blue bar at the top of the screen right? If not, then I'm confused with what's happening here
There was a problem hiding this comment.
yeah, we kept the dashboard app bar, but removed the blue theme from it
| // region Personalization Settings | ||
| fun getCountrySettingFlow() = getPersonalizationCountryFlow() | ||
|
|
||
| fun getPersonalizationCountryFlow() = dataStorePreferences.data |
There was a problem hiding this comment.
Why did you decide to make a function out of this? Readability or ease of finding it in the future?
There was a problem hiding this comment.
I was renaming it to reference that it's related to personalization only, I kept the old function around to prevent the change from breaking code you were working on. At a future time I was going to remove the old method.
| else -> toolsRepository.getNormalToolsFlowByLanguage(language) | ||
| } | ||
|
|
||
| val defaultVariantsFlow = toolsRepository.getMetaToolsFlow() |
There was a problem hiding this comment.
I'm not sure what a metatool is, and I think that might be hindering me from getting whats going on here.
There was a problem hiding this comment.
Wait... maybe I do know what that is. Is this how the 4 Spiritual Laws booklet relates to the KGP or Would You Like To Know God Personally?
There was a problem hiding this comment.
metatools are a way of grouping tools together that are the same content just presented towards different audiences. You can see them if you open tool details of 4 laws or kgp, it's on the "Versions" tab.
We previously had been hiding those other versions from the all tools list, but part of the requested changes was to make them available on the all tools UI
|
|
||
| @Composable | ||
| override fun present(): UiState { | ||
| val isPersonalizationEnabled = rememberSaveable { |
There was a problem hiding this comment.
rememberSaveable is so that it persists across refreshes and activity destruction / recreation right?
There was a problem hiding this comment.
yes, we want to load whether personalization is enabled/disabled at an app level when the screen is launched, and then prevent it from causing the UI to jump if the setting changes while the user is viewing the screen.
So, we load it once and store it via rememberSaveable. It will stay in the same mode while the screen is up and then re-evaluate if you relaunch the app/dashboard fresh
| fun getFlow(mode: Mode, category: String? = null, language: Locale? = null): Flow<List<Tool>> { | ||
| val baseFlow = when { | ||
| mode == Mode.PERSONALIZATION -> { | ||
| val languageFlow = if (language != null) flowOf(language) else settings.appLanguageFlow |
There was a problem hiding this comment.
Is this to take into account if someone sets a personalization country and the language is different then their app language and we need to pull the tools for that specific language? Want to make sure I understand what is happening here
There was a problem hiding this comment.
on the Dashboard they want the list of tools/lessons to take the language filter into account and default to the appLanguage
| import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiState.Mode | ||
|
|
||
| class FakeToolFiltersStateProducer : ToolFiltersStateProducer { | ||
| val filters = MutableStateFlow(Filters()) |
There was a problem hiding this comment.
I don't understand why we need a fakeToolFiltersStateProducer
There was a problem hiding this comment.
It's a test utility to help isolate the individual components for testing, a fake is similar to a mock.
I want to start using Fakes when the object being faked/mocked has a composable function we need to override, the mockposable dependency we've been using to mock objects like this tends to delay uptake of new Kotlin versions due to compatibility.
| // region Personalized Tools | ||
| private val personalizedToolsMutex = MutexMap() | ||
| // region Tool Order | ||
| private val toolOrderMutex = MutexMap() |
There was a problem hiding this comment.
I had to look this up. It seems similar to a semaphore but not quite the same as the gate analogy that was for a semaphore
There was a problem hiding this comment.
a Mutex is effectively a single permit semaphore
tjohnson009
left a comment
There was a problem hiding this comment.
I took a look at just about everything. I had more questions but they can definitely be for another time.
Summary
Test plan
🤖 Generated with Claude Code