Skip to content

Commit

Permalink
Develop (#34)
Browse files Browse the repository at this point in the history
* Improve the LessonContent DSL

* WIP: Lesson + fix stuff

* WIP: First lesson

* WIP: Lesson 1

* WIP: Support choice

* Support choice

* WIP: Fix chaining issues

* Fix stuff

* Improve UX

* WIP

* WIP
  • Loading branch information
ILIYANGERMANOV authored Jun 3, 2024
1 parent 5316e05 commit 248980e
Show file tree
Hide file tree
Showing 39 changed files with 693 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import androidx.compose.ui.Modifier
import io.github.alexzhirkevich.compottie.LottieAnimation
import io.github.alexzhirkevich.compottie.LottieCompositionSpec
import io.github.alexzhirkevich.compottie.rememberLottieComposition
import ivy.data.LottieAnimationLoader
import ivy.di.Di
import learn.composeapp.generated.resources.Res
import org.jetbrains.compose.resources.ExperimentalResourceApi

Expand All @@ -14,7 +16,7 @@ import org.jetbrains.compose.resources.ExperimentalResourceApi
*/
@OptIn(ExperimentalResourceApi::class)
@Composable
fun LearnLottieAnimation(
fun LocalLottieAnimation(
animationFile: String,
repeat: Boolean,
modifier: Modifier = Modifier,
Expand All @@ -31,4 +33,27 @@ fun LearnLottieAnimation(
iterations = if (repeat) Int.MAX_VALUE else 1,
)
}
}

@Composable
fun RemoteLottieAnimation(
animationUrl: String,
repeat: Boolean,
modifier: Modifier = Modifier,
) {
var lottieJson by remember { mutableStateOf<String?>(null) }
LaunchedEffect(Unit) {
Di.get<LottieAnimationLoader>().loadJson(animationUrl)
.onRight { json ->
lottieJson = json
}
}
lottieJson?.let {
val composition by rememberLottieComposition(LottieCompositionSpec.JsonString(it))
LottieAnimation(
modifier = modifier,
composition = composition,
iterations = if (repeat) Int.MAX_VALUE else 1,
)
}
}
18 changes: 18 additions & 0 deletions composeApp/src/commonMain/kotlin/component/button/PrimaryButton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package component.button

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material.Button
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -22,4 +23,21 @@ fun PrimaryButton(
) {
Text(text = text)
}
}

@Composable
fun PrimaryOutlinedButton(
text: String,
modifier: Modifier = Modifier,
enabled: Boolean = true,
onClick: () -> Unit,
) {
OutlinedButton(
modifier = modifier,
enabled = enabled,
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
onClick = onClick
) {
Text(text = text)
}
}
19 changes: 19 additions & 0 deletions composeApp/src/commonMain/kotlin/component/text/Body.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp

@Composable
fun BodyBig(
text: String,
modifier: Modifier = Modifier,
textAlign: TextAlign = TextAlign.Start,
) {
Text(
modifier = modifier,
text = text,
style = MaterialTheme.typography.body1.copy(
fontSize = 18.sp
),
textAlign = textAlign,
)
}


@Composable
fun Body(
Expand Down
7 changes: 5 additions & 2 deletions composeApp/src/commonMain/kotlin/component/text/Subtitle.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight

@Composable
fun SubTitle(
text: String,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
fontWeight: FontWeight? = null,
) {
Text(
modifier = modifier,
text = text,
style = MaterialTheme.typography.subtitle1
style = MaterialTheme.typography.subtitle1,
fontWeight = fontWeight,
)
}
17 changes: 16 additions & 1 deletion composeApp/src/commonMain/kotlin/data/LessonRepository.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package data

import arrow.core.Either
import arrow.core.right
import ivy.content.lesson.programmingfundamentals.programmingMathInDisguise
import ivy.data.source.LessonDataSource
import ivy.model.CourseId
import ivy.model.ImageUrl
import ivy.model.Lesson
import ivy.model.LessonId
import kotlinx.coroutines.withContext
Expand All @@ -12,10 +15,22 @@ class LessonRepository(
private val dispatchers: DispatchersProvider,
private val datasource: LessonDataSource,
) {
private val fakeLessonEnabled = true

suspend fun fetchLesson(
course: CourseId,
lesson: LessonId
): Either<String, Lesson> = withContext(dispatchers.io) {
datasource.fetchLesson(course, lesson)
fakeLesson()?.right() ?: datasource.fetchLesson(course, lesson)
}

private fun fakeLesson(): Lesson? = if (fakeLessonEnabled) {
Lesson(
id = LessonId("fake"),
name = "Programming: Math in disguise",
tagline = "",
image = ImageUrl(""),
content = programmingMathInDisguise(),
)
} else null
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.LearnLottieAnimation
import component.LocalLottieAnimation
import component.button.CtaButton
import component.platformHorizontalPadding
import component.text.Headline
Expand All @@ -31,7 +31,7 @@ fun IntroContent(
verticalArrangement = Arrangement.Center
) {
Spacer(modifier = Modifier.weight(1f))
LearnLottieAnimation(
LocalLottieAnimation(
modifier = Modifier.size(400.dp),
animationFile = "intro_lottie_anim.json",
repeat = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class LessonScreen(
register { QuestionViewEventHandler(Di.get()) }
register { OnSoundClickEventHandler(Di.get()) }
register { OnFinishClickEventHandler(Di.get(), Di.get()) }
register { OnChoiceClickEventHandler(Di.get()) }
register {
LessonViewModel(
courseId = courseId,
Expand All @@ -40,6 +41,7 @@ class LessonScreen(
Di.get<QuestionViewEventHandler>(),
Di.get<OnSoundClickEventHandler>(),
Di.get<OnFinishClickEventHandler>(),
Di.get<OnChoiceClickEventHandler>(),
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ data class TextItemViewState(

@Immutable
enum class TextStyleViewState {
Heading, Body
Heading, Body, BodyBigSpacing
}

@Immutable
Expand Down Expand Up @@ -98,7 +98,7 @@ data class ImageItemViewState(
data class ChoiceItemViewState(
override val id: LessonItemIdViewState,
val question: String,
val options: List<ChoiceOptionViewState>,
val options: ImmutableList<ChoiceOptionViewState>,
) : LessonItemViewState

@Immutable
Expand Down Expand Up @@ -130,19 +130,23 @@ sealed interface LessonViewEvent {
data class OnContinueClick(val currentItemId: LessonItemIdViewState) : LessonViewEvent
data class OnSoundClick(val soundUrl: String) : LessonViewEvent
data class OnFinishClick(val currentItemId: LessonItemIdViewState) : LessonViewEvent
data class OnChoiceClick(
val questionId: LessonItemIdViewState,
val choiceId: String
) : LessonViewEvent
}

sealed interface QuestionViewEvent : LessonViewEvent {
val questionId: LessonItemIdViewState

data class AnswerCheckChange(
data class OnAnswerCheckChange(
override val questionId: LessonItemIdViewState,
val questionType: QuestionTypeViewState,
val answerId: String,
val checked: Boolean
) : QuestionViewEvent

data class CheckClick(
data class OnCheckClick(
override val questionId: LessonItemIdViewState,
val answers: List<AnswerViewState>,
) : QuestionViewEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private fun FinishButton(
) {
CtaButton(
modifier = modifier,
text = "FINISH!",
text = "COMPLETE LESSON",
onClick = onClick,
)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package ui.screen.lesson.composable

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
Expand All @@ -14,15 +11,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.BackButton
import component.LearnScaffold
import component.platformHorizontalPadding
import component.ScreenType
import component.screenType
import kotlinx.coroutines.delay
import ui.screen.lesson.*
import ui.screen.lesson.composable.item.ImageLessonItem
import ui.screen.lesson.composable.item.QuestionLessonItem
import ui.screen.lesson.composable.item.SoundLessonItem
import ui.screen.lesson.composable.item.TextLessonItem
import ui.screen.lesson.composable.item.*

val ItemSpacing = 12.dp
val ItemSpacingBig = 16.dp
val ItemSpacingBig = 48.dp

@Composable
fun LessonContent(
Expand Down Expand Up @@ -65,12 +61,20 @@ private fun LessonItemsLazyColum(
onEvent: (LessonViewEvent) -> Unit,
modifier: Modifier = Modifier,
) {
val horizontalPadding = platformHorizontalPadding()
val horizontalPadding = when (screenType()) {
ScreenType.Mobile -> 16.dp
ScreenType.Tablet -> 24.dp
ScreenType.Desktop -> 64.dp
}
val listState = rememberLazyListState()

LaunchedEffect(viewState.items.size) {
if (viewState.items.size > 1) {
listState.animateScrollToItem(viewState.items.lastIndex)
// ensure auto scrolls works for images that are loading
repeat(4) {
listState.animateScrollToItem(viewState.items.lastIndex)
delay(200)
}
}
}

Expand All @@ -92,9 +96,17 @@ private fun LessonItemsLazyColum(
}
) { itemViewState ->
when (itemViewState) {
is ChoiceItemViewState -> {
// TODO
}
is ChoiceItemViewState -> ChoiceLessonItem(
viewState = itemViewState,
onChoiceClick = { choiceOptionViewState ->
onEvent(
LessonViewEvent.OnChoiceClick(
questionId = itemViewState.id,
choiceId = choiceOptionViewState.id
)
)
}
)

is ImageItemViewState -> ImageLessonItem(itemViewState)

Expand All @@ -106,9 +118,7 @@ private fun LessonItemsLazyColum(
// TODO
}

is LottieAnimationItemViewState -> {
// TODO
}
is LottieAnimationItemViewState -> LottieAnimationLessonItem(itemViewState)

is MysteryItemViewState -> {
// TODO
Expand All @@ -122,7 +132,7 @@ private fun LessonItemsLazyColum(
viewState = itemViewState,
onAnswerCheckChange = { type, answerViewState, checked ->
onEvent(
QuestionViewEvent.AnswerCheckChange(
QuestionViewEvent.OnAnswerCheckChange(
questionId = itemViewState.id,
questionType = type,
answerId = answerViewState.id,
Expand All @@ -131,7 +141,7 @@ private fun LessonItemsLazyColum(
)
},
onCheckClick = { answers ->
onEvent(QuestionViewEvent.CheckClick(itemViewState.id, answers))
onEvent(QuestionViewEvent.OnCheckClick(itemViewState.id, answers))
}
)

Expand All @@ -145,5 +155,8 @@ private fun LessonItemsLazyColum(
)
}
}
item("empty_space") {
Spacer(Modifier.height(200.dp))
}
}
}
Loading

0 comments on commit 248980e

Please sign in to comment.