Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #34

Merged
merged 11 commits into from
Jun 3, 2024
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
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