Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6c80a05
Add Surface box to end of tools layout for personalization
tjohnson009 May 8, 2026
395a54f
Create and insert localizations settings box for tools and lessons pa…
tjohnson009 May 8, 2026
7a21b48
Add string resources for lessons layout personalization
tjohnson009 May 8, 2026
2c19b7d
Add UiEvent for going to localization settings from lesson layout
tjohnson009 May 8, 2026
36181b3
Add locationSettingsBox to lessons layout; Make padding similar to to…
tjohnson009 May 8, 2026
5494846
Remove unused imports
tjohnson009 May 8, 2026
8a9b2c8
Remove unnecessary Row composable for center alignment; Remove unused…
tjohnson009 May 8, 2026
4bf1afe
Remove unused imports
tjohnson009 May 8, 2026
361f267
Gate the localization settings banner based on the isPersonalizationE…
tjohnson009 May 8, 2026
6efb509
Minor lint fix
tjohnson009 May 8, 2026
020a67c
Make localizationSettingsBox internal following lessons and tools lay…
tjohnson009 May 8, 2026
8ef1933
Revert erroneous padding changes and correct personalization if state…
tjohnson009 May 12, 2026
9054ca1
Correct personalization if statement for personalization settings box
tjohnson009 May 12, 2026
4b9b9b4
Add snapshot tests for lessons and tools localization settings box
tjohnson009 May 12, 2026
dfdbc53
Record updated snapshots
tjohnson009 May 12, 2026
6b2b9b4
Retrigger CI
tjohnson009 May 12, 2026
f83b562
Update modifier line to single line
tjohnson009 May 12, 2026
41ac74e
Add a custom vertical arrangement to LazyColumn to pin localization t…
tjohnson009 May 15, 2026
5c49967
Record updated snapshots
tjohnson009 May 15, 2026
ee5daf1
Retrigger CI
tjohnson009 May 12, 2026
13f52e6
Bring in rememberPinLastArrangement composable to both tools and lessons
tjohnson009 May 15, 2026
3843f36
Create rememberPinLastItemBottomArrangement composable for reuse in t…
tjohnson009 May 15, 2026
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,50 @@
package org.cru.godtools.ui.dashboard

import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import org.cru.godtools.R

@Composable
internal fun LocalizationSettingsBox(
@StringRes title: Int,
@StringRes description: Int,
onClickSettings: () -> Unit,
modifier: Modifier = Modifier,
) {
Surface(
color = MaterialTheme.colorScheme.primaryContainer,
modifier = modifier.fillMaxWidth(),
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = stringResource(title),
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.bodyLarge
)
Text(
text = stringResource(description),
style = MaterialTheme.typography.bodySmall
)
Button(
onClick = onClickSettings,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 8.dp)
) {
Text(stringResource(R.string.dashboard_section_localization_box_button))
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.cru.godtools.ui.dashboard

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.Density

@Composable
internal fun rememberPinLastItemBottomArrangement(items: Int): Arrangement.Vertical = remember(items) {
object : Arrangement.Vertical {
override fun Density.arrange(totalSize: Int, sizes: IntArray, outPositions: IntArray) {
var currentOffset = 0
sizes.forEachIndexed { index, size ->
if (index == sizes.lastIndex) {
outPositions[index] = maxOf(currentOffset, totalSize - size)
} else {
outPositions[index] = currentOffset
currentOffset += size
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.cru.godtools.ui.dashboard.lessons

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
Expand All @@ -14,22 +17,37 @@ import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.slack.circuit.codegen.annotations.CircuitInject
import dagger.hilt.components.SingletonComponent
import org.ccci.gto.android.common.compose.foundation.layout.padding
import org.cru.godtools.R
import org.cru.godtools.base.ui.circuit.screen.dashboard.page.LessonsScreen
import org.cru.godtools.ui.dashboard.LocalizationSettingsBox
import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiEvent
import org.cru.godtools.ui.dashboard.lessons.LessonsPresenter.UiState
import org.cru.godtools.ui.dashboard.rememberPinLastItemBottomArrangement
import org.cru.godtools.ui.tools.LessonToolCard

internal val MARGIN_LESSONS_LAYOUT_HORIZONTAL = 16.dp

@Composable
@CircuitInject(LessonsScreen::class, SingletonComponent::class)
internal fun LessonsLayout(state: UiState, modifier: Modifier = Modifier) {
LazyColumn(contentPadding = PaddingValues(start = 16.dp, end = 16.dp, bottom = 16.dp), modifier = modifier) {
Comment thread
tjohnson009 marked this conversation as resolved.
val verticalArrangement = if (state.mode == UiState.Mode.PERSONALIZATION) {
rememberPinLastItemBottomArrangement(state.lessons.size)
} else {
Arrangement.Top
}

LazyColumn(
verticalArrangement = remember { verticalArrangement },
modifier = modifier.fillMaxHeight()
) {
if (state.isPersonalizationEnabled) {
item("mode-toggle", "mode-toggle") {
PersonalizationToggle(
Expand All @@ -42,9 +60,11 @@ internal fun LessonsLayout(state: UiState, modifier: Modifier = Modifier) {
}

item("header", "header") {
LessonsHeader(state.mode, modifier = Modifier.padding(top = 16.dp))
HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp))
LessonFilters(state)
LessonsHeader(state.mode, Modifier.padding(top = 16.dp, horizontal = MARGIN_LESSONS_LAYOUT_HORIZONTAL))
HorizontalDivider(
modifier = Modifier.padding(vertical = 12.dp, horizontal = MARGIN_LESSONS_LAYOUT_HORIZONTAL)
)
LessonFilters(state, modifier = Modifier.padding(horizontal = MARGIN_LESSONS_LAYOUT_HORIZONTAL))
}

items(state.lessons, { it.toolCode.orEmpty() }, { "lesson" }) { toolState ->
Expand All @@ -54,9 +74,23 @@ internal fun LessonsLayout(state: UiState, modifier: Modifier = Modifier) {
showProgress = true,
modifier = Modifier
.animateItem()
.padding(top = 16.dp)
.padding(top = 16.dp, horizontal = MARGIN_LESSONS_LAYOUT_HORIZONTAL)
)
}

item("spacer", "spacer") {
Spacer(modifier = Modifier.height(16.dp))
}

if (state.mode == UiState.Mode.PERSONALIZATION) {
item("localization-settings-box", "localization-settings-box") {
LocalizationSettingsBox(
title = R.string.dashboard_lessons_section_personalized_localization_title,
description = R.string.dashboard_lessons_section_personalized_localization_text,
onClickSettings = { state.eventSink(UiEvent.OpenLocalizationSettings) }
)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ 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.settings.country.CountrySettingsScreen
import org.cru.godtools.ui.tools.ToolCardPresenter
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
import org.cru.godtools.util.createToolIntent
Expand Down Expand Up @@ -89,6 +90,7 @@ class LessonsPresenter @AssistedInject internal constructor(

internal sealed interface UiEvent : CircuitUiEvent {
data class ChangeMode(val mode: UiState.Mode) : UiEvent
data object OpenLocalizationSettings : UiEvent
}
// endregion UiState / UiEvent

Expand All @@ -114,6 +116,7 @@ class LessonsPresenter @AssistedInject internal constructor(
) {
when (it) {
is UiEvent.ChangeMode -> mode = it.mode
is UiEvent.OpenLocalizationSettings -> navigator.goTo(CountrySettingsScreen)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.cru.godtools.ui.dashboard.tools
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
Expand Down Expand Up @@ -30,6 +31,8 @@ import org.ccci.gto.android.common.compose.foundation.layout.padding
import org.cru.godtools.R
import org.cru.godtools.base.ui.circuit.screen.dashboard.page.ToolsScreen
import org.cru.godtools.ui.banner.Banners
import org.cru.godtools.ui.dashboard.LocalizationSettingsBox
import org.cru.godtools.ui.dashboard.rememberPinLastItemBottomArrangement
import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiEvent
import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiState
import org.cru.godtools.ui.tools.SquareToolCard
Expand All @@ -46,8 +49,17 @@ internal fun ToolsLayout(state: UiState, modifier: Modifier = Modifier) {

val columnState = rememberLazyListState()
LaunchedEffect(state.banner?.type) { if (state.banner != null) columnState.animateScrollToItem(0) }
val verticalArrangement = if (state.mode == UiState.Mode.PERSONALIZATION) {
rememberPinLastItemBottomArrangement(state.tools.size)
} else {
Arrangement.Top
}

LazyColumn(state = columnState, modifier = modifier) {
LazyColumn(
state = columnState,
verticalArrangement = verticalArrangement,
modifier = modifier.fillMaxHeight()
) {
if (!state.dataLoaded) return@LazyColumn

item("banners", "banners") {
Expand Down Expand Up @@ -121,6 +133,16 @@ internal fun ToolsLayout(state: UiState, modifier: Modifier = Modifier) {
.padding(bottom = 16.dp, horizontal = MARGIN_TOOLS_LAYOUT_HORIZONTAL)
)
}

if (state.mode == UiState.Mode.PERSONALIZATION) {
item("localization-settings-box", "localization-settings-box") {
LocalizationSettingsBox(
title = R.string.dashboard_tools_section_personalized_localization_title,
description = R.string.dashboard_tools_section_personalized_localization_text,
onClickSettings = { state.eventSink(UiEvent.OpenLocalizationSettings) }
)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import org.cru.godtools.ui.dashboard.SyncTaskRegistry.Companion.syncTaskRegistry
import org.cru.godtools.ui.dashboard.tools.ToolFiltersStateProducer.Filters
import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiState
import org.cru.godtools.ui.dashboard.tools.ToolsPresenter.UiState.Mode
import org.cru.godtools.ui.settings.country.CountrySettingsScreen
import org.cru.godtools.ui.tooldetails.ToolDetailsScreen
import org.cru.godtools.ui.tools.ToolCardPresenter
import org.cru.godtools.ui.tools.ToolCardPresenter.ToolCardEvent
Expand Down Expand Up @@ -79,6 +80,7 @@ class ToolsPresenter @AssistedInject internal constructor(

sealed interface UiEvent : CircuitUiEvent {
data class ChangeMode(val mode: Mode) : UiEvent
data object OpenLocalizationSettings : UiEvent
}
// endregion UiState / UiEvent

Expand Down Expand Up @@ -120,6 +122,7 @@ class ToolsPresenter @AssistedInject internal constructor(
) {
when (it) {
is UiEvent.ChangeMode -> mode = it.mode
is UiEvent.OpenLocalizationSettings -> navigator.goTo(CountrySettingsScreen)
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ An online version can be found at https://knowgod.com/</string>
</plurals>
<string name="dashboard_lessons_progress_completed">Completed</string>
<string name="dashboard_lessons_progress_in_progress">%1$d%% Complete</string>
<string name="dashboard_lessons_section_personalized_localization_title">Displaying localized Lessons list</string>
<string name="dashboard_lessons_section_personalized_localization_text">The lessons shown on this page are based on your Localization setting. You can alter this at any time.</string>

<!-- Home -->
<eat-comment />
Expand Down Expand Up @@ -83,6 +85,9 @@ An online version can be found at https://knowgod.com/</string>
<string name="dashboard_tools_section_categories_all">All Tools</string>
<string name="dashboard_tools_section_spotlight_label">Featured</string>
<string name="dashboard_tools_section_spotlight_description">Here are some tools we thought you might like</string>
<string name="dashboard_tools_section_personalized_localization_title">Displaying localized Tools list</string>
<string name="dashboard_tools_section_personalized_localization_text">The tools shown in your Personalized Tools page are selected based on your Language and Localization setting. You can alter this by editing your setting.</string>
<string name="dashboard_section_localization_box_button">Change Localization Settings</string>

<!-- Tool Cards -->
<eat-comment />
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,17 @@ class DashboardLayoutPaparazziTest(
snapshotDashboardLayout(state.copy(initialPage = ToolsScreen))
}

@Test
fun `ToolsLayout() - Personalization - Localization Settings Box`() {
assumeTrue(locale == null)
toolsState = toolsState.copy(
mode = ToolsPresenter.UiState.Mode.PERSONALIZATION,
spotlightTools = emptyList(),
tools = emptyList(),
)
snapshotDashboardLayout(state.copy(initialPage = ToolsScreen))
}

@Test
fun `ToolsLayout() - No Personalization`() {
assumeTrue(locale == null)
Expand Down Expand Up @@ -303,6 +314,16 @@ class DashboardLayoutPaparazziTest(
snapshotDashboardLayout(state.copy(initialPage = LessonsScreen))
}

@Test
fun `LessonsLayout() - Personalization - Localization Settings Box`() {
assumeTrue(locale == null)
lessonsState = lessonsState.copy(
mode = LessonsPresenter.UiState.Mode.PERSONALIZATION,
lessons = emptyList(),
)
snapshotDashboardLayout(state.copy(initialPage = LessonsScreen))
}

@Test
fun `LessonsLayout() - Personalization Disabled`() {
lessonsState = lessonsState.copy(isPersonalizationEnabled = false)
Expand Down