Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<List<Tool>> {
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 } }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -28,56 +32,90 @@ 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
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
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<UiState> {
// 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<Language> = FilterMenu.UiState(),
val lessons: List<ToolCardPresenter.UiState> = 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
Expand Down Expand Up @@ -140,12 +178,8 @@ class LessonsPresenter @AssistedInject constructor(
}

@Composable
private fun rememberLessons(locale: Locale): List<ToolCardPresenter.UiState> {
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<ToolCardPresenter.UiState> {
val lessons by remember(mode, locale) { lessonsFlowProducer.getFlow(mode, locale) }.collectAsState(emptyList())
return lessons.map { tool ->
key(tool.code) {
lateinit var toolState: ToolCardPresenter.UiState
Expand Down Expand Up @@ -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
}
}
2 changes: 1 addition & 1 deletion app/src/main/res/values-af/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<string name="menu_version">Weergawe: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">Lesse</string>
<string name="dashboard_lessons_header_title">Lesse vir jou gemaak</string>
<string name="dashboard_lessons_header_title_personalized">Lesse vir jou gemaak</string>
<string name="dashboard_lessons_header_description">Praktiese idees om verhoudings te bou en betekenisvolle gesprekke te voer.</string>
<string name="dashboard_lessons_section_filter_label">Lesse in:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-am/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<string name="menu_version">ሥሪት: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">ትምህርቶች</string>
<string name="dashboard_lessons_header_title">ለእርስዎ የተዘጋጁ ትምህርቶች</string>
<string name="dashboard_lessons_header_title_personalized">ለእርስዎ የተዘጋጁ ትምህርቶች</string>
<string name="dashboard_lessons_header_description">ግንኙነቶችን ለመፍጠር እና ትርጉም ያለው ውይይት ለመጀመር ተግባራዊ ሀሳቦች።</string>
<string name="dashboard_lessons_section_filter_label">ትምህርቶች በ</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-ar/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ https://godtoolsapp.com \n\n
<string name="menu_version">الإصدار: %1$s(%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">الدروس</string>
<string name="dashboard_lessons_header_title">الدروس المُعدة لأجلك</string>
<string name="dashboard_lessons_header_title_personalized">الدروس المُعدة لأجلك</string>
<string name="dashboard_lessons_header_description">أفكار عملية لبناء علاقات وبدء محادثات هادفة.</string>
<string name="dashboard_lessons_section_filter_label">دروس في:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-bn/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ https://knowgod.com/-তে একটি অনলাইন সংস্কর
<string name="menu_version">সংস্করণ: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">পাঠগুলি</string>
<string name="dashboard_lessons_header_title">আপনার জন্য তৈরি পাঠগুলি</string>
<string name="dashboard_lessons_header_title_personalized">আপনার জন্য তৈরি পাঠগুলি</string>
<string name="dashboard_lessons_header_description">সম্পর্ক তৈরি করার এবং অর্থপূর্ণ কথাবার্তা শুরু করার ব্যবহারিক ধারণা</string>
<string name="dashboard_lessons_section_filter_label">এগুলিতে পাঠসমূহ:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-de/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Eine Online-Version findest du unter https://knowgod.com/</string>
<string name="menu_version">Version: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">Lektionen</string>
<string name="dashboard_lessons_header_title">Für dich gemachte Lektionen</string>
<string name="dashboard_lessons_header_title_personalized">Für dich gemachte Lektionen</string>
<string name="dashboard_lessons_header_description">Praktische Ideen zum Aufbau von Beziehungen und zum Beginn bedeutungsvoller Unterhaltungen.</string>
<string name="dashboard_lessons_section_filter_label">Lektionen in:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-es/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Puedes acceer a una versión online en https://knowgod.com/</string>
<string name="menu_version">Versión: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">Lecciones</string>
<string name="dashboard_lessons_header_title">Lecciones hechas para ti</string>
<string name="dashboard_lessons_header_title_personalized">Lecciones hechas para ti</string>
<string name="dashboard_lessons_header_description">Ideas prácticas para establecer relaciones e iniciar conversaciones significativas.</string>
<string name="dashboard_lessons_section_filter_label">Lecciones en:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-fr/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Une version en ligne est disponible sur https://knowgod.com</string>
<string name="menu_version">Version: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">Leçons</string>
<string name="dashboard_lessons_header_title">Des leçons faites pour vous</string>
<string name="dashboard_lessons_header_title_personalized">Des leçons faites pour vous</string>
<string name="dashboard_lessons_header_description">Des idées pratiques pour nouer des relations et entamer des conversations significatives.</string>
<string name="dashboard_lessons_section_filter_label">Leçons en :</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-ha/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<string name="menu_version">Sigar: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">Darussan</string>
<string name="dashboard_lessons_header_title">Darussan da aka yi muku</string>
<string name="dashboard_lessons_header_title_personalized">Darussan da aka yi muku</string>
<string name="dashboard_lessons_header_description">Ra\'ayoyi masu amfani don gina dangantaka da fara tattaunawa mai ma\'ana</string>
<string name="dashboard_lessons_section_filter_label">Darussa a cikin:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-hi/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<string name="menu_version">संस्करण: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">अध्याय</string>
<string name="dashboard_lessons_header_title">आपके लिए बनाए गए अध्याय</string>
<string name="dashboard_lessons_header_title_personalized">आपके लिए बनाए गए अध्याय</string>
<string name="dashboard_lessons_header_description">संबंध बनाने और अर्थपूर्ण वार्तालाप शुरू करने के लिए व्यावहारिक सुझाव।</string>
<string name="dashboard_lessons_section_filter_label">इसमें पाठ:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-in/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Versi online dapat ditemukan di https://knowgod.com/id</string>
<string name="menu_version">Versi: %1$s (%2$d)</string>
<!-- Lessons -->
<string name="nav_lessons">Pelajaran</string>
<string name="dashboard_lessons_header_title">Pelajaran-pelajaran untuk Saudara</string>
<string name="dashboard_lessons_header_title_personalized">Pelajaran-pelajaran untuk Saudara</string>
<string name="dashboard_lessons_header_description">Ide-ide praktis membangun hubungan dan memulai percakapan yang bermakna.</string>
<string name="dashboard_lessons_section_filter_label">Pelajaran dalam bahasa:</string>
<plurals name="dashboard_lessons_section_filter_available_lessons">
Expand Down
Loading