Skip to content

Commit

Permalink
Develop (#32)
Browse files Browse the repository at this point in the history
* Refactor server url provider

* Improve LessonContentDataSource error handling

* Fix the sound button styling

* Play sounds on "Continue" and "Question" answer

* Add "Finish!" button on the end of the lesson

* Improve lesson item spacing
  • Loading branch information
ILIYANGERMANOV authored May 31, 2024
1 parent d4533c9 commit 5316e05
Show file tree
Hide file tree
Showing 19 changed files with 144 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import androidx.compose.foundation.BorderStroke
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.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Text
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
Expand All @@ -25,6 +22,9 @@ fun SecondaryButton(
modifier = modifier,
enabled = enabled,
border = BorderStroke(1.dp, MaterialTheme.colors.secondary),
colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.secondary,
),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
onClick = onClick
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import ivy.model.CourseId
import ivy.model.LessonId
import ui.navigation.Screen
import ui.screen.lesson.composable.LessonContent
import ui.screen.lesson.handler.OnBackClickEventHandler
import ui.screen.lesson.handler.OnContinueClickEventHandler
import ui.screen.lesson.handler.OnSoundClickEventHandler
import ui.screen.lesson.handler.QuestionViewEventHandler
import ui.screen.lesson.handler.*
import ui.screen.lesson.mapper.LessonTreeManager
import ui.screen.lesson.mapper.LessonViewStateMapper

Expand All @@ -25,9 +22,10 @@ class LessonScreen(
register { LessonTreeManager() }
register { LessonViewStateMapper(Di.get(), Di.get()) }
register { OnBackClickEventHandler(Di.get()) }
register { OnContinueClickEventHandler() }
register { QuestionViewEventHandler() }
register { OnContinueClickEventHandler(Di.get()) }
register { QuestionViewEventHandler(Di.get()) }
register { OnSoundClickEventHandler(Di.get()) }
register { OnFinishClickEventHandler(Di.get(), Di.get()) }
register {
LessonViewModel(
courseId = courseId,
Expand All @@ -40,7 +38,8 @@ class LessonScreen(
Di.get<OnBackClickEventHandler>(),
Di.get<OnContinueClickEventHandler>(),
Di.get<QuestionViewEventHandler>(),
Di.get<OnSoundClickEventHandler>()
Di.get<OnSoundClickEventHandler>(),
Di.get<OnFinishClickEventHandler>(),
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ sealed interface CtaViewState {
val currentItemId: LessonItemIdViewState

data class Continue(override val currentItemId: LessonItemIdViewState) : CtaViewState
data class Finish(override val currentItemId: LessonItemIdViewState) : CtaViewState
}

@Immutable
Expand Down Expand Up @@ -128,6 +129,7 @@ sealed interface LessonViewEvent {
data object OnBackClick : LessonViewEvent
data class OnContinueClick(val currentItemId: LessonItemIdViewState) : LessonViewEvent
data class OnSoundClick(val soundUrl: String) : LessonViewEvent
data class OnFinishClick(val currentItemId: LessonItemIdViewState) : LessonViewEvent
}

sealed interface QuestionViewEvent : LessonViewEvent {
Expand All @@ -140,5 +142,8 @@ sealed interface QuestionViewEvent : LessonViewEvent {
val checked: Boolean
) : QuestionViewEvent

data class CheckClick(override val questionId: LessonItemIdViewState) : QuestionViewEvent
data class CheckClick(
override val questionId: LessonItemIdViewState,
val answers: List<AnswerViewState>,
) : QuestionViewEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ui.screen.lesson.LessonItemIdViewState
fun CtaBar(
viewState: CtaViewState,
onContinueClick: (LessonItemIdViewState) -> Unit,
onFinishClick: (LessonItemIdViewState) -> Unit,
modifier: Modifier = Modifier,
) {
Box(
Expand All @@ -29,6 +30,10 @@ fun CtaBar(
is CtaViewState.Continue -> ContinueButton(
onClick = { onContinueClick(viewState.currentItemId) }
)

is CtaViewState.Finish -> FinishButton(
onClick = { onFinishClick(viewState.currentItemId) }
)
}
}
}
Expand All @@ -43,4 +48,16 @@ private fun ContinueButton(
text = "CONTINUE",
onClick = onClick,
)
}

@Composable
private fun FinishButton(
modifier: Modifier = Modifier,
onClick: () -> Unit,
) {
CtaButton(
modifier = modifier,
text = "FINISH!",
onClick = onClick,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import ui.screen.lesson.composable.item.QuestionLessonItem
import ui.screen.lesson.composable.item.SoundLessonItem
import ui.screen.lesson.composable.item.TextLessonItem

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

@Composable
fun LessonContent(
viewState: LessonViewState,
Expand All @@ -47,6 +50,9 @@ fun LessonContent(
onContinueClick = { itemId ->
onEvent(LessonViewEvent.OnContinueClick(itemId))
},
onFinishClick = { itemId ->
onEvent(LessonViewEvent.OnFinishClick(itemId))
}
)
}
}
Expand Down Expand Up @@ -84,13 +90,13 @@ private fun LessonItemsLazyColum(
key = {
it.id.value
}
) {
when (it) {
) { itemViewState ->
when (itemViewState) {
is ChoiceItemViewState -> {
// TODO
}

is ImageItemViewState -> ImageLessonItem(it)
is ImageItemViewState -> ImageLessonItem(itemViewState)

is LessonNavigationItemViewState -> {
// TODO
Expand All @@ -113,26 +119,26 @@ private fun LessonItemsLazyColum(
}

is QuestionItemViewState -> QuestionLessonItem(
viewState = it,
viewState = itemViewState,
onAnswerCheckChange = { type, answerViewState, checked ->
onEvent(
QuestionViewEvent.AnswerCheckChange(
questionId = it.id,
questionId = itemViewState.id,
questionType = type,
answerId = answerViewState.id,
checked = checked,
)
)
},
onCheckClick = {
onEvent(QuestionViewEvent.CheckClick(it.id))
onCheckClick = { answers ->
onEvent(QuestionViewEvent.CheckClick(itemViewState.id, answers))
}
)

is TextItemViewState -> TextLessonItem(it)
is TextItemViewState -> TextLessonItem(itemViewState)

is SoundItemViewState -> SoundLessonItem(
viewState = it,
viewState = itemViewState,
onClick = { soundUrl ->
onEvent(LessonViewEvent.OnSoundClick(soundUrl))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import androidx.compose.ui.unit.dp
import io.kamel.image.KamelImage
import io.kamel.image.asyncPainterResource
import ui.screen.lesson.ImageItemViewState
import ui.screen.lesson.composable.ItemSpacing

@Composable
fun ImageLessonItem(
viewState: ImageItemViewState,
modifier: Modifier = Modifier,
) {
KamelImage(
modifier = modifier.padding(top = 12.dp)
modifier = modifier.padding(top = ItemSpacing)
.clip(RoundedCornerShape(16.dp)),
resource = asyncPainterResource(viewState.imageUrl),
contentDescription = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import component.text.SubTitle
import ui.screen.lesson.AnswerViewState
import ui.screen.lesson.QuestionItemViewState
import ui.screen.lesson.QuestionTypeViewState
import ui.screen.lesson.composable.ItemSpacingBig
import ui.theme.Green
import ui.theme.Red

Expand All @@ -25,10 +26,10 @@ fun QuestionLessonItem(
viewState: QuestionItemViewState,
modifier: Modifier = Modifier,
onAnswerCheckChange: (QuestionTypeViewState, AnswerViewState, Boolean) -> Unit,
onCheckClick: () -> Unit
onCheckClick: (List<AnswerViewState>) -> Unit
) {
Card(
modifier = modifier.padding(top = 12.dp),
modifier = modifier.padding(top = ItemSpacingBig),
shape = RoundedCornerShape(16.dp),
elevation = 4.dp
) {
Expand All @@ -54,7 +55,7 @@ fun QuestionLessonItem(
CheckButton(
modifier = Modifier.align(Alignment.End),
enabled = viewState.answers.any { it.selected },
onClick = onCheckClick
onClick = { onCheckClick(viewState.answers) }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.button.SecondaryButton
import ui.screen.lesson.SoundItemViewState
import ui.screen.lesson.composable.ItemSpacing

@Composable
fun SoundLessonItem(
Expand All @@ -16,7 +16,7 @@ fun SoundLessonItem(
modifier: Modifier = Modifier,
) {
SecondaryButton(
modifier = modifier.padding(top = 12.dp),
modifier = modifier.padding(top = ItemSpacing),
text = viewState.text,
icon = Icons.Default.PlayArrow,
onClick = { onClick(viewState.soundUrl) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package ui.screen.lesson.composable.item
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.text.Body
import component.text.HeadlineSmall
import ui.screen.lesson.TextItemViewState
import ui.screen.lesson.TextStyleViewState
import ui.screen.lesson.composable.ItemSpacing
import ui.screen.lesson.composable.ItemSpacingBig

@Composable
fun TextLessonItem(
Expand All @@ -16,12 +17,12 @@ fun TextLessonItem(
) {
when (viewState.style) {
TextStyleViewState.Heading -> HeadlineSmall(
modifier = modifier.padding(top = 16.dp),
modifier = modifier.padding(top = ItemSpacingBig),
text = viewState.text
)

TextStyleViewState.Body -> Body(
modifier = modifier.padding(top = 12.dp),
modifier = modifier.padding(top = ItemSpacing),
text = viewState.text
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package ui.screen.lesson.handler

import Platform
import ivy.content.SoundsUrls
import ui.EventHandler
import ui.screen.lesson.LessonViewEvent
import ui.screen.lesson.LessonViewModel.LocalState
import ui.screen.lesson.LessonVmContext
import ui.screen.lesson.completed
import ui.screen.lesson.mapper.toDomain

class OnContinueClickEventHandler :
class OnContinueClickEventHandler(
private val platform: Platform,
) :
EventHandler<LessonViewEvent.OnContinueClick, LocalState> {
override val eventTypes = setOf(LessonViewEvent.OnContinueClick::class)

Expand All @@ -19,5 +23,6 @@ class OnContinueClickEventHandler :
completed + event.currentItemId.toDomain()
}
}
platform.playSound(SoundsUrls.Complete)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ui.screen.lesson.handler

import Platform
import ivy.content.SoundsUrls
import ui.EventHandler
import ui.navigation.Navigation
import ui.screen.lesson.LessonViewEvent
import ui.screen.lesson.LessonViewModel.LocalState
import ui.screen.lesson.LessonVmContext

class OnFinishClickEventHandler(
private val platform: Platform,
private val navigation: Navigation,
) :
EventHandler<LessonViewEvent.OnContinueClick, LocalState> {
override val eventTypes = setOf(LessonViewEvent.OnContinueClick::class)

override suspend fun LessonVmContext.handleEvent(
event: LessonViewEvent.OnContinueClick
) {
navigation.back()
platform.playSound(SoundsUrls.CompleteLesson)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ui.screen.lesson.handler

import Platform
import arrow.optics.dsl.index
import arrow.optics.typeclasses.Index
import ivy.content.SoundsUrls
import ivy.model.AnswerId
import ui.EventHandler
import ui.screen.lesson.LessonViewModel.LocalState
Expand All @@ -13,7 +15,9 @@ import ui.screen.lesson.answers
import ui.screen.lesson.completed
import ui.screen.lesson.mapper.toDomain

class QuestionViewEventHandler :
class QuestionViewEventHandler(
private val platform: Platform,
) :
EventHandler<QuestionViewEvent, LocalState> {
override val eventTypes = setOf(
QuestionViewEvent.AnswerCheckChange::class,
Expand Down Expand Up @@ -70,5 +74,11 @@ class QuestionViewEventHandler :
completed + event.questionId.toDomain()
}
}
val correctAnswer = event.answers.all {
it.selected == it.correct
}
platform.playSound(
if (correctAnswer) SoundsUrls.Success else SoundsUrls.Ups
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ class LessonViewStateMapper(
null, is QuestionItem, is OpenQuestionItem,
is ChoiceItem -> null

else -> CtaViewState.Continue(currentItem.id.toViewState())
else -> {
platform.log(LogLevel.Debug, "Current item: $currentItem")
if (currentItem is LinearItem && currentItem.next == null) {
CtaViewState.Finish(currentItem.id.toViewState())
} else {
CtaViewState.Continue(currentItem.id.toViewState())
}
}
}
)
}
Expand Down
Loading

0 comments on commit 5316e05

Please sign in to comment.