diff --git a/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsFlowProducer.kt b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsFlowProducer.kt new file mode 100644 index 0000000000..3ee50d2830 --- /dev/null +++ b/app/src/main/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsFlowProducer.kt @@ -0,0 +1,35 @@ +package org.cru.godtools.ui.dashboard.lessons + +import java.util.Locale +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import org.cru.godtools.base.Settings +import org.cru.godtools.db.repository.ToolsRepository +import org.cru.godtools.model.Tool +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState.Mode + +internal class LessonsFlowProducer @Inject constructor( + private val settings: Settings, + private val toolsRepository: ToolsRepository, +) { + @OptIn(ExperimentalCoroutinesApi::class) + fun getFlow(mode: Mode, locale: Locale): Flow> { + val baseFlow = when (mode) { + Mode.PERSONALIZATION -> settings.getPersonalizationCountryFlow() + .flatMapLatest { toolsRepository.getPersonalizedLessonsFlow(locale, it) } + .combine(toolsRepository.getPersonalizedLessonsFlow(locale, null)) { lessons, fallback -> + lessons.ifEmpty { fallback } + } + .distinctUntilChanged() + + Mode.ALL_LESSONS -> toolsRepository.getLessonsFlowByLanguage(locale).map { it.sortedBy { it.defaultOrder } } + } + + return baseFlow.map { it.filterNot { it.isHidden } } + } +} 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 c662ae0d8a..4dd655489e 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 @@ -2,30 +2,47 @@ package org.cru.godtools.ui.dashboard.lessons import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SegmentedButtonDefaults +import androidx.compose.material3.SingleChoiceSegmentedButtonRow 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.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.slack.circuit.codegen.annotations.CircuitInject import dagger.hilt.components.SingletonComponent import org.cru.godtools.R import org.cru.godtools.base.ui.circuit.screen.dashboard.page.LessonsScreen +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiEvent import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState import org.cru.godtools.ui.tools.LessonToolCard @Composable @CircuitInject(LessonsScreen::class, SingletonComponent::class) internal fun LessonsLayout(state: UiState, modifier: Modifier = Modifier) { - LazyColumn(contentPadding = PaddingValues(16.dp), modifier = modifier) { + LazyColumn(contentPadding = PaddingValues(start = 16.dp, end = 16.dp, bottom = 16.dp), modifier = modifier) { + if (state.isPersonalizationEnabled) { + item("mode-toggle", "mode-toggle") { + PersonalizationToggle( + state, + modifier = Modifier + .fillMaxWidth() + .wrapContentWidth(Alignment.CenterHorizontally) + ) + } + } + item("header", "header") { - LessonsHeader() + LessonsHeader(state.mode, modifier = Modifier.padding(top = 16.dp)) HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp)) LessonFilters(state) } @@ -44,10 +61,35 @@ internal fun LessonsLayout(state: UiState, modifier: Modifier = Modifier) { } @Composable -@Preview(showBackground = true) -private fun LessonsHeader() = Column { +private fun PersonalizationToggle(state: UiState, modifier: Modifier = Modifier) { + SingleChoiceSegmentedButtonRow(modifier = modifier) { + SegmentedButton( + selected = state.mode == UiState.Mode.PERSONALIZATION, + onClick = { state.eventSink(UiEvent.ChangeMode(UiState.Mode.PERSONALIZATION)) }, + shape = SegmentedButtonDefaults.itemShape(0, 2), + ) { + Text(stringResource(R.string.dashboard_lessons_toggle_personalized)) + } + + SegmentedButton( + selected = state.mode == UiState.Mode.ALL_LESSONS, + onClick = { state.eventSink(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) }, + shape = SegmentedButtonDefaults.itemShape(1, 2), + ) { + Text(stringResource(R.string.dashboard_lessons_toggle_all)) + } + } +} + +@Composable +private fun LessonsHeader(mode: UiState.Mode, modifier: Modifier = Modifier) = Column(modifier = modifier) { Text( - stringResource(R.string.dashboard_lessons_header_title), + stringResource( + when (mode) { + UiState.Mode.PERSONALIZATION -> R.string.dashboard_lessons_header_title_personalized + UiState.Mode.ALL_LESSONS -> R.string.dashboard_lessons_header_title_all + } + ), style = MaterialTheme.typography.titleLarge ) Text( 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 cb093fc820..8fdb399832 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 @@ -2,6 +2,7 @@ package org.cru.godtools.ui.dashboard.lessons import android.content.Context import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -11,7 +12,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow +import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.slack.circuit.codegen.annotations.CircuitInject +import com.slack.circuit.runtime.CircuitContext +import com.slack.circuit.runtime.CircuitUiEvent import com.slack.circuit.runtime.CircuitUiState import com.slack.circuit.runtime.Navigator import com.slack.circuit.runtime.presenter.Presenter @@ -28,14 +32,17 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import org.ccci.gto.android.common.dagger.coroutines.DispatcherType import org.ccci.gto.android.common.dagger.coroutines.DispatcherType.Type.IO +import org.ccci.gto.android.common.sync.SyncTracker import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.ACTION_OPEN_LESSON import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.SOURCE_LESSONS +import org.cru.godtools.base.CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED import org.cru.godtools.base.Settings import org.cru.godtools.base.ui.circuit.screen.dashboard.page.LessonsScreen import org.cru.godtools.db.repository.LanguagesRepository @@ -43,6 +50,8 @@ import org.cru.godtools.db.repository.ToolsRepository import org.cru.godtools.db.repository.TranslationsRepository import org.cru.godtools.model.Language import org.cru.godtools.model.Language.Companion.filterByDisplayAndNativeName +import org.cru.godtools.sync.GodToolsSyncService +import org.cru.godtools.ui.dashboard.SyncTaskRegistry.Companion.syncTaskRegistry import org.cru.godtools.ui.dashboard.filters.FilterMenu import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState import org.cru.godtools.ui.tools.ToolCardPresenter @@ -50,34 +59,63 @@ import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent import org.cru.godtools.util.createToolIntent import org.greenrobot.eventbus.EventBus -class LessonsPresenter @AssistedInject constructor( +class LessonsPresenter @AssistedInject internal constructor( @param:ApplicationContext private val context: Context, private val eventBus: EventBus, private val languagesRepository: LanguagesRepository, + private val lessonsFlowProducer: LessonsFlowProducer, + private val remoteConfig: FirebaseRemoteConfig, private val settings: Settings, + private val syncService: GodToolsSyncService, private val toolCardPresenter: ToolCardPresenter, private val toolsRepository: ToolsRepository, private val translationsRepository: TranslationsRepository, @param:DispatcherType(IO) private val ioDispatcher: CoroutineDispatcher, + @Assisted private val circuitContext: CircuitContext, @Assisted private val navigator: Navigator, ) : Presenter { - // region UiState - data class UiState( + // region UiState / UiEvent + @ConsistentCopyVisibility + data class UiState internal constructor( + val mode: Mode = Mode.ALL_LESSONS, + val isPersonalizationEnabled: Boolean = false, val languageFilter: FilterMenu.UiState = FilterMenu.UiState(), val lessons: List = emptyList(), - ) : CircuitUiState - // endregion UiState + internal val eventSink: (UiEvent) -> Unit = {}, + ) : CircuitUiState { + enum class Mode { PERSONALIZATION, ALL_LESSONS } + } + + internal sealed interface UiEvent : CircuitUiEvent { + data class ChangeMode(val mode: UiState.Mode) : UiEvent + } + // endregion UiState / UiEvent @Composable override fun present(): UiState { + val isPersonalizationEnabled = rememberSaveable { + remoteConfig.getBoolean(CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED) + } + var mode by rememberSaveable { + mutableStateOf(if (isPersonalizationEnabled) UiState.Mode.PERSONALIZATION else UiState.Mode.ALL_LESSONS) + } + val appLanguage by settings.appLanguageFlow.collectAsState() val languageFilter = rememberLanguagesFilter() + RegisterSyncTask(languageFilter.selectedItem?.code ?: appLanguage) + return UiState( + mode = mode, + isPersonalizationEnabled = isPersonalizationEnabled, languageFilter = languageFilter, - lessons = rememberLessons(languageFilter.selectedItem?.code ?: appLanguage), - ) + lessons = rememberLessons(mode, languageFilter.selectedItem?.code ?: appLanguage), + ) { + when (it) { + is UiEvent.ChangeMode -> mode = it.mode + } + } } @Composable @@ -140,12 +178,8 @@ class LessonsPresenter @AssistedInject constructor( } @Composable - private fun rememberLessons(locale: Locale): List { - val lessons by remember(locale) { - toolsRepository.getLessonsFlowByLanguage(locale) - .map { it.filterNot { it.isHidden }.sortedBy { it.defaultOrder } } - }.collectAsState(emptyList()) - + 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 -> key(tool.code) { lateinit var toolState: ToolCardPresenter.UiState @@ -176,9 +210,24 @@ class LessonsPresenter @AssistedInject constructor( } } + @Composable + private fun RegisterSyncTask(locale: Locale) { + val syncRegistry = circuitContext.syncTaskRegistry + DisposableEffect(syncRegistry, locale) { + if (syncRegistry == null) return@DisposableEffect onDispose { } + val id = syncRegistry.registerSyncTask { force -> syncData(locale, force) } + onDispose { syncRegistry.unregisterSyncTask(id) } + } + } + + private fun SyncTracker.syncData(locale: Locale, force: Boolean = false) = launchSync { + val country = settings.getCountrySettingFlow().first() + syncService.syncToolOrder(locale, country, force) + } + @AssistedFactory @CircuitInject(LessonsScreen::class, SingletonComponent::class) interface Factory { - fun create(navigator: Navigator): LessonsPresenter + fun create(circuitContext: CircuitContext, navigator: Navigator): LessonsPresenter } } diff --git a/app/src/main/res/values-af/strings_dashboard.xml b/app/src/main/res/values-af/strings_dashboard.xml index a6a033bea9..848a8cd4c2 100644 --- a/app/src/main/res/values-af/strings_dashboard.xml +++ b/app/src/main/res/values-af/strings_dashboard.xml @@ -32,7 +32,7 @@ Weergawe: %1$s (%2$d) Lesse - Lesse vir jou gemaak + Lesse vir jou gemaak Praktiese idees om verhoudings te bou en betekenisvolle gesprekke te voer. Lesse in: diff --git a/app/src/main/res/values-am/strings_dashboard.xml b/app/src/main/res/values-am/strings_dashboard.xml index ff05e34b97..ca116c0d07 100644 --- a/app/src/main/res/values-am/strings_dashboard.xml +++ b/app/src/main/res/values-am/strings_dashboard.xml @@ -32,7 +32,7 @@ ሥሪት: %1$s (%2$d) ትምህርቶች - ለእርስዎ የተዘጋጁ ትምህርቶች + ለእርስዎ የተዘጋጁ ትምህርቶች ግንኙነቶችን ለመፍጠር እና ትርጉም ያለው ውይይት ለመጀመር ተግባራዊ ሀሳቦች። ትምህርቶች በ diff --git a/app/src/main/res/values-ar/strings_dashboard.xml b/app/src/main/res/values-ar/strings_dashboard.xml index a2f2127994..3c237cc996 100644 --- a/app/src/main/res/values-ar/strings_dashboard.xml +++ b/app/src/main/res/values-ar/strings_dashboard.xml @@ -33,7 +33,7 @@ https://godtoolsapp.com \n\n الإصدار: %1$s(%2$d) الدروس - الدروس المُعدة لأجلك + الدروس المُعدة لأجلك أفكار عملية لبناء علاقات وبدء محادثات هادفة. دروس في: diff --git a/app/src/main/res/values-bn/strings_dashboard.xml b/app/src/main/res/values-bn/strings_dashboard.xml index 65de852a85..7d567943f5 100644 --- a/app/src/main/res/values-bn/strings_dashboard.xml +++ b/app/src/main/res/values-bn/strings_dashboard.xml @@ -32,7 +32,7 @@ https://knowgod.com/-তে একটি অনলাইন সংস্কর সংস্করণ: %1$s (%2$d) পাঠগুলি - আপনার জন্য তৈরি পাঠগুলি + আপনার জন্য তৈরি পাঠগুলি সম্পর্ক তৈরি করার এবং অর্থপূর্ণ কথাবার্তা শুরু করার ব্যবহারিক ধারণা এগুলিতে পাঠসমূহ: diff --git a/app/src/main/res/values-de/strings_dashboard.xml b/app/src/main/res/values-de/strings_dashboard.xml index a84b43b956..d027b67212 100644 --- a/app/src/main/res/values-de/strings_dashboard.xml +++ b/app/src/main/res/values-de/strings_dashboard.xml @@ -32,7 +32,7 @@ Eine Online-Version findest du unter https://knowgod.com/ Version: %1$s (%2$d) Lektionen - Für dich gemachte Lektionen + Für dich gemachte Lektionen Praktische Ideen zum Aufbau von Beziehungen und zum Beginn bedeutungsvoller Unterhaltungen. Lektionen in: diff --git a/app/src/main/res/values-es/strings_dashboard.xml b/app/src/main/res/values-es/strings_dashboard.xml index 41b94e6b75..495db4792e 100644 --- a/app/src/main/res/values-es/strings_dashboard.xml +++ b/app/src/main/res/values-es/strings_dashboard.xml @@ -32,7 +32,7 @@ Puedes acceer a una versión online en https://knowgod.com/ Versión: %1$s (%2$d) Lecciones - Lecciones hechas para ti + Lecciones hechas para ti Ideas prácticas para establecer relaciones e iniciar conversaciones significativas. Lecciones en: diff --git a/app/src/main/res/values-fr/strings_dashboard.xml b/app/src/main/res/values-fr/strings_dashboard.xml index baec0dcfb2..a4d5c7db03 100644 --- a/app/src/main/res/values-fr/strings_dashboard.xml +++ b/app/src/main/res/values-fr/strings_dashboard.xml @@ -32,7 +32,7 @@ Une version en ligne est disponible sur https://knowgod.com Version: %1$s (%2$d) Leçons - Des leçons faites pour vous + Des leçons faites pour vous Des idées pratiques pour nouer des relations et entamer des conversations significatives. Leçons en : diff --git a/app/src/main/res/values-ha/strings_dashboard.xml b/app/src/main/res/values-ha/strings_dashboard.xml index 03417fcf83..5277c392e8 100644 --- a/app/src/main/res/values-ha/strings_dashboard.xml +++ b/app/src/main/res/values-ha/strings_dashboard.xml @@ -30,7 +30,7 @@ Sigar: %1$s (%2$d) Darussan - Darussan da aka yi muku + Darussan da aka yi muku Ra\'ayoyi masu amfani don gina dangantaka da fara tattaunawa mai ma\'ana Darussa a cikin: diff --git a/app/src/main/res/values-hi/strings_dashboard.xml b/app/src/main/res/values-hi/strings_dashboard.xml index 7de7b9296e..27e1b28612 100644 --- a/app/src/main/res/values-hi/strings_dashboard.xml +++ b/app/src/main/res/values-hi/strings_dashboard.xml @@ -32,7 +32,7 @@ संस्करण: %1$s (%2$d) अध्याय - आपके लिए बनाए गए अध्याय + आपके लिए बनाए गए अध्याय संबंध बनाने और अर्थपूर्ण वार्तालाप शुरू करने के लिए व्यावहारिक सुझाव। इसमें पाठ: diff --git a/app/src/main/res/values-in/strings_dashboard.xml b/app/src/main/res/values-in/strings_dashboard.xml index 3c8e69032c..c3a750ca0c 100644 --- a/app/src/main/res/values-in/strings_dashboard.xml +++ b/app/src/main/res/values-in/strings_dashboard.xml @@ -32,7 +32,7 @@ Versi online dapat ditemukan di https://knowgod.com/id Versi: %1$s (%2$d) Pelajaran - Pelajaran-pelajaran untuk Saudara + Pelajaran-pelajaran untuk Saudara Ide-ide praktis membangun hubungan dan memulai percakapan yang bermakna. Pelajaran dalam bahasa: diff --git a/app/src/main/res/values-ja/strings_dashboard.xml b/app/src/main/res/values-ja/strings_dashboard.xml index f3cfee9155..b9824e0ef3 100644 --- a/app/src/main/res/values-ja/strings_dashboard.xml +++ b/app/src/main/res/values-ja/strings_dashboard.xml @@ -32,7 +32,7 @@ バージョン:%1$s (%2$d) レッスン - あなた専用のレッスン + あなた専用のレッスン 信頼関係を築き、意義のある会話を始めるための実践的なアイデアです。 レッスン: diff --git a/app/src/main/res/values-ko/strings_dashboard.xml b/app/src/main/res/values-ko/strings_dashboard.xml index 04faa8651c..1649bd5235 100644 --- a/app/src/main/res/values-ko/strings_dashboard.xml +++ b/app/src/main/res/values-ko/strings_dashboard.xml @@ -32,7 +32,7 @@ 버전: %1$s (%2$d) 수업 - 맞춤 수업 + 맞춤 수업 관계를 형성하고 의미 있는 대화를 시작하기 위한 실용적인 아이디어입니다. 수업 언어: diff --git a/app/src/main/res/values-lv/strings_dashboard.xml b/app/src/main/res/values-lv/strings_dashboard.xml index 5b1059fa15..292c5d22c4 100644 --- a/app/src/main/res/values-lv/strings_dashboard.xml +++ b/app/src/main/res/values-lv/strings_dashboard.xml @@ -32,7 +32,7 @@ Rīku tīmekļa versijas ir pieejamas: https://KnowGod.com/lv Versija: %1$s (%2$d) Nodarbības - Nodarbības, kas pielāgotas tev + Nodarbības, kas pielāgotas tev Praktiskas idejas attiecību veidošanai un nozīmīgu sarunu uzsākšanai. Nodarbības: diff --git a/app/src/main/res/values-ne/strings_dashboard.xml b/app/src/main/res/values-ne/strings_dashboard.xml index 863f78eb2f..2b4a007cc1 100644 --- a/app/src/main/res/values-ne/strings_dashboard.xml +++ b/app/src/main/res/values-ne/strings_dashboard.xml @@ -33,7 +33,7 @@ https://knowgod.com/ संस्करण : %1$s (%2$d) पाठहरु - तपाईको लागि बनाइएको पाठहरु + तपाईको लागि बनाइएको पाठहरु सम्बन्ध निर्माण गर्न र अर्थपूर्ण कुराकानी सुरु गर्न व्यावहारिक विचारहरू। पाठहरुमा: diff --git a/app/src/main/res/values-om/strings_dashboard.xml b/app/src/main/res/values-om/strings_dashboard.xml index 80e1328146..6ade7cf0e7 100644 --- a/app/src/main/res/values-om/strings_dashboard.xml +++ b/app/src/main/res/values-om/strings_dashboard.xml @@ -31,7 +31,7 @@ Marsariitii https://knowgod.com/ irrattis argachuu ni dandeessa. Version: %1$s (%2$d) Barannoowwan - Barannoowwan siif qopha\'an + Barannoowwan siif qopha\'an Yaadota qabatamaa hariiroo ijaaruu fi haasawa hiika qabu jalqabuuf gargaaraan. Barannoowwaan afaan: diff --git a/app/src/main/res/values-pt/strings_dashboard.xml b/app/src/main/res/values-pt/strings_dashboard.xml index 0030f4bc7a..9f29d80705 100644 --- a/app/src/main/res/values-pt/strings_dashboard.xml +++ b/app/src/main/res/values-pt/strings_dashboard.xml @@ -32,7 +32,7 @@ Há uma versão online aqui: https://knowgod.com/ Versão: %1$s (%2$d) Lições - Lições feitas para você + Lições feitas para você Ideias práticas para construir relacionamentos e iniciar conversas relevantes. Lições em: diff --git a/app/src/main/res/values-ro/strings_dashboard.xml b/app/src/main/res/values-ro/strings_dashboard.xml index e64df50ffa..727a1ecc5e 100644 --- a/app/src/main/res/values-ro/strings_dashboard.xml +++ b/app/src/main/res/values-ro/strings_dashboard.xml @@ -32,7 +32,7 @@ Găsești versiunea online aici https://knowgod.com/ Versiune: %1$s (%2$d) Lecții - Lecții create pentru tine + Lecții create pentru tine Idei practice pentru a construi relații și a începe conversații relevante. Lecții în: diff --git a/app/src/main/res/values-ru/strings_dashboard.xml b/app/src/main/res/values-ru/strings_dashboard.xml index 469b410013..f45a9c9009 100644 --- a/app/src/main/res/values-ru/strings_dashboard.xml +++ b/app/src/main/res/values-ru/strings_dashboard.xml @@ -32,7 +32,7 @@ Версия: %1$s (%2$d) Уроки - Уроки для вас + Уроки для вас Практические идеи для построения отношений и начала содержательных бесед. Язык уроков: diff --git a/app/src/main/res/values-sw/strings_dashboard.xml b/app/src/main/res/values-sw/strings_dashboard.xml index c2f094790d..1451f8d93a 100644 --- a/app/src/main/res/values-sw/strings_dashboard.xml +++ b/app/src/main/res/values-sw/strings_dashboard.xml @@ -32,7 +32,7 @@ Toleo la mtandao linaweza kupatikana kwenye https://knowgod.com/ Matoleo: %1$s (%2$d) Masomo - Masomo kwa ajili yako + Masomo kwa ajili yako Mikakati ya kivitendo ya kujenga mahusiano na kuanzisha mazungumzo yenye maana. Masomo yaliyopo: diff --git a/app/src/main/res/values-ur/strings_dashboard.xml b/app/src/main/res/values-ur/strings_dashboard.xml index 187850fe27..3d2cadd209 100644 --- a/app/src/main/res/values-ur/strings_dashboard.xml +++ b/app/src/main/res/values-ur/strings_dashboard.xml @@ -33,7 +33,7 @@ https://knowgod.com/ نسخہ: %1$s (%2$d) اسباق - آپ کے لئے بنائے گئے اسباق + آپ کے لئے بنائے گئے اسباق تعلقات استوار کرنے اور با معنی گفتگو شروع کرنے کے عملی خیالات اسباق در: diff --git a/app/src/main/res/values-vi/strings_dashboard.xml b/app/src/main/res/values-vi/strings_dashboard.xml index 1178fdc8cb..9485170a4d 100644 --- a/app/src/main/res/values-vi/strings_dashboard.xml +++ b/app/src/main/res/values-vi/strings_dashboard.xml @@ -32,7 +32,7 @@ Một phiên bản trực tuyến có thể tìm thấy ở https://knowgod.com/ Phiên bản: %1$s (%2$d) Bài học - Bài học dành cho bạn + Bài học dành cho bạn Những ý tưởng thiết thực giúp xây dựng mối quan hệ và bắt đầu cuộc trò chuyện đầy ý nghĩa. Bài học bằng: diff --git a/app/src/main/res/values-zh-rCN/strings_dashboard.xml b/app/src/main/res/values-zh-rCN/strings_dashboard.xml index 345d032f82..d83ba733f3 100644 --- a/app/src/main/res/values-zh-rCN/strings_dashboard.xml +++ b/app/src/main/res/values-zh-rCN/strings_dashboard.xml @@ -32,7 +32,7 @@ 版本:%1$s (%2$d) 课程 - 为你制定的课程 + 为你制定的课程 建立关系,开启有意义对话的实用点子 课程所用语言: diff --git a/app/src/main/res/values-zh-rTW/strings_dashboard.xml b/app/src/main/res/values-zh-rTW/strings_dashboard.xml index 0eba9353b3..40f9bf5c98 100644 --- a/app/src/main/res/values-zh-rTW/strings_dashboard.xml +++ b/app/src/main/res/values-zh-rTW/strings_dashboard.xml @@ -32,7 +32,7 @@ 版本:%1$s (%2$d) 課程 - 為您打造的課程 + 為您打造的課程 建立關係和開始有意義對話的實用想法 課程語言: diff --git a/app/src/main/res/values/strings_dashboard.xml b/app/src/main/res/values/strings_dashboard.xml index 16416dd988..51486d7454 100644 --- a/app/src/main/res/values/strings_dashboard.xml +++ b/app/src/main/res/values/strings_dashboard.xml @@ -37,7 +37,10 @@ An online version can be found at https://knowgod.com/ Lessons - Lessons made for you + Personalized + All Lessons + Lessons + Lessons made for you Practical ideas to build relationships and start meaningful conversations. Lessons in: diff --git a/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsFlowProducerTest.kt b/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsFlowProducerTest.kt new file mode 100644 index 0000000000..7b9bbe12e9 --- /dev/null +++ b/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsFlowProducerTest.kt @@ -0,0 +1,118 @@ +package org.cru.godtools.ui.dashboard.lessons + +import app.cash.turbine.test +import io.mockk.every +import io.mockk.mockk +import io.mockk.verifyAll +import java.util.Locale +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.cru.godtools.base.Settings +import org.cru.godtools.db.repository.ToolsRepository +import org.cru.godtools.model.Tool +import org.cru.godtools.model.randomTool +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState.Mode + +@Suppress("UnusedFlow") +class LessonsFlowProducerTest { + private val countryFlow = MutableStateFlow(null) + + private val settings: Settings = mockk { + every { getPersonalizationCountryFlow() } returns countryFlow + } + private val toolsRepository: ToolsRepository = mockk { + every { getLessonsFlowByLanguage(any()) } returns flowOf(emptyList()) + every { getPersonalizedLessonsFlow(any(), any()) } returns flowOf(emptyList()) + } + + private val producer = LessonsFlowProducer(settings = settings, toolsRepository = toolsRepository) + + // region ALL_LESSONS mode + @Test + fun `getFlow - All Lessons - uses getLessonsFlowByLanguage`() = runTest { + producer.getFlow(mode = Mode.ALL_LESSONS, locale = Locale.ENGLISH).first() + verifyAll { + toolsRepository.getLessonsFlowByLanguage(Locale.ENGLISH) + } + } + + @Test + fun `getFlow - All Lessons - excludes hidden lessons`() = runTest { + val hidden = createLesson(isHidden = true) + val visible = createLesson(isHidden = false) + every { toolsRepository.getLessonsFlowByLanguage(any()) } returns flowOf(listOf(hidden, visible)) + + assertEquals(listOf(visible), producer.getFlow(mode = Mode.ALL_LESSONS, locale = Locale.ENGLISH).first()) + } + + @Test + fun `getFlow - All Lessons - sorted by defaultOrder`() = runTest { + val lessons = List(5) { createLesson(defaultOrder = it) } + every { toolsRepository.getLessonsFlowByLanguage(any()) } returns flowOf(lessons.shuffled()) + + assertEquals(lessons, producer.getFlow(mode = Mode.ALL_LESSONS, locale = Locale.ENGLISH).first()) + } + // endregion ALL_LESSONS mode + + // region PERSONALIZATION mode + @Test + fun `getFlow - Personalization - uses getPersonalizedLessonsFlow`() = runTest { + countryFlow.value = "US" + producer.getFlow(mode = Mode.PERSONALIZATION, locale = Locale.GERMAN).first() + verifyAll { + toolsRepository.getPersonalizedLessonsFlow(Locale.GERMAN, "US") + toolsRepository.getPersonalizedLessonsFlow(Locale.GERMAN, null) + } + } + + @Test + fun `getFlow - Personalization - returns personalized lessons when non-empty`() = runTest { + val lesson = createLesson() + val fallback = createLesson() + countryFlow.value = "US" + every { toolsRepository.getPersonalizedLessonsFlow(Locale.ENGLISH, "US") } returns flowOf(listOf(lesson)) + every { toolsRepository.getPersonalizedLessonsFlow(Locale.ENGLISH, null) } returns flowOf(listOf(fallback)) + + assertEquals(listOf(lesson), producer.getFlow(mode = Mode.PERSONALIZATION, locale = Locale.ENGLISH).first()) + } + + @Test + fun `getFlow - Personalization - falls back to language only when no country-specific lessons`() = runTest { + val fallback = createLesson() + countryFlow.value = "US" + every { toolsRepository.getPersonalizedLessonsFlow(Locale.ENGLISH, "US") } returns flowOf(emptyList()) + every { toolsRepository.getPersonalizedLessonsFlow(Locale.ENGLISH, null) } returns flowOf(listOf(fallback)) + + assertEquals(listOf(fallback), producer.getFlow(mode = Mode.PERSONALIZATION, locale = Locale.ENGLISH).first()) + } + + @Test + fun `getFlow - Personalization - excludes hidden lessons`() = runTest { + val hidden = createLesson(isHidden = true) + val visible = createLesson(isHidden = false) + every { toolsRepository.getPersonalizedLessonsFlow(any(), any()) } returns flowOf(listOf(hidden, visible)) + + assertEquals(listOf(visible), producer.getFlow(mode = Mode.PERSONALIZATION, locale = Locale.ENGLISH).first()) + } + + @Test + fun `getFlow - Personalization - updates when country changes`() = runTest { + val usLesson = createLesson() + every { toolsRepository.getPersonalizedLessonsFlow(Locale.ENGLISH, "US") } returns flowOf(listOf(usLesson)) + + producer.getFlow(mode = Mode.PERSONALIZATION, locale = Locale.ENGLISH).test { + assertEquals(emptyList(), awaitItem()) + + countryFlow.value = "US" + assertEquals(listOf(usLesson), awaitItem()) + } + } + // endregion PERSONALIZATION mode + + private fun createLesson(defaultOrder: Int = 0, isHidden: Boolean = false) = + randomTool(type = Tool.Type.LESSON, defaultOrder = defaultOrder, isHidden = isHidden) +} diff --git a/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt b/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt similarity index 68% rename from app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt rename to app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt index c49e8270dd..9f37d96efe 100644 --- a/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt +++ b/app/src/test/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsPresenterTest.kt @@ -9,13 +9,19 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import app.cash.turbine.ReceiveTurbine import app.cash.turbine.Turbine +import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.slack.circuit.backstack.SaveableBackStack import com.slack.circuit.foundation.Circuit import com.slack.circuit.foundation.CircuitCompositionLocals import com.slack.circuit.foundation.NavigableCircuitContent +import com.slack.circuit.runtime.CircuitContext +import com.slack.circuit.runtime.InternalCircuitApi import com.slack.circuit.test.FakeNavigator import com.slack.circuit.test.test import com.slack.circuitx.android.IntentScreen +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.coVerifyAll import io.mockk.every import io.mockk.mockk import io.mockk.verify @@ -27,16 +33,20 @@ import kotlin.test.assertIs import kotlin.test.assertNotNull import kotlin.test.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.ccci.gto.android.common.androidx.compose.ui.platform.AndroidUiDispatcherUtil +import org.ccci.gto.android.common.sync.SyncTracker import org.ccci.gto.android.common.util.content.equalsIntent +import org.ccci.gto.support.turbine.awaitItemMatching import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.ACTION_OPEN_LESSON import org.cru.godtools.analytics.model.OpenAnalyticsActionEvent.Companion.SOURCE_LESSONS +import org.cru.godtools.base.CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED import org.cru.godtools.base.Settings import org.cru.godtools.base.ui.circuit.screen.dashboard.page.LessonsScreen import org.cru.godtools.db.repository.LanguagesRepository @@ -47,7 +57,12 @@ import org.cru.godtools.model.Tool import org.cru.godtools.model.Translation import org.cru.godtools.model.randomTool import org.cru.godtools.model.randomTranslation +import org.cru.godtools.sync.GodToolsSyncService +import org.cru.godtools.ui.dashboard.SyncTaskRegistry +import org.cru.godtools.ui.dashboard.SyncTaskRegistry.Companion.syncTaskRegistry import org.cru.godtools.ui.dashboard.filters.FilterMenu +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiEvent +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState import org.cru.godtools.ui.tools.FakeToolCardPresenter import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent import org.cru.godtools.util.createToolIntent @@ -61,27 +76,41 @@ import org.robolectric.annotation.Config @OptIn(ExperimentalCoroutinesApi::class) class LessonsPresenterTest { private val appLangFlow = MutableStateFlow(Locale.ENGLISH) + private val countryFlow = MutableStateFlow("US") private val lessonsFlow = MutableStateFlow(emptyList()) private val enLessonsFlow = MutableStateFlow(emptyList()) private val languagesFlow = MutableStateFlow(emptyList()) private val translationsFlow = MutableStateFlow(emptyList()) + private val toolOrderSync = Channel() + private var isPersonalizationEnabled = true private val testScope = TestScope() - + @OptIn(InternalCircuitApi::class) + private val circuitContext = CircuitContext(null).apply { + syncTaskRegistry = SyncTaskRegistry(SyncTracker(testScope.backgroundScope)) + } private val context: Context = ApplicationProvider.getApplicationContext() private val eventBus: EventBus = mockk(relaxUnitFun = true) + private val remoteConfig: FirebaseRemoteConfig = mockk { + every { getBoolean(CONFIG_UI_DASHBOARD_PERSONALIZATION_ENABLED) } answers { isPersonalizationEnabled } + } private val languagesRepository: LanguagesRepository = mockk { every { findLanguageFlow(any()) } answers { flowOf(Language(firstArg())) } every { getLanguagesFlow() } returns languagesFlow } private val settings: Settings = mockk { every { appLanguageFlow } returns appLangFlow + every { getCountrySettingFlow() } returns countryFlow + } + private val syncService: GodToolsSyncService = mockk { + coEvery { syncToolOrder(any(), any(), any()) } coAnswers { toolOrderSync.receive() } + } + private val lessonsFlowProducer: LessonsFlowProducer = mockk { + every { getFlow(any(), any()) } returns flowOf(emptyList()) + every { getFlow(any(), Locale.ENGLISH) } returns enLessonsFlow } private val toolsRepository: ToolsRepository = mockk { every { getLessonsFlow() } returns lessonsFlow - - every { getLessonsFlowByLanguage(any()) } returns flowOf(emptyList()) - every { getLessonsFlowByLanguage(Locale.ENGLISH) } returns enLessonsFlow } private val translationsRepository: TranslationsRepository = mockk { every { getTranslationsFlowForTools(any()) } returns translationsFlow @@ -94,11 +123,15 @@ class LessonsPresenterTest { context = context, eventBus = eventBus, languagesRepository = languagesRepository, + lessonsFlowProducer = lessonsFlowProducer, + remoteConfig = remoteConfig, settings = settings, + syncService = syncService, toolCardPresenter = FakeToolCardPresenter(), toolsRepository = toolsRepository, translationsRepository = translationsRepository, ioDispatcher = UnconfinedTestDispatcher(testScope.testScheduler), + circuitContext = circuitContext, navigator = navigator, ) @@ -110,12 +143,12 @@ class LessonsPresenterTest { // This logic is based on the Sample AnsweringNavigatorTest in the circuit library. // see: https://github.com/slackhq/circuit/blob/main/circuit-foundation/src/jvmTest/kotlin/com/slack/circuit/foundation/AnsweringNavigatorTest.kt - private fun testPresenterWithStateRestoration(): ReceiveTurbine { - val presenterState = Turbine() + private fun testPresenterWithStateRestoration(): ReceiveTurbine { + val presenterState = Turbine() val circuit = Circuit.Builder() - .addPresenter { s, n, _ -> presenter } - .addUi { state, _ -> SideEffect { presenterState.add(state) } } + .addPresenter { _, _, _ -> presenter } + .addUi { state, _ -> SideEffect { presenterState.add(state) } } .build() stateRestorationTester.setContent { @@ -140,6 +173,41 @@ class LessonsPresenterTest { navigator.assertResetRootIsEmpty() } + // region State.mode + @Test + fun `State - mode - personalization disabled`() = testScope.runTest { + isPersonalizationEnabled = false + presenter.test { + assertEquals(UiState.Mode.ALL_LESSONS, expectMostRecentItem().mode) + } + } + + @Test + fun `State - mode - personalization enabled`() = testScope.runTest { + presenter.test { + val state = awaitItem() + assertEquals(UiState.Mode.PERSONALIZATION, state.mode) + + state.eventSink(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) + assertEquals(UiState.Mode.ALL_LESSONS, awaitItem().mode) + } + } + + @Test + fun `State - mode - persisted through state save & restore`() = testScope.runTest { + testPresenterWithStateRestoration().test { + val state = expectMostRecentItem() + assertEquals(UiState.Mode.PERSONALIZATION, state.mode) + state.eventSink(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) + composeTestRule.waitForIdle() + assertEquals(UiState.Mode.ALL_LESSONS, expectMostRecentItem().mode) + + stateRestorationTester.emulateSavedInstanceStateRestore() + assertEquals(UiState.Mode.ALL_LESSONS, awaitItem().mode) + } + } + // endregion State.mode + // region State.languageFilter.selectedItem @Test fun `State - languageFilter - selectedItem - default to app language`() = testScope.runTest { @@ -294,8 +362,6 @@ class LessonsPresenterTest { // region State.languageFilter Event.SelectItem @Test fun `State - languageFilter - Event - SelectItem`() = testScope.runTest { - every { toolsRepository.getLessonsFlowByLanguage(any()) } returns flowOf(emptyList()) - presenter.test { expectMostRecentItem().languageFilter .also { assertEquals(appLangFlow.value, it.selectedItem?.code) } @@ -309,35 +375,7 @@ class LessonsPresenterTest { // region State.lessons @Test fun `State - lessons`() = testScope.runTest { - enLessonsFlow.value = listOf( - randomTool("lesson1", isHidden = false, defaultOrder = 0), - randomTool("lesson2", isHidden = false, defaultOrder = 1), - ) - - presenter.test { - assertEquals(listOf("lesson1", "lesson2"), expectMostRecentItem().lessons.map { it.toolCode }) - } - } - - @Test - fun `State - lessons - hide hidden lessons`() = testScope.runTest { - enLessonsFlow.value = listOf( - randomTool("lesson1", isHidden = false, defaultOrder = 0), - randomTool("lesson2", isHidden = true, defaultOrder = 1), - randomTool("lesson3", isHidden = false, defaultOrder = 2), - ) - - presenter.test { - assertEquals(listOf("lesson1", "lesson3"), expectMostRecentItem().lessons.map { it.toolCode }) - } - } - - @Test - fun `State - lessons - sorted by defaultOrder`() = testScope.runTest { - enLessonsFlow.value = listOf( - randomTool("lesson2", isHidden = false, defaultOrder = 1), - randomTool("lesson1", isHidden = false, defaultOrder = 0), - ) + enLessonsFlow.value = listOf(randomTool("lesson1"), randomTool("lesson2")) presenter.test { assertEquals(listOf("lesson1", "lesson2"), expectMostRecentItem().lessons.map { it.toolCode }) @@ -346,27 +384,39 @@ class LessonsPresenterTest { @Test fun `State - lessons - Filtered by selected language`() = testScope.runTest { - every { toolsRepository.getLessonsFlowByLanguage(Locale.FRENCH) } - .returns(flowOf(listOf(randomTool("lesson", isHidden = false)))) + every { lessonsFlowProducer.getFlow(any(), Locale.FRENCH) } returns flowOf(listOf(randomTool("lesson"))) presenter.test { with(expectMostRecentItem()) { assertEquals(emptyList(), lessons) - verify(exactly = 0) { toolsRepository.getLessonsFlowByLanguage(Locale.FRENCH) } + verify(exactly = 0) { lessonsFlowProducer.getFlow(any(), Locale.FRENCH) } languageFilter.eventSink(FilterMenu.Event.SelectItem(Language(Locale.FRENCH))) } assertEquals(listOf("lesson"), expectMostRecentItem().lessons.map { it.toolCode }) - verify { toolsRepository.getLessonsFlowByLanguage(Locale.FRENCH) } + verify { lessonsFlowProducer.getFlow(any(), Locale.FRENCH) } + } + } + + @Test + fun `State - lessons - passes mode to lessonsFlowProducer`() = testScope.runTest { + presenter.test { + val state = expectMostRecentItem() + assertEquals(UiState.Mode.PERSONALIZATION, state.mode) + verify { lessonsFlowProducer.getFlow(UiState.Mode.PERSONALIZATION, any()) } + + state.eventSink(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) + awaitItem() + verify { lessonsFlowProducer.getFlow(UiState.Mode.ALL_LESSONS, any()) } } } @Test fun `State - lessons - Event - Click`() = testScope.runTest { enLessonsFlow.value = listOf( - randomTool("lesson1", isHidden = false, defaultOrder = 0), - randomTool("lesson2", type = Tool.Type.LESSON, isHidden = false, defaultOrder = 1), + randomTool("lesson1"), + randomTool("lesson2", type = Tool.Type.LESSON), ) presenter.test { @@ -382,4 +432,53 @@ class LessonsPresenterTest { verify { eventBus.post(OpenAnalyticsActionEvent(ACTION_OPEN_LESSON, "lesson2", SOURCE_LESSONS)) } } // endregion State.lessons + + // region SideEffect - RegisterSyncTask + @Test + fun `SideEffect - RegisterSyncTask - Triggers initial sync`() = testScope.runTest { + presenter.test { + awaitItem() + toolOrderSync.send(true) + coVerifyAll { syncService.syncToolOrder(Locale.ENGLISH, "US", false) } + } + } + + @Test + fun `SideEffect - RegisterSyncTask - uses locale from language filter`() = testScope.runTest { + appLangFlow.value = Locale.FRENCH + presenter.test { + awaitItem() + toolOrderSync.send(true) + coVerifyAll { syncService.syncToolOrder(Locale.FRENCH, "US", false) } + } + } + + @Test + fun `SideEffect - RegisterSyncTask - re-syncs when locale changes`() = testScope.runTest { + presenter.test { + val initialState = awaitItem() + toolOrderSync.send(true) + coVerify { syncService.syncToolOrder(Locale.ENGLISH, "US", false) } + + initialState.languageFilter.eventSink(FilterMenu.Event.SelectItem(Language(Locale.FRENCH))) + awaitItemMatching { it.languageFilter.selectedItem?.code == Locale.FRENCH } + toolOrderSync.send(true) + coVerify { syncService.syncToolOrder(Locale.FRENCH, "US", false) } + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `SideEffect - RegisterSyncTask - passes force on triggered sync`() = testScope.runTest { + presenter.test { + awaitItem() + toolOrderSync.send(true) + coVerify { syncService.syncToolOrder(Locale.ENGLISH, "US", false) } + + circuitContext.syncTaskRegistry!!.triggerSyncTasks(force = true) + toolOrderSync.send(true) + coVerify { syncService.syncToolOrder(Locale.ENGLISH, "US", true) } + } + } + // endregion SideEffect - RegisterSyncTask } diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index 8fda51b45f..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:49c3f3f20aff7b082d9ad498d2ecc7fd366c629a7726ad8ebc2ce06c42541640 -size 83947 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index 325301d3aa..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51148e16e5d46d85fbd70badeab73db9bcce7d34da9dc7089fb0790a4b0e29ab -size 83965 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index eae968b388..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b08fd347ddc9ef0bf74f7f32465e332b0c5b4a6b10f3be6c9c9abe2af44c5222 -size 85656 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png deleted file mode 100644 index 97df2e2d9c..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9229aa87cab21c136f8ffa28156c3548d09ee519c1f0306b3314b346bffa18ea -size 149805 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index b76285383e..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5c5c05d3a53c65ea2cfc00608e44df2caa051ce7f913466e2c272535536006d -size 86043 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index 3673f82806..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fcb5bdf26b73438276d61252c0f1a9f1d6980ee04a0dd267d03a856ed37ddb14 -size 87365 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index 5b1116ef6d..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5c483e6488de8be710c0eb7794af11c64bfbfdd94b70fd264e1acd92da969c4 -size 87451 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index 01782cd772..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6af373663faf39f4f76c968d4e90d1411a4f0c6466f084971d94c069bbb1763e -size 83693 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png deleted file mode 100644 index 347a5ccbd0..0000000000 --- a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e3049bc3556dd34f3bfa8cd4e26b0e0056dde76fe1c944e2ae4062d4901da30 -size 83797 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..796117e814 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:448469cbc2140bc0736542ac678cb67dff67850e6ca4578f6172e90e86336f00 +size 78637 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..488a63955c --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edbc0d233bc43d70476b17f2cac7d3741d96ed06107d275d63fef62370efb095 +size 78908 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..f4f63eb27d --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:804ff68ec72cd0a3c0bddb9d2bab0caf8588eeade24a0e83e624d90e65ecb819 +size 82561 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png new file mode 100644 index 0000000000..411058f1bb --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a70abbd3b344e04aec89b39808758c0249c3d62ff0b8cf2202f011dd647c9fa +size 144549 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..d0f397833a --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57b1bdb7e96383e14d48d26ba1b1c04f5a75393c57dfdf0e00f64cff29b5b343 +size 82914 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..4b4a44b044 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01bd17d6a8ec016eba611ddf35b54be22554c77ddca35077114329e40b0bd97e +size 84900 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..f8c6f1866b --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d55cba06f6460a058e5ddde80f989149b80c96966c32061d664d84f754a497e9 +size 85405 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..5617b307ee --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31f2e5f6484dc744163a36656a2a925c1fdbb9324690d433d19f3d7fedfbe3d5 +size 82885 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..933e0c07b5 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_All_Lessons[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f09254d56e30427289978d6a489232b808a36e2d6a1c3f7bd6cf756ed7a43ecd +size 83479 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..6433f1151e --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcce7688333b3b2b8c2dc405723ea969a2cdc1a91432164ecfb8dbaaf50a1096 +size 75912 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..2a80a7993b --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d334a21ce4a655bda44c8c9ac674210fe51ce2e83c269a6ccf218874a866fc28 +size 75871 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..aa4eed2848 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a208ad0f9086672a5267a05f2a68f791564bacfade8758fbb8cd39cefe4d033e +size 85480 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png new file mode 100644 index 0000000000..4c83858594 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d6276dc6d0a8d7278655a96a831242ba1af844ab6453e71ce09eb0aa914c0ef2 +size 148186 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..6430fed175 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f494ff0e0b4f74d609d424c476e183bafa864e41402769c10343376dfeb48e4f +size 85726 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..aebcbebae4 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0bc2b54e8ff92822780bdaee40e589dbbc8f213b7307f993262c258378bb221 +size 88489 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..0eee209fa1 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:20f755870d9db5a88b10344c4010b4aeb395325cda96dd9f5b0e10c69e253a22 +size 88850 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..56d525e5a3 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36787a74c0e187c202352a473e3cf98458c55fed23f3dc5b84cfa0de2b8de3bc +size 84702 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..f0a5fbe744 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2155a133f707303c9bd3f6666ff9235f031167ed7f2c7652f6d6c4d0e63d6a1a +size 85302 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..0bf5f4403f --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,in,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2181f3813790ff2ad788663d0c50dc4897625690f06648d4c9b3ed86958cee6a +size 83916 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..c2bacf5d94 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,in,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1715381b662c94564ff4b2c65559bf5a9d7d2aec6ee258fece567050bfe72cf1 +size 84411 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..ef1eb2f42d --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72b7ccf33552dbc814cfa633f6684eb16210fde69868bd888c6865a868fc3cad +size 83029 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png new file mode 100644 index 0000000000..43ba42a90f --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NOTNIGHT,ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3afed9c05e4afd720d67e7b3aee44146ff0bcad1a2f83483b1945c9936aeca3 +size 146080 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..69ada8f2f4 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Nexus_5,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:237bf9294be2aaf01f7f05d646c251f508bfc2d64c2c19247589ed4b3e1dbdfa +size 83566 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..462ecb8160 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,in,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d439ca0fe086be23eb888485ba3284a7fe258c711319cd46e77d07b30054e60 +size 83809 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..f014d47acd --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,in,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb18967b7d769167a246a58f2e5ef02df72be35130d1393cc68bdaef220fb220 +size 83913 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..bdfedc9650 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,locale=null,NIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d282b7ba5142dd4f985ca75072d29e3729908260d8f2b973533a02ffae3d5689 +size 81763 diff --git a/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png new file mode 100644 index 0000000000..afb4b8a999 --- /dev/null +++ b/app/src/test/snapshots/images/org.cru.godtools.ui.dashboard_DashboardLayoutPaparazziTest_LessonsLayout()_-_Personalization_Disabled[Pixel_6_Pro,locale=null,NOTNIGHT,NO_ACCESSIBILITY].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4e1fe731270ed2150d1272111000cae011a982b6d284a2ebb82200f0a4b795b +size 81868 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 8071e2f131..13739919fd 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 @@ -277,7 +277,8 @@ class DashboardLayoutPaparazziTest( // endregion AllFavoritesLayout // region LessonsLayout - private val lessonsState = LessonsPresenter.UiState( + private var lessonsState = LessonsPresenter.UiState( + isPersonalizationEnabled = true, languageFilter = FilterMenu.UiState( selectedItem = Language(Locale.ENGLISH) ), @@ -291,7 +292,20 @@ class DashboardLayoutPaparazziTest( ) @Test - fun `LessonsLayout()`() { + fun `LessonsLayout() - Personalization`() { + lessonsState = lessonsState.copy(mode = LessonsPresenter.UiState.Mode.PERSONALIZATION) + snapshotDashboardLayout(state.copy(initialPage = LessonsScreen)) + } + + @Test + fun `LessonsLayout() - All Lessons`() { + lessonsState = lessonsState.copy(mode = LessonsPresenter.UiState.Mode.ALL_LESSONS) + snapshotDashboardLayout(state.copy(initialPage = LessonsScreen)) + } + + @Test + fun `LessonsLayout() - Personalization Disabled`() { + lessonsState = lessonsState.copy(isPersonalizationEnabled = false) snapshotDashboardLayout(state.copy(initialPage = LessonsScreen)) } // endregion LessonsLayout diff --git a/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayoutTest.kt b/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayoutTest.kt new file mode 100644 index 0000000000..4648d642a1 --- /dev/null +++ b/app/src/testDebug/kotlin/org/cru/godtools/ui/dashboard/lessons/LessonsLayoutTest.kt @@ -0,0 +1,92 @@ +package org.cru.godtools.ui.dashboard.lessons + +import android.app.Application +import android.content.Context +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.v2.runComposeUiTest +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.slack.circuit.test.TestEventSink +import kotlin.test.Test +import org.cru.godtools.R +import org.cru.godtools.model.randomTranslation +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiEvent +import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState +import org.cru.godtools.ui.tools.ToolCardPresenter +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +@RunWith(AndroidJUnit4::class) +@Config(application = Application::class) +@OptIn(ExperimentalTestApi::class) +class LessonsLayoutTest { + private val context: Context get() = ApplicationProvider.getApplicationContext() + private val events = TestEventSink() + + // region PersonalizationToggle + @Test + fun `PersonalizationToggle - not shown when personalization is disabled`() = runComposeUiTest { + setContent { LessonsLayout(UiState(isPersonalizationEnabled = false, eventSink = events)) } + + onNodeWithText(context.getString(R.string.dashboard_lessons_toggle_personalized)).assertDoesNotExist() + onNodeWithText(context.getString(R.string.dashboard_lessons_toggle_all)).assertDoesNotExist() + } + + @Test + fun `PersonalizationToggle - shown when personalization is enabled`() = runComposeUiTest { + setContent { LessonsLayout(UiState(isPersonalizationEnabled = true, eventSink = events)) } + + onNodeWithText(context.getString(R.string.dashboard_lessons_toggle_personalized)).assertExists() + onNodeWithText(context.getString(R.string.dashboard_lessons_toggle_all)).assertExists() + } + + @Test + fun `PersonalizationToggle - click Personalized fires ChangeMode(PERSONALIZATION)`() = runComposeUiTest { + setContent { + LessonsLayout(UiState(isPersonalizationEnabled = true, mode = UiState.Mode.ALL_LESSONS, eventSink = events)) + } + + onNodeWithText(context.getString(R.string.dashboard_lessons_toggle_personalized)).performClick() + events.assertEvent(UiEvent.ChangeMode(UiState.Mode.PERSONALIZATION)) + } + + @Test + fun `PersonalizationToggle - click All Lessons fires ChangeMode(ALL_LESSONS)`() = runComposeUiTest { + setContent { + LessonsLayout( + UiState(isPersonalizationEnabled = true, mode = UiState.Mode.PERSONALIZATION, eventSink = events) + ) + } + + onNodeWithText(context.getString(R.string.dashboard_lessons_toggle_all)).performClick() + events.assertEvent(UiEvent.ChangeMode(UiState.Mode.ALL_LESSONS)) + } + // endregion PersonalizationToggle + + // region LessonToolCard + @Test + fun `LessonToolCard - click fires ToolCardEvent_Click`() = runComposeUiTest { + val cardEvents = TestEventSink() + setContent { + LessonsLayout( + UiState( + lessons = listOf( + ToolCardPresenter.UiState( + toolCode = "lesson1", + translation = randomTranslation(toolCode = "lesson1", name = "Test Lesson"), + eventSink = cardEvents, + ) + ), + eventSink = events, + ) + ) + } + + onNodeWithText("Test Lesson").performClick() + cardEvents.assertEvent(ToolCardPresenter.ToolCardEvent.Click) + events.assertNoEvents() + } + // endregion LessonToolCard +}