Skip to content

Commit

Permalink
Develop (#35)
Browse files Browse the repository at this point in the history
* Improve the text items

* Fix auto-scrolling on mobile

* Fix ChoiceItem on mobile

* WIP: Add progress bar

* Fix the progress bar

* Refactor the progress bar composable
  • Loading branch information
ILIYANGERMANOV authored Jun 4, 2024
1 parent 248980e commit 2d6f71d
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 32 deletions.
36 changes: 20 additions & 16 deletions composeApp/src/commonMain/kotlin/component/LearnScaffold.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
package component

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
Expand All @@ -38,14 +29,16 @@ fun LearnScaffold(
modifier: Modifier = Modifier,
bottomBar: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
topBarCenterContent: (@Composable () -> Unit)? = null,
content: @Composable (PaddingValues) -> Unit
) {
Scaffold(
modifier = modifier,
topBar = {
LearnTopAppBar(
backButton = backButton,
title = title
title = title,
centerContent = topBarCenterContent,
)
},
bottomBar = bottomBar,
Expand All @@ -59,7 +52,8 @@ private fun LearnTopAppBar(
backButton: BackButton?,
title: String,
modifier: Modifier = Modifier,
actions: @Composable (Modifier) -> Unit = {}
actions: @Composable (Modifier) -> Unit = {},
centerContent: (@Composable () -> Unit)? = null,
) {
TopAppBar(
modifier = modifier,
Expand All @@ -78,7 +72,17 @@ private fun LearnTopAppBar(
Spacer(Modifier.weight(1f))
Spacer(Modifier.width(actionsWidth))

Text(title)
if (centerContent != null) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(title)
Spacer(Modifier.height(4.dp))
centerContent()
}
} else {
Text(title)
}

Spacer(Modifier.weight(1f))
actions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class LessonViewModel(
title = lessonName,
items = persistentListOf(),
cta = null,
progress = LessonProgressViewState(0, 1),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ data class LessonViewState(
val title: String,
val items: ImmutableList<LessonItemViewState>,
val cta: CtaViewState?,
val progress: LessonProgressViewState,
)

@Immutable
data class LessonProgressViewState(
val done: Int,
val total: Int,
)

@Immutable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.BackButton
import component.LearnScaffold
import component.ScreenType
import component.ScreenType.*
import component.screenType
import kotlinx.coroutines.delay
import ui.screen.lesson.*
Expand All @@ -26,10 +26,15 @@ fun LessonContent(
onEvent: (LessonViewEvent) -> Unit
) {
LearnScaffold(
backButton = BackButton(onBackClick = {
onEvent(LessonViewEvent.OnBackClick)
}),
title = viewState.title
backButton = BackButton(
onBackClick = {
onEvent(LessonViewEvent.OnBackClick)
}
),
title = viewState.title,
topBarCenterContent = {
LessonProgressBar(viewState = viewState.progress)
}
) { contentPadding ->
Box(
modifier = Modifier.fillMaxSize()
Expand Down Expand Up @@ -62,9 +67,9 @@ private fun LessonItemsLazyColum(
modifier: Modifier = Modifier,
) {
val horizontalPadding = when (screenType()) {
ScreenType.Mobile -> 16.dp
ScreenType.Tablet -> 24.dp
ScreenType.Desktop -> 64.dp
Mobile -> 16.dp
Tablet -> 24.dp
Desktop -> 64.dp
}
val listState = rememberLazyListState()

Expand Down Expand Up @@ -156,7 +161,14 @@ private fun LessonItemsLazyColum(
}
}
item("empty_space") {
Spacer(Modifier.height(200.dp))
Spacer(
Modifier.height(
when (screenType()) {
Mobile, Tablet -> 32.dp
Desktop -> 200.dp
}
)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ui.screen.lesson.composable

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.coerceAtMost
import androidx.compose.ui.unit.dp
import ui.screen.lesson.LessonProgressViewState
import ui.theme.Gray


@Composable
fun LessonProgressBar(
viewState: LessonProgressViewState,
modifier: Modifier = Modifier,
progressBarWidth: Dp = 124.dp,
) {
Box(modifier = modifier) {
val progressPercent by animateFloatAsState(
targetValue = viewState.done / viewState.total.toFloat(),
)
// background (total)
ProgressBarLine(width = progressBarWidth, color = Gray)
// foreground (progress)
val progressWidth = (progressBarWidth * progressPercent).coerceAtMost(progressBarWidth)
ProgressBarLine(width = progressWidth, color = MaterialTheme.colors.primary)
}
}

@Composable
private fun ProgressBarLine(
width: Dp,
color: Color,
modifier: Modifier = Modifier,
) {
Spacer(
modifier.height(8.dp)
.width(width)
.background(color, RoundedCornerShape(percent = 50))
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.ScreenType.*
import component.button.PrimaryButton
import component.screenType
import kotlinx.collections.immutable.ImmutableList
import ui.screen.lesson.ChoiceItemViewState
import ui.screen.lesson.ChoiceOptionViewState
Expand Down Expand Up @@ -37,10 +39,7 @@ private fun ChoicesOptions(
onChoiceClick: (ChoiceOptionViewState) -> Unit,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
) {
ChoiceOptionsContainer(modifier = modifier) {
for ((index, itemViewState) in options.withIndex()) {
ChoiceOption(
viewState = itemViewState,
Expand All @@ -53,6 +52,27 @@ private fun ChoicesOptions(
}
}

@Composable
private fun ChoiceOptionsContainer(
modifier: Modifier = Modifier,
options: @Composable () -> Unit
) {
when (screenType()) {
Mobile, Tablet -> Column(
modifier = modifier,
) {
options()
}

Desktop -> Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
) {
options()
}
}
}

@Composable
private fun ChoiceOption(
viewState: ChoiceOptionViewState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ fun TextLessonItem(
top = ItemSpacing
),
text = viewState.text,
textAlign = TextAlign.Center,
textAlign = TextAlign.Start,
)

TextStyleViewState.BodyBigSpacing -> BodyBig(
modifier = modifier.padding(
top = ItemSpacingBig
),
text = viewState.text,
textAlign = TextAlign.Center,
textAlign = TextAlign.Start,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,23 @@ class LessonViewStateMapper(
CtaViewState.Continue(currentItem.id.toViewState())
}
}
}
},
progress = toProgressViewState(lessonItems)
)
}

private fun Lesson.toProgressViewState(
lessonItems: List<LessonItem>,
): LessonProgressViewState {
val done = lessonItems.size
val unreachablePaths = content.items.values.sumOf {
if (it is ChoiceItem) (it.options.size - 1).coerceAtLeast(0) else 0
}
val total = (content.items.size - unreachablePaths - 1) // -1 for the finish item
.coerceAtLeast(0)
return LessonProgressViewState(done, total)
}

private fun LessonItem.toViewState(
localState: LessonViewModel.LocalState,
items: Map<LessonItemId, LessonItem>
Expand Down

0 comments on commit 2d6f71d

Please sign in to comment.