diff --git a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Buttons.kt b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Buttons.kt
index f37d9c332..d881c10da 100644
--- a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Buttons.kt
+++ b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Buttons.kt
@@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
@@ -93,7 +92,7 @@ fun TvManiacOutlinedButton(
borderColor: Color,
modifier: Modifier = Modifier,
enabled: Boolean = true,
- shape: Shape = RoundedCornerShape(4.dp),
+ shape: Shape = MaterialTheme.shapes.small,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit,
) {
diff --git a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Card.kt b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Card.kt
index 2dd7640c4..1cd86ba95 100644
--- a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Card.kt
+++ b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Card.kt
@@ -14,7 +14,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
@@ -26,6 +26,7 @@ fun TvPosterCard(
posterImageUrl: String?,
title: String,
modifier: Modifier = Modifier,
+ shape: Shape = MaterialTheme.shapes.small,
imageWidth: Dp = 120.dp,
onClick: () -> Unit = {},
) {
@@ -33,7 +34,7 @@ fun TvPosterCard(
modifier = modifier
.width(imageWidth)
.clickable { onClick() },
- shape = RectangleShape,
+ shape = shape,
elevation = CardDefaults.cardElevation(
defaultElevation = 4.dp,
),
diff --git a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Dialogs.kt b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Dialogs.kt
index c46fdf376..0564f8365 100644
--- a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Dialogs.kt
+++ b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/components/Dialogs.kt
@@ -9,7 +9,6 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
@@ -24,7 +23,7 @@ fun BasicDialog(
enableConfirmButton: Boolean = true,
enableDismissButton: Boolean = true,
dismissButtonText: String? = null,
- shape: Shape = RectangleShape,
+ shape: Shape = MaterialTheme.shapes.small,
onDismissDialog: () -> Unit = {},
confirmButtonClicked: () -> Unit = {},
dismissButtonClicked: () -> Unit = {},
diff --git a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Shape.kt b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Shape.kt
new file mode 100644
index 000000000..6e386334c
--- /dev/null
+++ b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Shape.kt
@@ -0,0 +1,11 @@
+package com.thomaskioko.tvmaniac.compose.theme
+
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Shapes
+import androidx.compose.ui.unit.dp
+
+val tvManiacShapes = Shapes(
+ small = RoundedCornerShape(4.dp),
+ medium = RoundedCornerShape(8.dp),
+ large = RoundedCornerShape(16.dp),
+)
diff --git a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Theme.kt b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Theme.kt
index a949932c5..398d8ae47 100644
--- a/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Theme.kt
+++ b/android-core/designsystem/src/main/kotlin/com/thomaskioko/tvmaniac/compose/theme/Theme.kt
@@ -54,6 +54,7 @@ fun TvManiacTheme(
MaterialTheme(
colorScheme = colorScheme,
typography = tvManiacTypography,
+ shapes = tvManiacShapes,
content = content,
)
}
diff --git a/android-core/resources/src/main/res/values/strings.xml b/android-core/resources/src/main/res/values/strings.xml
index 3e72dc04e..6e8fd09b7 100644
--- a/android-core/resources/src/main/res/values/strings.xml
+++ b/android-core/resources/src/main/res/values/strings.xml
@@ -40,6 +40,7 @@
Settings
All Seasons
+ All Episodes
Watch Next
Back Online!
No Internet Connection!
diff --git a/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverScreen.kt b/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverScreen.kt
index 10f919358..02f532554 100644
--- a/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverScreen.kt
+++ b/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverScreen.kt
@@ -417,7 +417,7 @@ fun HorizontalPagerItem(
}
}
-@OptIn(ExperimentalSnapperApi::class)
+@OptIn(ExperimentalSnapperApi::class, ExperimentalFoundationApi::class)
@Composable
private fun RowContent(
category: Category,
@@ -449,6 +449,8 @@ private fun RowContent(
posterImageUrl = tvShow.posterImageUrl,
title = tvShow.title,
onClick = { onItemClicked(tvShow.traktId) },
+ modifier = Modifier
+ .animateItemPlacement(),
)
}
}
diff --git a/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonDetailsScreen.kt b/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonDetailsScreen.kt
index 6d78b3315..92757d8b2 100644
--- a/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonDetailsScreen.kt
+++ b/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonDetailsScreen.kt
@@ -7,10 +7,13 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -41,10 +44,14 @@ import com.thomaskioko.tvmaniac.presentation.seasondetails.Loading
import com.thomaskioko.tvmaniac.presentation.seasondetails.LoadingError
import com.thomaskioko.tvmaniac.presentation.seasondetails.SeasonDetailsLoaded
import com.thomaskioko.tvmaniac.presentation.seasondetails.SeasonDetailsState
+import com.thomaskioko.tvmaniac.presentation.seasondetails.model.Episode
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.SeasonDetails
import com.thomaskioko.tvmaniac.resources.R
import com.thomaskioko.tvmaniac.seasondetails.components.CollapsableContent
-import com.thomaskioko.tvmaniac.seasondetails.components.WatchNextContent
+import com.thomaskioko.tvmaniac.seasondetails.components.EpisodeItem
+import dev.chrisbanes.snapper.ExperimentalSnapperApi
+import dev.chrisbanes.snapper.rememberSnapperFlingBehavior
+import kotlinx.collections.immutable.ImmutableList
import me.tatarka.inject.annotations.Assisted
import me.tatarka.inject.annotations.Inject
@@ -106,8 +113,7 @@ internal fun SeasonDetailScreen(
navigateUp = onBackClicked,
)
},
- modifier = modifier
- .statusBarsPadding(),
+ modifier = modifier.statusBarsPadding(),
content = { contentPadding ->
when (state) {
Loading -> LoadingIndicator(
@@ -116,14 +122,13 @@ internal fun SeasonDetailScreen(
.wrapContentSize(Alignment.Center),
)
- is LoadingError ->
- ErrorUi(
- errorMessage = state.message,
- onRetry = {},
- modifier = Modifier
- .fillMaxSize()
- .wrapContentSize(Alignment.Center),
- )
+ is LoadingError -> ErrorUi(
+ errorMessage = state.message,
+ onRetry = {},
+ modifier = Modifier
+ .fillMaxSize()
+ .wrapContentSize(Alignment.Center),
+ )
is SeasonDetailsLoaded -> {
SeasonContent(
@@ -155,7 +160,7 @@ private fun TopBar(
@Composable
private fun SeasonContent(
- seasonsEpList: List?,
+ seasonsEpList: ImmutableList?,
initialSeasonName: String?,
listState: LazyListState,
contentPadding: PaddingValues,
@@ -179,7 +184,9 @@ private fun SeasonContent(
LazyColumn(
state = listState,
contentPadding = contentPadding.copy(copyTop = false),
- modifier = Modifier.fillMaxSize(),
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .fillMaxSize(),
) {
item { Spacer(modifier = Modifier.height(64.dp)) }
@@ -187,7 +194,11 @@ private fun SeasonContent(
item { Spacer(modifier = Modifier.height(16.dp)) }
- item { AllSeasonsTitle() }
+ item {
+ LabelTitle(
+ label = stringResource(id = R.string.title_all_episodes),
+ )
+ }
itemsIndexed(seasonsEpList) { index, season ->
CollapsableContent(
@@ -204,20 +215,57 @@ private fun SeasonContent(
}
}
+@OptIn(ExperimentalSnapperApi::class)
+@Composable
+fun WatchNextContent(
+ episodeList: ImmutableList?,
+ modifier: Modifier = Modifier,
+ onEpisodeClicked: () -> Unit = {},
+) {
+ episodeList?.let {
+ LabelTitle(
+ modifier = modifier
+ .padding(top = 16.dp, bottom = 8.dp),
+ label = stringResource(id = R.string.title_watch_next),
+ )
+
+ val lazyListState = rememberLazyListState()
+
+ LazyRow(
+ state = lazyListState,
+ flingBehavior = rememberSnapperFlingBehavior(lazyListState),
+ ) {
+ itemsIndexed(episodeList) { index, episode ->
+ val value = if (index == 0) 0 else 8
+ Spacer(modifier = Modifier.width(value.dp))
+
+ EpisodeItem(
+ modifier = modifier.size(width = 320.dp, height = 90.dp),
+ imageUrl = episode.imageUrl,
+ title = episode.seasonEpisodeNumber,
+ episodeOverview = episode.overview,
+ onEpisodeClicked = onEpisodeClicked,
+ )
+ }
+
+ item { Spacer(modifier = Modifier.height(16.dp)) }
+ }
+ }
+}
+
@Composable
-private fun AllSeasonsTitle(
+private fun LabelTitle(
+ label: String,
modifier: Modifier = Modifier,
) {
Box(
- modifier = modifier
- .fillMaxWidth()
- .padding(2.dp),
+ modifier = modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
Spacer(modifier = Modifier.height(8.dp))
Text(
- text = stringResource(id = R.string.title_all_seasons),
+ text = label,
style = MaterialTheme.typography.labelMedium.copy(MaterialTheme.colorScheme.secondary),
)
}
@@ -226,8 +274,7 @@ private fun AllSeasonsTitle(
@ThemePreviews
@Composable
private fun SeasonDetailScreenPreview(
- @PreviewParameter(SeasonPreviewParameterProvider::class)
- state: SeasonDetailsState,
+ @PreviewParameter(SeasonPreviewParameterProvider::class) state: SeasonDetailsState,
) {
TvManiacTheme {
Surface {
diff --git a/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonPreviewParameterProvider.kt b/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonPreviewParameterProvider.kt
index b13afa457..5f2080937 100644
--- a/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonPreviewParameterProvider.kt
+++ b/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/SeasonPreviewParameterProvider.kt
@@ -6,6 +6,8 @@ import com.thomaskioko.tvmaniac.presentation.seasondetails.SeasonDetailsLoaded
import com.thomaskioko.tvmaniac.presentation.seasondetails.SeasonDetailsState
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.Episode
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.SeasonDetails
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toPersistentList
val episode = Episode(
id = 2534997,
@@ -27,7 +29,7 @@ val seasonDetails = SeasonDetails(
watchProgress = 0.4f,
episodes = List(8) {
episode
- },
+ }.toPersistentList(),
)
class SeasonPreviewParameterProvider : PreviewParameterProvider {
@@ -36,7 +38,7 @@ class SeasonPreviewParameterProvider : PreviewParameterProvider Unit = {},
) {
val transitionState = remember {
@@ -112,11 +111,10 @@ private fun SeasonTitleHeader(
)
Card(
- shape = RectangleShape,
+ shape = shape,
modifier = Modifier
.fillMaxWidth()
.height(64.dp)
- .padding(horizontal = 16.dp)
.clickable { onSeasonHeaderClicked() },
) {
ConstraintLayout(
@@ -209,108 +207,6 @@ private fun SeasonTitleHeader(
}
}
-@Composable
-fun EpisodeItem(
- episode: Episode,
- modifier: Modifier = Modifier,
- onEpisodeClicked: (Long) -> Unit = {},
-) {
- Card(
- shape = RectangleShape,
- modifier = modifier
- .fillMaxWidth()
- .defaultMinSize(minHeight = 84.dp)
- .padding(horizontal = 16.dp)
- .clickable { onEpisodeClicked(episode.id) },
- ) {
- ConstraintLayout(
- modifier = Modifier.fillMaxWidth(),
- ) {
- val (episodeTitle, image, overview, watchedStatusIcon) = createRefs()
-
- AsyncImageComposable(
- model = episode.imageUrl,
- contentDescription = stringResource(
- R.string.cd_show_poster,
- episode.episodeNumberTitle,
- ),
- contentScale = ContentScale.Crop,
- modifier = Modifier
- .width(94.dp)
- .constrainAs(image) {
- start.linkTo(parent.start)
- top.linkTo(parent.top)
- bottom.linkTo(parent.bottom)
-
- height = Dimension.fillToConstraints
- },
- )
-
- Text(
- text = episode.episodeNumberTitle,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- style = MaterialTheme.typography.titleMedium,
- fontWeight = FontWeight.Bold,
- color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier
- .constrainAs(episodeTitle) {
- start.linkTo(image.end, 8.dp)
- end.linkTo(watchedStatusIcon.start)
- top.linkTo(parent.top, 8.dp)
-
- width = Dimension.fillToConstraints
- },
- )
-
- Text(
- text = episode.overview,
- maxLines = 3,
- overflow = TextOverflow.Ellipsis,
- style = MaterialTheme.typography.bodyMedium,
- modifier = Modifier
- .constrainAs(overview) {
- start.linkTo(image.end, 8.dp)
- top.linkTo(episodeTitle.bottom, 5.dp)
- end.linkTo(watchedStatusIcon.start, 8.dp)
- bottom.linkTo(parent.bottom, 8.dp)
-
- width = Dimension.fillToConstraints
- },
- )
-
- IconButton(
- onClick = {},
- modifier = Modifier
- .constrainAs(watchedStatusIcon) {
- centerVerticallyTo(parent)
- end.linkTo(parent.end, 8.dp)
- },
- ) {
- Icon(
- imageVector = Icons.Filled.CheckCircle,
- contentDescription = stringResource(R.string.cd_navigate_back),
- tint = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier
- .size(32.dp),
- )
- }
- }
- }
-}
-
-@ThemePreviews
-@Composable
-fun EpisodeItemPreview() {
- TvManiacTheme {
- Surface {
- EpisodeItem(
- episode = episode,
- )
- }
- }
-}
-
@ThemePreviews
@Composable
fun SeasonTitleHeaderPreview() {
diff --git a/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/components/WatchNextList.kt b/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/components/EpisodeItem.kt
similarity index 53%
rename from android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/components/WatchNextList.kt
rename to android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/components/EpisodeItem.kt
index 57773e9b1..047a9bb7d 100644
--- a/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/components/WatchNextList.kt
+++ b/android-features/season-details/src/main/java/com/thomaskioko/tvmaniac/seasondetails/components/EpisodeItem.kt
@@ -1,16 +1,9 @@
package com.thomaskioko.tvmaniac.seasondetails.components
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyRow
-import androidx.compose.foundation.lazy.itemsIndexed
-import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material3.Card
@@ -20,11 +13,11 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
@@ -32,67 +25,22 @@ import androidx.constraintlayout.compose.Dimension
import com.thomaskioko.tvmaniac.compose.components.AsyncImageComposable
import com.thomaskioko.tvmaniac.compose.components.ThemePreviews
import com.thomaskioko.tvmaniac.compose.theme.TvManiacTheme
-import com.thomaskioko.tvmaniac.presentation.seasondetails.model.Episode
import com.thomaskioko.tvmaniac.resources.R
import com.thomaskioko.tvmaniac.seasondetails.episode
-import dev.chrisbanes.snapper.ExperimentalSnapperApi
-import dev.chrisbanes.snapper.rememberSnapperFlingBehavior
-@OptIn(ExperimentalSnapperApi::class)
@Composable
-fun WatchNextContent(
- episodeList: List?,
+fun EpisodeItem(
+ imageUrl: String?,
+ title: String,
+ episodeOverview: String,
modifier: Modifier = Modifier,
-) {
- episodeList?.let {
- Box(
- modifier = modifier
- .fillMaxWidth()
- .padding(top = 16.dp),
- contentAlignment = Alignment.Center,
- ) {
- Spacer(modifier = Modifier.height(8.dp))
-
- Text(
- text = stringResource(id = R.string.title_watch_next),
- style = MaterialTheme.typography.labelMedium.copy(MaterialTheme.colorScheme.secondary),
- )
- }
-
- Spacer(modifier = Modifier.height(8.dp))
-
- val lazyListState = rememberLazyListState()
-
- LazyRow(
- state = lazyListState,
- flingBehavior = rememberSnapperFlingBehavior(lazyListState),
- ) {
- itemsIndexed(episodeList) { index, episode ->
- val value = if (index == 0) 32 else 8
- Spacer(modifier = Modifier.width(value.dp))
-
- WatchNextItem(
- episode = episode,
- onEpisodeClicked = {},
- )
- }
-
- item { Spacer(modifier = Modifier.height(16.dp)) }
- }
- }
-}
-
-@Composable
-fun WatchNextItem(
- episode: Episode,
- modifier: Modifier = Modifier,
- onEpisodeClicked: (Long) -> Unit = {},
+ shape: Shape = MaterialTheme.shapes.small,
+ onEpisodeClicked: () -> Unit = {},
) {
Card(
- shape = RectangleShape,
+ shape = shape,
modifier = modifier
- .size(width = 260.dp, height = 90.dp)
- .clickable { onEpisodeClicked(episode.id) },
+ .clickable { onEpisodeClicked() },
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
@@ -100,54 +48,51 @@ fun WatchNextItem(
val (episodeTitle, image, overview, watchedStatusIcon) = createRefs()
AsyncImageComposable(
- model = episode.imageUrl,
+ model = imageUrl,
contentDescription = stringResource(
R.string.cd_show_poster,
- episode.episodeNumberTitle,
+ title,
),
contentScale = ContentScale.Crop,
modifier = Modifier
- .width(84.dp)
+ .width(94.dp)
.constrainAs(image) {
start.linkTo(parent.start)
- bottom.linkTo(parent.bottom)
top.linkTo(parent.top)
+ bottom.linkTo(parent.bottom)
height = Dimension.fillToConstraints
},
)
Text(
- text = episode.seasonEpisodeNumber,
+ text = title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier
.constrainAs(episodeTitle) {
- linkTo(
- start = image.end,
- end = watchedStatusIcon.start,
- startMargin = 8.dp,
- bias = 0f,
- )
- top.linkTo(parent.top, 16.dp)
+ start.linkTo(image.end, 8.dp)
+ end.linkTo(watchedStatusIcon.start)
+ top.linkTo(parent.top, 8.dp)
- width = Dimension.preferredWrapContent
+ width = Dimension.fillToConstraints
},
)
Text(
- text = episode.episodeTitle,
- maxLines = 1,
+ text = episodeOverview,
+ maxLines = 3,
overflow = TextOverflow.Ellipsis,
- style = MaterialTheme.typography.titleMedium,
+ style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
- .padding(bottom = 8.dp)
.constrainAs(overview) {
start.linkTo(image.end, 8.dp)
top.linkTo(episodeTitle.bottom, 5.dp)
end.linkTo(watchedStatusIcon.start, 8.dp)
- bottom.linkTo(parent.bottom)
+ bottom.linkTo(parent.bottom, 8.dp)
width = Dimension.fillToConstraints
},
@@ -163,7 +108,7 @@ fun WatchNextItem(
) {
Icon(
imageVector = Icons.Filled.CheckCircle,
- contentDescription = null,
+ contentDescription = stringResource(R.string.cd_navigate_back),
tint = MaterialTheme.colorScheme.onSurface,
modifier = Modifier
.size(32.dp),
@@ -178,8 +123,10 @@ fun WatchNextItem(
fun WatchlistRowItemPreview() {
TvManiacTheme {
Surface {
- WatchNextItem(
- episode = episode,
+ EpisodeItem(
+ title = episode.episodeNumberTitle,
+ episodeOverview = episode.overview,
+ imageUrl = episode.imageUrl,
)
}
}
diff --git a/android-features/show-details/src/main/kotlin/com/thomaskioko/showdetails/ShowDetailScreen.kt b/android-features/show-details/src/main/kotlin/com/thomaskioko/showdetails/ShowDetailScreen.kt
index 2b7f07cc2..c9ad89deb 100644
--- a/android-features/show-details/src/main/kotlin/com/thomaskioko/showdetails/ShowDetailScreen.kt
+++ b/android-features/show-details/src/main/kotlin/com/thomaskioko/showdetails/ShowDetailScreen.kt
@@ -1,6 +1,7 @@
package com.thomaskioko.showdetails
import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -670,7 +671,7 @@ private fun TrailersContent(
}
}
-@OptIn(ExperimentalSnapperApi::class)
+@OptIn(ExperimentalSnapperApi::class, ExperimentalFoundationApi::class)
@Composable
fun SimilarShowsContent(
isLoading: Boolean,
@@ -696,6 +697,8 @@ fun SimilarShowsContent(
Spacer(modifier = Modifier.width(value.dp))
TvPosterCard(
+ modifier = Modifier
+ .animateItemPlacement(),
posterImageUrl = tvShow.posterImageUrl,
title = tvShow.title,
onClick = { onShowClicked(tvShow.traktId) },
diff --git a/android-features/watchlist/src/main/kotlin/com/thomaskioko/tvmaniac/watchlist/WatchlistScreen.kt b/android-features/watchlist/src/main/kotlin/com/thomaskioko/tvmaniac/watchlist/WatchlistScreen.kt
index 448dcaba9..b4db906cb 100644
--- a/android-features/watchlist/src/main/kotlin/com/thomaskioko/tvmaniac/watchlist/WatchlistScreen.kt
+++ b/android-features/watchlist/src/main/kotlin/com/thomaskioko/tvmaniac/watchlist/WatchlistScreen.kt
@@ -1,5 +1,6 @@
package com.thomaskioko.tvmaniac.watchlist
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.statusBarsPadding
@@ -113,6 +114,7 @@ private fun WatchlistScreen(
)
}
+@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun FollowingGridContent(
list: List,
@@ -128,6 +130,8 @@ private fun FollowingGridContent(
) { show ->
TvPosterCard(
+ modifier = Modifier
+ .animateItemPlacement(),
posterImageUrl = show.posterImageUrl,
title = show.title,
onClick = { onItemClicked(show.traktId) },
diff --git a/app/src/main/kotlin/com/thomaskioko/tvmaniac/inject/ApplicationComponent.kt b/app/src/main/kotlin/com/thomaskioko/tvmaniac/inject/ApplicationComponent.kt
index e18516b79..1c2518ed5 100644
--- a/app/src/main/kotlin/com/thomaskioko/tvmaniac/inject/ApplicationComponent.kt
+++ b/app/src/main/kotlin/com/thomaskioko/tvmaniac/inject/ApplicationComponent.kt
@@ -3,11 +3,10 @@ package com.thomaskioko.tvmaniac.inject
import android.app.Application
import android.content.Context
import com.thomaskioko.trakt.service.implementation.inject.TraktComponent
-import com.thomaskioko.trakt.service.implementation.inject.TraktPlatformComponent
import com.thomaskioko.tvmaniac.TvManicApplication
import com.thomaskioko.tvmaniac.data.category.implementation.CategoryComponent
import com.thomaskioko.tvmaniac.data.trailers.implementation.TrailerComponent
-import com.thomaskioko.tvmaniac.datastore.implementation.DataStorePlatformComponent
+import com.thomaskioko.tvmaniac.datastore.implementation.DataStoreComponent
import com.thomaskioko.tvmaniac.db.DatabaseComponent
import com.thomaskioko.tvmaniac.episodeimages.implementation.EpisodeImageComponent
import com.thomaskioko.tvmaniac.episodes.implementation.EpisodeComponent
@@ -21,7 +20,6 @@ import com.thomaskioko.tvmaniac.showimages.implementation.ShowImagesComponent
import com.thomaskioko.tvmaniac.shows.implementation.DiscoverComponent
import com.thomaskioko.tvmaniac.similar.implementation.SimilarShowsComponent
import com.thomaskioko.tvmaniac.tmdb.implementation.TmdbComponent
-import com.thomaskioko.tvmaniac.tmdb.implementation.TmdbPlatformComponent
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthComponent
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthenticationComponent
import com.thomaskioko.tvmaniac.util.inject.UtilPlatformComponent
@@ -39,7 +37,7 @@ abstract class ApplicationComponent(
) : UtilPlatformComponent,
CategoryComponent,
DatabaseComponent,
- DataStorePlatformComponent,
+ DataStoreComponent,
EpisodeComponent,
EpisodeImageComponent,
WatchlistComponent,
@@ -54,9 +52,7 @@ abstract class ApplicationComponent(
StatsComponent,
TasksComponent,
TmdbComponent,
- TmdbPlatformComponent,
TraktComponent,
- TraktPlatformComponent,
TrailerComponent,
TraktAuthComponent,
TraktAuthenticationComponent {
diff --git a/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt b/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
deleted file mode 100644
index 174189203..000000000
--- a/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.thomaskioko.tvmaniac.db
-
-import android.app.Application
-import app.cash.sqldelight.db.SqlDriver
-import app.cash.sqldelight.driver.android.AndroidSqliteDriver
-import com.thomaskioko.tvmaniac.core.db.Episode
-import com.thomaskioko.tvmaniac.core.db.Episode_image
-import com.thomaskioko.tvmaniac.core.db.Last_requests
-import com.thomaskioko.tvmaniac.core.db.Season
-import com.thomaskioko.tvmaniac.core.db.Show
-import com.thomaskioko.tvmaniac.core.db.Show_category
-import com.thomaskioko.tvmaniac.core.db.Show_image
-import com.thomaskioko.tvmaniac.core.db.Similar_shows
-import com.thomaskioko.tvmaniac.core.db.Trailers
-import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
-import com.thomaskioko.tvmaniac.core.db.Watchlist
-import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
-import me.tatarka.inject.annotations.Provides
-
-actual interface DatabaseComponent {
-
- @ApplicationScope
- @Provides
- fun provideSqlDriver(
- application: Application,
- ): SqlDriver = AndroidSqliteDriver(
- schema = TvManiacDatabase.Schema,
- context = application,
- name = "tvShows.db",
- )
-
- @ApplicationScope
- @Provides
- fun provideTvManiacDatabase(
- sqlDriver: SqlDriver,
- ): TvManiacDatabase = TvManiacDatabase(
- driver = sqlDriver,
- showAdapter = Show.Adapter(
- genresAdapter = stringColumnAdapter,
- idAdapter = IdAdapter(),
- ),
- last_requestsAdapter = Last_requests.Adapter(
- timestampAdapter = InstantColumnAdapter,
- ),
- episode_imageAdapter = Episode_image.Adapter(
- idAdapter = IdAdapter(),
- tmdb_idAdapter = IdAdapter(),
- ),
- episodeAdapter = Episode.Adapter(
- idAdapter = IdAdapter(),
- season_idAdapter = IdAdapter(),
- ),
- seasonAdapter = Season.Adapter(
- idAdapter = IdAdapter(),
- show_idAdapter = IdAdapter(),
- ),
- show_imageAdapter = Show_image.Adapter(
- idAdapter = IdAdapter(),
- ),
- similar_showsAdapter = Similar_shows.Adapter(
- idAdapter = IdAdapter(),
- similar_show_idAdapter = IdAdapter(),
- ),
- watchlistAdapter = Watchlist.Adapter(
- idAdapter = IdAdapter(),
- ),
- show_categoryAdapter = Show_category.Adapter(
- idAdapter = IdAdapter(),
- category_idAdapter = IdAdapter(),
- ),
- trailersAdapter = Trailers.Adapter(
- show_idAdapter = IdAdapter(),
- ),
- )
-
- @ApplicationScope
- @Provides
- fun provideDbTransactionRunner(
- bind: DbTransactionRunner,
- ): DatabaseTransactionRunner = bind
-}
diff --git a/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt b/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
new file mode 100644
index 000000000..f1f79a2c6
--- /dev/null
+++ b/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
@@ -0,0 +1,21 @@
+package com.thomaskioko.tvmaniac.db
+
+import android.app.Application
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.android.AndroidSqliteDriver
+import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
+import me.tatarka.inject.annotations.Provides
+
+actual interface DatabasePlatformComponent {
+
+ @ApplicationScope
+ @Provides
+ fun provideSqlDriver(
+ application: Application,
+ ): SqlDriver = AndroidSqliteDriver(
+ schema = TvManiacDatabase.Schema,
+ context = application,
+ name = "tvShows.db",
+ )
+}
diff --git a/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabaseComponent.kt b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabaseComponent.kt
deleted file mode 100644
index 10b34033d..000000000
--- a/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabaseComponent.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.thomaskioko.tvmaniac.db
-
-expect interface DatabaseComponent
diff --git a/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabasePlatformComponent.kt
similarity index 91%
rename from core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
rename to core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabasePlatformComponent.kt
index ff47263d0..1c7284223 100644
--- a/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
+++ b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabasePlatformComponent.kt
@@ -1,7 +1,6 @@
package com.thomaskioko.tvmaniac.db
import app.cash.sqldelight.db.SqlDriver
-import app.cash.sqldelight.driver.native.NativeSqliteDriver
import com.thomaskioko.tvmaniac.core.db.Episode
import com.thomaskioko.tvmaniac.core.db.Episode_image
import com.thomaskioko.tvmaniac.core.db.Last_requests
@@ -16,12 +15,9 @@ import com.thomaskioko.tvmaniac.core.db.Watchlist
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import me.tatarka.inject.annotations.Provides
-actual interface DatabaseComponent {
-
- @ApplicationScope
- @Provides
- fun provideSqlDriver(): SqlDriver = NativeSqliteDriver(TvManiacDatabase.Schema, "tvShows.db")
+expect interface DatabasePlatformComponent
+interface DatabaseComponent : DatabasePlatformComponent {
@ApplicationScope
@Provides
fun provideTvManiacDatabase(
@@ -65,4 +61,10 @@ actual interface DatabaseComponent {
show_idAdapter = IdAdapter(),
),
)
+
+ @ApplicationScope
+ @Provides
+ fun provideDbTransactionRunner(
+ bind: DbTransactionRunner,
+ ): DatabaseTransactionRunner = bind
}
diff --git a/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt b/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
new file mode 100644
index 000000000..e1816c660
--- /dev/null
+++ b/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
@@ -0,0 +1,14 @@
+package com.thomaskioko.tvmaniac.db
+
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.native.NativeSqliteDriver
+import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
+import me.tatarka.inject.annotations.Provides
+
+actual interface DatabasePlatformComponent {
+
+ @ApplicationScope
+ @Provides
+ fun provideSqlDriver(): SqlDriver = NativeSqliteDriver(TvManiacDatabase.Schema, "tvShows.db")
+}
diff --git a/core/database/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt b/core/database/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
deleted file mode 100644
index 312227327..000000000
--- a/core/database/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.thomaskioko.tvmaniac.db
-
-actual interface DatabaseComponent
diff --git a/core/database/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt b/core/database/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
new file mode 100644
index 000000000..952dcb6ec
--- /dev/null
+++ b/core/database/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
@@ -0,0 +1,3 @@
+package com.thomaskioko.tvmaniac.db
+
+actual interface DatabasePlatformComponent
diff --git a/core/datastore/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt b/core/datastore/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
index dab2f748c..0e9996d76 100644
--- a/core/datastore/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
+++ b/core/datastore/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
@@ -3,7 +3,6 @@ package com.thomaskioko.tvmaniac.datastore.implementation
import android.app.Application
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
-import com.thomaskioko.tvmaniac.datastore.api.DatastoreRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import me.tatarka.inject.annotations.Provides
@@ -19,8 +18,4 @@ actual interface DataStorePlatformComponent {
coroutineScope = scope.io,
producePath = { context.filesDir.resolve(dataStoreFileName).absolutePath },
)
-
- @ApplicationScope
- @Provides
- fun provideDatastoreRepository(bind: DatastoreRepositoryImpl): DatastoreRepository = bind
}
diff --git a/core/datastore/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt b/core/datastore/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
index 09e6ef4be..9c911c7c5 100644
--- a/core/datastore/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
+++ b/core/datastore/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
@@ -1,3 +1,14 @@
package com.thomaskioko.tvmaniac.datastore.implementation
+import com.thomaskioko.tvmaniac.datastore.api.DatastoreRepository
+import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
+import me.tatarka.inject.annotations.Provides
+
expect interface DataStorePlatformComponent
+
+interface DataStoreComponent : DataStorePlatformComponent {
+
+ @ApplicationScope
+ @Provides
+ fun provideDatastoreRepository(bind: DatastoreRepositoryImpl): DatastoreRepository = bind
+}
diff --git a/core/datastore/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt b/core/datastore/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
index b08b6606b..3bf7f2a80 100644
--- a/core/datastore/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
+++ b/core/datastore/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/datastore/implementation/DataStorePlatformComponent.kt
@@ -2,7 +2,6 @@ package com.thomaskioko.tvmaniac.datastore.implementation
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
-import com.thomaskioko.tvmaniac.datastore.api.DatastoreRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import kotlinx.cinterop.ExperimentalForeignApi
@@ -32,8 +31,4 @@ actual interface DataStorePlatformComponent {
requireNotNull(documentDirectory).path + "/$dataStoreFileName"
},
)
-
- @ApplicationScope
- @Provides
- fun provideDatastoreRepository(bind: DatastoreRepositoryImpl): DatastoreRepository = bind
}
diff --git a/core/tmdb-api/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt b/core/tmdb-api/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
index 22e3c071d..455994245 100644
--- a/core/tmdb-api/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
+++ b/core/tmdb-api/implementation/src/androidMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
@@ -4,7 +4,7 @@ import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import io.ktor.client.engine.okhttp.OkHttp
import me.tatarka.inject.annotations.Provides
-interface TmdbPlatformComponent {
+actual interface TmdbPlatformComponent {
@ApplicationScope
@Provides
diff --git a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbClient.kt b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbClient.kt
index 168135818..b8ac6d96e 100644
--- a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbClient.kt
+++ b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbClient.kt
@@ -52,11 +52,11 @@ fun tmdbHttpClient(
}
install(Logging) {
- level = LogLevel.BODY
+ level = LogLevel.INFO
logger = if (isDebug) {
object : Logger {
override fun log(message: String) {
- kermitLogger.debug(message)
+ kermitLogger.info("TmbdHttp", message)
}
}
} else {
diff --git a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbComponent.kt b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbComponent.kt
index 732c2fdfd..d621cc0d6 100644
--- a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbComponent.kt
+++ b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbComponent.kt
@@ -14,7 +14,9 @@ typealias TmdbHttpClient = HttpClient
typealias TmdbHttpClientEngine = HttpClientEngine
typealias TmdbJson = Json
-interface TmdbComponent {
+expect interface TmdbPlatformComponent
+
+interface TmdbComponent : TmdbPlatformComponent {
@OptIn(ExperimentalSerializationApi::class)
@ApplicationScope
diff --git a/core/tmdb-api/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt b/core/tmdb-api/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
index fc7eb13eb..930725e2d 100644
--- a/core/tmdb-api/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
+++ b/core/tmdb-api/implementation/src/iosMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
@@ -4,7 +4,7 @@ import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import io.ktor.client.engine.darwin.Darwin
import me.tatarka.inject.annotations.Provides
-interface TmdbPlatformComponent {
+actual interface TmdbPlatformComponent {
@ApplicationScope
@Provides
diff --git a/core/tmdb-api/implementation/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt b/core/tmdb-api/implementation/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
index 0706afc5c..fbd673b97 100644
--- a/core/tmdb-api/implementation/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
+++ b/core/tmdb-api/implementation/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
@@ -1,3 +1,3 @@
package com.thomaskioko.tvmaniac.tmdb.implementation
-interface TmdbPlatformComponent
+actual interface TmdbPlatformComponent
diff --git a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktHttpClient.kt b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktHttpClient.kt
index 7cd4e27c3..056487169 100644
--- a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktHttpClient.kt
+++ b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktHttpClient.kt
@@ -87,7 +87,7 @@ fun traktHttpClient(
logger = if (isDebug) {
object : Logger {
override fun log(message: String) {
- kermitLogger.debug(message)
+ kermitLogger.info("TraktHttp", message)
}
}
} else {
diff --git a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/inject/TraktComponent.kt b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/inject/TraktComponent.kt
index 44e786260..6f5f234ba 100644
--- a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/inject/TraktComponent.kt
+++ b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/inject/TraktComponent.kt
@@ -21,7 +21,7 @@ import me.tatarka.inject.annotations.Provides
typealias TraktHttpClient = HttpClient
typealias TraktJson = Json
-interface TraktComponent {
+interface TraktComponent : TraktPlatformComponent {
@ApplicationScope
@Provides
diff --git a/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageRepositoryImpl.kt b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageRepositoryImpl.kt
index fcbf7d916..441bd3eda 100644
--- a/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageRepositoryImpl.kt
+++ b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageRepositoryImpl.kt
@@ -1,5 +1,6 @@
package com.thomaskioko.tvmaniac.episodeimages.implementation
+import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageDao
import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageRepository
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
@@ -20,19 +21,23 @@ class EpisodeImageRepositoryImpl(
private val dispatchers: AppCoroutineDispatchers,
private val requestManagerRepository: RequestManagerRepository,
private val store: EpisodeImageStore,
+ private val episodeImageDao: EpisodeImageDao,
) : EpisodeImageRepository {
override fun updateEpisodeImage(traktId: Long): Flow> =
- store.stream(
- StoreReadRequest.cached(
- key = traktId,
- refresh = requestManagerRepository.isRequestExpired(
- entityId = traktId,
- requestType = "EPISODE_IMAGE",
- threshold = 1.hours,
- ),
- ),
- )
+ episodeImageDao.observeEpisodeImage(traktId)
+ .flatMapLatest {
+ store.stream(
+ StoreReadRequest.cached(
+ key = traktId,
+ refresh = requestManagerRepository.isRequestExpired(
+ entityId = traktId,
+ requestType = "EPISODE_IMAGE",
+ threshold = 1.hours,
+ ),
+ ),
+ )
+ }
.flatMapLatest { flowOf(Either.Right(Unit)) }
.flowOn(dispatchers.io)
}
diff --git a/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageStore.kt b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageStore.kt
index 05b40b00e..27c9fd74a 100644
--- a/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageStore.kt
+++ b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageStore.kt
@@ -31,7 +31,6 @@ class EpisodeImageStore(
private val scope: AppCoroutineScope,
) : Store> by StoreBuilder.from(
fetcher = Fetcher.of { id ->
-
episodeImageDao.getEpisodeImage(id)
.filter { it.tmdb_id != null && it.image_url == null }
.map { episodeArt ->
diff --git a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsStore.kt b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsStore.kt
index ff39ad426..d8f961290 100644
--- a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsStore.kt
+++ b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsStore.kt
@@ -2,6 +2,7 @@ package com.thomaskioko.tvmaniac.seasondetails.implementation
import com.thomaskioko.tvmaniac.core.db.Season
import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
+import com.thomaskioko.tvmaniac.db.DbTransactionRunner
import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.episodes.api.EpisodesDao
import com.thomaskioko.tvmaniac.seasons.api.SeasonsDao
@@ -21,6 +22,7 @@ class SeasonDetailsStore(
private val seasonCache: SeasonsDao,
private val episodesDao: EpisodesDao,
private val scope: AppCoroutineScope,
+ private val dbTransactionRunner: DbTransactionRunner,
private val logger: KermitLogger,
) : Store> by StoreBuilder
.from(
@@ -46,19 +48,21 @@ class SeasonDetailsStore(
sourceOfTruth = SourceOfTruth.of(
reader = seasonCache::observeSeasonEpisodeDetailsById,
writer = { id, list ->
- list.forEach { season ->
- seasonCache.upsert(
- Season(
- id = Id(season.seasonId),
- show_id = Id(id),
- season_number = season.seasonNumber,
- title = season.title,
- episode_count = season.episodeCount,
- overview = season.overview,
- ),
- )
+ dbTransactionRunner {
+ list.forEach { season ->
+ seasonCache.upsert(
+ Season(
+ id = Id(season.seasonId),
+ show_id = Id(id),
+ season_number = season.seasonNumber,
+ title = season.title,
+ episode_count = season.episodeCount,
+ overview = season.overview,
+ ),
+ )
- episodesDao.insert(season.episodes)
+ episodesDao.insert(season.episodes)
+ }
}
},
delete = seasonCache::delete,
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index cb32e8463..9da524c3a 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,8 +1,8 @@
[versions]
accompanist = "0.33.2-alpha"
-agp = "8.1.3"
-androidx-activity = "1.8.0"
-androidx-browser = "1.6.0"
+agp = "8.1.4"
+androidx-activity = "1.8.1"
+androidx-browser = "1.7.0"
androidx-core = "1.12.0"
androidx-core-splashscreen = "1.0.1"
androidx-datastore = "1.1.0-alpha06"
@@ -13,7 +13,7 @@ androidx-palette = "1.0.0"
androidx-work = "2.8.1"
appauth = "0.11.1"
atomicfu = "0.22.0"
-coil = "2.4.0"
+coil = "2.5.0"
compose-bom = "2023.10.01"
compose-constraintlayout = "1.0.1"
compose-paging = "3.2.1"
@@ -23,7 +23,7 @@ datetime = "0.4.1"
dependency-analysis = "1.25.0"
dependency-check = "0.49.0"
desugar = "2.0.4"
-detekt = "1.23.0"
+detekt = "1.23.3"
flowredux = "1.2.0"
kenburns = "1.0.7"
kermit = "1.2.3"
@@ -32,8 +32,8 @@ kotest = "5.5.4"
kotlin = "1.9.20"
kotlininject = "0.6.3"
kotlinx-collections = "0.3.6"
-ksp = "1.9.20-1.0.14"
-ktor = "2.3.5"
+ksp = "1.9.20-1.0.13"
+ktor = "2.3.6"
lint = "1.2.0"
moko-resources = "0.23.0"
shared-module-version = "0.8.0"
diff --git a/presentation/seasondetails/build.gradle.kts b/presentation/seasondetails/build.gradle.kts
index 797a389a7..1fb41a044 100644
--- a/presentation/seasondetails/build.gradle.kts
+++ b/presentation/seasondetails/build.gradle.kts
@@ -13,6 +13,8 @@ kotlin {
implementation(projects.data.episodes.api)
implementation(projects.data.seasondetails.api)
+ api(libs.kotlinx.collections)
+
implementation(libs.flowredux)
implementation(libs.kotlinInject.runtime)
}
diff --git a/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/Mapper.kt b/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/Mapper.kt
index e04b38087..ec0b75584 100644
--- a/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/Mapper.kt
+++ b/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/Mapper.kt
@@ -3,18 +3,24 @@ package com.thomaskioko.tvmaniac.presentation.seasondetails
import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.Episode
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.SeasonDetails
+import kotlinx.collections.immutable.PersistentList
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.collections.immutable.toImmutableList
+import kotlinx.collections.immutable.toPersistentList
-fun List?.toSeasonWithEpisodes(): List {
- return this?.groupBy { it.season_id }?.map { (_, groupMap) ->
- val seasonRow = groupMap.first()
- SeasonDetails(
- seasonId = seasonRow.season_id.id,
- seasonName = seasonRow.season_title,
- episodes = groupMap.map { it.toEpisode() },
- episodeCount = seasonRow.episode_count,
- watchProgress = 0f,
- )
- } ?: emptyList()
+fun List?.toSeasonWithEpisodes(): PersistentList {
+ return this
+ ?.groupBy { it.season_id }
+ ?.map { (_, groupMap) ->
+ val seasonRow = groupMap.first()
+ SeasonDetails(
+ seasonId = seasonRow.season_id.id,
+ seasonName = seasonRow.season_title,
+ episodes = groupMap.map { it.toEpisode() }.toImmutableList(),
+ episodeCount = seasonRow.episode_count,
+ watchProgress = 0f,
+ )
+ }?.toPersistentList() ?: persistentListOf()
}
fun SeasonEpisodeDetailsById.toEpisode(): Episode {
diff --git a/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/SeasonDetailsState.kt b/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/SeasonDetailsState.kt
index 184c48226..449f31bcf 100644
--- a/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/SeasonDetailsState.kt
+++ b/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/SeasonDetailsState.kt
@@ -1,14 +1,16 @@
package com.thomaskioko.tvmaniac.presentation.seasondetails
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.SeasonDetails
+import kotlinx.collections.immutable.PersistentList
+import kotlinx.collections.immutable.persistentListOf
sealed interface SeasonDetailsState
-object Loading : SeasonDetailsState
+data object Loading : SeasonDetailsState
data class SeasonDetailsLoaded(
val showTitle: String = "",
- val seasonDetailsList: List = emptyList(),
+ val seasonDetailsList: PersistentList = persistentListOf(),
val errorMessage: String? = null,
) : SeasonDetailsState
diff --git a/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/model/SeasonDetails.kt b/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/model/SeasonDetails.kt
index b46347ed2..312eeeb06 100644
--- a/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/model/SeasonDetails.kt
+++ b/presentation/seasondetails/src/commonMain/kotlin/com/thomaskioko/tvmaniac/presentation/seasondetails/model/SeasonDetails.kt
@@ -1,9 +1,11 @@
package com.thomaskioko.tvmaniac.presentation.seasondetails.model
+import kotlinx.collections.immutable.ImmutableList
+
data class SeasonDetails(
val seasonId: Long,
val seasonName: String,
val episodeCount: Long,
val watchProgress: Float,
- val episodes: List,
+ val episodes: ImmutableList,
)
diff --git a/presentation/seasondetails/src/commonTest/kotlin/com/thomaskioko/tvmaniac/data/seasondetails/MockData.kt b/presentation/seasondetails/src/commonTest/kotlin/com/thomaskioko/tvmaniac/data/seasondetails/MockData.kt
index 261f3f860..73f19a495 100644
--- a/presentation/seasondetails/src/commonTest/kotlin/com/thomaskioko/tvmaniac/data/seasondetails/MockData.kt
+++ b/presentation/seasondetails/src/commonTest/kotlin/com/thomaskioko/tvmaniac/data/seasondetails/MockData.kt
@@ -3,8 +3,9 @@ package com.thomaskioko.tvmaniac.data.seasondetails
import com.thomaskioko.tvmaniac.presentation.seasondetails.SeasonDetailsLoaded
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.Episode
import com.thomaskioko.tvmaniac.presentation.seasondetails.model.SeasonDetails
+import kotlinx.collections.immutable.persistentListOf
-val episodes = listOf(
+val episodes = persistentListOf(
Episode(
id = 12345,
seasonId = 12343,
@@ -19,7 +20,7 @@ val episodes = listOf(
),
)
-val seasonDetailsList = listOf(
+val seasonDetailsList = persistentListOf(
SeasonDetails(
seasonId = 12343,
seasonName = "Season 01",
diff --git a/shared/src/iosMain/kotlin/com.thomaskioko.tvmaniac.shared/base/ApplicationComponent.kt b/shared/src/iosMain/kotlin/com.thomaskioko.tvmaniac.shared/base/ApplicationComponent.kt
index 36e7baf91..2af826c9b 100644
--- a/shared/src/iosMain/kotlin/com.thomaskioko.tvmaniac.shared/base/ApplicationComponent.kt
+++ b/shared/src/iosMain/kotlin/com.thomaskioko.tvmaniac.shared/base/ApplicationComponent.kt
@@ -1,10 +1,9 @@
package com.thomaskioko.tvmaniac.shared.base
import com.thomaskioko.trakt.service.implementation.inject.TraktComponent
-import com.thomaskioko.trakt.service.implementation.inject.TraktPlatformComponent
import com.thomaskioko.tvmaniac.data.category.implementation.CategoryComponent
import com.thomaskioko.tvmaniac.data.trailers.implementation.TrailerComponent
-import com.thomaskioko.tvmaniac.datastore.implementation.DataStorePlatformComponent
+import com.thomaskioko.tvmaniac.datastore.implementation.DataStoreComponent
import com.thomaskioko.tvmaniac.db.DatabaseComponent
import com.thomaskioko.tvmaniac.episodeimages.implementation.EpisodeImageComponent
import com.thomaskioko.tvmaniac.episodes.implementation.EpisodeComponent
@@ -24,7 +23,6 @@ import com.thomaskioko.tvmaniac.showimages.implementation.ShowImagesComponent
import com.thomaskioko.tvmaniac.shows.implementation.DiscoverComponent
import com.thomaskioko.tvmaniac.similar.implementation.SimilarShowsComponent
import com.thomaskioko.tvmaniac.tmdb.implementation.TmdbComponent
-import com.thomaskioko.tvmaniac.tmdb.implementation.TmdbPlatformComponent
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthenticationComponent
import com.thomaskioko.tvmaniac.util.inject.UtilPlatformComponent
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
@@ -36,7 +34,7 @@ import me.tatarka.inject.annotations.Component
abstract class ApplicationComponent :
CategoryComponent,
DatabaseComponent,
- DataStorePlatformComponent,
+ DataStoreComponent,
EpisodeComponent,
EpisodeImageComponent,
ProfileComponent,
@@ -48,9 +46,7 @@ abstract class ApplicationComponent :
SimilarShowsComponent,
StatsComponent,
TmdbComponent,
- TmdbPlatformComponent,
TraktComponent,
- TraktPlatformComponent,
TraktAuthenticationComponent,
TrailerComponent,
UtilPlatformComponent,