From 734522897ed9f2761b0349f6916bbe0c25e6e1d3 Mon Sep 17 00:00:00 2001 From: Nicole Georgieva <93789076+nicolegeorgieva@users.noreply.github.com> Date: Sat, 4 May 2024 21:35:23 +0300 Subject: [PATCH] Lesson (#20) * Create the UI layer of Lesson screen * Update LessonViewState and LessonContent * Navigate to LessonScreen from CourseScreen * Handle back event --- .../ui/screen/course/CourseViewModel.kt | 15 +++- .../kotlin/ui/screen/lesson/LessonScreen.kt | 29 ++++++++ .../ui/screen/lesson/LessonViewModel.kt | 52 ++++++++++++++ .../ui/screen/lesson/LessonViewState.kt | 13 ++++ .../screen/lesson/composable/LessonContent.kt | 71 +++++++++++++++++++ 5 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonScreen.kt create mode 100644 composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewModel.kt create mode 100644 composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewState.kt create mode 100644 composeApp/src/commonMain/kotlin/ui/screen/lesson/composable/LessonContent.kt diff --git a/composeApp/src/commonMain/kotlin/ui/screen/course/CourseViewModel.kt b/composeApp/src/commonMain/kotlin/ui/screen/course/CourseViewModel.kt index 5dfcba6f..61ce432d 100644 --- a/composeApp/src/commonMain/kotlin/ui/screen/course/CourseViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ui/screen/course/CourseViewModel.kt @@ -1,14 +1,20 @@ package ui.screen.course -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import arrow.core.identity import data.CourseRepository import ivy.data.source.model.CourseResponse import ivy.model.CourseId +import ivy.model.LessonId import kotlinx.collections.immutable.persistentListOf import ui.ComposeViewModel import ui.navigation.Navigation import ui.screen.course.mapper.CourseViewStateMapper +import ui.screen.lesson.LessonScreen class CourseViewModel( private val courseId: CourseId, @@ -47,6 +53,11 @@ class CourseViewModel( } private fun handleLessonClick(lesson: CourseItemViewState.Lesson) { - // TODO - navigate to lesson + navigation.navigate( + LessonScreen( + id = LessonId("4579"), + name = "Lesson 1" + ) + ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonScreen.kt b/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonScreen.kt new file mode 100644 index 00000000..aaa058f6 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonScreen.kt @@ -0,0 +1,29 @@ +package ui.screen.lesson + +import androidx.compose.runtime.Composable +import ivy.di.Di +import ivy.di.Di.register +import ivy.model.LessonId +import ui.navigation.Screen +import ui.screen.lesson.composable.LessonContent + +class LessonScreen( + id: LessonId, + name: String +) : Screen() { + override val path: String = "lesson" + + override fun onDi(): Di.ScreenScope.() -> Unit = { + register { LessonViewModel(Di.get()) } + } + + private val viewModel: LessonViewModel by lazy { Di.get() } + + @Composable + override fun Content() { + LessonContent( + viewState = viewModel.viewState(), + onEvent = viewModel::onEvent + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewModel.kt b/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewModel.kt new file mode 100644 index 00000000..928bbf7a --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewModel.kt @@ -0,0 +1,52 @@ +package ui.screen.lesson + +import androidx.compose.runtime.Composable +import ivy.model.ImageUrl +import ivy.model.Lesson +import ivy.model.LessonContent +import ivy.model.LessonId +import ivy.model.LessonItemId +import ivy.model.TextContentItem +import ivy.model.TextContentStyle +import ui.ComposeViewModel +import ui.navigation.Navigation + +class LessonViewModel( + private val navigation: Navigation +) : ComposeViewModel { + @Composable + override fun viewState(): LessonViewState { + return LessonViewState( + lesson = Lesson( + id = LessonId(value = "123"), + name = "Lesson 1", + tagline = "Learn programming by thinking...", + image = ImageUrl( + url = "https://cdn.pixabay.com/photo/2024/04/23/11/55/building-" + + "8714863_1280.jpg" + ), + content = LessonContent( + rootItem = LessonItemId(value = "324"), + items = mapOf( + LessonItemId("4") to TextContentItem( + id = LessonItemId(value = "5"), + text = "What are ADTs - ADTs or algebraic data types are...", + style = TextContentStyle.Body, + next = null + ) + ) + ) + ) + ) + } + + override fun onEvent(event: LessonViewEvent) { + when (event) { + LessonViewEvent.OnBackClick -> handleBackClick() + } + } + + private fun handleBackClick() { + navigation.back() + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewState.kt b/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewState.kt new file mode 100644 index 00000000..12bc1e93 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ui/screen/lesson/LessonViewState.kt @@ -0,0 +1,13 @@ +package ui.screen.lesson + +import androidx.compose.runtime.Immutable +import ivy.model.Lesson + +@Immutable +data class LessonViewState( + val lesson: Lesson +) + +sealed interface LessonViewEvent { + data object OnBackClick : LessonViewEvent +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ui/screen/lesson/composable/LessonContent.kt b/composeApp/src/commonMain/kotlin/ui/screen/lesson/composable/LessonContent.kt new file mode 100644 index 00000000..307e992b --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ui/screen/lesson/composable/LessonContent.kt @@ -0,0 +1,71 @@ +package ui.screen.lesson.composable + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import component.BackButton +import component.LearnScaffold +import component.platformHorizontalPadding +import ivy.model.ChoiceItem +import ivy.model.ImageItem +import ivy.model.LessonNavigationItem +import ivy.model.LinkItem +import ivy.model.LottieAnimationItem +import ivy.model.MysteryItem +import ivy.model.OpenQuestionItem +import ivy.model.QuestionItem +import ivy.model.TextContentItem +import ui.screen.lesson.LessonViewEvent +import ui.screen.lesson.LessonViewState + +@Composable +fun LessonContent( + viewState: LessonViewState, + onEvent: (LessonViewEvent) -> Unit +) { + LearnScaffold( + backButton = BackButton(onBackClick = { + onEvent(LessonViewEvent.OnBackClick) + }), + title = viewState.lesson.name + ) { contentPadding -> + val horizontalPadding = platformHorizontalPadding() + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(contentPadding), + verticalArrangement = Arrangement.spacedBy(12.dp), + horizontalAlignment = Alignment.CenterHorizontally, + contentPadding = PaddingValues( + top = 32.dp, + bottom = 48.dp, + start = horizontalPadding, + end = horizontalPadding, + ) + ) { + item(key = "lesson") { + val lesson = viewState.lesson.content.items.entries.first().value + when (lesson) { + is ChoiceItem -> TODO() + is ImageItem -> TODO() + is LessonNavigationItem -> TODO() + is LinkItem -> TODO() + is LottieAnimationItem -> TODO() + is MysteryItem -> TODO() + is OpenQuestionItem -> TODO() + is QuestionItem -> TODO() + is TextContentItem -> { + Text(lesson.text) + } + } + } + } + } +} \ No newline at end of file