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

First lesson #31

Merged
merged 12 commits into from
May 31, 2024
15 changes: 15 additions & 0 deletions composeApp/src/commonMain/kotlin/component/ComposeUtils.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package component

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo
Expand All @@ -18,6 +19,20 @@ fun screenWidth(): Dp {
return with(density) { containerSize.width.toDp() }
}

@Composable
fun screenType(): ScreenType = when {
screenWidth() < 600.dp -> ScreenType.Mobile
screenWidth() < 1200.dp -> ScreenType.Tablet
else -> ScreenType.Desktop
}

@Immutable
enum class ScreenType {
Mobile,
Tablet,
Desktop
}

@Composable
fun platformHorizontalPadding(): Dp {
return if (isLargeScreen()) 24.dp else 16.dp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fun PrimaryButton(
Button(
modifier = modifier,
enabled = enabled,
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
onClick = onClick
) {
Text(text = text)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package component.button

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.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp

@Composable
fun SecondaryButton(
text: String,
modifier: Modifier = Modifier,
icon: ImageVector? = null,
enabled: Boolean = true,
onClick: () -> Unit,
) {
OutlinedButton(
modifier = modifier,
enabled = enabled,
border = BorderStroke(1.dp, MaterialTheme.colors.secondary),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
onClick = onClick
) {
if (icon != null) {
Icon(imageVector = icon, contentDescription = null)
Spacer(Modifier.width(8.dp))
}
Text(text = text)
}
}
15 changes: 15 additions & 0 deletions composeApp/src/commonMain/kotlin/component/text/Headline.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,19 @@ fun Headline(
color = color,
fontWeight = FontWeight.Black,
)
}

@Composable
fun HeadlineSmall(
text: String,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colors.onBackground,
) {
Text(
modifier = modifier,
text = text,
style = MaterialTheme.typography.h5,
color = color,
fontWeight = FontWeight.Black,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import component.ScreenType.*
import component.isLargeScreen
import component.screenType
import component.text.SubTitle
import component.text.Title
import io.kamel.image.KamelImage
Expand Down Expand Up @@ -67,7 +69,13 @@ private fun Banner(
KamelImage(
modifier = modifier
.fillMaxWidth()
.aspectRatio(if (isLargeScreen()) 4f else 3.5f),
.aspectRatio(
when (screenType()) {
Mobile -> 3.5f
Tablet -> 4f
Desktop -> 5f
}
),
contentScale = ContentScale.Crop,
resource = asyncPainterResource(imageUrl),
contentDescription = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ fun HomeContent(
),
title = "Learn"
) { contentPadding ->
val columnsCount = when (screenWidth().value) {
in 0f..600f -> 1
in 600f..1200f -> 2
else -> 3
val columnsCount = when (screenType()) {
ScreenType.Mobile -> 1
ScreenType.Tablet -> 2
ScreenType.Desktop -> 3
}
val horizontalPadding = platformHorizontalPadding()
LazyVerticalGrid(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
package ui.screen.intro.composable

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
Expand Down Expand Up @@ -60,7 +54,7 @@ private fun ContinueButton(
) {
CtaButton(
modifier = modifier,
text = "LET'S GO",
text = "LET'S GO!",
onClick = onClick
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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.mapper.LessonTreeManager
import ui.screen.lesson.mapper.LessonViewStateMapper
Expand All @@ -26,6 +27,7 @@ class LessonScreen(
register { OnBackClickEventHandler(Di.get()) }
register { OnContinueClickEventHandler() }
register { QuestionViewEventHandler() }
register { OnSoundClickEventHandler(Di.get()) }
register {
LessonViewModel(
courseId = courseId,
Expand All @@ -38,6 +40,7 @@ class LessonScreen(
Di.get<OnBackClickEventHandler>(),
Di.get<OnContinueClickEventHandler>(),
Di.get<QuestionViewEventHandler>(),
Di.get<OnSoundClickEventHandler>()
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,17 @@ data class MysteryItemViewState(
@Immutable
value class LessonItemIdViewState(val value: String)

@Immutable
data class SoundItemViewState(
override val id: LessonItemIdViewState,
val text: String,
val soundUrl: String
) : LessonItemViewState

sealed interface LessonViewEvent {
data object OnBackClick : LessonViewEvent
data class OnContinueClick(val currentItemId: LessonItemIdViewState) : LessonViewEvent
data class OnSoundClick(val soundUrl: String) : LessonViewEvent
}

sealed interface QuestionViewEvent : LessonViewEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fun CtaBar(
Box(
modifier = modifier.fillMaxWidth()
.background(MaterialTheme.colors.background)
.padding(bottom = 16.dp, top = 12.dp),
.padding(vertical = 8.dp),
contentAlignment = Alignment.Center,
) {
when (viewState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Expand All @@ -16,6 +18,7 @@ import component.platformHorizontalPadding
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

@Composable
Expand Down Expand Up @@ -57,9 +60,18 @@ private fun LessonItemsLazyColum(
modifier: Modifier = Modifier,
) {
val horizontalPadding = platformHorizontalPadding()
val listState = rememberLazyListState()

LaunchedEffect(viewState.items.size) {
if (viewState.items.size > 1) {
listState.animateScrollToItem(viewState.items.lastIndex)
}
}

LazyColumn(
modifier = modifier
.fillMaxSize(),
state = listState,
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = PaddingValues(
bottom = 96.dp,
Expand Down Expand Up @@ -118,6 +130,13 @@ private fun LessonItemsLazyColum(
)

is TextItemViewState -> TextLessonItem(it)

is SoundItemViewState -> SoundLessonItem(
viewState = it,
onClick = { soundUrl ->
onEvent(LessonViewEvent.OnSoundClick(soundUrl))
}
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package ui.screen.lesson.composable.item

import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import io.kamel.image.KamelImage
import io.kamel.image.asyncPainterResource
Expand All @@ -14,7 +16,8 @@ fun ImageLessonItem(
modifier: Modifier = Modifier,
) {
KamelImage(
modifier = modifier.padding(top = 12.dp),
modifier = modifier.padding(top = 12.dp)
.clip(RoundedCornerShape(16.dp)),
resource = asyncPainterResource(viewState.imageUrl),
contentDescription = null
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fun QuestionLessonItem(
)
}
if (!viewState.answered) {
Spacer(Modifier.height(12.dp))
Spacer(Modifier.height(8.dp))
CheckButton(
modifier = Modifier.align(Alignment.End),
enabled = viewState.answers.any { it.selected },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ui.screen.lesson.composable.item

import androidx.compose.foundation.layout.padding
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

@Composable
fun SoundLessonItem(
viewState: SoundItemViewState,
onClick: (soundUrl: String) -> Unit,
modifier: Modifier = Modifier,
) {
SecondaryButton(
modifier = modifier.padding(top = 12.dp),
text = viewState.text,
icon = Icons.Default.PlayArrow,
onClick = { onClick(viewState.soundUrl) },
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import component.text.Body
import component.text.Headline
import component.text.HeadlineSmall
import ui.screen.lesson.TextItemViewState
import ui.screen.lesson.TextStyleViewState

Expand All @@ -15,7 +15,7 @@ fun TextLessonItem(
modifier: Modifier = Modifier
) {
when (viewState.style) {
TextStyleViewState.Heading -> Headline(
TextStyleViewState.Heading -> HeadlineSmall(
modifier = modifier.padding(top = 16.dp),
text = viewState.text
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ui.screen.lesson.handler

import Platform
import ui.EventHandler
import ui.screen.lesson.LessonViewEvent
import ui.screen.lesson.LessonViewModel
import ui.screen.lesson.LessonVmContext

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

override suspend fun LessonVmContext.handleEvent(event: LessonViewEvent.OnSoundClick) {
platform.playSound(soundUrl = event.soundUrl)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class LessonTreeManager {
currentItemId in localState.completed
}

is SoundItem -> true

else -> {
currentItemId in localState.completed || autoLoadNextN > 0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class LessonViewStateMapper(
is OpenQuestionItem -> toViewState(localState)
is QuestionItem -> toViewState(localState)
is TextItem -> toViewState()
is SoundItem -> toViewState()
}

private fun ChoiceItem.toViewState(): ChoiceItemViewState = ChoiceItemViewState(
Expand Down Expand Up @@ -133,6 +134,12 @@ class LessonViewStateMapper(
Body -> TextStyleViewState.Body
}
)

private fun SoundItem.toViewState(): SoundItemViewState = SoundItemViewState(
id = id.toViewState(),
soundUrl = sound.url,
text = text,
)
}

fun LessonItemId.toViewState(): LessonItemIdViewState = LessonItemIdViewState(value)
Expand Down
Loading