diff --git a/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayout.kt b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayout.kt index b9debb7f54..498d2dd8a1 100644 --- a/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayout.kt +++ b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayout.kt @@ -72,6 +72,15 @@ internal fun LessonsLayout(state: UiState, modifier: Modifier = Modifier) { ) } + if (state.mode == UiState.Mode.PERSONALIZATION && state.dataLoaded && state.lessons.isEmpty()) { + item("no-personalized-lessons", "no-personalized-lessons") { + NoPersonalizedLessons( + onGoToAllLessons = { state.eventSink(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) }, + modifier = Modifier.padding(top = 16.dp, horizontal = MARGIN_LESSONS_LAYOUT_HORIZONTAL) + ) + } + } + item("spacer", "spacer") { Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenter.kt b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenter.kt index 58924ec3cd..43cc0e05bf 100644 --- a/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenter.kt +++ b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenter.kt @@ -81,6 +81,7 @@ class LessonsPresenter @AssistedInject internal constructor( data class UiState internal constructor( val mode: Mode = Mode.ALL_LESSONS, val isPersonalizationEnabled: Boolean = false, + val dataLoaded: Boolean = true, val languageFilter: FilterMenu.UiState = FilterMenu.UiState(), val lessons: List = emptyList(), internal val eventSink: (UiEvent) -> Unit = {}, @@ -108,11 +109,14 @@ class LessonsPresenter @AssistedInject internal constructor( RegisterSyncTask(languageFilter.selectedItem?.code ?: appLanguage) + val lessons = rememberLessons(mode, languageFilter.selectedItem?.code ?: appLanguage) + return UiState( mode = mode, isPersonalizationEnabled = isPersonalizationEnabled, + dataLoaded = lessons != null, languageFilter = languageFilter, - lessons = rememberLessons(mode, languageFilter.selectedItem?.code ?: appLanguage), + lessons = lessons.orEmpty(), ) { when (it) { is UiEvent.ChangeMode -> mode = it.mode @@ -181,9 +185,9 @@ class LessonsPresenter @AssistedInject internal constructor( } @Composable - private fun rememberLessons(mode: UiState.Mode, locale: Locale): List { - val lessons by remember(mode, locale) { lessonsFlowProducer.getFlow(mode, locale) }.collectAsState(emptyList()) - return lessons.map { tool -> + private fun rememberLessons(mode: UiState.Mode, locale: Locale): List? { + val lessons by remember(mode, locale) { lessonsFlowProducer.getFlow(mode, locale) }.collectAsState(null) + return lessons?.map { tool -> key(tool.code) { lateinit var toolState: ToolCardPresenter.UiState toolState = toolCardPresenter.present( diff --git a/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/NoPersonalizedLessons.kt b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/NoPersonalizedLessons.kt new file mode 100644 index 0000000000..3b30f6cd7c --- /dev/null +++ b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/NoPersonalizedLessons.kt @@ -0,0 +1,56 @@ +package org.cru.godtools.ui.dashboard.lessons + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import org.cru.godtools.R + +@Composable +internal fun NoPersonalizedLessons(onGoToAllLessons: () -> Unit, modifier: Modifier = Modifier) { + Surface( + color = MaterialTheme.colorScheme.surfaceVariant, + modifier = modifier.fillMaxWidth(), + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(24.dp), + ) { + Icon( + painter = painterResource(R.drawable.ic_priority_high), + contentDescription = null, + modifier = Modifier.size(64.dp), + ) + Text( + text = stringResource(R.string.dashboard_lessons_section_personalized_no_lessons_title), + style = MaterialTheme.typography.titleMedium, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 16.dp), + ) + Text( + text = stringResource(R.string.dashboard_lessons_section_personalized_no_lessons_description), + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 8.dp), + ) + Button( + onClick = onGoToAllLessons, + modifier = Modifier.padding(top = 16.dp), + ) { + Text(stringResource(R.string.dashboard_lessons_section_personalized_no_lessons_action_all_lessons)) + } + } + } +} diff --git a/app/src/main/res/drawable/ic_priority_high.xml b/app/src/main/res/drawable/ic_priority_high.xml new file mode 100644 index 0000000000..6529fb45cd --- /dev/null +++ b/app/src/main/res/drawable/ic_priority_high.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings_dashboard.xml b/app/src/main/res/values/strings_dashboard.xml index 82e4902e8e..bd745c0e1f 100644 --- a/app/src/main/res/values/strings_dashboard.xml +++ b/app/src/main/res/values/strings_dashboard.xml @@ -51,6 +51,9 @@ An online version can be found at https://knowgod.com/ %1$d%% Complete Displaying localized Lessons list The lessons shown on this page are based on your Localization setting. You can alter this at any time. + Personalization unavailable + The lessons shown on this page are based on your Language and Localization settings. Your current selection does not yet offer personalization. + Go to All Lessons diff --git a/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt b/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt index 9f37d96efe..436444db51 100644 --- a/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt +++ b/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt @@ -185,7 +185,7 @@ class LessonsPresenterTest { @Test fun `State - mode - personalization enabled`() = testScope.runTest { presenter.test { - val state = awaitItem() + val state = awaitItemMatching { it.dataLoaded } assertEquals(UiState.Mode.PERSONALIZATION, state.mode) state.eventSink(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) @@ -437,7 +437,7 @@ class LessonsPresenterTest { @Test fun `SideEffect - RegisterSyncTask - Triggers initial sync`() = testScope.runTest { presenter.test { - awaitItem() + awaitItemMatching { it.dataLoaded } toolOrderSync.send(true) coVerifyAll { syncService.syncToolOrder(Locale.ENGLISH, "US", false) } } @@ -447,7 +447,7 @@ class LessonsPresenterTest { fun `SideEffect - RegisterSyncTask - uses locale from language filter`() = testScope.runTest { appLangFlow.value = Locale.FRENCH presenter.test { - awaitItem() + awaitItemMatching { it.dataLoaded } toolOrderSync.send(true) coVerifyAll { syncService.syncToolOrder(Locale.FRENCH, "US", false) } } @@ -471,7 +471,7 @@ class LessonsPresenterTest { @Test fun `SideEffect - RegisterSyncTask - passes force on triggered sync`() = testScope.runTest { presenter.test { - awaitItem() + awaitItemMatching { it.dataLoaded } toolOrderSync.send(true) coVerify { syncService.syncToolOrder(Locale.ENGLISH, "US", false) } diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png index 925feefd2d..6396703e71 100644 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d9d96f5cdfaf62bc45e1509300796ddf4a69ae2fff390919fd764edf323f22b -size 61882 +oid sha256:68341c9c8c63b4dc34c0b82164e0a5985be9d58717e82a36d2784b6e52ec11f9 +size 80851 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png index 087227707e..2c086cded2 100644 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04d1e03ce2c6572cbeb3af4df08c432c71e3662eb98b8da07591b322366b1bf0 -size 148513 +oid sha256:a336e47d0fe1b518f3e67db571b939739c6b2ac6a850f9dd2e85713d8ecac4af +size 163533 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png index 26b3d0700d..863c0b1046 100644 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e4f144fce3a76e433cc79a770839208d716481d3e5e1e8be0a1409ecc5e1c6e2 -size 60360 +oid sha256:60bd4960ec9fe5fb2bcf3301dae11ddfbd49542373a438c2af9bbc05af46b3a8 +size 80572 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png index d8f9cce371..b193cb54dd 100644 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c0e48a2493a3c1860f2a1ad290dc3324031a6a00da1338379fc8027f1ec7362 -size 46047 +oid sha256:207653748f74d04de16d2422ec44269cc6e8f2628bf08c2c320dcc237fb6153b +size 67145 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png index 593f73172d..a680f8bd8f 100644 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_Localization_Settings_Box[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:50dc48e17855a6a6e18776cafb327ad6bd8e7337f0764e35a3244fdcb56d59c5 -size 45114 +oid sha256:59a6629ba7821981fe14dbcbbf88b0edfcba603277eb0abd59e3f22c84c6d5a0 +size 66697 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..2158c7041f --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:985034ad85373512116a505ff37253398c8f4bc4b769f1d8bc9a7fc52dc23f26 +size 64825 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png new file mode 100644 index 0000000000..37c90082c8 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9dbd859e2649cf0fa879ac69754e449f5498fcd04d28fe2086c42fce5e99b97b +size 157893 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..78ece20b91 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:80098ca42edb96ba1c374a64722967f4d6d61a477ad8d7767aa51a791eb4b82a +size 64173 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..3d1650ed29 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95e87080661320fe329905ee33ed13151b4293bdbef97e46b7e30db75e6cb539 +size 65132 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..2542c65b16 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_-_No_Personalized_Lessons[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a24212a0ece6dcdf4b64b3d42bb7dfa85d849ebec8bd2bb769f8d0687bcf3ef0 +size 64426 diff --git a/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/DashboardLayoutPaparazziTest.kt b/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/DashboardLayoutPaparazziTest.kt index 5befbe7864..fc90b9fc06 100644 --- a/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/DashboardLayoutPaparazziTest.kt +++ b/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/DashboardLayoutPaparazziTest.kt @@ -316,6 +316,16 @@ class DashboardLayoutPaparazziTest( @Test fun `LessonsLayout() - Personalization - Localization Settings Box`() { + assumeTrue(locale == null) + lessonsState = lessonsState.copy( + mode = LessonsPresenter.UiState.Mode.PERSONALIZATION, + lessons = lessonsState.lessons.subList(0, 1) + ) + snapshotDashboardLayout(state.copy(initialPage = LessonsScreen)) + } + + @Test + fun `LessonsLayout() - Personalization - No Personalized Lessons`() { assumeTrue(locale == null) lessonsState = lessonsState.copy( mode = LessonsPresenter.UiState.Mode.PERSONALIZATION,