diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 96fccbcfc..6c4c8a177 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -102,6 +102,9 @@ jobs:
- name: unitTest
run: ./gradlew testDemoDebug
+ - name: Jvm Test
+ run: ./gradlew jvmTest
+
- uses: actions/upload-artifact@v3
with:
name: unit-test-report
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/DiscoverPreviewParameterProvider.kt b/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverPreviewParameterProvider.kt
index b0d86f32d..19b4f1c14 100644
--- a/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverPreviewParameterProvider.kt
+++ b/android-features/discover/src/main/java/com/thomaskioko/tvmaniac/discover/DiscoverPreviewParameterProvider.kt
@@ -3,6 +3,7 @@ package com.thomaskioko.tvmaniac.discover
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.thomaskioko.tvmaniac.presentation.discover.DataLoaded
import com.thomaskioko.tvmaniac.presentation.discover.DiscoverState
+import com.thomaskioko.tvmaniac.presentation.discover.ErrorState
import com.thomaskioko.tvmaniac.presentation.discover.model.TvShow
import kotlinx.collections.immutable.toImmutableList
@@ -39,7 +40,7 @@ class DiscoverPreviewParameterProvider : PreviewParameterProvider
get() {
return sequenceOf(
discoverContentSuccess,
- DataLoaded(errorMessage = "Opps! Something went wrong"),
+ ErrorState(errorMessage = "Opps! Something went wrong"),
)
}
}
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 464ab936b..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
@@ -57,7 +57,6 @@ import androidx.compose.ui.util.lerp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.thomaskioko.tvmaniac.category.api.model.Category
import com.thomaskioko.tvmaniac.compose.components.BoxTextItems
-import com.thomaskioko.tvmaniac.compose.components.EmptyUi
import com.thomaskioko.tvmaniac.compose.components.ErrorUi
import com.thomaskioko.tvmaniac.compose.components.LoadingIndicator
import com.thomaskioko.tvmaniac.compose.components.ThemePreviews
@@ -72,6 +71,7 @@ import com.thomaskioko.tvmaniac.compose.util.rememberDominantColorState
import com.thomaskioko.tvmaniac.navigation.extensions.viewModel
import com.thomaskioko.tvmaniac.presentation.discover.DataLoaded
import com.thomaskioko.tvmaniac.presentation.discover.DiscoverState
+import com.thomaskioko.tvmaniac.presentation.discover.ErrorState
import com.thomaskioko.tvmaniac.presentation.discover.Loading
import com.thomaskioko.tvmaniac.presentation.discover.RetryLoading
import com.thomaskioko.tvmaniac.presentation.discover.SnackBarDismissed
@@ -140,49 +140,33 @@ private fun DiscoverScreen(
onMoreClicked: (showType: Long) -> Unit,
) {
when (state) {
- Loading ->
- LoadingIndicator(
- modifier = Modifier
- .fillMaxSize()
- .wrapContentSize(Alignment.Center),
- )
-
- is DataLoaded ->
- when {
- state.isContentEmpty && state.errorMessage != null -> {
- ErrorUi(
- errorMessage = state.errorMessage,
- onRetry = onRetry,
- modifier = Modifier
- .fillMaxSize()
- .wrapContentSize(Alignment.Center),
- )
- }
-
- state.isContentEmpty -> {
- EmptyUi(
- modifier = Modifier
- .fillMaxSize()
- .wrapContentSize(Alignment.Center),
- )
- }
-
- else -> {
- DiscoverScrollContent(
- modifier = modifier,
- pagerState = pagerState,
- snackBarHostState = snackBarHostState,
- onShowClicked = onShowClicked,
- onMoreClicked = onMoreClicked,
- onSnackBarErrorDismissed = onErrorDismissed,
- trendingShows = state.trendingShows,
- popularShows = state.popularShows,
- anticipatedShows = state.anticipatedShows,
- recommendedShows = state.recommendedShows,
- errorMessage = state.errorMessage,
- )
- }
- }
+ Loading -> LoadingIndicator(
+ modifier = Modifier
+ .fillMaxSize()
+ .wrapContentSize(Alignment.Center),
+ )
+
+ is DataLoaded -> DiscoverScrollContent(
+ modifier = modifier,
+ pagerState = pagerState,
+ snackBarHostState = snackBarHostState,
+ onShowClicked = onShowClicked,
+ onMoreClicked = onMoreClicked,
+ onSnackBarErrorDismissed = onErrorDismissed,
+ trendingShows = state.trendingShows,
+ popularShows = state.popularShows,
+ anticipatedShows = state.anticipatedShows,
+ recommendedShows = state.recommendedShows,
+ errorMessage = state.errorMessage,
+ )
+
+ is ErrorState -> ErrorUi(
+ errorMessage = state.errorMessage,
+ onRetry = onRetry,
+ modifier = Modifier
+ .fillMaxSize()
+ .wrapContentSize(Alignment.Center),
+ )
}
}
@@ -433,7 +417,7 @@ fun HorizontalPagerItem(
}
}
-@OptIn(ExperimentalSnapperApi::class)
+@OptIn(ExperimentalSnapperApi::class, ExperimentalFoundationApi::class)
@Composable
private fun RowContent(
category: Category,
@@ -465,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/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/GridStateMachine.kt b/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/GridStateMachine.kt
index 2a42501ed..52008a7f7 100644
--- a/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/GridStateMachine.kt
+++ b/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/GridStateMachine.kt
@@ -3,13 +3,13 @@ package com.thomaskioko.tvmaniac.showsgrid
import com.freeletics.flowredux.dsl.ChangedState
import com.freeletics.flowredux.dsl.FlowReduxStateMachine
import com.freeletics.flowredux.dsl.State
+import com.thomaskioko.tvmaniac.category.api.model.getCategory
import com.thomaskioko.tvmaniac.shows.api.DiscoverRepository
+import com.thomaskioko.tvmaniac.util.model.Either
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.FlowPreview
import me.tatarka.inject.annotations.Inject
-import org.mobilenativefoundation.store.store5.StoreReadResponse
-@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class GridStateMachine(
private val repository: DiscoverRepository,
@@ -39,22 +39,18 @@ class GridStateMachine(
action: LoadShows,
): ChangedState {
var nextState: ChangedState = state.noChange()
- repository.observeShowsByCategory(action.category)
+ repository.observeShowCategory(category = action.category.getCategory())
.collect { result ->
nextState = when (result) {
- is StoreReadResponse.NoNewData -> state.noChange()
- is StoreReadResponse.Loading -> state.override { LoadingContent }
- is StoreReadResponse.Data -> state.override {
+ is Either.Left -> state.override {
+ LoadingContentError(result.error.errorMessage)
+ }
+
+ is Either.Right -> state.override {
ShowsLoaded(
- list = result.requireData().toTvShowList(),
+ list = result.data.map { it.toTvShow() },
)
}
- is StoreReadResponse.Error.Exception -> state.override {
- LoadingContentError(result.error.message)
- }
- is StoreReadResponse.Error.Message -> state.override {
- LoadingContentError(result.message)
- }
}
}
diff --git a/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/Mapper.kt b/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/Mapper.kt
index f16897513..8133b8d22 100644
--- a/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/Mapper.kt
+++ b/android-features/shows-grid/src/main/kotlin/com/thomaskioko/tvmaniac/showsgrid/Mapper.kt
@@ -3,10 +3,8 @@ package com.thomaskioko.tvmaniac.showsgrid
import com.thomaskioko.tvmaniac.core.db.ShowsByCategory
import com.thomaskioko.tvmaniac.showsgrid.model.TvShow
-fun List.toTvShowList(): List = map { it.toTvShow() }
-
fun ShowsByCategory.toTvShow(): TvShow = TvShow(
- traktId = trakt_id,
+ traktId = id.id,
tmdbId = tmdb_id,
title = title,
posterImageUrl = poster_url,
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/build.gradle.kts b/app/build.gradle.kts
index 55798b445..f3b931cbc 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -23,6 +23,7 @@ android {
packaging {
resources {
excludes.add("/META-INF/{AL2.0,LGPL2.1}")
+ excludes.add("/META-INF/versions/9/previous-compilation-data.bin")
}
}
}
@@ -44,7 +45,6 @@ dependencies {
implementation(projects.androidFeatures.watchlist)
implementation(projects.core.database)
- implementation(projects.core.networkutil)
implementation(projects.core.util)
implementation(projects.core.datastore.api)
implementation(projects.core.datastore.implementation)
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 b4dd2eb2f..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,12 +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.core.networkutil.inject.NetworkPlatformComponent
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 +19,7 @@ import com.thomaskioko.tvmaniac.seasons.implementation.SeasonsComponent
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.TmdbPlatformComponent
+import com.thomaskioko.tvmaniac.tmdb.implementation.TmdbComponent
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthComponent
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthenticationComponent
import com.thomaskioko.tvmaniac.util.inject.UtilPlatformComponent
@@ -37,10 +35,9 @@ import me.tatarka.inject.annotations.Provides
abstract class ApplicationComponent(
@get:Provides val application: Application,
) : UtilPlatformComponent,
- NetworkPlatformComponent,
CategoryComponent,
DatabaseComponent,
- DataStorePlatformComponent,
+ DataStoreComponent,
EpisodeComponent,
EpisodeImageComponent,
WatchlistComponent,
@@ -54,9 +51,8 @@ abstract class ApplicationComponent(
SimilarShowsComponent,
StatsComponent,
TasksComponent,
- TmdbPlatformComponent,
+ TmdbComponent,
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/DatabasePlatformComponent.kt
similarity index 52%
rename from core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
rename to core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
index 0115d508c..f1f79a2c6 100644
--- a/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
+++ b/core/database/src/androidMain/kotlin/com/thomaskioko/tvmaniac/db/DatabasePlatformComponent.kt
@@ -3,13 +3,11 @@ 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.Last_requests
-import com.thomaskioko.tvmaniac.core.db.Show
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import me.tatarka.inject.annotations.Provides
-actual interface DatabaseComponent {
+actual interface DatabasePlatformComponent {
@ApplicationScope
@Provides
@@ -20,18 +18,4 @@ actual interface DatabaseComponent {
context = application,
name = "tvShows.db",
)
-
- @ApplicationScope
- @Provides
- fun provideTvManiacDatabase(
- sqlDriver: SqlDriver,
- ): TvManiacDatabase = TvManiacDatabase(
- driver = sqlDriver,
- showAdapter = Show.Adapter(
- genresAdapter = stringColumnAdapter,
- ),
- last_requestsAdapter = Last_requests.Adapter(
- timestampAdapter = InstantColumnAdapter,
- ),
- )
}
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/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabaseIdsExt.kt b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabaseIdsExt.kt
new file mode 100644
index 000000000..55561c0be
--- /dev/null
+++ b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabaseIdsExt.kt
@@ -0,0 +1,24 @@
+package com.thomaskioko.tvmaniac.db
+
+import kotlin.jvm.JvmInline
+
+@JvmInline
+value class CategoryId(val id: Long)
+
+@JvmInline
+value class EpisodeId(val traktId: Long)
+
+@JvmInline
+value class EpisodeImageId(val traktId: Long)
+
+@JvmInline
+value class SeasonId(val id: Long)
+
+@JvmInline
+value class ShowId(val traktId: Long)
+
+@JvmInline
+value class SimilarShowId(val id: Long)
+
+@JvmInline
+value class Id(val id: Long)
diff --git a/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabasePlatformComponent.kt b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabasePlatformComponent.kt
new file mode 100644
index 000000000..1c7284223
--- /dev/null
+++ b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DatabasePlatformComponent.kt
@@ -0,0 +1,70 @@
+package com.thomaskioko.tvmaniac.db
+
+import app.cash.sqldelight.db.SqlDriver
+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
+
+expect interface DatabasePlatformComponent
+
+interface DatabaseComponent : DatabasePlatformComponent {
+ @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/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DbTransactionRunner.kt b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DbTransactionRunner.kt
new file mode 100644
index 000000000..08febe361
--- /dev/null
+++ b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/DbTransactionRunner.kt
@@ -0,0 +1,17 @@
+package com.thomaskioko.tvmaniac.db
+
+import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import me.tatarka.inject.annotations.Inject
+
+interface DatabaseTransactionRunner {
+ operator fun invoke(block: () -> T): T
+}
+
+@Inject
+class DbTransactionRunner(private val db: TvManiacDatabase) : DatabaseTransactionRunner {
+ override fun invoke(block: () -> T): T {
+ return db.transactionWithResult {
+ block()
+ }
+ }
+}
diff --git a/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/IdAdapter.kt b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/IdAdapter.kt
new file mode 100644
index 000000000..957180058
--- /dev/null
+++ b/core/database/src/commonMain/kotlin/com.thomaskioko.tvmaniac.db/IdAdapter.kt
@@ -0,0 +1,8 @@
+package com.thomaskioko.tvmaniac.db
+
+import app.cash.sqldelight.ColumnAdapter
+
+internal class IdAdapter : ColumnAdapter, Long> {
+ override fun decode(databaseValue: Long): Id = Id(id = databaseValue)
+ override fun encode(value: Id): Long = value.id
+}
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/SeasonEpisodes.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/SeasonEpisodes.sq
deleted file mode 100644
index 58284cffd..000000000
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/SeasonEpisodes.sq
+++ /dev/null
@@ -1,30 +0,0 @@
-CREATE TABLE season_episodes (
-show_id INTEGER DEFAULT NULL PRIMARY KEY,
-season_id INTEGER DEFAULT NULL,
-season_number INTEGER DEFAULT NULL,
-FOREIGN KEY (season_id) REFERENCES seasons(id),
-FOREIGN KEY (show_id) REFERENCES show(trakt_id)
-);
-
-insertOrReplace:
-INSERT OR REPLACE INTO season_episodes(
-show_id,
-season_id,
-season_number
-)VALUES(?,?,?);
-
-seasonWithEpisodes:
-SELECT show.trakt_id, show.tmdb_id ,show.title, seasons.id , seasons.name, seasons.season_number, seasons.episode_count,
-episodes.trakt_id, episodes.season_id, episodes.title , episodes.episode_number, episodes.overview, episodes.runtime,
-episodes.ratings, episodes.votes, episode_image.image_url
-FROM show
-INNER JOIN seasons ON seasons.show_trakt_id = show.trakt_id
-INNER JOIN episodes ON episodes.season_id = seasons.id
-LEFT OUTER JOIN episode_image ON episode_image.trakt_id = episodes.trakt_id
-WHERE show.trakt_id = ? AND season_number != 0 ORDER BY seasons.season_number, episode_number ASC;
-
-delete:
-DELETE FROM season_episodes WHERE season_id = ?;
-
-deleteAll:
-DELETE FROM season_episodes;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episode_image.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episode_image.sq
index 8df845156..f8b3111fa 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episode_image.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episode_image.sq
@@ -1,28 +1,43 @@
+import com.thomaskioko.tvmaniac.db.EpisodeId;
+import com.thomaskioko.tvmaniac.db.EpisodeImageId;
+import com.thomaskioko.tvmaniac.db.Id;
+
CREATE TABLE episode_image (
-trakt_id INTEGER NOT NULL PRIMARY KEY,
-tmdb_id INTEGER NOT NULL,
-image_url TEXT DEFAULT NULL,
-FOREIGN KEY (trakt_id) REFERENCES episodes(trakt_id) ON DELETE CASCADE
+ id INTEGER AS Id NOT NULL PRIMARY KEY,
+ tmdb_id INTEGER AS Id,
+ image_url TEXT DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES episode(id) ON DELETE CASCADE,
+ UNIQUE(id)
);
insertOrReplace:
INSERT OR REPLACE INTO episode_image(
-trakt_id,
-tmdb_id,
-image_url
+ id,
+ tmdb_id,
+ image_url
)
VALUES(?,?,?);
episodeImage:
-SELECT show.tmdb_id, seasons.season_number, episodes.trakt_id, episodes.episode_number
-FROM episodes
-LEFT JOIN seasons ON seasons.id = episodes.season_id
-LEFT JOIN show ON show.trakt_id = seasons.show_trakt_id
-LEFT OUTER JOIN episode_image ON episode_image.trakt_id = episodes.trakt_id
-WHERE episode_image.image_url IS NULL;
+SELECT
+ show.tmdb_id,
+ season.season_number,
+ episode.id,
+ episode.episode_number,
+ episode_image.image_url
+FROM
+ episode
+LEFT JOIN
+ season ON season.id = episode.season_id
+LEFT JOIN
+ show ON show.id = season.show_id
+LEFT OUTER JOIN
+ episode_image ON episode_image.id = episode.id
+WHERE
+ show.id = :showId AND episode_image.image_url IS NULL;
delete:
-DELETE FROM episode_image WHERE trakt_id = ?;
+DELETE FROM episode_image WHERE id = ?;
deleteAll:
DELETE FROM episode_image;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episodes.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episodes.sq
index 205600cd7..de0ceb564 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episodes.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/episodes.sq
@@ -1,40 +1,48 @@
-CREATE TABLE episodes (
-trakt_id INTEGER NOT NULL PRIMARY KEY,
-season_id INTEGER NOT NULL,
-tmdb_id INTEGER,
-title TEXT NOT NULL,
-overview TEXT NOT NULL,
-ratings REAL NOT NULL,
-runtime INTEGER NOT NULL,
-votes INTEGER NOT NULL,
-episode_number TEXT NOT NULL,
-FOREIGN KEY (season_id) REFERENCES seasons(id)
+import com.thomaskioko.tvmaniac.db.EpisodeId;
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.SeasonId;
+
+CREATE TABLE episode (
+ id INTEGER AS Id NOT NULL PRIMARY KEY,
+ season_id INTEGER AS Id NOT NULL,
+ tmdb_id INTEGER,
+ title TEXT NOT NULL,
+ overview TEXT NOT NULL,
+ ratings REAL NOT NULL,
+ runtime INTEGER NOT NULL,
+ votes INTEGER NOT NULL,
+ episode_number TEXT NOT NULL,
+ FOREIGN KEY(season_id) REFERENCES season(id)
);
insertOrReplace:
-INSERT OR REPLACE INTO episodes(
-trakt_id,
-season_id,
-tmdb_id,
-title,
-overview,
-ratings,
-runtime,
-votes,
-episode_number
+INSERT OR REPLACE INTO episode(
+ id,
+ season_id,
+ tmdb_id,
+ title,
+ overview,
+ ratings,
+ runtime,
+ votes,
+ episode_number
)
VALUES(?,?,?,?,?,?,?,?,?);
-episodeById:
+episodesById:
SELECT *
-FROM episodes
-LEFT OUTER JOIN episode_image ON episode_image.trakt_id = episodes.trakt_id
-WHERE episodes.trakt_id = ?
-ORDER BY episode_number ASC ;
+FROM
+ episode
+LEFT OUTER JOIN
+ episode_image ON episode_image.id = episode.id
+WHERE
+ episode.id = ?
+ORDER BY
+ episode_number ASC;
delete:
-DELETE FROM episodes WHERE trakt_id = ?;
+DELETE FROM episode WHERE id = ?;
deleteAll:
-DELETE FROM episodes;
+DELETE FROM episode;
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/season.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/season.sq
index 3c136c079..b1cc881b0 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/season.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/season.sq
@@ -1,32 +1,76 @@
-CREATE TABLE seasons (
-id INTEGER NOT NULL PRIMARY KEY,
-show_trakt_id INTEGER NOT NULL,
-season_number INTEGER NOT NULL,
-episode_count INTEGER NOT NULL,
-name TEXT NOT NULL,
-overview TEXT,
-FOREIGN KEY (show_trakt_id) REFERENCES show(trakt_id)
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.SeasonId;
+import com.thomaskioko.tvmaniac.db.ShowId;
+
+CREATE TABLE season (
+ id INTEGER AS Id NOT NULL PRIMARY KEY,
+ show_id INTEGER AS Id NOT NULL,
+ season_number INTEGER NOT NULL,
+ title TEXT NOT NULL,
+ episode_count INTEGER NOT NULL,
+ overview TEXT,
+ FOREIGN KEY(show_id) REFERENCES show(id)
);
insertOrReplace:
-INSERT OR REPLACE INTO seasons(
-id,
-show_trakt_id,
-season_number,
-episode_count,
-name,
-overview
+INSERT OR REPLACE INTO season(
+ id,
+ show_id,
+ season_number,
+ episode_count,
+ title,
+ overview
)
VALUES(?,?,?,?,?,?);
-seasonById:
-SELECT *
-FROM seasons
-WHERE seasons.show_trakt_id = ? AND season_number != 0
-ORDER BY season_number ASC;
+seasonsByShowId:
+SELECT
+ show.id AS show_id,
+ season.id AS season_id,
+ season.title AS season_title,
+ season.season_number
+FROM
+ show
+JOIN
+ season ON show.id = season.show_id
+WHERE
+ show.id = ?;
+
+seasonEpisodeDetailsById:
+SELECT
+ show.id AS show_id,
+ show.title AS show_title,
+ season.id AS season_id,
+ season.title AS season_title,
+ season.overview AS season_overview,
+ season.season_number,
+ season.episode_count,
+ episode.id AS episode_id,
+ episode.season_id AS episode_season_id,
+ episode.title AS episode_title,
+ episode.episode_number,
+ episode.overview,
+ episode.runtime,
+ episode.ratings,
+ episode.votes,
+ episode_image.image_url AS episode_image_url
+FROM
+ show
+INNER JOIN
+ season ON season.show_id = show.id
+INNER JOIN
+ episode ON episode.season_id = season.id
+LEFT OUTER JOIN
+ episode_image ON episode_image.id = episode.id
+WHERE
+ show.id = ?
+AND
+ season_number != 0
+ORDER BY
+ season.season_number, episode_number ASC;
delete:
-DELETE FROM seasons WHERE show_trakt_id = ?;
+DELETE FROM season WHERE show_id = ?;
deleteAll:
-DELETE FROM seasons;
+DELETE FROM season;
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show.sq
index 6d59b4b4d..36c234fce 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show.sq
@@ -1,68 +1,90 @@
-import kotlin.collections.List;
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.ShowId;
import kotlin.String;
+import kotlin.collections.List;
CREATE TABLE show(
-trakt_id INTEGER NOT NULL PRIMARY KEY,
-tmdb_id INTEGER,
-title TEXT NOT NULL,
-overview TEXT NOT NULL,
-language TEXT,
-year TEXT NOT NULL,
-rating REAL NOT NULL,
-status TEXT NOT NULL,
-runtime INTEGER NOT NULL,
-votes INTEGER NOT NULL,
-aired_episodes INTEGER DEFAULT NULL,
-genres TEXT AS List NOT NULL
+ id INTEGER AS Id NOT NULL PRIMARY KEY,
+ tmdb_id INTEGER,
+ title TEXT NOT NULL,
+ overview TEXT NOT NULL,
+ language TEXT,
+ year TEXT NOT NULL,
+ rating REAL NOT NULL,
+ status TEXT NOT NULL,
+ runtime INTEGER NOT NULL,
+ votes INTEGER NOT NULL,
+ aired_episodes INTEGER DEFAULT NULL,
+ genres TEXT AS List NOT NULL
);
insertOrReplace:
INSERT OR REPLACE INTO show(
-trakt_id,
-tmdb_id,
-title,
-overview,
-language,
-year,
-votes,
-runtime,
-rating,
-genres,
-status
+ id,
+ tmdb_id,
+ title,
+ overview,
+ language,
+ year,
+ votes,
+ runtime,
+ rating,
+ genres,
+ status
)
VALUES(?,?,?,?,?,?,?,?,?,?,?);
showById:
-SELECT * FROM show
-LEFT OUTER JOIN show_image ON show_image.trakt_id = show.trakt_id
-LEFT OUTER JOIN watchlist ON show.trakt_id = watchlist.id
-WHERE show.trakt_id = ?;
-
-selectShowByTmdbId:
-SELECT * FROM show
-WHERE tmdb_id = ?;
+SELECT
+ show.id,
+ show.tmdb_id ,
+ show.title,
+ show.overview,
+ show.language,
+ show.year,
+ show.rating,
+ show.votes,
+ show.status,
+ show.runtime,
+ show.genres,
+ show.aired_episodes,
+ show_image.poster_url,
+ show_image.backdrop_url,
+ CASE WHEN watchlist.id IS NOT NULL THEN 1 ELSE 0 END AS in_watchlist
+FROM
+ show
+LEFT OUTER JOIN
+ show_image ON show_image.id = show.id
+LEFT OUTER JOIN
+ watchlist ON show.id = watchlist.id
+WHERE
+ show.id = ?;
shows:
-SELECT show.trakt_id, show.tmdb_id ,show.title, show.overview, show.language, show.year, show.rating,
-show.votes, show.status, show.runtime, show.genres, show.aired_episodes, show_image.poster_url, show_image.backdrop_url,
-show_category.category_id
-FROM show
-INNER JOIN show_category ON show_category.trakt_id = show.trakt_id
-LEFT OUTER JOIN show_image ON show_image.trakt_id = show.trakt_id
-ORDER BY show.rating, show.year DESC;
-
-showsByCategory:
-SELECT show.trakt_id, show.tmdb_id ,show.title, show.overview, show.language, show.year, show.rating,
-show.votes, show.status, show.runtime, show.genres, show.aired_episodes, show_image.poster_url, show_image.backdrop_url,
-show_category.category_id
-FROM show
-INNER JOIN show_category ON show_category.trakt_id = show.trakt_id
-LEFT OUTER JOIN show_image ON show_image.trakt_id = show.trakt_id
-WHERE show_category.category_id = ?
-ORDER BY show.rating, show.year DESC;
-
-delete:
-DELETE FROM show WHERE trakt_id = ?;
+SELECT
+ show.id,
+ show.tmdb_id ,
+ show.title,
+ show.overview,
+ show.language,
+ show.year,
+ show.rating,
+ show.votes,
+ show.status,
+ show.runtime,
+ show.genres,
+ show.aired_episodes,
+ show_image.poster_url,
+ show_image.backdrop_url,
+ show_category.category_id
+FROM
+ show
+JOIN
+ show_category ON show_category.id = show.id
+LEFT OUTER JOIN
+ show_image ON show_image.id = show.id
+ORDER BY
+ show.rating, show.year DESC;
deleteAll:
DELETE FROM show;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_category.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_category.sq
index 5bd008c92..1f01b9862 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_category.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_category.sq
@@ -1,12 +1,45 @@
+import com.thomaskioko.tvmaniac.db.CategoryId;
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.ShowId;
+
CREATE TABLE show_category (
-trakt_id INTEGER DEFAULT NULL PRIMARY KEY,
-category_id INTEGER DEFAULT NULL,
-FOREIGN KEY (trakt_id) REFERENCES show(trakt_id)
+ id INTEGER AS Id DEFAULT NULL,
+ category_id INTEGER AS Id DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES show(id),
+ PRIMARY KEY(id, category_id)
);
insertOrReplace:
INSERT OR REPLACE INTO show_category(
-trakt_id,
-category_id
+ id,
+ category_id
)
-VALUES(?,?);
\ No newline at end of file
+VALUES(?,?);
+
+showsByCategory:
+SELECT
+ show.id,
+ show.tmdb_id ,
+ show.title,
+ show.overview,
+ show.language,
+ show.year,
+ show.rating,
+ show.votes,
+ show.status,
+ show.runtime,
+ show.genres,
+ show.aired_episodes,
+ show_image.poster_url,
+ show_image.backdrop_url,
+ show_category.category_id
+FROM
+ show
+INNER JOIN
+ show_category ON show_category.id = show.id
+LEFT OUTER JOIN
+ show_image ON show_image.id = show.id
+WHERE
+ show_category.category_id = ?
+ORDER BY
+ show.rating, show.year DESC;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_image.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_image.sq
index 54a9c127f..fe7c3b00e 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_image.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/show_image.sq
@@ -1,31 +1,39 @@
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.ShowId;
+
CREATE TABLE show_image (
-trakt_id INTEGER NOT NULL PRIMARY KEY,
-tmdb_id INTEGER DEFAULT NULL,
-poster_url TEXT DEFAULT NULL,
-backdrop_url TEXT DEFAULT NULL,
-FOREIGN KEY (trakt_id) REFERENCES show(trakt_id) ON DELETE CASCADE
+ id INTEGER AS Id NOT NULL PRIMARY KEY,
+ tmdb_id INTEGER DEFAULT NULL,
+ poster_url TEXT DEFAULT NULL,
+ backdrop_url TEXT DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES show(id) ON DELETE CASCADE,
+ UNIQUE(id)
);
insertOrReplace:
INSERT OR REPLACE INTO show_image(
-trakt_id,
-tmdb_id,
-poster_url,
-backdrop_url
+ id,
+ tmdb_id,
+ poster_url,
+ backdrop_url
)
VALUES(?,?,?,?);
-selectImages:
-SELECT * FROM show_image
-WHERE poster_url IS NULL;
-
-selectShowImages:
-SELECT show.trakt_id, show.tmdb_id FROM show
-LEFT OUTER JOIN show_image ON show_image.trakt_id = show.trakt_id
-WHERE poster_url IS NULL AND backdrop_url IS NULL;
+emptyShowImage:
+SELECT
+ show.id,
+ show.tmdb_id,
+ show_image.poster_url,
+ show_image.backdrop_url
+FROM
+ show
+LEFT OUTER JOIN
+ show_image ON show_image.id = show.id
+WHERE
+ poster_url IS NULL AND backdrop_url IS NULL;
delete:
-DELETE FROM show_image WHERE trakt_id = ?;
+DELETE FROM show_image WHERE id = ?;
deleteAll:
DELETE FROM show_image;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/similar_shows.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/similar_shows.sq
index fa61f1337..ed4637853 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/similar_shows.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/similar_shows.sq
@@ -1,26 +1,48 @@
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.ShowId;
+import com.thomaskioko.tvmaniac.db.SimilarShowId;
+
CREATE TABLE similar_shows (
-id INTEGER DEFAULT NULL PRIMARY KEY,
-trakt_id INTEGER NOT NULL,
-FOREIGN KEY (trakt_id) REFERENCES show(trakt_id)
+ id INTEGER AS Id,
+ similar_show_id INTEGER AS Id NOT NULL,
+ PRIMARY KEY (similar_show_id, id),
+ FOREIGN KEY(similar_show_id) REFERENCES show(id),
+ FOREIGN KEY(id) REFERENCES show(id)
);
insertOrReplace:
INSERT OR REPLACE INTO similar_shows(
-id,
-trakt_id
+ id,
+ similar_show_id
)
VALUES(?,?);
similarShows:
-SELECT show.trakt_id, show.tmdb_id ,show.title, show.overview, show.language, show.year, show.rating, show.votes, show.status,
-show.runtime, show.genres, show_image.poster_url, show_image.backdrop_url
-FROM show
-JOIN similar_shows ON show.trakt_id = similar_shows.id
-INNER JOIN show_image ON show_image.trakt_id = similar_shows.id
-WHERE similar_shows.trakt_id = ?;
+SELECT
+ show.id,
+ show.tmdb_id ,
+ show.title,
+ show.overview,
+ show.language,
+ show.year,
+ show.rating,
+ show.votes,
+ show.status,
+ show.runtime,
+ show.genres,
+ show_image.poster_url,
+ show_image.backdrop_url
+FROM
+ show
+JOIN
+ similar_shows ON show.id = similar_shows.id
+INNER JOIN
+ show_image ON show_image.id = similar_shows.id
+WHERE
+ similar_shows.similar_show_id = ?;
delete:
-DELETE FROM similar_shows WHERE trakt_id = ?;
+DELETE FROM similar_shows WHERE similar_show_id = ?;
deleteAll:
DELETE FROM similar_shows;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/stats.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/stats.sq
index e51acf2f8..28b9ff4bc 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/stats.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/stats.sq
@@ -1,20 +1,20 @@
CREATE TABLE stats(
-slug TEXT NOT NULL PRIMARY KEY,
-months Text NOT NULL,
-days Text NOT NULL,
-hours Text NOT NULL,
-collected_shows Text NOT NULL,
-episodes_watched Text NOT NULL
+ slug TEXT NOT NULL PRIMARY KEY,
+ months Text NOT NULL,
+ days Text NOT NULL,
+ hours Text NOT NULL,
+ collected_shows Text NOT NULL,
+ episodes_watched Text NOT NULL
);
insertOrReplace:
INSERT OR REPLACE INTO stats(
-slug,
-months,
-days,
-hours,
-collected_shows,
-episodes_watched
+ slug,
+ months,
+ days,
+ hours,
+ collected_shows,
+ episodes_watched
)
VALUES(?,?,?,?,?,?);
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trailers.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trailers.sq
index e94540844..171f4ebcf 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trailers.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trailers.sq
@@ -1,33 +1,36 @@
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.ShowId;
+
CREATE TABLE trailers (
-id TEXT NOT NULL PRIMARY KEY,
-trakt_id INTEGER NOT NULL,
-key TEXT NOT NULL,
-name TEXT NOT NULL,
-site TEXT NOT NULL,
-size INTEGER NOT NULL,
-type TEXT NOT NULL,
-FOREIGN KEY (trakt_id) REFERENCES show(trakt_id)
+ id TEXT NOT NULL PRIMARY KEY,
+ show_id INTEGER AS Id NOT NULL,
+ key TEXT NOT NULL,
+ name TEXT NOT NULL,
+ site TEXT NOT NULL,
+ size INTEGER NOT NULL,
+ type TEXT NOT NULL,
+ FOREIGN KEY(show_id)REFERENCES show(id)
);
insertOrReplace:
INSERT OR REPLACE INTO trailers(
-id,
-trakt_id,
-key,
-name,
-site,
-size,
-type
+ id,
+ show_id,
+ key,
+ name,
+ site,
+ size,
+ type
)
VALUES(?,?,?,?,?,?,?);
selectByShowId:
SELECT *
FROM trailers
-WHERE trakt_id = ?;
+WHERE show_id = ?;
delete:
-DELETE FROM trailers WHERE trakt_id = ?;
+DELETE FROM trailers WHERE show_id = ?;
deleteAll:
DELETE FROM trailers;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trakt_shows_list.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trakt_shows_list.sq
index 292d0a3fe..eb3f25b61 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trakt_shows_list.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/trakt_shows_list.sq
@@ -1,14 +1,14 @@
CREATE TABLE trakt_shows_list (
-id INTEGER NOT NULL PRIMARY KEY,
-slug TEXT NOT NULL,
-description TEXT NOT NULL
+ id INTEGER NOT NULL PRIMARY KEY,
+ slug TEXT NOT NULL,
+ description TEXT NOT NULL
);
insertOrReplace:
INSERT OR REPLACE INTO trakt_shows_list(
-id,
-slug,
-description
+ id,
+ slug,
+ description
)
VALUES(?,?,?);
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/user.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/user.sq
index 08aebafd3..a55bbb7c0 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/user.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/user.sq
@@ -1,35 +1,43 @@
import kotlin.Boolean;
CREATE TABLE user (
-slug TEXT NOT NULL PRIMARY KEY,
-user_name Text NOT NULL,
-full_name TEXT,
-profile_picture TEXT,
-is_me INTEGER AS Boolean NOT NULL DEFAULT 0
+ slug TEXT NOT NULL PRIMARY KEY,
+ user_name Text NOT NULL,
+ full_name TEXT,
+ profile_picture TEXT,
+ is_me INTEGER AS Boolean NOT NULL DEFAULT 0
);
insertOrReplace:
INSERT OR REPLACE INTO user(
-slug,
-user_name,
-full_name,
-profile_picture,
-is_me
+ slug,
+ user_name,
+ full_name,
+ profile_picture,
+ is_me
)
VALUES(?,?,?,?,? );
userBySlug:
-SELECT *
-FROM user
-WHERE slug = ?;
+SELECT
+ *
+FROM
+ user
+WHERE
+ slug = ?;
getCurrentUser:
-SELECT *
-FROM user
-WHERE is_me != 0;
+SELECT
+ *
+FROM
+ user
+WHERE
+ is_me != 0;
delete:
-DELETE FROM user WHERE slug = ?;
+DELETE FROM
+ user
+WHERE slug = ?;
deleteAll:
DELETE FROM user;
\ No newline at end of file
diff --git a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/watchlist.sq b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/watchlist.sq
index d2e89de4c..ccb4cc502 100644
--- a/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/watchlist.sq
+++ b/core/database/src/commonMain/sqldelight/com/thomaskioko/tvmaniac/core/db/watchlist.sq
@@ -1,36 +1,67 @@
+import com.thomaskioko.tvmaniac.db.Id;
+import com.thomaskioko.tvmaniac.db.ShowId;
import kotlin.Boolean;
CREATE TABLE watchlist (
-id INTEGER PRIMARY KEY,
-synced INTEGER AS Boolean NOT NULL DEFAULT 0,
-created_at INTEGER NOT NULL,
-FOREIGN KEY (id) REFERENCES show(trakt_id) ON DELETE CASCADE
+ id INTEGER AS Id PRIMARY KEY,
+ synced INTEGER AS Boolean NOT NULL DEFAULT 0,
+ created_at INTEGER NOT NULL,
+ FOREIGN KEY(id) REFERENCES show(id) ON DELETE CASCADE,
+ UNIQUE(id)
);
insertOrReplace:
INSERT OR REPLACE INTO watchlist(
-id,
-synced,
-created_at
+ id,
+ synced,
+ created_at
)
-VALUES(?, ?, ?);
+VALUES( ?, ?, ?);
-selectUnsyncedShows:
-SELECT * FROM watchlist
-WHERE synced != 1;
+unsyncedShows:
+SELECT
+ *
+FROM
+ watchlist
+WHERE
+ synced != 1;
-selectWatchlist:
-SELECT *
-FROM watchlist
-INNER JOIN show ON show.trakt_id = watchlist.id
-INNER JOIN show_image ON show_image.trakt_id = watchlist.id
-ORDER BY created_at DESC;
-
-removeShow:
-DELETE FROM watchlist
-WHERE id = ?;
+watchedShow:
+SELECT
+ show.id AS show_id,
+ show.tmdb_id,
+ show.title,
+ show.overview,
+ show.language,
+ show.year,
+ show.rating,
+ show.votes,
+ show.status,
+ show.runtime,
+ show.genres,
+ show.aired_episodes,
+ show_image.poster_url,
+ show_image.backdrop_url,
+ watchlist.created_at
+FROM
+ show
+JOIN
+ watchlist ON show.id = watchlist.id
+INNER JOIN
+ show_image ON show_image.id = watchlist.id
+ORDER BY
+ watchlist.created_at DESC;
updateFollowedState:
-UPDATE watchlist
-SET synced = ?
-WHERE id = ?;
\ No newline at end of file
+UPDATE
+ watchlist
+SET
+ synced = ?
+WHERE
+ id = ?;
+
+removeShowFromWatchlist:
+DELETE FROM
+ watchlist
+WHERE
+ id = ?;
\ No newline at end of file
diff --git a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/BaseDatabaseTest.kt b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/BaseDatabaseTest.kt
index 55b8c55ea..d009bd850 100644
--- a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/BaseDatabaseTest.kt
+++ b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/BaseDatabaseTest.kt
@@ -1,6 +1,7 @@
package com.thomaskioko.tvmaniac.core.db
import app.cash.sqldelight.db.SqlDriver
+import com.thomaskioko.tvmaniac.db.IdAdapter
import com.thomaskioko.tvmaniac.db.InstantColumnAdapter
import com.thomaskioko.tvmaniac.db.stringColumnAdapter
import kotlin.test.AfterTest
@@ -18,10 +19,40 @@ abstract class BaseDatabaseTest {
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(),
+ ),
)
@AfterTest
diff --git a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/EpisodesCacheTest.kt b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/EpisodesCacheTest.kt
index e31efd02d..602b0ad12 100644
--- a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/EpisodesCacheTest.kt
+++ b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/EpisodesCacheTest.kt
@@ -1,6 +1,7 @@
package com.thomaskioko.tvmaniac.core.db
import com.thomaskioko.tvmaniac.core.db.MockData.getEpisodeCacheList
+import com.thomaskioko.tvmaniac.db.Id
import io.kotest.matchers.shouldBe
import kotlin.test.Test
@@ -13,9 +14,9 @@ internal class EpisodesCacheTest : BaseDatabaseTest() {
getEpisodeCacheList().insertEpisodeEntityQuery()
val entity = getEpisodeCacheList().first()
- val queryResult = episodeQueries.episodeById(2534997).executeAsOne()
+ val queryResult = episodeQueries.episodesById(Id(2534997)).executeAsOne()
- queryResult.trakt_id shouldBe entity.trakt_id
+ queryResult.id.id shouldBe entity.id.id
queryResult.season_id shouldBe entity.season_id
queryResult.title shouldBe entity.title
queryResult.overview shouldBe entity.overview
@@ -23,13 +24,13 @@ internal class EpisodesCacheTest : BaseDatabaseTest() {
queryResult.votes shouldBe entity.votes
}
- private fun List.insertEpisodeEntityQuery() {
+ private fun List.insertEpisodeEntityQuery() {
map { it.insertEpisodeEntityQuery() }
}
- private fun Episodes.insertEpisodeEntityQuery() {
+ private fun Episode.insertEpisodeEntityQuery() {
episodeQueries.insertOrReplace(
- trakt_id = trakt_id,
+ id = id,
season_id = season_id,
title = title,
overview = overview,
diff --git a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/MockData.kt b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/MockData.kt
index 110e51607..89fbcbd40 100644
--- a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/MockData.kt
+++ b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/MockData.kt
@@ -1,13 +1,14 @@
package com.thomaskioko.tvmaniac.core.db
-import com.thomaskioko.tvmaniac.core.db.Episodes as EpisodeCache
+import com.thomaskioko.tvmaniac.db.Id
+import com.thomaskioko.tvmaniac.core.db.Episode as EpisodeCache
object MockData {
fun getEpisodeCacheList() = listOf(
EpisodeCache(
- trakt_id = 2534997,
- season_id = 114355,
+ id = Id(2534997),
+ season_id = Id(114355),
title = "Glorious Purpose",
overview = "After stealing the Tesseract in Avengers: Endgame, Loki lands before the Time Variance Authority.",
votes = 42,
@@ -17,8 +18,8 @@ object MockData {
tmdb_id = 1,
),
EpisodeCache(
- trakt_id = 2927202,
- season_id = 114355,
+ id = Id(2927202),
+ season_id = Id(114355),
title = "The Variant",
overview = "Mobius puts Loki to work, but not everyone at TVA is thrilled about the God of Mischief's presence.",
votes = 23,
@@ -30,7 +31,7 @@ object MockData {
)
fun getShow() = Show(
- trakt_id = 84958,
+ id = Id(84958),
title = "Loki",
overview = "After stealing the Tesseract during the events of “Avengers: Endgame,” " +
"an alternate version of Loki is brought to the mysterious Time Variance " +
@@ -51,7 +52,7 @@ object MockData {
fun showList() = listOf(
Show(
- trakt_id = 84958,
+ id = Id(84958),
title = "Loki",
overview = "After stealing the Tesseract during the events of “Avengers: Endgame,” " +
"an alternate version of Loki is brought to the mysterious Time Variance " +
@@ -70,7 +71,7 @@ object MockData {
aired_episodes = 12,
),
Show(
- trakt_id = 126280,
+ id = Id(126280),
title = "Sex/Life",
overview = "A woman's daring sexual past collides with her married-with-kids " +
"present when the bad-boy ex she can't stop fantasizing about crashes " +
@@ -88,7 +89,7 @@ object MockData {
)
fun showCategory(traktId: Long, categoryId: Long) = Show_category(
- trakt_id = traktId,
- category_id = categoryId,
+ id = Id(traktId),
+ category_id = Id(categoryId),
)
}
diff --git a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/TvShowCacheTest.kt b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/TvShowCacheTest.kt
index 425b5beec..95ab895d1 100644
--- a/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/TvShowCacheTest.kt
+++ b/core/database/src/commonTest/kotlin/com/thomaskioko/tvmaniac/core/db/TvShowCacheTest.kt
@@ -19,7 +19,7 @@ internal class TvShowCacheTest : BaseDatabaseTest() {
shows.insertTvShowsEntityList()
for (show in shows) {
- showCategory(show.trakt_id, 1).insertCategory()
+ showCategory(show.id.id, 1).insertCategory()
}
val entities = tvShowQueries.shows().executeAsList()
@@ -31,7 +31,7 @@ internal class TvShowCacheTest : BaseDatabaseTest() {
fun verify_selectByShowId_returnTvShowEntity_afterInsertHasBeenDone() {
getShow().insertTvShowQuery()
- val entity = tvShowQueries.showById(getShow().trakt_id)
+ val entity = tvShowQueries.showById(getShow().id)
.executeAsOne()
entity shouldNotBe null
@@ -48,7 +48,7 @@ internal class TvShowCacheTest : BaseDatabaseTest() {
tvShowQueries.deleteAll()
- val entity = tvShowQueries.showById(getShow().trakt_id)
+ val entity = tvShowQueries.showById(getShow().id)
.executeAsOneOrNull()
entity shouldBe null
@@ -60,7 +60,7 @@ internal class TvShowCacheTest : BaseDatabaseTest() {
private fun Show.insertTvShowQuery() {
tvShowQueries.insertOrReplace(
- trakt_id = trakt_id,
+ id = id,
title = title,
overview = overview,
language = language,
@@ -76,7 +76,7 @@ internal class TvShowCacheTest : BaseDatabaseTest() {
private fun Show_category.insertCategory() {
showCategoryQueries.insertOrReplace(
- trakt_id = trakt_id,
+ id = id,
category_id = category_id,
)
}
diff --git a/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt b/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
deleted file mode 100644
index 2c2d1e0b3..000000000
--- a/core/database/src/iosMain/kotlin/com/thomaskioko/tvmaniac/db/DatabaseComponent.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.thomaskioko.tvmaniac.db
-
-import app.cash.sqldelight.db.SqlDriver
-import app.cash.sqldelight.driver.native.NativeSqliteDriver
-import com.thomaskioko.tvmaniac.core.db.Last_requests
-import com.thomaskioko.tvmaniac.core.db.Show
-import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
-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")
-
- @ApplicationScope
- @Provides
- fun provideTvManiacDatabase(
- sqlDriver: SqlDriver,
- ): TvManiacDatabase = TvManiacDatabase(
- driver = sqlDriver,
- showAdapter = Show.Adapter(
- genresAdapter = stringColumnAdapter,
- ),
- last_requestsAdapter = Last_requests.Adapter(
- timestampAdapter = InstantColumnAdapter,
- ),
- )
-}
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/networkutil/src/androidMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt b/core/networkutil/src/androidMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
deleted file mode 100644
index 6c16a51cb..000000000
--- a/core/networkutil/src/androidMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.thomaskioko.tvmaniac.core.networkutil.inject
-
-import com.thomaskioko.tvmaniac.core.networkutil.AndroidNetworkExceptionHandlerUtil
-import com.thomaskioko.tvmaniac.core.networkutil.NetworkExceptionHandler
-import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
-import me.tatarka.inject.annotations.Provides
-
-actual interface NetworkPlatformComponent {
-
- @ApplicationScope
- @Provides
- fun provideNetworkExceptionHandler(
- bind: AndroidNetworkExceptionHandlerUtil,
- ): NetworkExceptionHandler = bind
-}
diff --git a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/NetworkBoundResource.kt b/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/NetworkBoundResource.kt
deleted file mode 100644
index e0290f6fb..000000000
--- a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/NetworkBoundResource.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.thomaskioko.tvmaniac.core.networkutil
-
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOn
-
-inline fun networkBoundResult(
- crossinline query: () -> Flow,
- crossinline fetch: suspend () -> RequestType,
- crossinline saveFetchResult: suspend (RequestType) -> Unit,
- crossinline shouldFetch: (ResultType?) -> Boolean = { true },
- exceptionHandler: NetworkExceptionHandler,
- coroutineDispatcher: CoroutineDispatcher,
-) = flow> {
- val data = query().first()
-
- if (shouldFetch(data)) {
- try {
- saveFetchResult(fetch())
- emit(Either.Right(query().first()))
- } catch (e: Exception) {
- emit(Either.Left(DefaultError(exceptionHandler.resolveError(e))))
- }
- } else {
- emit(Either.Right(query().first()))
- }
-}.catch {
- emit(Either.Left(DefaultError(exceptionHandler.resolveError(it))))
-}.flowOn(coroutineDispatcher)
diff --git a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt b/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
deleted file mode 100644
index 75bef7e04..000000000
--- a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.thomaskioko.tvmaniac.core.networkutil.inject
-
-expect interface NetworkPlatformComponent
diff --git a/core/networkutil/src/iosMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt b/core/networkutil/src/iosMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
deleted file mode 100644
index 0f8f5b4eb..000000000
--- a/core/networkutil/src/iosMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.thomaskioko.tvmaniac.core.networkutil.inject
-
-import com.thomaskioko.tvmaniac.core.networkutil.IosExceptionHandler
-import com.thomaskioko.tvmaniac.core.networkutil.NetworkExceptionHandler
-import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
-import me.tatarka.inject.annotations.Provides
-
-actual interface NetworkPlatformComponent {
- @ApplicationScope
- @Provides
- fun provideExceptionHandler(bind: IosExceptionHandler): NetworkExceptionHandler = bind
-}
diff --git a/core/networkutil/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt b/core/networkutil/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
deleted file mode 100644
index 5bea96170..000000000
--- a/core/networkutil/src/jvmMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/inject/NetworkPlatformComponent.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.thomaskioko.tvmaniac.core.networkutil.inject
-
-actual interface NetworkPlatformComponent
diff --git a/core/tmdb-api/api/build.gradle.kts b/core/tmdb-api/api/build.gradle.kts
index 9d4ac4c41..cf71540da 100644
--- a/core/tmdb-api/api/build.gradle.kts
+++ b/core/tmdb-api/api/build.gradle.kts
@@ -8,7 +8,7 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
+ api(projects.core.util)
implementation(libs.ktor.serialization)
}
diff --git a/core/tmdb-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/api/TmdbNetworkDataSource.kt b/core/tmdb-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/api/TmdbNetworkDataSource.kt
index fc55d52c4..41e1a03d5 100644
--- a/core/tmdb-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/api/TmdbNetworkDataSource.kt
+++ b/core/tmdb-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/api/TmdbNetworkDataSource.kt
@@ -1,10 +1,10 @@
package com.thomaskioko.tvmaniac.tmdb.api
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.EpisodesResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.ShowDetailResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.TrailersResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
interface TmdbNetworkDataSource {
diff --git a/core/tmdb-api/implementation/build.gradle.kts b/core/tmdb-api/implementation/build.gradle.kts
index 2244ed949..a3f1192a9 100644
--- a/core/tmdb-api/implementation/build.gradle.kts
+++ b/core/tmdb-api/implementation/build.gradle.kts
@@ -20,6 +20,7 @@ kotlin {
implementation(libs.kotlinInject.runtime)
implementation(libs.ktor.core)
+ implementation(libs.ktor.logging)
implementation(libs.ktor.negotiation)
implementation(libs.ktor.serialization.json)
implementation(libs.sqldelight.extensions)
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 a7feec22b..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
@@ -1,38 +1,12 @@
package com.thomaskioko.tvmaniac.tmdb.implementation
-import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
-import com.thomaskioko.tvmaniac.util.model.Configs
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import io.ktor.client.engine.okhttp.OkHttp
-import kotlinx.serialization.json.Json
import me.tatarka.inject.annotations.Provides
actual interface TmdbPlatformComponent {
- @ApplicationScope
- @Provides
- fun provideTmdbJson(): TmdbJson = Json {
- ignoreUnknownKeys = true
- prettyPrint = true
- encodeDefaults = true
- }
-
@ApplicationScope
@Provides
fun provideTmdbHttpClientEngine(): TmdbHttpClientEngine = OkHttp.create()
-
- @ApplicationScope
- @Provides
- fun provideTmdbHttpClient(
- configs: Configs,
- json: TmdbJson,
- httpClientEngine: TmdbHttpClientEngine,
- ): TmdbHttpClient = tmdbHttpClient(
- tmdbApiKey = configs.tmdbApiKey,
- json = json,
- httpClientEngine = httpClientEngine,
- )
-
- @Provides
- fun provideTmdbService(bind: TmdbNetworkDataSourceImpl): TmdbNetworkDataSource = bind
}
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 30e8fba69..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
@@ -1,10 +1,15 @@
package com.thomaskioko.tvmaniac.tmdb.implementation
+import com.thomaskioko.tvmaniac.util.KermitLogger
import io.ktor.client.HttpClient
import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.client.plugins.logging.EMPTY
+import io.ktor.client.plugins.logging.LogLevel
+import io.ktor.client.plugins.logging.Logger
+import io.ktor.client.plugins.logging.Logging
import io.ktor.client.request.headers
import io.ktor.http.HttpHeaders
import io.ktor.http.URLProtocol
@@ -14,9 +19,11 @@ import kotlinx.serialization.json.Json
const val TIMEOUT_DURATION: Long = 60_000
fun tmdbHttpClient(
+ isDebug: Boolean = false,
tmdbApiKey: String,
json: Json,
httpClientEngine: HttpClientEngine,
+ kermitLogger: KermitLogger,
) = HttpClient(httpClientEngine) {
install(ContentNegotiation) {
json(json = json)
@@ -43,4 +50,17 @@ fun tmdbHttpClient(
connectTimeoutMillis = TIMEOUT_DURATION
socketTimeoutMillis = TIMEOUT_DURATION
}
+
+ install(Logging) {
+ level = LogLevel.INFO
+ logger = if (isDebug) {
+ object : Logger {
+ override fun log(message: String) {
+ kermitLogger.info("TmbdHttp", message)
+ }
+ }
+ } else {
+ Logger.EMPTY
+ }
+ }
}
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
new file mode 100644
index 000000000..d621cc0d6
--- /dev/null
+++ b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbComponent.kt
@@ -0,0 +1,48 @@
+package com.thomaskioko.tvmaniac.tmdb.implementation
+
+import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
+import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.Configs
+import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
+import io.ktor.client.HttpClient
+import io.ktor.client.engine.HttpClientEngine
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.json.Json
+import me.tatarka.inject.annotations.Provides
+
+typealias TmdbHttpClient = HttpClient
+typealias TmdbHttpClientEngine = HttpClientEngine
+typealias TmdbJson = Json
+
+expect interface TmdbPlatformComponent
+
+interface TmdbComponent : TmdbPlatformComponent {
+
+ @OptIn(ExperimentalSerializationApi::class)
+ @ApplicationScope
+ @Provides
+ fun provideTmdbJson(): TmdbJson = Json {
+ isLenient = true
+ ignoreUnknownKeys = true
+ useAlternativeNames = false
+ explicitNulls = false
+ }
+
+ @ApplicationScope
+ @Provides
+ fun provideTmdbHttpClient(
+ configs: Configs,
+ json: TmdbJson,
+ httpClientEngine: TmdbHttpClientEngine,
+ logger: KermitLogger,
+ ): TmdbHttpClient = tmdbHttpClient(
+ tmdbApiKey = configs.tmdbApiKey,
+ json = json,
+ httpClientEngine = httpClientEngine,
+ kermitLogger = logger,
+ isDebug = configs.isDebug,
+ )
+
+ @Provides
+ fun provideTmdbService(bind: TmdbNetworkDataSourceImpl): TmdbNetworkDataSource = bind
+}
diff --git a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbNetworkDataSourceImpl.kt b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbNetworkDataSourceImpl.kt
index cc8129c84..dc99aa1a3 100644
--- a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbNetworkDataSourceImpl.kt
+++ b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbNetworkDataSourceImpl.kt
@@ -1,12 +1,12 @@
package com.thomaskioko.tvmaniac.tmdb.implementation
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.safeRequest
import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
import com.thomaskioko.tvmaniac.tmdb.api.model.EpisodesResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.ShowDetailResponse
import com.thomaskioko.tvmaniac.tmdb.api.model.TrailersResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
+import com.thomaskioko.tvmaniac.util.model.safeRequest
import io.ktor.http.HttpMethod
import io.ktor.http.path
import me.tatarka.inject.annotations.Inject
diff --git a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt b/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
deleted file mode 100644
index a4fc2c2bc..000000000
--- a/core/tmdb-api/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/implementation/TmdbPlatformComponent.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.thomaskioko.tvmaniac.tmdb.implementation
-
-import io.ktor.client.HttpClient
-import io.ktor.client.engine.HttpClientEngine
-import kotlinx.serialization.json.Json
-
-typealias TmdbHttpClient = HttpClient
-typealias TmdbHttpClientEngine = HttpClientEngine
-typealias TmdbJson = Json
-
-expect interface TmdbPlatformComponent
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 9159ffdd6..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
@@ -1,41 +1,12 @@
package com.thomaskioko.tvmaniac.tmdb.implementation
-import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
-import com.thomaskioko.tvmaniac.util.model.Configs
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import io.ktor.client.engine.darwin.Darwin
-import kotlinx.serialization.ExperimentalSerializationApi
-import kotlinx.serialization.json.Json
import me.tatarka.inject.annotations.Provides
actual interface TmdbPlatformComponent {
- @OptIn(ExperimentalSerializationApi::class)
- @ApplicationScope
- @Provides
- fun provideTmdbJson(): TmdbJson = Json {
- isLenient = true
- ignoreUnknownKeys = true
- useAlternativeNames = false
- explicitNulls = false
- }
-
@ApplicationScope
@Provides
fun provideTmdbHttpClientEngine(): TmdbHttpClientEngine = Darwin.create()
-
- @ApplicationScope
- @Provides
- fun provideTmdbHttpClient(
- configs: Configs,
- json: TmdbJson,
- httpClientEngine: TmdbHttpClientEngine,
- ): TmdbHttpClient = tmdbHttpClient(
- json = json,
- httpClientEngine = httpClientEngine,
- tmdbApiKey = configs.tmdbApiKey,
- )
-
- @Provides
- fun provideTmdbService(bind: TmdbNetworkDataSourceImpl): TmdbNetworkDataSource = bind
}
diff --git a/core/trakt-api/api/build.gradle.kts b/core/trakt-api/api/build.gradle.kts
index 60fcd9da5..90d336850 100644
--- a/core/trakt-api/api/build.gradle.kts
+++ b/core/trakt-api/api/build.gradle.kts
@@ -7,7 +7,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
- api(projects.core.networkutil)
+ api(projects.core.util)
implementation(libs.ktor.serialization)
}
}
diff --git a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktListRemoteDataSource.kt b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktListRemoteDataSource.kt
index 417b15265..b431f73b3 100644
--- a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktListRemoteDataSource.kt
+++ b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktListRemoteDataSource.kt
@@ -1,6 +1,5 @@
package com.thomaskioko.tvmaniac.trakt.api
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktAddRemoveShowFromListResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktAddShowToListResponse
@@ -8,6 +7,7 @@ import com.thomaskioko.tvmaniac.trakt.api.model.TraktCreateListResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktFollowedShowResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktPersonalListsResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktUserResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
interface TraktListRemoteDataSource {
diff --git a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktShowsRemoteDataSource.kt b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktShowsRemoteDataSource.kt
index 07a9350da..b74d073a4 100644
--- a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktShowsRemoteDataSource.kt
+++ b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktShowsRemoteDataSource.kt
@@ -1,11 +1,11 @@
package com.thomaskioko.tvmaniac.trakt.api
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonEpisodesResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonsResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowsResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
private const val DEFAULT_API_PAGE: Long = 1
private const val FETCH_PERIOD: String = "daily"
diff --git a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktStatsRemoteDataSource.kt b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktStatsRemoteDataSource.kt
index b58628730..3287ac69d 100644
--- a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktStatsRemoteDataSource.kt
+++ b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktStatsRemoteDataSource.kt
@@ -1,8 +1,8 @@
package com.thomaskioko.tvmaniac.trakt.api
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktUserStatsResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
interface TraktStatsRemoteDataSource {
diff --git a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktUserRemoteDataSource.kt b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktUserRemoteDataSource.kt
index 60702f1c6..bab0c6b76 100644
--- a/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktUserRemoteDataSource.kt
+++ b/core/trakt-api/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/api/TraktUserRemoteDataSource.kt
@@ -1,9 +1,9 @@
package com.thomaskioko.tvmaniac.trakt.api
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktPersonalListsResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktUserResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
interface TraktUserRemoteDataSource {
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 6a96376fa..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
@@ -2,8 +2,8 @@ package com.thomaskioko.trakt.service.implementation
import com.thomaskioko.trakt.service.implementation.inject.TraktHttpClientEngine
import com.thomaskioko.trakt.service.implementation.inject.TraktJson
-import com.thomaskioko.tvmaniac.core.networkutil.HttpExceptions
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.HttpExceptions
import io.ktor.client.HttpClient
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.HttpResponseValidator
@@ -83,11 +83,11 @@ fun traktHttpClient(
}
install(Logging) {
- level = LogLevel.BODY
+ level = LogLevel.INFO
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/TraktListRemoteDataSourceImpl.kt b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktListRemoteDataSourceImpl.kt
index d9db22d63..28294203f 100644
--- a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktListRemoteDataSourceImpl.kt
+++ b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktListRemoteDataSourceImpl.kt
@@ -1,8 +1,6 @@
package com.thomaskioko.trakt.service.implementation
import com.thomaskioko.trakt.service.implementation.inject.TraktHttpClient
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.safeRequest
import com.thomaskioko.tvmaniac.trakt.api.TraktListRemoteDataSource
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktAddRemoveShowFromListResponse
@@ -15,6 +13,8 @@ import com.thomaskioko.tvmaniac.trakt.api.model.TraktPersonalListsResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShow
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowIds
import com.thomaskioko.tvmaniac.trakt.api.model.TraktUserResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
+import com.thomaskioko.tvmaniac.util.model.safeRequest
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.parameter
diff --git a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktShowsShowsRemoteDataSourceImpl.kt b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktShowsShowsRemoteDataSourceImpl.kt
index 9399a7e93..02ea930c9 100644
--- a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktShowsShowsRemoteDataSourceImpl.kt
+++ b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktShowsShowsRemoteDataSourceImpl.kt
@@ -1,14 +1,14 @@
package com.thomaskioko.trakt.service.implementation
import com.thomaskioko.trakt.service.implementation.inject.TraktHttpClient
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.safeRequest
import com.thomaskioko.tvmaniac.trakt.api.TraktShowsRemoteDataSource
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonEpisodesResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonsResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowsResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
+import com.thomaskioko.tvmaniac.util.model.safeRequest
import io.ktor.client.request.parameter
import io.ktor.http.HttpMethod
import io.ktor.http.path
diff --git a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktStatsRemoteDataSourceImpl.kt b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktStatsRemoteDataSourceImpl.kt
index c4c2572ac..e648e5777 100644
--- a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktStatsRemoteDataSourceImpl.kt
+++ b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktStatsRemoteDataSourceImpl.kt
@@ -1,11 +1,11 @@
package com.thomaskioko.trakt.service.implementation
import com.thomaskioko.trakt.service.implementation.inject.TraktHttpClient
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.safeRequest
import com.thomaskioko.tvmaniac.trakt.api.TraktStatsRemoteDataSource
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktUserStatsResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
+import com.thomaskioko.tvmaniac.util.model.safeRequest
import io.ktor.http.HttpMethod
import io.ktor.http.path
import me.tatarka.inject.annotations.Inject
diff --git a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktUserRemoteDataSourceImpl.kt b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktUserRemoteDataSourceImpl.kt
index 6b33c77f9..7e04c468e 100644
--- a/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktUserRemoteDataSourceImpl.kt
+++ b/core/trakt-api/implementation/src/commonMain/kotlin/com/thomaskioko/trakt/service/implementation/TraktUserRemoteDataSourceImpl.kt
@@ -1,12 +1,12 @@
package com.thomaskioko.trakt.service.implementation
import com.thomaskioko.trakt.service.implementation.inject.TraktHttpClient
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.safeRequest
import com.thomaskioko.tvmaniac.trakt.api.TraktUserRemoteDataSource
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktPersonalListsResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktUserResponse
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
+import com.thomaskioko.tvmaniac.util.model.safeRequest
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.parameter
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/core/networkutil/src/androidMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/AndroidNetworkExceptionHandlerUtil.kt b/core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/AndroidNetworkExceptionHandlerUtil.kt
similarity index 95%
rename from core/networkutil/src/androidMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/AndroidNetworkExceptionHandlerUtil.kt
rename to core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/AndroidNetworkExceptionHandlerUtil.kt
index 728098381..f99b2d385 100644
--- a/core/networkutil/src/androidMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/AndroidNetworkExceptionHandlerUtil.kt
+++ b/core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/AndroidNetworkExceptionHandlerUtil.kt
@@ -1,4 +1,4 @@
-package com.thomaskioko.tvmaniac.core.networkutil
+package com.thomaskioko.tvmaniac.util
import com.thomaskioko.tvmaniac.util.model.Configs
import io.ktor.client.call.NoTransformationFoundException
diff --git a/core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt b/core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt
index 9d16508c7..64a944220 100644
--- a/core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt
+++ b/core/util/src/androidMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt
@@ -3,10 +3,12 @@ package com.thomaskioko.tvmaniac.util.inject
import com.thomaskioko.tvmaniac.util.AndroidAppUtils
import com.thomaskioko.tvmaniac.util.AndroidDateUtil
import com.thomaskioko.tvmaniac.util.AndroidFormatterUtil
+import com.thomaskioko.tvmaniac.util.AndroidNetworkExceptionHandlerUtil
import com.thomaskioko.tvmaniac.util.AppUtils
import com.thomaskioko.tvmaniac.util.ClasspathResourceReader
import com.thomaskioko.tvmaniac.util.DateFormatter
import com.thomaskioko.tvmaniac.util.FormatterUtil
+import com.thomaskioko.tvmaniac.util.NetworkExceptionHandler
import com.thomaskioko.tvmaniac.util.ResourceReader
import com.thomaskioko.tvmaniac.util.YamlResourceReader
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
@@ -59,4 +61,10 @@ actual interface UtilPlatformComponent {
@ApplicationScope
@Provides
fun provideResourceReader(bind: ClasspathResourceReader): ResourceReader = bind
+
+ @ApplicationScope
+ @Provides
+ fun provideNetworkExceptionHandler(
+ bind: AndroidNetworkExceptionHandlerUtil,
+ ): NetworkExceptionHandler = bind
}
diff --git a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/NetworkExceptionHandler.kt b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/NetworkExceptionHandler.kt
similarity index 64%
rename from core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/NetworkExceptionHandler.kt
rename to core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/NetworkExceptionHandler.kt
index 759880a89..f587c0e83 100644
--- a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/NetworkExceptionHandler.kt
+++ b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/NetworkExceptionHandler.kt
@@ -1,4 +1,4 @@
-package com.thomaskioko.tvmaniac.core.networkutil
+package com.thomaskioko.tvmaniac.util
interface NetworkExceptionHandler {
diff --git a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/ApiResponse.kt b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/ApiResponse.kt
similarity index 98%
rename from core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/ApiResponse.kt
rename to core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/ApiResponse.kt
index 1491d65bb..b547ecb9f 100644
--- a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/ApiResponse.kt
+++ b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/ApiResponse.kt
@@ -1,4 +1,4 @@
-package com.thomaskioko.tvmaniac.core.networkutil
+package com.thomaskioko.tvmaniac.util.model
import io.ktor.client.HttpClient
import io.ktor.client.call.body
diff --git a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/Either.kt b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/Either.kt
similarity index 53%
rename from core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/Either.kt
rename to core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/Either.kt
index d03480de2..9f89dc382 100644
--- a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/Either.kt
+++ b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/Either.kt
@@ -1,13 +1,16 @@
-package com.thomaskioko.tvmaniac.core.networkutil
+package com.thomaskioko.tvmaniac.util.model
sealed class Either {
data class Left(val error: L) : Either()
- data class Right(val data: R?) : Either()
+ data class Right(val data: R) : Either()
fun fold(lfn: (L) -> T, rfn: (R?) -> T): T = when (this) {
is Left -> lfn(error)
is Right -> rfn(data)
}
+
+ fun getOrNull(): R? = (this as? Right)?.data
+ fun getErrorOrNull(): L? = (this as? Left)?.error
}
diff --git a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/Failure.kt b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/Failure.kt
similarity index 55%
rename from core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/Failure.kt
rename to core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/Failure.kt
index 443bb8f4e..417ece0c4 100644
--- a/core/networkutil/src/commonMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/Failure.kt
+++ b/core/util/src/commonMain/kotlin/com/thomaskioko/tvmaniac/util/model/Failure.kt
@@ -1,4 +1,4 @@
-package com.thomaskioko.tvmaniac.core.networkutil
+package com.thomaskioko.tvmaniac.util.model
sealed class Failure(
val throwable: Throwable,
@@ -9,3 +9,8 @@ class DefaultError(val message: String?) : Failure(
throwable = Throwable(message),
errorMessage = message,
)
+
+data class ServerError(val message: String?) : Failure(
+ throwable = Throwable(message),
+ errorMessage = message,
+)
diff --git a/core/networkutil/src/iosMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/IosExceptionHandler.kt b/core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/IosExceptionHandler.kt
similarity index 95%
rename from core/networkutil/src/iosMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/IosExceptionHandler.kt
rename to core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/IosExceptionHandler.kt
index 647edda45..425a07614 100644
--- a/core/networkutil/src/iosMain/kotlin/com/thomaskioko/tvmaniac/core/networkutil/IosExceptionHandler.kt
+++ b/core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/IosExceptionHandler.kt
@@ -1,4 +1,4 @@
-package com.thomaskioko.tvmaniac.core.networkutil
+package com.thomaskioko.tvmaniac.util
import com.thomaskioko.tvmaniac.util.model.Configs
import io.ktor.client.call.NoTransformationFoundException
diff --git a/core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt b/core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt
index 9e04184c4..31f02ef7c 100644
--- a/core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt
+++ b/core/util/src/iosMain/kotlin/com/thomaskioko/tvmaniac/util/inject/UtilPlatformComponent.kt
@@ -7,7 +7,9 @@ import com.thomaskioko.tvmaniac.util.DateFormatter
import com.thomaskioko.tvmaniac.util.FormatterUtil
import com.thomaskioko.tvmaniac.util.IosAppUtils
import com.thomaskioko.tvmaniac.util.IosDateFormatter
+import com.thomaskioko.tvmaniac.util.IosExceptionHandler
import com.thomaskioko.tvmaniac.util.IosFormatterUtil
+import com.thomaskioko.tvmaniac.util.NetworkExceptionHandler
import com.thomaskioko.tvmaniac.util.ResourceReader
import com.thomaskioko.tvmaniac.util.YamlResourceReader
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
@@ -66,4 +68,8 @@ actual interface UtilPlatformComponent {
@ApplicationScope
@Provides
fun provideResourceReader(bind: BundleResourceReader): ResourceReader = bind
+
+ @ApplicationScope
+ @Provides
+ fun provideExceptionHandler(bind: IosExceptionHandler): NetworkExceptionHandler = bind
}
diff --git a/data/category/api/build.gradle.kts b/data/category/api/build.gradle.kts
index 2425bebf1..52cbdb79f 100644
--- a/data/category/api/build.gradle.kts
+++ b/data/category/api/build.gradle.kts
@@ -9,7 +9,7 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
+ api(projects.core.util)
implementation(projects.core.tmdbApi.api)
api(libs.coroutines.core)
diff --git a/data/category/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/category/api/cache/CategoryCache.kt b/data/category/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/category/api/cache/CategoryCache.kt
index d4a34253d..845e783ee 100644
--- a/data/category/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/category/api/cache/CategoryCache.kt
+++ b/data/category/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/category/api/cache/CategoryCache.kt
@@ -3,6 +3,6 @@ package com.thomaskioko.tvmaniac.category.api.cache
import com.thomaskioko.tvmaniac.core.db.Show_category
interface CategoryCache {
- fun insert(category: Show_category)
- fun insert(category: List)
+ fun upsert(category: Show_category)
+ fun upsert(category: List)
}
diff --git a/data/category/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/data/category/implementation/CategoryCacheImpl.kt b/data/category/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/data/category/implementation/CategoryCacheImpl.kt
index f7efa87b8..aea103b44 100644
--- a/data/category/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/data/category/implementation/CategoryCacheImpl.kt
+++ b/data/category/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/data/category/implementation/CategoryCacheImpl.kt
@@ -12,16 +12,16 @@ class CategoryCacheImpl(
private val showCategoryQuery get() = database.show_categoryQueries
- override fun insert(category: Show_category) {
+ override fun upsert(category: Show_category) {
database.transaction {
showCategoryQuery.insertOrReplace(
- trakt_id = category.trakt_id,
+ id = category.id,
category_id = category.category_id,
)
}
}
- override fun insert(category: List) {
- category.forEach { insert(it) }
+ override fun upsert(category: List) {
+ category.forEach { upsert(it) }
}
}
diff --git a/data/episodeimages/api/build.gradle.kts b/data/episodeimages/api/build.gradle.kts
index 5dd2099de..adc8836f5 100644
--- a/data/episodeimages/api/build.gradle.kts
+++ b/data/episodeimages/api/build.gradle.kts
@@ -7,7 +7,7 @@ kotlin {
commonMain {
dependencies {
api(projects.core.util)
- api(projects.core.networkutil)
+ api(projects.core.util)
api(projects.core.database)
api(libs.coroutines.core)
diff --git a/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageDao.kt b/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageDao.kt
index c74f48296..89cae219b 100644
--- a/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageDao.kt
+++ b/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageDao.kt
@@ -6,9 +6,15 @@ import kotlinx.coroutines.flow.Flow
interface EpisodeImageDao {
- fun insert(entity: Episode_image)
+ fun upsert(entity: Episode_image)
- fun insert(list: List)
+ fun upsert(list: List)
- fun observeEpisodeImage(): Flow>
+ fun observeEpisodeImage(showId: Long): Flow>
+
+ fun getEpisodeImage(showId: Long): List
+
+ fun delete(id: Long)
+
+ fun deleteAll()
}
diff --git a/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageRepository.kt b/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageRepository.kt
index 8d0ec4222..886c3e657 100644
--- a/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageRepository.kt
+++ b/data/episodeimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/api/EpisodeImageRepository.kt
@@ -1,10 +1,10 @@
package com.thomaskioko.tvmaniac.episodeimages.api
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
interface EpisodeImageRepository {
- fun updateEpisodeImage(): Flow>
+ fun updateEpisodeImage(traktId: Long): Flow>
}
diff --git a/data/episodeimages/implementation/build.gradle.kts b/data/episodeimages/implementation/build.gradle.kts
index ddb8a4baf..7dac36ace 100644
--- a/data/episodeimages/implementation/build.gradle.kts
+++ b/data/episodeimages/implementation/build.gradle.kts
@@ -10,9 +10,12 @@ kotlin {
dependencies {
implementation(projects.core.tmdbApi.api)
implementation(projects.data.episodeimages.api)
+ implementation(projects.data.requestManager.api)
implementation(libs.kotlinInject.runtime)
+ implementation(libs.kotlinx.atomicfu)
implementation(libs.sqldelight.extensions)
+ implementation(libs.store5)
}
}
diff --git a/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageDaoImpl.kt b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageDaoImpl.kt
index ab8fbd80e..13b3dd320 100644
--- a/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageDaoImpl.kt
+++ b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageDaoImpl.kt
@@ -5,6 +5,7 @@ import app.cash.sqldelight.coroutines.mapToList
import com.thomaskioko.tvmaniac.core.db.EpisodeImage
import com.thomaskioko.tvmaniac.core.db.Episode_image
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageDao
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
import kotlinx.coroutines.flow.Flow
@@ -18,22 +19,34 @@ class EpisodeImageDaoImpl(
private val episodeQueries get() = database.episode_imageQueries
- override fun insert(entity: Episode_image) {
+ override fun upsert(list: List) {
+ database.transaction {
+ list.forEach { upsert(it) }
+ }
+ }
+
+ override fun upsert(entity: Episode_image) {
episodeQueries.insertOrReplace(
- trakt_id = entity.trakt_id,
+ id = entity.id,
tmdb_id = entity.tmdb_id,
image_url = entity.image_url,
)
}
- override fun insert(list: List) {
- database.transaction {
- list.map { insert(it) }
- }
- }
-
- override fun observeEpisodeImage(): Flow> =
- episodeQueries.episodeImage()
+ override fun observeEpisodeImage(showId: Long): Flow> =
+ episodeQueries.episodeImage(Id(showId))
.asFlow()
.mapToList(dispatchers.io)
+
+ override fun getEpisodeImage(showId: Long): List =
+ episodeQueries.episodeImage(Id(showId))
+ .executeAsList()
+
+ override fun delete(id: Long) {
+ episodeQueries.delete(Id(id))
+ }
+
+ override fun deleteAll() {
+ episodeQueries.deleteAll()
+ }
}
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 94ee1a533..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,62 +1,43 @@
package com.thomaskioko.tvmaniac.episodeimages.implementation
-import com.thomaskioko.tvmaniac.core.db.Episode_image
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.DefaultError
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
-import com.thomaskioko.tvmaniac.core.networkutil.NetworkExceptionHandler
import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageDao
import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageRepository
-import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
-import com.thomaskioko.tvmaniac.util.FormatterUtil
-import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
+import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
+import org.mobilenativefoundation.store.store5.StoreReadRequest
+import kotlin.time.Duration.Companion.hours
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class EpisodeImageRepositoryImpl(
- private val tmdbNetworkDataSource: TmdbNetworkDataSource,
+ private val dispatchers: AppCoroutineDispatchers,
+ private val requestManagerRepository: RequestManagerRepository,
+ private val store: EpisodeImageStore,
private val episodeImageDao: EpisodeImageDao,
- private val formatterUtil: FormatterUtil,
- private val logger: KermitLogger,
- private val exceptionHandler: NetworkExceptionHandler,
) : EpisodeImageRepository {
- override fun updateEpisodeImage(): Flow> =
- episodeImageDao.observeEpisodeImage()
- .map { episode ->
- episode.forEach { episodeArt ->
- episodeArt.tmdb_id?.let { tmdbId ->
- val response = tmdbNetworkDataSource.getEpisodeDetails(
- tmdbShow = tmdbId,
- ssnNumber = episodeArt.season_number!!,
- epNumber = episodeArt.episode_number.toLong(),
- )
-
- when (response) {
- is ApiResponse.Success -> {
- episodeImageDao.insert(
- Episode_image(
- trakt_id = episodeArt.trakt_id,
- tmdb_id = response.body.id.toLong(),
- image_url = response.body.imageUrl?.let {
- formatterUtil.formatTmdbPosterPath(it)
- },
- ),
- )
- }
-
- is ApiResponse.Error -> {
- logger.error("updateEpisodeArtWork", "$response")
- }
- }
- }
- }
-
- Either.Right(Unit)
+ override fun updateEpisodeImage(traktId: Long): Flow> =
+ episodeImageDao.observeEpisodeImage(traktId)
+ .flatMapLatest {
+ store.stream(
+ StoreReadRequest.cached(
+ key = traktId,
+ refresh = requestManagerRepository.isRequestExpired(
+ entityId = traktId,
+ requestType = "EPISODE_IMAGE",
+ threshold = 1.hours,
+ ),
+ ),
+ )
}
- .catch { Either.Left(DefaultError(exceptionHandler.resolveError(it))) }
+ .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
new file mode 100644
index 000000000..27c9fd74a
--- /dev/null
+++ b/data/episodeimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodeimages/implementation/EpisodeImageStore.kt
@@ -0,0 +1,93 @@
+package com.thomaskioko.tvmaniac.episodeimages.implementation
+
+import com.thomaskioko.tvmaniac.core.db.EpisodeImage
+import com.thomaskioko.tvmaniac.core.db.Episode_image
+import com.thomaskioko.tvmaniac.db.DatabaseTransactionRunner
+import com.thomaskioko.tvmaniac.db.Id
+import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageDao
+import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
+import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
+import com.thomaskioko.tvmaniac.util.FormatterUtil
+import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
+import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
+import me.tatarka.inject.annotations.Inject
+import org.mobilenativefoundation.store.store5.Fetcher
+import org.mobilenativefoundation.store.store5.SourceOfTruth
+import org.mobilenativefoundation.store.store5.Store
+import org.mobilenativefoundation.store.store5.StoreBuilder
+import org.mobilenativefoundation.store.store5.Validator
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+
+@Inject
+class EpisodeImageStore(
+ private val tmdbNetworkDataSource: TmdbNetworkDataSource,
+ private val episodeImageDao: EpisodeImageDao,
+ private val requestManagerRepository: RequestManagerRepository,
+ private val dbTransactionRunner: DatabaseTransactionRunner,
+ private val formatterUtil: FormatterUtil,
+ private val logger: KermitLogger,
+ 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 ->
+ val apiResponse = tmdbNetworkDataSource.getEpisodeDetails(
+ tmdbShow = episodeArt.tmdb_id!!,
+ ssnNumber = episodeArt.season_number!!,
+ epNumber = episodeArt.episode_number.toLong(),
+ )
+
+ when (apiResponse) {
+ is ApiResponse.Success -> {
+ Episode_image(
+ id = Id(id = episodeArt.id.id),
+ tmdb_id = Id(id = episodeArt.tmdb_id!!),
+ image_url = apiResponse.body.imageUrl?.let {
+ formatterUtil.formatTmdbPosterPath(it)
+ },
+ )
+ }
+
+ is ApiResponse.Error -> {
+ logger.error("EpisodeImageStore", "$apiResponse")
+ throw Throwable("$apiResponse")
+ }
+ }
+ }
+ },
+ sourceOfTruth = SourceOfTruth.of(
+ reader = { id -> episodeImageDao.observeEpisodeImage(id) },
+ writer = { _, imageList ->
+ dbTransactionRunner {
+ episodeImageDao.upsert(imageList)
+ }
+ },
+ delete = episodeImageDao::delete,
+ deleteAll = { dbTransactionRunner(episodeImageDao::deleteAll) },
+ ),
+).validator(
+ Validator.by { result ->
+ if (result.isNotEmpty()) {
+ requestManagerRepository.isRequestExpired(
+ entityId = result.first().tmdb_id!!,
+ requestType = "EPISODE_IMAGE",
+ threshold = 180.days,
+ )
+ } else {
+ result.firstOrNull()?.tmdb_id?.let {
+ requestManagerRepository.isRequestExpired(
+ entityId = it,
+ requestType = "EPISODE_IMAGE",
+ threshold = 1.hours,
+ )
+ } ?: run {
+ true
+ }
+ }
+ },
+)
+ .scope(scope.io)
+ .build()
diff --git a/data/episodeimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/testing/FakeEpisodeImageRepository.kt b/data/episodeimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/testing/FakeEpisodeImageRepository.kt
index b80927a73..84cbebc38 100644
--- a/data/episodeimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/testing/FakeEpisodeImageRepository.kt
+++ b/data/episodeimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/testing/FakeEpisodeImageRepository.kt
@@ -1,12 +1,14 @@
package com.thomaskioko.tvmaniac.episodes.testing
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
import com.thomaskioko.tvmaniac.episodeimages.api.EpisodeImageRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
class FakeEpisodeImageRepository : EpisodeImageRepository {
- override fun updateEpisodeImage(): Flow> = flowOf(Either.Right(Unit))
+ override fun updateEpisodeImage(
+ traktId: Long,
+ ): Flow> = flowOf(Either.Right(Unit))
}
diff --git a/data/episodes/api/build.gradle.kts b/data/episodes/api/build.gradle.kts
index 5dd2099de..862106859 100644
--- a/data/episodes/api/build.gradle.kts
+++ b/data/episodes/api/build.gradle.kts
@@ -7,7 +7,6 @@ kotlin {
commonMain {
dependencies {
api(projects.core.util)
- api(projects.core.networkutil)
api(projects.core.database)
api(libs.coroutines.core)
diff --git a/data/episodes/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/api/EpisodesDao.kt b/data/episodes/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/api/EpisodesDao.kt
index ab85ff44c..56f0aac79 100644
--- a/data/episodes/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/api/EpisodesDao.kt
+++ b/data/episodes/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/api/EpisodesDao.kt
@@ -1,6 +1,6 @@
package com.thomaskioko.tvmaniac.episodes.api
-import com.thomaskioko.tvmaniac.core.db.Episodes as EpisodeCache
+import com.thomaskioko.tvmaniac.core.db.Episode as EpisodeCache
interface EpisodesDao {
diff --git a/data/episodes/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/implementation/EpisodesDaoImpl.kt b/data/episodes/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/implementation/EpisodesDaoImpl.kt
index e8e5e3f66..19848fdf0 100644
--- a/data/episodes/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/implementation/EpisodesDaoImpl.kt
+++ b/data/episodes/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/episodes/implementation/EpisodesDaoImpl.kt
@@ -1,9 +1,10 @@
package com.thomaskioko.tvmaniac.episodes.implementation
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.episodes.api.EpisodesDao
import me.tatarka.inject.annotations.Inject
-import com.thomaskioko.tvmaniac.core.db.Episodes as EpisodeCache
+import com.thomaskioko.tvmaniac.core.db.Episode as EpisodeCache
@Inject
class EpisodesDaoImpl(
@@ -15,7 +16,7 @@ class EpisodesDaoImpl(
override fun insert(entity: EpisodeCache) {
database.transaction {
episodeQueries.insertOrReplace(
- trakt_id = entity.trakt_id,
+ id = entity.id,
season_id = entity.season_id,
tmdb_id = entity.tmdb_id,
title = entity.title,
@@ -33,7 +34,7 @@ class EpisodesDaoImpl(
}
override fun delete(id: Long) {
- episodeQueries.delete(id)
+ episodeQueries.delete(Id(id))
}
override fun deleteAll() {
diff --git a/data/profile/api/build.gradle.kts b/data/profile/api/build.gradle.kts
index 978bdc459..30e94f05c 100644
--- a/data/profile/api/build.gradle.kts
+++ b/data/profile/api/build.gradle.kts
@@ -7,12 +7,9 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
api(projects.core.util)
api(libs.coroutines.core)
- api(libs.kotlinx.atomicfu)
- api(libs.store5)
}
}
}
diff --git a/data/profile/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/api/ProfileRepository.kt b/data/profile/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/api/ProfileRepository.kt
index b385f9fe1..fe67ad32a 100644
--- a/data/profile/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/api/ProfileRepository.kt
+++ b/data/profile/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/api/ProfileRepository.kt
@@ -1,10 +1,11 @@
package com.thomaskioko.tvmaniac.profile.api
import com.thomaskioko.tvmaniac.core.db.User
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
-import org.mobilenativefoundation.store.store5.StoreReadResponse
interface ProfileRepository {
- fun observeProfile(slug: String): Flow>
+ fun observeProfile(slug: String): Flow>
suspend fun clearProfile()
}
diff --git a/data/profile/implementation/build.gradle.kts b/data/profile/implementation/build.gradle.kts
index bb0cf83f7..3993d1ef3 100644
--- a/data/profile/implementation/build.gradle.kts
+++ b/data/profile/implementation/build.gradle.kts
@@ -14,6 +14,8 @@ kotlin {
implementation(libs.kotlinInject.runtime)
implementation(libs.sqldelight.extensions)
+ implementation(libs.kotlinx.atomicfu)
+ implementation(libs.store5)
}
}
}
diff --git a/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileRepositoryImpl.kt b/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileRepositoryImpl.kt
index 12b7122e0..9c61f157b 100644
--- a/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileRepositoryImpl.kt
+++ b/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileRepositoryImpl.kt
@@ -4,7 +4,14 @@ import com.thomaskioko.tvmaniac.core.db.User
import com.thomaskioko.tvmaniac.profile.api.ProfileRepository
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.ExperimentalStoreApi
@@ -12,15 +19,15 @@ import org.mobilenativefoundation.store.store5.StoreReadRequest
import org.mobilenativefoundation.store.store5.StoreReadResponse
import kotlin.time.Duration.Companion.days
-@OptIn(ExperimentalStoreApi::class)
+@OptIn(ExperimentalStoreApi::class, ExperimentalCoroutinesApi::class)
@Inject
-class ProfileRepositoryImpl constructor(
+class ProfileRepositoryImpl(
private val store: ProfileStore,
private val requestManagerRepository: RequestManagerRepository,
private val dispatchers: AppCoroutineDispatchers,
) : ProfileRepository {
- override fun observeProfile(slug: String): Flow> =
+ override fun observeProfile(slug: String): Flow> =
store.stream(
StoreReadRequest.cached(
key = slug,
@@ -31,9 +38,21 @@ class ProfileRepositoryImpl constructor(
),
),
)
- .flowOn(dispatchers.io)
+ .mapResult()
override suspend fun clearProfile() {
store.clear()
}
+
+ private fun Flow>.mapResult(): Flow> =
+ distinctUntilChanged()
+ .flatMapLatest {
+ val data = it.dataOrNull()
+ if (data != null) {
+ flowOf(Either.Right(data))
+ } else {
+ emptyFlow()
+ }
+ }
+ .flowOn(dispatchers.io)
}
diff --git a/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileStore.kt b/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileStore.kt
index 7e5948027..268965474 100644
--- a/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileStore.kt
+++ b/data/profile/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profile/implementation/ProfileStore.kt
@@ -1,12 +1,12 @@
package com.thomaskioko.tvmaniac.profile.implementation
import com.thomaskioko.tvmaniac.core.db.User
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.profile.api.ProfileDao
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.trakt.api.TraktUserRemoteDataSource
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
diff --git a/data/profile/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeProfileRepository.kt b/data/profile/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeProfileRepository.kt
index d27162001..b98a6e139 100644
--- a/data/profile/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeProfileRepository.kt
+++ b/data/profile/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeProfileRepository.kt
@@ -2,20 +2,21 @@ package com.thomaskioko.tvmaniac.trakt.profile.testing
import com.thomaskioko.tvmaniac.core.db.User
import com.thomaskioko.tvmaniac.profile.api.ProfileRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.receiveAsFlow
-import org.mobilenativefoundation.store.store5.StoreReadResponse
class FakeProfileRepository : ProfileRepository {
- private val userFlow: Channel> = Channel(Channel.UNLIMITED)
+ private val userFlow: Channel> = Channel(Channel.UNLIMITED)
- suspend fun setUserData(response: StoreReadResponse) {
+ suspend fun setUserData(response: Either) {
userFlow.send(response)
}
- override fun observeProfile(slug: String): Flow> =
+ override fun observeProfile(slug: String): Flow> =
userFlow.receiveAsFlow()
override suspend fun clearProfile() {
diff --git a/data/profilestats/api/build.gradle.kts b/data/profilestats/api/build.gradle.kts
index 978bdc459..30e94f05c 100644
--- a/data/profilestats/api/build.gradle.kts
+++ b/data/profilestats/api/build.gradle.kts
@@ -7,12 +7,9 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
api(projects.core.util)
api(libs.coroutines.core)
- api(libs.kotlinx.atomicfu)
- api(libs.store5)
}
}
}
diff --git a/data/profilestats/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/api/StatsRepository.kt b/data/profilestats/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/api/StatsRepository.kt
index 1f2cb32a2..f351705e7 100644
--- a/data/profilestats/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/api/StatsRepository.kt
+++ b/data/profilestats/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/api/StatsRepository.kt
@@ -1,9 +1,10 @@
package com.thomaskioko.tvmaniac.profilestats.api
import com.thomaskioko.tvmaniac.core.db.Stats
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
-import org.mobilenativefoundation.store.store5.StoreReadResponse
interface StatsRepository {
- fun observeStats(slug: String): Flow>
+ fun observeStats(slug: String): Flow>
}
diff --git a/data/profilestats/implementation/build.gradle.kts b/data/profilestats/implementation/build.gradle.kts
index 1f6a9d195..120f5b655 100644
--- a/data/profilestats/implementation/build.gradle.kts
+++ b/data/profilestats/implementation/build.gradle.kts
@@ -14,6 +14,8 @@ kotlin {
implementation(libs.kotlinInject.runtime)
implementation(libs.sqldelight.extensions)
+ implementation(libs.kotlinx.atomicfu)
+ implementation(libs.store5)
}
}
}
diff --git a/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsRepositoryImpl.kt b/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsRepositoryImpl.kt
index e67679454..c802465c2 100644
--- a/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsRepositoryImpl.kt
+++ b/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsRepositoryImpl.kt
@@ -4,13 +4,20 @@ import com.thomaskioko.tvmaniac.core.db.Stats
import com.thomaskioko.tvmaniac.profilestats.api.StatsRepository
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.StoreReadRequest
-import org.mobilenativefoundation.store.store5.StoreReadResponse
import kotlin.time.Duration.Companion.days
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class StatsRepositoryImpl(
private val store: StatsStore,
@@ -18,7 +25,7 @@ class StatsRepositoryImpl(
private val dispatchers: AppCoroutineDispatchers,
) : StatsRepository {
- override fun observeStats(slug: String): Flow> =
+ override fun observeStats(slug: String): Flow> =
store.stream(
StoreReadRequest.cached(
key = slug,
@@ -29,5 +36,14 @@ class StatsRepositoryImpl(
),
),
)
+ .distinctUntilChanged()
+ .flatMapLatest {
+ val data = it.dataOrNull()
+ if (data != null) {
+ flowOf(Either.Right(data))
+ } else {
+ emptyFlow()
+ }
+ }
.flowOn(dispatchers.io)
}
diff --git a/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsStore.kt b/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsStore.kt
index 59aeb69ae..4df803e1f 100644
--- a/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsStore.kt
+++ b/data/profilestats/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/profilestats/implementation/StatsStore.kt
@@ -1,12 +1,12 @@
package com.thomaskioko.tvmaniac.profilestats.implementation
import com.thomaskioko.tvmaniac.core.db.Stats
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.profilestats.api.StatsDao
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.trakt.api.TraktStatsRemoteDataSource
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
@@ -22,7 +22,7 @@ class StatsStore(
private val mapper: StatsMapper,
private val logger: KermitLogger,
private val scope: AppCoroutineScope,
-) : Store by storeBuilderFromFetcherAndSourceOfTruth(
+) : Store by storeBuilderFromFetcherAndSourceOfTruth(
fetcher = Fetcher.of { slug ->
when (val response = remoteDataSource.getStats(slug)) {
diff --git a/data/profilestats/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeStatsRepository.kt b/data/profilestats/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeStatsRepository.kt
index 4b03efbfb..c1e9404f3 100644
--- a/data/profilestats/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeStatsRepository.kt
+++ b/data/profilestats/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/trakt/profile/testing/FakeStatsRepository.kt
@@ -2,11 +2,12 @@ package com.thomaskioko.tvmaniac.trakt.profile.testing
import com.thomaskioko.tvmaniac.core.db.Stats
import com.thomaskioko.tvmaniac.profilestats.api.StatsRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
-import org.mobilenativefoundation.store.store5.StoreReadResponse
class FakeStatsRepository : StatsRepository {
- override fun observeStats(slug: String): Flow> =
+ override fun observeStats(slug: String): Flow> =
flowOf()
}
diff --git a/data/seasondetails/api/build.gradle.kts b/data/seasondetails/api/build.gradle.kts
index 3702698fc..30e94f05c 100644
--- a/data/seasondetails/api/build.gradle.kts
+++ b/data/seasondetails/api/build.gradle.kts
@@ -7,11 +7,9 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
+ api(projects.core.util)
api(libs.coroutines.core)
- api(libs.kotlinx.atomicfu)
- api(libs.store5)
}
}
}
diff --git a/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsDao.kt b/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsDao.kt
deleted file mode 100644
index 886107d9d..000000000
--- a/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsDao.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.thomaskioko.tvmaniac.seasondetails.api
-
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.db.Season_episodes
-import kotlinx.coroutines.flow.Flow
-
-interface SeasonDetailsDao {
-
- fun insert(entity: Season_episodes)
-
- fun observeShowEpisodes(showId: Long): Flow>
-
- fun delete(id: Long)
-
- fun deleteAll()
-}
diff --git a/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsRepository.kt b/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsRepository.kt
index 2d8e9b530..be291958e 100644
--- a/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsRepository.kt
+++ b/data/seasondetails/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/api/SeasonDetailsRepository.kt
@@ -1,13 +1,13 @@
package com.thomaskioko.tvmaniac.seasondetails.api
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
+import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
interface SeasonDetailsRepository {
- fun observeSeasonDetailsStream(traktId: Long): Flow>>
+ suspend fun fetchSeasonDetails(traktId: Long): List
- fun observeSeasonDetails(traktId: Long): Flow>>
+ fun observeSeasonDetailsStream(traktId: Long): Flow>>
}
diff --git a/data/seasondetails/implementation/build.gradle.kts b/data/seasondetails/implementation/build.gradle.kts
index 742fe3df8..af1dc42e1 100644
--- a/data/seasondetails/implementation/build.gradle.kts
+++ b/data/seasondetails/implementation/build.gradle.kts
@@ -13,12 +13,14 @@ kotlin {
implementation(projects.core.traktApi.api)
implementation(projects.core.util)
implementation(projects.data.episodes.api)
- implementation(projects.data.seasons.api)
+ implementation(projects.data.requestManager.api)
implementation(projects.data.seasondetails.api)
+ implementation(projects.data.seasons.api)
implementation(libs.kotlinInject.runtime)
+ implementation(libs.kotlinx.atomicfu)
implementation(libs.sqldelight.extensions)
-
+ implementation(libs.store5)
}
}
diff --git a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/Mapper.kt b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/Mapper.kt
index 33d7aa01f..9595a6c9b 100644
--- a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/Mapper.kt
+++ b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/Mapper.kt
@@ -1,31 +1,27 @@
package com.thomaskioko.tvmaniac.seasondetails.implementation
-import com.thomaskioko.tvmaniac.core.db.Episodes
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.trakt.api.model.TraktEpisodesResponse
+import com.thomaskioko.tvmaniac.core.db.Episode
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonEpisodesResponse
-fun TraktSeasonEpisodesResponse.toEpisodeCacheList(): List {
- return episodes.map { episodeResponse ->
- Episodes(
- season_id = ids.trakt.toLong(),
- trakt_id = episodeResponse.ids.trakt.toLong(),
- tmdb_id = episodeResponse.ids.tmdb?.toLong(),
- title = episodeResponse.title,
- overview = episodeResponse.overview ?: "TBA",
- ratings = episodeResponse.ratings,
- runtime = episodeResponse.runtime.toLong(),
- votes = episodeResponse.votes.toLong(),
- episode_number = episodeResponse.episodeNumber.toString().padStart(2, '0'),
+internal fun List.toSeasonWithEpisodes(): List {
+ return map { season ->
+ SeasonData(
+ seasonId = season.ids.trakt.toLong(),
+ title = season.title,
+ overview = season.overview ?: "TBA",
+ episodeCount = season.episodeCount.toLong(),
+ seasonNumber = season.number.toLong(),
+ episodes = season.toEpisodeCacheList(),
)
}
}
-fun List.toEpisodeCache(seasonId: Long): List {
- return map { episodeResponse ->
- Episodes(
- season_id = seasonId,
- trakt_id = episodeResponse.ids.trakt.toLong(),
+fun TraktSeasonEpisodesResponse.toEpisodeCacheList(): List {
+ return episodes.map { episodeResponse ->
+ Episode(
+ id = Id(episodeResponse.ids.trakt.toLong()),
+ season_id = Id(ids.trakt.toLong()),
tmdb_id = episodeResponse.ids.tmdb?.toLong(),
title = episodeResponse.title,
overview = episodeResponse.overview ?: "TBA",
@@ -37,7 +33,11 @@ fun List.toEpisodeCache(seasonId: Long): List {
}
}
-fun List.toSeasonWithEpisodes(): List {
- // TODO:: Add mapping #59
- return emptyList()
-}
+internal data class SeasonData(
+ val seasonId: Long,
+ val title: String,
+ val overview: String,
+ val seasonNumber: Long,
+ val episodeCount: Long,
+ val episodes: List,
+)
diff --git a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsComponent.kt b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsComponent.kt
index 491235e1b..d5568bbbf 100644
--- a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsComponent.kt
+++ b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsComponent.kt
@@ -1,6 +1,5 @@
package com.thomaskioko.tvmaniac.seasondetails.implementation
-import com.thomaskioko.tvmaniac.seasondetails.api.SeasonDetailsDao
import com.thomaskioko.tvmaniac.seasondetails.api.SeasonDetailsRepository
import com.thomaskioko.tvmaniac.util.scope.ApplicationScope
import me.tatarka.inject.annotations.Provides
@@ -12,8 +11,4 @@ interface SeasonDetailsComponent {
fun provideSeasonDetailsRepository(
bind: SeasonDetailsRepositoryImpl,
): SeasonDetailsRepository = bind
-
- @ApplicationScope
- @Provides
- fun provideSeasonsDetailsDao(bind: SeasonDetailsDaoImpl): SeasonDetailsDao = bind
}
diff --git a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsDaoImpl.kt b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsDaoImpl.kt
deleted file mode 100644
index ea10d5227..000000000
--- a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsDaoImpl.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.thomaskioko.tvmaniac.seasondetails.implementation
-
-import app.cash.sqldelight.coroutines.asFlow
-import app.cash.sqldelight.coroutines.mapToList
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.db.Season_episodes
-import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
-import com.thomaskioko.tvmaniac.seasondetails.api.SeasonDetailsDao
-import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
-import kotlinx.coroutines.flow.Flow
-import me.tatarka.inject.annotations.Inject
-
-@Inject
-class SeasonDetailsDaoImpl(
- private val database: TvManiacDatabase,
- private val dispatcher: AppCoroutineDispatchers,
-) : SeasonDetailsDao {
-
- override fun insert(entity: Season_episodes) {
- database.transaction {
- database.seasonEpisodesQueries.insertOrReplace(
- show_id = entity.show_id,
- season_id = entity.season_id,
- season_number = entity.season_number,
- )
- }
- }
-
- override fun observeShowEpisodes(showId: Long): Flow> =
- database.seasonEpisodesQueries.seasonWithEpisodes(showId)
- .asFlow()
- .mapToList(dispatcher.io)
-
- override fun delete(id: Long) {
- database.seasonEpisodesQueries.delete(id)
- }
-
- override fun deleteAll() {
- database.transaction {
- database.seasonEpisodesQueries.deleteAll()
- }
- }
-}
diff --git a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsRepositoryImpl.kt b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsRepositoryImpl.kt
index 5d3e3bec8..ff4590c11 100644
--- a/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsRepositoryImpl.kt
+++ b/data/seasondetails/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/implementation/SeasonDetailsRepositoryImpl.kt
@@ -1,84 +1,55 @@
package com.thomaskioko.tvmaniac.seasondetails.implementation
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.db.Season_episodes
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.DefaultError
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
-import com.thomaskioko.tvmaniac.core.networkutil.NetworkExceptionHandler
-import com.thomaskioko.tvmaniac.core.networkutil.networkBoundResult
-import com.thomaskioko.tvmaniac.episodes.api.EpisodesDao
-import com.thomaskioko.tvmaniac.seasondetails.api.SeasonDetailsDao
+import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
+import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.seasondetails.api.SeasonDetailsRepository
-import com.thomaskioko.tvmaniac.trakt.api.TraktShowsRemoteDataSource
-import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
-import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonEpisodesResponse
-import com.thomaskioko.tvmaniac.util.KermitLogger
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
+import org.mobilenativefoundation.store.store5.StoreReadRequest
+import org.mobilenativefoundation.store.store5.impl.extensions.get
+import kotlin.time.Duration.Companion.days
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class SeasonDetailsRepositoryImpl(
- private val remoteDataSource: TraktShowsRemoteDataSource,
- private val seasonCache: SeasonDetailsDao,
- private val episodesDao: EpisodesDao,
- private val exceptionHandler: NetworkExceptionHandler,
+ private val seasonDetailsStore: SeasonDetailsStore,
+ private val requestManagerRepository: RequestManagerRepository,
private val dispatcher: AppCoroutineDispatchers,
- private val logger: KermitLogger,
) : SeasonDetailsRepository {
- override fun observeSeasonDetailsStream(traktId: Long): Flow>> =
- networkBoundResult(
- query = { seasonCache.observeShowEpisodes(traktId) },
- shouldFetch = { it.isNullOrEmpty() },
- fetch = { remoteDataSource.getSeasonEpisodes(traktId) },
- saveFetchResult = { mapResponse(traktId, it) },
- exceptionHandler = exceptionHandler,
- coroutineDispatcher = dispatcher.io,
+ override fun observeSeasonDetailsStream(
+ traktId: Long,
+ ): Flow>> =
+ seasonDetailsStore.stream(
+ StoreReadRequest.cached(
+ key = traktId,
+ refresh = requestManagerRepository.isRequestExpired(
+ entityId = traktId,
+ requestType = "SEASON_DETAILS",
+ threshold = 3.days,
+ ),
+ ),
)
-
- override fun observeSeasonDetails(traktId: Long): Flow>> =
- seasonCache.observeShowEpisodes(traktId)
- .catch { Either.Left(DefaultError(exceptionHandler.resolveError(it))) }
- .map { Either.Right(it) }
-
- private fun mapResponse(
- showId: Long,
- response: ApiResponse, ErrorResponse>,
- ) {
- when (response) {
- is ApiResponse.Success -> {
- response.body.forEach { season ->
- episodesDao.insert(season.toEpisodeCacheList())
-
- seasonCache.insert(
- Season_episodes(
- show_id = showId,
- season_id = season.ids.trakt.toLong(),
- season_number = season.number.toLong(),
- ),
- )
+ .distinctUntilChanged()
+ .flatMapLatest {
+ val data = it.dataOrNull()
+ if (data != null) {
+ flowOf(Either.Right(data))
+ } else {
+ emptyFlow()
}
}
+ .flowOn(dispatcher.io)
- is ApiResponse.Error.GenericError -> {
- logger.error("observeSeasonDetails", "$response")
- throw Throwable("${response.errorMessage}")
- }
-
- is ApiResponse.Error.HttpError -> {
- logger.error("observeSeasonDetails", "$response")
- throw Throwable("${response.code} - ${response.errorMessage}")
- }
-
- is ApiResponse.Error.SerializationError -> {
- logger.error("observeSeasonDetails", "${response.errorMessage}")
- throw Throwable("${response.errorMessage}")
- }
- }
- }
+ override suspend fun fetchSeasonDetails(traktId: Long): List =
+ seasonDetailsStore.get(traktId)
}
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 cfdff1f1e..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
@@ -1,13 +1,14 @@
package com.thomaskioko.tvmaniac.seasondetails.implementation
-import com.thomaskioko.tvmaniac.core.db.Episodes
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.db.Season_episodes
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
+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.seasondetails.api.SeasonDetailsDao
+import com.thomaskioko.tvmaniac.seasons.api.SeasonsDao
import com.thomaskioko.tvmaniac.trakt.api.TraktShowsRemoteDataSource
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
@@ -18,12 +19,13 @@ import org.mobilenativefoundation.store.store5.StoreBuilder
@Inject
class SeasonDetailsStore(
private val remoteDataSource: TraktShowsRemoteDataSource,
- private val seasonDetailsDao: SeasonDetailsDao,
+ private val seasonCache: SeasonsDao,
private val episodesDao: EpisodesDao,
private val scope: AppCoroutineScope,
+ private val dbTransactionRunner: DbTransactionRunner,
private val logger: KermitLogger,
-) : Store> by StoreBuilder
- .from, List>(
+) : Store> by StoreBuilder
+ .from(
fetcher = Fetcher.of { id: Long ->
when (val response = remoteDataSource.getSeasonEpisodes(id)) {
is ApiResponse.Success -> response.body.toSeasonWithEpisodes()
@@ -44,34 +46,27 @@ class SeasonDetailsStore(
}
},
sourceOfTruth = SourceOfTruth.of(
- reader = seasonDetailsDao::observeShowEpisodes,
+ reader = seasonCache::observeSeasonEpisodeDetailsById,
writer = { id, list ->
- list.forEach { season ->
- episodesDao.insert(
- Episodes(
- trakt_id = season.trakt_id,
- season_id = season.season_id,
- title = season.title,
- tmdb_id = season.tmdb_id,
- overview = season.overview,
- ratings = season.ratings,
- runtime = season.runtime,
- votes = season.votes,
- episode_number = season.episode_number,
- ),
- )
+ 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,
+ ),
+ )
- seasonDetailsDao.insert(
- Season_episodes(
- show_id = id,
- season_id = season.trakt_id,
- season_number = season.season_number,
- ),
- )
+ episodesDao.insert(season.episodes)
+ }
}
},
- delete = seasonDetailsDao::delete,
- deleteAll = seasonDetailsDao::deleteAll,
+ delete = seasonCache::delete,
+ deleteAll = seasonCache::deleteAll,
),
)
.scope(scope.io)
diff --git a/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/FakeSeasonDetailsRepository.kt b/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/FakeSeasonDetailsRepository.kt
index c2f7a12fd..eba976381 100644
--- a/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/FakeSeasonDetailsRepository.kt
+++ b/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/FakeSeasonDetailsRepository.kt
@@ -1,33 +1,31 @@
package com.thomaskioko.tvmaniac.seasondetails.testing
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.db.Seasons
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
+import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
import com.thomaskioko.tvmaniac.seasondetails.api.SeasonDetailsRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
-import org.mobilenativefoundation.store.store5.StoreReadResponse
+import kotlinx.coroutines.flow.receiveAsFlow
class FakeSeasonDetailsRepository : SeasonDetailsRepository {
- private var seasonsResult = flowOf>>()
+ private val seasonsResult: Channel>> = Channel(Channel.UNLIMITED)
+ private val cachedResult: Channel> = Channel(Channel.UNLIMITED)
- private var seasonEpisodesResult = flowOf>>()
-
- suspend fun setSeasonsResult(result: StoreReadResponse>) {
- seasonsResult = flow { emit(result) }
+ suspend fun setSeasonsResult(result: Either>) {
+ seasonsResult.send(result)
}
- suspend fun setSeasonDetails(result: Either>) {
- seasonEpisodesResult = flow { emit(result) }
+ suspend fun setCachedResults(result: List) {
+ cachedResult.send(result)
}
- override fun observeSeasonDetails(traktId: Long): Flow>> =
- seasonEpisodesResult
+ override suspend fun fetchSeasonDetails(
+ traktId: Long,
+ ): List = cachedResult.receive()
override fun observeSeasonDetailsStream(
traktId: Long,
- ): Flow>> = seasonEpisodesResult
+ ): Flow>> = seasonsResult.receiveAsFlow()
}
diff --git a/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/MockData.kt b/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/MockData.kt
index f83ccbae7..a4b5c86a7 100644
--- a/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/MockData.kt
+++ b/data/seasondetails/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasondetails/testing/MockData.kt
@@ -1,24 +1,25 @@
package com.thomaskioko.tvmaniac.seasondetails.testing
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
+import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
+import com.thomaskioko.tvmaniac.db.Id
-val seasonDetails = listOf(
- SeasonWithEpisodes(
- trakt_id = 84958,
- tmdb_id = 849583,
- title = "Loki",
+val SeasonWithEpisodeList = listOf(
+ SeasonEpisodeDetailsById(
+ show_id = Id(84958),
+ season_id = Id(12343),
+ show_title = "Loki",
overview = "After stealing the Tesseract in Avengers: Endgame, Loki lands before the Time Variance Authority.",
runtime = 45,
- id = 12345,
- season_id = 12343,
season_number = 0,
- episode_count = 15,
- name = "Season 01",
- trakt_id_ = 12345,
- title_ = "Some title",
+ episode_count = 1,
+ season_title = "Season 01",
+ season_overview = "The journey to reunite the Ingham family continues as they travel to the USA.",
ratings = 4.5,
episode_number = "01",
votes = 4958,
- image_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
+ episode_image_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
+ episode_title = "Some title",
+ episode_season_id = Id(12345),
+ episode_id = Id(12345),
),
)
diff --git a/data/seasons/api/build.gradle.kts b/data/seasons/api/build.gradle.kts
index 3702698fc..30e94f05c 100644
--- a/data/seasons/api/build.gradle.kts
+++ b/data/seasons/api/build.gradle.kts
@@ -7,11 +7,9 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
+ api(projects.core.util)
api(libs.coroutines.core)
- api(libs.kotlinx.atomicfu)
- api(libs.store5)
}
}
}
diff --git a/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsDao.kt b/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsDao.kt
index b66e72782..58d129411 100644
--- a/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsDao.kt
+++ b/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsDao.kt
@@ -1,15 +1,21 @@
package com.thomaskioko.tvmaniac.seasons.api
-import com.thomaskioko.tvmaniac.core.db.Seasons
+import com.thomaskioko.tvmaniac.core.db.Season
+import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
+import com.thomaskioko.tvmaniac.core.db.SeasonsByShowId
import kotlinx.coroutines.flow.Flow
interface SeasonsDao {
- fun insertSeason(season: Seasons)
+ fun upsert(season: Season)
- fun insertSeasons(entityList: List)
+ fun upsert(entityList: List)
- fun observeSeasons(traktId: Long): Flow>
+ fun fetchSeasonDetails(traktId: Long): List
+
+ fun observeSeasonsByShowId(traktId: Long): Flow>
+
+ fun observeSeasonEpisodeDetailsById(showId: Long): Flow>
fun delete(id: Long)
diff --git a/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsRepository.kt b/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsRepository.kt
index ebeb06def..4224e76b1 100644
--- a/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsRepository.kt
+++ b/data/seasons/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/api/SeasonsRepository.kt
@@ -1,11 +1,12 @@
package com.thomaskioko.tvmaniac.seasons.api
-import com.thomaskioko.tvmaniac.core.db.Seasons
+import com.thomaskioko.tvmaniac.core.db.SeasonsByShowId
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
-import org.mobilenativefoundation.store.store5.StoreReadResponse
interface SeasonsRepository {
- suspend fun getSeasons(traktId: Long): List
- fun observeSeasonsStoreResponse(traktId: Long): Flow>>
+ suspend fun fetchSeasonsByShowId(traktId: Long): List
+ fun observeSeasonsByShowId(traktId: Long): Flow>>
}
diff --git a/data/seasons/implementation/build.gradle.kts b/data/seasons/implementation/build.gradle.kts
index 54722660a..27f02d9ec 100644
--- a/data/seasons/implementation/build.gradle.kts
+++ b/data/seasons/implementation/build.gradle.kts
@@ -19,7 +19,8 @@ kotlin {
implementation(libs.kotlinInject.runtime)
implementation(libs.sqldelight.extensions)
-
+ implementation(libs.kotlinx.atomicfu)
+ implementation(libs.store5)
}
}
diff --git a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/Mapper.kt b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/Mapper.kt
index 533d6d27d..21500488a 100644
--- a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/Mapper.kt
+++ b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/Mapper.kt
@@ -1,15 +1,16 @@
package com.thomaskioko.tvmaniac.seasons.implementation
-import com.thomaskioko.tvmaniac.core.db.Seasons
+import com.thomaskioko.tvmaniac.core.db.Season
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.trakt.api.model.TraktSeasonsResponse
-fun List.toSeasonCacheList(traktId: Long): List =
+fun List.toSeasonCacheList(traktId: Long): List =
map { seasonResponse ->
- Seasons(
- show_trakt_id = traktId,
- id = seasonResponse.ids.trakt.toLong(),
+ Season(
+ show_id = Id(traktId),
+ id = Id(id = seasonResponse.ids.trakt.toLong()),
season_number = seasonResponse.number.toLong(),
- name = seasonResponse.title,
+ title = seasonResponse.title,
overview = seasonResponse.overview,
episode_count = seasonResponse.episodeCount.toLong(),
)
diff --git a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsDaoImpl.kt b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsDaoImpl.kt
index 1e596acd3..0b344db0b 100644
--- a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsDaoImpl.kt
+++ b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsDaoImpl.kt
@@ -2,8 +2,11 @@ package com.thomaskioko.tvmaniac.seasons.implementation
import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
-import com.thomaskioko.tvmaniac.core.db.Seasons
+import com.thomaskioko.tvmaniac.core.db.Season
+import com.thomaskioko.tvmaniac.core.db.SeasonEpisodeDetailsById
+import com.thomaskioko.tvmaniac.core.db.SeasonsByShowId
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.seasons.api.SeasonsDao
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
import kotlinx.coroutines.flow.Flow
@@ -17,31 +20,40 @@ class SeasonsDaoImpl(
private val seasonQueries get() = database.seasonQueries
- override fun insertSeason(season: Seasons) {
+ override fun upsert(season: Season) {
database.transaction {
seasonQueries.insertOrReplace(
id = season.id,
- show_trakt_id = season.show_trakt_id,
+ show_id = season.show_id,
season_number = season.season_number,
episode_count = season.episode_count,
- name = season.name,
+ title = season.title,
overview = season.overview,
)
}
}
- override fun insertSeasons(entityList: List) {
- entityList.forEach { insertSeason(it) }
+ override fun upsert(entityList: List) {
+ entityList.forEach { upsert(it) }
}
- override fun observeSeasons(traktId: Long): Flow> {
- return seasonQueries.seasonById(traktId)
+ override fun observeSeasonsByShowId(traktId: Long): Flow> {
+ return database.seasonQueries.seasonsByShowId(Id(traktId))
.asFlow()
.mapToList(dispatcher.io)
}
+ override fun fetchSeasonDetails(traktId: Long): List =
+ database.seasonQueries.seasonEpisodeDetailsById(id = Id(traktId))
+ .executeAsList()
+
+ override fun observeSeasonEpisodeDetailsById(showId: Long): Flow> =
+ database.seasonQueries.seasonEpisodeDetailsById(id = Id(showId))
+ .asFlow()
+ .mapToList(dispatcher.io)
+
override fun delete(id: Long) {
- seasonQueries.delete(id)
+ seasonQueries.delete(Id(id))
}
override fun deleteAll() {
diff --git a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsRepositoryImpl.kt b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsRepositoryImpl.kt
index 111e35373..3c28dcf5c 100644
--- a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsRepositoryImpl.kt
+++ b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsRepositoryImpl.kt
@@ -1,17 +1,24 @@
package com.thomaskioko.tvmaniac.seasons.implementation
-import com.thomaskioko.tvmaniac.core.db.Seasons
+import com.thomaskioko.tvmaniac.core.db.SeasonsByShowId
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.seasons.api.SeasonsRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.StoreReadRequest
-import org.mobilenativefoundation.store.store5.StoreReadResponse
import org.mobilenativefoundation.store.store5.impl.extensions.get
import kotlin.time.Duration.Companion.days
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class SeasonsRepositoryImpl(
private val seasonsStore: SeasonsStore,
@@ -19,10 +26,10 @@ class SeasonsRepositoryImpl(
private val dispatcher: AppCoroutineDispatchers,
) : SeasonsRepository {
- override suspend fun getSeasons(traktId: Long): List =
+ override suspend fun fetchSeasonsByShowId(traktId: Long): List =
seasonsStore.get(traktId)
- override fun observeSeasonsStoreResponse(traktId: Long): Flow>> =
+ override fun observeSeasonsByShowId(traktId: Long): Flow>> =
seasonsStore.stream(
StoreReadRequest.cached(
key = traktId,
@@ -33,5 +40,14 @@ class SeasonsRepositoryImpl(
),
),
)
+ .distinctUntilChanged()
+ .flatMapLatest {
+ val data = it.dataOrNull()
+ if (data != null) {
+ flowOf(Either.Right(data))
+ } else {
+ emptyFlow()
+ }
+ }
.flowOn(dispatcher.io)
}
diff --git a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsStore.kt b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsStore.kt
index 54f07ca2e..afe4299a5 100644
--- a/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsStore.kt
+++ b/data/seasons/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/implementation/SeasonsStore.kt
@@ -1,12 +1,12 @@
package com.thomaskioko.tvmaniac.seasons.implementation
-import com.thomaskioko.tvmaniac.core.db.Seasons
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
+import com.thomaskioko.tvmaniac.core.db.SeasonsByShowId
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.seasons.api.SeasonsDao
import com.thomaskioko.tvmaniac.trakt.api.TraktShowsRemoteDataSource
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import kotlinx.datetime.Clock
import me.tatarka.inject.annotations.Inject
@@ -22,7 +22,7 @@ class SeasonsStore(
private val seasonsDao: SeasonsDao,
private val scope: AppCoroutineScope,
private val logger: KermitLogger,
-) : Store> by StoreBuilder.from, List>(
+) : Store> by StoreBuilder.from(
fetcher = Fetcher.of { id ->
when (val response = remoteDataSource.getShowSeasons(id)) {
is ApiResponse.Success -> response.body.toSeasonCacheList(id)
@@ -43,14 +43,14 @@ class SeasonsStore(
}
},
sourceOfTruth = SourceOfTruth.of(
- reader = seasonsDao::observeSeasons,
+ reader = seasonsDao::observeSeasonsByShowId,
writer = { id, list ->
- seasonsDao.insertSeasons(list)
+ seasonsDao.upsert(list)
requestManagerRepository.insert(
LastRequest(
- id = list.first().id,
+ id = list.first().id.id,
entityId = id,
requestType = "SEASON",
timestamp = Clock.System.now(),
diff --git a/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/FakeSeasonsRepository.kt b/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/FakeSeasonsRepository.kt
index 413e0d877..eceb5705f 100644
--- a/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/FakeSeasonsRepository.kt
+++ b/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/FakeSeasonsRepository.kt
@@ -1,30 +1,36 @@
package com.thomaskioko.tvmaniac.seasons.testing
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-import com.thomaskioko.tvmaniac.core.db.Seasons
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
+import com.thomaskioko.tvmaniac.core.db.SeasonsByShowId
import com.thomaskioko.tvmaniac.seasons.api.SeasonsRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
-import org.mobilenativefoundation.store.store5.StoreReadResponse
+import kotlinx.coroutines.flow.receiveAsFlow
class FakeSeasonsRepository : SeasonsRepository {
- private var seasonsResult = flowOf>>()
+ private var seasonsList: Channel> = Channel(Channel.UNLIMITED)
+ private var seasonsResult: Channel>> = Channel(Channel.UNLIMITED)
- private var seasonEpisodesResult = flowOf>>()
+ private var seasonEpisodesResult: Channel>> =
+ Channel(Channel.UNLIMITED)
- suspend fun setSeasonsResult(result: StoreReadResponse>) {
- seasonsResult = flow { emit(result) }
+ suspend fun setSeasonWithEpisodes(result: Either>) {
+ seasonEpisodesResult.send(result)
}
- suspend fun setSeasonDetails(result: Either>) {
- seasonEpisodesResult = flow { emit(result) }
+ suspend fun setSeasons(result: List) {
+ seasonsList.send(result)
}
- override suspend fun getSeasons(traktId: Long): List = emptyList()
+ suspend fun setSeasonsResult(result: Either>) {
+ seasonsResult.send(result)
+ }
+
+ override suspend fun fetchSeasonsByShowId(traktId: Long): List = seasonsList.receive()
- override fun observeSeasonsStoreResponse(traktId: Long): Flow>> = seasonsResult
+ override fun observeSeasonsByShowId(
+ traktId: Long,
+ ): Flow>> = seasonsResult.receiveAsFlow()
}
diff --git a/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/MockData.kt b/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/MockData.kt
deleted file mode 100644
index cdf6a1b02..000000000
--- a/data/seasons/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/seasons/testing/MockData.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.thomaskioko.tvmaniac.seasons.testing
-
-import com.thomaskioko.tvmaniac.core.db.SeasonWithEpisodes
-
-val seasonDetails = listOf(
- SeasonWithEpisodes(
- trakt_id = 84958,
- tmdb_id = 849583,
- title = "Loki",
- overview = "After stealing the Tesseract in Avengers: Endgame, Loki lands before the Time Variance Authority.",
- runtime = 45,
- id = 12345,
- season_id = 12343,
- season_number = 0,
- episode_count = 15,
- name = "Season 01",
- trakt_id_ = 12345,
- title_ = "Some title",
- ratings = 4.5,
- episode_number = "01",
- votes = 4958,
- image_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
- ),
-)
diff --git a/data/showimages/api/build.gradle.kts b/data/showimages/api/build.gradle.kts
index 59e60b379..30e94f05c 100644
--- a/data/showimages/api/build.gradle.kts
+++ b/data/showimages/api/build.gradle.kts
@@ -7,7 +7,7 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
+ api(projects.core.util)
api(libs.coroutines.core)
}
diff --git a/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesDao.kt b/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesDao.kt
index 1adf44f43..164483c7e 100644
--- a/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesDao.kt
+++ b/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesDao.kt
@@ -1,12 +1,20 @@
package com.thomaskioko.tvmaniac.showimages.api
-import com.thomaskioko.tvmaniac.core.db.SelectShowImages
+import com.thomaskioko.tvmaniac.core.db.EmptyShowImage
import com.thomaskioko.tvmaniac.core.db.Show_image
import kotlinx.coroutines.flow.Flow
interface ShowImagesDao {
- fun insert(image: Show_image)
+ fun upsert(images: List)
- fun observeShowImages(): Flow>
+ fun upsert(image: Show_image)
+
+ fun observeShowImages(): Flow>
+
+ fun fetchShowImages(): List
+
+ fun delete(id: Long)
+
+ fun deleteAll()
}
diff --git a/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesRepository.kt b/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesRepository.kt
index 49ea9df12..5cb3717c8 100644
--- a/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesRepository.kt
+++ b/data/showimages/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/api/ShowImagesRepository.kt
@@ -1,7 +1,7 @@
package com.thomaskioko.tvmaniac.showimages.api
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
interface ShowImagesRepository {
diff --git a/data/showimages/implementation/build.gradle.kts b/data/showimages/implementation/build.gradle.kts
index 11b76c2e6..1285c1f04 100644
--- a/data/showimages/implementation/build.gradle.kts
+++ b/data/showimages/implementation/build.gradle.kts
@@ -14,7 +14,9 @@ kotlin {
implementation(projects.core.tmdbApi.api)
implementation(libs.kotlinInject.runtime)
+ implementation(libs.kotlinx.atomicfu)
implementation(libs.sqldelight.extensions)
+ implementation(libs.store5)
}
}
diff --git a/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesDaoImpl.kt b/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesDaoImpl.kt
index 4317e5410..2fa8a2759 100644
--- a/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesDaoImpl.kt
+++ b/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesDaoImpl.kt
@@ -2,9 +2,10 @@ package com.thomaskioko.tvmaniac.showimages.implementation
import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
-import com.thomaskioko.tvmaniac.core.db.SelectShowImages
+import com.thomaskioko.tvmaniac.core.db.EmptyShowImage
import com.thomaskioko.tvmaniac.core.db.Show_image
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.showimages.api.ShowImagesDao
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
import kotlinx.coroutines.flow.Flow
@@ -16,20 +17,37 @@ class ShowImagesDaoImpl(
private val dispatchers: AppCoroutineDispatchers,
) : ShowImagesDao {
- override fun insert(image: Show_image) {
+ override fun upsert(images: List) {
database.transaction {
- database.show_imageQueries.insertOrReplace(
- trakt_id = image.trakt_id,
- tmdb_id = image.tmdb_id,
- poster_url = image.poster_url,
- backdrop_url = image.backdrop_url,
- )
+ images.forEach { upsert(it) }
}
}
- override fun observeShowImages(): Flow> {
- return database.show_imageQueries.selectShowImages()
+ override fun upsert(image: Show_image) {
+ database.show_imageQueries.insertOrReplace(
+ id = image.id,
+ tmdb_id = image.tmdb_id,
+ poster_url = image.poster_url,
+ backdrop_url = image.backdrop_url,
+ )
+ }
+
+ override fun observeShowImages(): Flow> {
+ return database.show_imageQueries.emptyShowImage()
.asFlow()
.mapToList(dispatchers.io)
}
+
+ override fun fetchShowImages(): List {
+ return database.show_imageQueries.emptyShowImage()
+ .executeAsList()
+ }
+
+ override fun delete(id: Long) {
+ database.show_imageQueries.delete(Id(id))
+ }
+
+ override fun deleteAll() {
+ database.show_imageQueries.deleteAll()
+ }
}
diff --git a/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesRepositoryImpl.kt b/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesRepositoryImpl.kt
index 67ae3ef6d..52dc3432b 100644
--- a/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesRepositoryImpl.kt
+++ b/data/showimages/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/showimages/implementation/ShowImagesRepositoryImpl.kt
@@ -1,11 +1,7 @@
package com.thomaskioko.tvmaniac.showimages.implementation
import com.thomaskioko.tvmaniac.core.db.Show_image
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
-import com.thomaskioko.tvmaniac.core.networkutil.DefaultError
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
-import com.thomaskioko.tvmaniac.core.networkutil.NetworkExceptionHandler
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.showimages.api.ShowImagesDao
@@ -13,13 +9,17 @@ import com.thomaskioko.tvmaniac.showimages.api.ShowImagesRepository
import com.thomaskioko.tvmaniac.tmdb.api.TmdbNetworkDataSource
import com.thomaskioko.tvmaniac.util.FormatterUtil
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.NetworkExceptionHandler
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.DefaultError
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import me.tatarka.inject.annotations.Inject
-import kotlin.time.Duration.Companion.days
@Inject
class ShowImagesRepositoryImpl(
@@ -36,41 +36,33 @@ class ShowImagesRepositoryImpl(
imageCache.observeShowImages()
.map { shows ->
shows.forEach { show ->
- val shouldFetch = requestManagerRepository.isRequestExpired(
- entityId = show.trakt_id,
- requestType = "SHOW_ARTWORK",
- threshold = 1.days,
- )
- if (shouldFetch) {
- show.tmdb_id?.let { tmdbId ->
-
- when (val response = networkDataSource.getTvShowDetails(tmdbId)) {
- is ApiResponse.Error -> {
- logger.error("updateShowArtWork", "$response")
- }
+ show.tmdb_id?.let { tmdbId ->
+ when (val response = networkDataSource.getTvShowDetails(tmdbId)) {
+ is ApiResponse.Error -> {
+ logger.error("updateShowArtWork", "$response")
+ }
- is ApiResponse.Success -> {
- imageCache.insert(
- Show_image(
- trakt_id = show.trakt_id,
- tmdb_id = tmdbId,
- poster_url = response.body.posterPath?.let {
- formatterUtil.formatTmdbPosterPath(it)
- },
- backdrop_url = response.body.backdropPath?.let {
- formatterUtil.formatTmdbPosterPath(it)
- },
- ),
- )
+ is ApiResponse.Success -> {
+ imageCache.upsert(
+ Show_image(
+ id = Id(id = show.id.id),
+ tmdb_id = tmdbId,
+ poster_url = response.body.posterPath?.let {
+ formatterUtil.formatTmdbPosterPath(it)
+ },
+ backdrop_url = response.body.backdropPath?.let {
+ formatterUtil.formatTmdbPosterPath(it)
+ },
+ ),
+ )
- requestManagerRepository.insert(
- LastRequest(
- id = tmdbId,
- entityId = show.trakt_id,
- requestType = "SHOW_ARTWORK",
- ),
- )
- }
+ requestManagerRepository.insert(
+ LastRequest(
+ id = tmdbId,
+ entityId = show.id.id,
+ requestType = "SHOW_ARTWORK",
+ ),
+ )
}
}
}
diff --git a/data/showimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/testing/FakeShowImagesRepository.kt b/data/showimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/testing/FakeShowImagesRepository.kt
index 10dde84fa..cb2746a1f 100644
--- a/data/showimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/testing/FakeShowImagesRepository.kt
+++ b/data/showimages/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/tmdb/testing/FakeShowImagesRepository.kt
@@ -1,8 +1,8 @@
package com.thomaskioko.tvmaniac.tmdb.testing
-import com.thomaskioko.tvmaniac.core.networkutil.Either
-import com.thomaskioko.tvmaniac.core.networkutil.Failure
import com.thomaskioko.tvmaniac.showimages.api.ShowImagesRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
diff --git a/data/shows/api/build.gradle.kts b/data/shows/api/build.gradle.kts
index 1437f8489..ad9438ae9 100644
--- a/data/shows/api/build.gradle.kts
+++ b/data/shows/api/build.gradle.kts
@@ -7,12 +7,9 @@ kotlin {
commonMain {
dependencies {
api(projects.core.database)
- api(projects.core.networkutil)
api(projects.data.category.api)
api(libs.coroutines.core)
- api(libs.kotlinx.atomicfu)
- api(libs.store5)
}
}
}
diff --git a/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/DiscoverRepository.kt b/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/DiscoverRepository.kt
index 928891f5d..ae538c16d 100644
--- a/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/DiscoverRepository.kt
+++ b/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/DiscoverRepository.kt
@@ -3,22 +3,20 @@ package com.thomaskioko.tvmaniac.shows.api
import com.thomaskioko.tvmaniac.category.api.model.Category
import com.thomaskioko.tvmaniac.core.db.ShowById
import com.thomaskioko.tvmaniac.core.db.ShowsByCategory
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
-import org.mobilenativefoundation.store.store5.StoreReadResponse
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.days
interface DiscoverRepository {
- fun observeShow(traktId: Long): Flow>
+ fun observeShow(traktId: Long): Flow>
- fun observeShowsByCategory(categoryId: Long): Flow>>
-
- fun observeTrendingShows(): Flow>>
-
- fun observePopularShows(): Flow>>
-
- fun observeAnticipatedShows(): Flow>>
-
- fun observeRecommendedShows(): Flow>>
+ fun observeShowCategory(
+ category: Category,
+ duration: Duration = 3.days,
+ ): Flow>>
suspend fun fetchDiscoverShows()
diff --git a/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/ShowsDao.kt b/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/ShowsDao.kt
index 4393a466b..c2720edf6 100644
--- a/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/ShowsDao.kt
+++ b/data/shows/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/api/ShowsDao.kt
@@ -8,9 +8,9 @@ import kotlinx.coroutines.flow.Flow
interface ShowsDao {
- fun insert(show: Show)
+ fun upsert(show: Show)
- fun insert(list: List)
+ fun upsert(list: List)
fun observeTvShow(showId: Long): Flow
@@ -21,6 +21,4 @@ interface ShowsDao {
fun getTvShow(traktId: Long): ShowById
fun deleteTvShows()
-
- fun getShowsByCategoryID(categoryId: Long): List
}
diff --git a/data/shows/implementation/build.gradle.kts b/data/shows/implementation/build.gradle.kts
index fb0c55523..40aeabdf2 100644
--- a/data/shows/implementation/build.gradle.kts
+++ b/data/shows/implementation/build.gradle.kts
@@ -17,6 +17,8 @@ kotlin {
implementation(libs.kotlinInject.runtime)
implementation(libs.sqldelight.extensions)
+ implementation(libs.kotlinx.atomicfu)
+ implementation(libs.store5)
}
}
diff --git a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverRepositoryImpl.kt b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverRepositoryImpl.kt
index b28e4c47c..21e36e4e0 100644
--- a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverRepositoryImpl.kt
+++ b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverRepositoryImpl.kt
@@ -5,111 +5,67 @@ import com.thomaskioko.tvmaniac.category.api.model.Category.ANTICIPATED
import com.thomaskioko.tvmaniac.category.api.model.Category.POPULAR
import com.thomaskioko.tvmaniac.category.api.model.Category.RECOMMENDED
import com.thomaskioko.tvmaniac.category.api.model.Category.TRENDING
-import com.thomaskioko.tvmaniac.category.api.model.getCategory
import com.thomaskioko.tvmaniac.core.db.ShowById
import com.thomaskioko.tvmaniac.core.db.ShowsByCategory
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.shows.api.DiscoverRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.StoreReadRequest
import org.mobilenativefoundation.store.store5.StoreReadResponse
import org.mobilenativefoundation.store.store5.impl.extensions.get
+import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
-class DiscoverRepositoryImpl constructor(
+class DiscoverRepositoryImpl(
private val showStore: ShowStore,
private val discoverShowsStore: DiscoverShowsStore,
private val requestManagerRepository: RequestManagerRepository,
private val dispatchers: AppCoroutineDispatchers,
) : DiscoverRepository {
- override suspend fun getShowById(traktId: Long): ShowById =
- showStore.get(key = traktId)
+ override suspend fun getShowById(traktId: Long): ShowById = showStore.get(key = traktId)
- override fun observeShow(traktId: Long): Flow> =
- showStore.stream(
- StoreReadRequest.cached(
- key = traktId,
- refresh = requestManagerRepository.isRequestExpired(
- entityId = traktId,
- requestType = "SHOW_DETAILS",
- threshold = 6.days,
- ),
+ override fun observeShow(traktId: Long): Flow> = showStore.stream(
+ StoreReadRequest.cached(
+ key = traktId,
+ refresh = requestManagerRepository.isRequestExpired(
+ entityId = traktId,
+ requestType = "SHOW_DETAILS",
+ threshold = 6.days,
),
- )
- .flowOn(dispatchers.io)
+ ),
+ )
+ .mapResult()
override suspend fun fetchShows(category: Category): List =
discoverShowsStore.get(key = category)
- override fun observeShowsByCategory(categoryId: Long): Flow>> =
- discoverShowsStore.stream(
- StoreReadRequest.cached(
- key = categoryId.getCategory(),
- refresh = requestManagerRepository.isRequestExpired(
- entityId = categoryId,
- requestType = categoryId.getCategory().title,
- threshold = 3.days,
- ),
- ),
- )
- .flowOn(dispatchers.io)
-
- override fun observeTrendingShows(): Flow>> =
- discoverShowsStore.stream(
- StoreReadRequest.cached(
- key = TRENDING,
- refresh = requestManagerRepository.isRequestExpired(
- entityId = TRENDING.id,
- requestType = TRENDING.title,
- threshold = 3.days,
- ),
- ),
- )
- .flowOn(dispatchers.io)
-
- override fun observePopularShows(): Flow>> =
- discoverShowsStore.stream(
- StoreReadRequest.cached(
- key = POPULAR,
- refresh = requestManagerRepository.isRequestExpired(
- entityId = POPULAR.id,
- requestType = POPULAR.title,
- threshold = 3.days,
- ),
- ),
- )
- .flowOn(dispatchers.io)
-
- override fun observeAnticipatedShows(): Flow>> =
- discoverShowsStore.stream(
- StoreReadRequest.cached(
- key = ANTICIPATED,
- refresh = requestManagerRepository.isRequestExpired(
- entityId = ANTICIPATED.id,
- requestType = ANTICIPATED.title,
- threshold = 3.days,
- ),
- ),
- )
- .flowOn(dispatchers.io)
-
- override fun observeRecommendedShows(): Flow>> =
- discoverShowsStore.stream(
- StoreReadRequest.cached(
- key = RECOMMENDED,
- refresh = requestManagerRepository.isRequestExpired(
- entityId = RECOMMENDED.id,
- requestType = RECOMMENDED.title,
- threshold = 1.days,
- ),
+ override fun observeShowCategory(
+ category: Category,
+ duration: Duration,
+ ): Flow>> = discoverShowsStore.stream(
+ StoreReadRequest.cached(
+ key = category,
+ refresh = requestManagerRepository.isRequestExpired(
+ entityId = category.id,
+ requestType = category.title,
+ threshold = duration,
),
- )
- .flowOn(dispatchers.io)
+ ),
+ )
+ .mapResult()
override suspend fun fetchDiscoverShows() {
val categories = listOf(TRENDING, POPULAR, ANTICIPATED, RECOMMENDED)
@@ -118,4 +74,16 @@ class DiscoverRepositoryImpl constructor(
discoverShowsStore.get(category)
}
}
+
+ private fun Flow>.mapResult(): Flow> =
+ distinctUntilChanged()
+ .flatMapLatest {
+ val data = it.dataOrNull()
+ if (data != null) {
+ flowOf(Either.Right(data))
+ } else {
+ emptyFlow()
+ }
+ }
+ .flowOn(dispatchers.io)
}
diff --git a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverResponseMapper.kt b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverResponseMapper.kt
index 43aa2a87e..8db1bdaa5 100644
--- a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverResponseMapper.kt
+++ b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverResponseMapper.kt
@@ -5,7 +5,7 @@ import com.thomaskioko.tvmaniac.core.db.Show
import com.thomaskioko.tvmaniac.core.db.ShowById
import com.thomaskioko.tvmaniac.core.db.Show_category
import com.thomaskioko.tvmaniac.core.db.ShowsByCategory
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.trakt.api.model.ErrorResponse
@@ -13,6 +13,7 @@ import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowResponse
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowsResponse
import com.thomaskioko.tvmaniac.util.FormatterUtil
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import me.tatarka.inject.annotations.Inject
@Inject
@@ -35,10 +36,12 @@ class DiscoverResponseMapper(
logger.error("ShowStore GenericError", "${response.errorBody}")
throw Throwable("${response.errorMessage}")
}
+
is ApiResponse.Error.GenericError -> {
logger.error("ShowStore GenericError", "${response.errorMessage}")
throw Throwable("${response.errorMessage}")
}
+
is ApiResponse.Error.SerializationError -> {
logger.error("ShowStore GenericError", "${response.errorMessage}")
throw Throwable("${response.errorMessage}")
@@ -58,10 +61,12 @@ class DiscoverResponseMapper(
logger.error("ShowStore GenericError", "${response.errorBody}")
throw Throwable("${response.errorMessage}")
}
+
is ApiResponse.Error.SerializationError -> {
logger.error("ShowStore GenericError", "${response.errorMessage}")
throw Throwable("${response.errorMessage}")
}
+
is ApiResponse.Error.GenericError -> {
logger.error("ShowStore GenericError", "${response.errorMessage}")
throw Throwable("${response.errorMessage}")
@@ -69,7 +74,7 @@ class DiscoverResponseMapper(
}
private fun responseToEntity(response: TraktShowResponse) = ShowsByCategory(
- trakt_id = response.ids.trakt.toLong(),
+ id = Id(id = response.ids.trakt.toLong()),
tmdb_id = response.ids.tmdb?.toLong(),
title = response.title,
overview = response.overview ?: "",
@@ -87,7 +92,7 @@ class DiscoverResponseMapper(
)
fun responseToShow(response: TraktShowResponse) = ShowById(
- trakt_id = response.ids.trakt.toLong(),
+ id = Id(id = response.ids.trakt.toLong()),
tmdb_id = response.ids.tmdb?.toLong(),
title = response.title,
overview = response.overview ?: "",
@@ -99,18 +104,14 @@ class DiscoverResponseMapper(
rating = formatterUtil.formatDouble(response.rating, 1),
genres = response.genres.map { it.replaceFirstChar { it.uppercase() } },
status = response.status.replaceFirstChar { it.uppercase() },
- trakt_id_ = null,
- tmdb_id_ = null,
poster_url = null,
backdrop_url = null,
- id = null,
- created_at = null,
- synced = false,
+ in_watchlist = 0L,
)
fun toShow(showById: ShowById) =
Show(
- trakt_id = showById.trakt_id,
+ id = showById.id,
tmdb_id = showById.tmdb_id,
title = showById.title,
overview = showById.overview,
@@ -126,7 +127,7 @@ class DiscoverResponseMapper(
private fun showResponseToCacheList(response: TraktShowsResponse): ShowsByCategory =
ShowsByCategory(
- trakt_id = response.show.ids.trakt.toLong(),
+ id = Id(id = response.show.ids.trakt.toLong()),
tmdb_id = response.show.ids.tmdb?.toLong(),
title = response.show.title,
overview = response.show.overview ?: "",
@@ -145,8 +146,8 @@ class DiscoverResponseMapper(
fun toCategoryCache(shows: List, categoryId: Long) = shows.map {
Show_category(
- trakt_id = it.trakt_id,
- category_id = categoryId,
+ id = Id(id = it.id.id),
+ category_id = Id(categoryId),
)
}
}
diff --git a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverShowsStore.kt b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverShowsStore.kt
index 4a95c4894..582847bb3 100644
--- a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverShowsStore.kt
+++ b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/DiscoverShowsStore.kt
@@ -47,7 +47,7 @@ class DiscoverShowsStore(
val shows = list.map {
Show(
- trakt_id = it.trakt_id,
+ id = it.id,
tmdb_id = it.tmdb_id,
title = it.title,
overview = it.overview,
@@ -61,8 +61,8 @@ class DiscoverShowsStore(
genres = it.genres,
)
}
- showsDao.insert(shows)
- categoryCache.insert(mapper.toCategoryCache(shows, category.id))
+ showsDao.upsert(shows)
+ categoryCache.upsert(mapper.toCategoryCache(shows, category.id))
},
),
)
diff --git a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowDaoImpl.kt b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowDaoImpl.kt
index ce12d3ea4..5107b4362 100644
--- a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowDaoImpl.kt
+++ b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowDaoImpl.kt
@@ -8,21 +8,22 @@ import com.thomaskioko.tvmaniac.core.db.ShowById
import com.thomaskioko.tvmaniac.core.db.Shows
import com.thomaskioko.tvmaniac.core.db.ShowsByCategory
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.shows.api.ShowsDao
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
import kotlinx.coroutines.flow.Flow
import me.tatarka.inject.annotations.Inject
@Inject
-class ShowDaoImpl constructor(
+class ShowDaoImpl(
private val database: TvManiacDatabase,
private val dispatchers: AppCoroutineDispatchers,
) : ShowsDao {
- override fun insert(show: Show) {
+ override fun upsert(show: Show) {
database.showQueries.transaction {
database.showQueries.insertOrReplace(
- trakt_id = show.trakt_id,
+ id = show.id,
tmdb_id = show.tmdb_id,
title = show.title,
overview = show.overview,
@@ -37,18 +38,18 @@ class ShowDaoImpl constructor(
}
}
- override fun insert(list: List) {
- list.forEach { insert(it) }
+ override fun upsert(list: List) {
+ list.forEach { upsert(it) }
}
override fun observeTvShow(showId: Long): Flow {
- return database.showQueries.showById(showId)
+ return database.showQueries.showById(Id(showId))
.asFlow()
.mapToOne(dispatchers.io)
}
override fun observeCachedShows(categoryId: Long): Flow> {
- return database.showQueries.showsByCategory(categoryId)
+ return database.show_categoryQueries.showsByCategory(Id(categoryId))
.asFlow()
.mapToList(dispatchers.io)
}
@@ -60,14 +61,10 @@ class ShowDaoImpl constructor(
}
override fun getTvShow(traktId: Long): ShowById =
- database.showQueries.showById(traktId)
+ database.showQueries.showById(Id(traktId))
.executeAsOne()
override fun deleteTvShows() {
database.showQueries.deleteAll()
}
-
- override fun getShowsByCategoryID(categoryId: Long): List =
- database.showQueries.showsByCategory(categoryId)
- .executeAsList()
}
diff --git a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowStore.kt b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowStore.kt
index 5e8e16573..710ce4799 100644
--- a/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowStore.kt
+++ b/data/shows/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/implementation/ShowStore.kt
@@ -1,12 +1,12 @@
package com.thomaskioko.tvmaniac.shows.implementation
import com.thomaskioko.tvmaniac.core.db.ShowById
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.shows.api.ShowsDao
import com.thomaskioko.tvmaniac.trakt.api.TraktShowsRemoteDataSource
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
@@ -49,11 +49,11 @@ class ShowStore(
reader = { traktId -> showsDao.observeTvShow(traktId) },
writer = { id, show ->
- showsDao.insert(mapper.toShow(show))
+ showsDao.upsert(mapper.toShow(show))
requestManagerRepository.insert(
LastRequest(
- id = id + show.trakt_id,
+ id = id + show.id.id,
entityId = id,
requestType = "SHOW_DETAILS",
),
diff --git a/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/FakeDiscoverRepository.kt b/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/FakeDiscoverRepository.kt
index dafc7c483..64e4d25f4 100644
--- a/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/FakeDiscoverRepository.kt
+++ b/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/FakeDiscoverRepository.kt
@@ -3,75 +3,60 @@ package com.thomaskioko.tvmaniac.shows.testing
import com.thomaskioko.tvmaniac.category.api.model.Category
import com.thomaskioko.tvmaniac.core.db.ShowById
import com.thomaskioko.tvmaniac.core.db.ShowsByCategory
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.shows.api.DiscoverRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
-import org.mobilenativefoundation.store.store5.StoreReadResponse
+import kotlinx.coroutines.flow.receiveAsFlow
+import kotlin.time.Duration
class FakeDiscoverRepository : DiscoverRepository {
- private var featuredResult = flowOf>>()
+ private var showById: Channel = Channel(Channel.UNLIMITED)
+ private var updatedShowCategoryResult: Channel>> =
+ Channel(Channel.UNLIMITED)
- private var anticipatedResult = flowOf>>()
+ private var showCategoryResult: Channel> = Channel(Channel.UNLIMITED)
- private var popularResult = flowOf>>()
+ private var showByIdResult: Channel> =
+ Channel(Channel.UNLIMITED)
- private var trendingResult = flowOf>>()
-
- private var showResult = flowOf>()
-
- suspend fun setFeaturedResult(result: StoreReadResponse>) {
- featuredResult = flow { emit(result) }
- }
-
- suspend fun setAnticipatedResult(result: StoreReadResponse>) {
- anticipatedResult = flow { emit(result) }
- }
-
- suspend fun setPopularResult(result: StoreReadResponse>) {
- popularResult = flow { emit(result) }
+ suspend fun setShowCategory(result: List) {
+ showCategoryResult.send(result)
}
- suspend fun setTrendingResult(result: StoreReadResponse>) {
- trendingResult = flow { emit(result) }
+ suspend fun setShowById(result: ShowById) {
+ showById.send(result)
}
- suspend fun setShowResult(result: StoreReadResponse) {
- showResult = flow { emit(result) }
+ suspend fun setTrendingResult(result: Either>) {
+ updatedShowCategoryResult.send(result)
}
- override fun observeShow(traktId: Long): Flow> = showResult
-
- override fun observeShowsByCategory(
- categoryId: Long,
- ): Flow>> = featuredResult
-
- override fun observeTrendingShows(): Flow>> {
- return trendingResult
- }
-
- override fun observePopularShows(): Flow>> {
- return popularResult
+ suspend fun setShowResult(result: Either) {
+ showByIdResult.send(result)
}
- override fun observeAnticipatedShows(): Flow>> {
- return anticipatedResult
- }
+ override fun observeShow(traktId: Long): Flow> =
+ showByIdResult.receiveAsFlow()
- override fun observeRecommendedShows(): Flow>> {
- return featuredResult
- }
+ override fun observeShowCategory(
+ category: Category,
+ duration: Duration,
+ ): Flow>> = updatedShowCategoryResult.receiveAsFlow()
override suspend fun fetchDiscoverShows() {}
- override suspend fun fetchShows(category: Category): List = emptyList()
+ override suspend fun fetchShows(category: Category): List =
+ showCategoryResult.receive()
- override suspend fun getShowById(traktId: Long): ShowById = selectedShow
+ override suspend fun getShowById(traktId: Long): ShowById = showById.receive()
}
val selectedShow = ShowById(
- trakt_id = 84958,
+ id = Id(84958),
tmdb_id = 849583,
title = "Loki",
overview = "After stealing the Tesseract during the events of “Avengers: Endgame,” " +
@@ -90,9 +75,5 @@ val selectedShow = ShowById(
poster_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
backdrop_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
aired_episodes = 12,
- trakt_id_ = 1234,
- id = 12345,
- created_at = null,
- synced = false,
- tmdb_id_ = 1232,
+ in_watchlist = 0,
)
diff --git a/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/MockData.kt b/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/MockData.kt
deleted file mode 100644
index 93227f89a..000000000
--- a/data/shows/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/shows/testing/MockData.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.thomaskioko.tvmaniac.shows.testing
-
-import com.thomaskioko.tvmaniac.core.db.SelectWatchlist
-
-val selectWatchList = listOf(
- SelectWatchlist(
- trakt_id = 84958,
- tmdb_id = 849583,
- title = "Loki",
- overview = "After stealing the Tesseract during the events of “Avengers: Endgame,” " +
- "an alternate version of Loki is brought to the mysterious Time Variance " +
- "Authority, a bureaucratic organization that exists outside of time and " +
- "space and monitors the timeline. They give Loki a choice: face being " +
- "erased from existence due to being a “time variant”or help fix " +
- "the timeline and stop a greater threat.",
- language = "en",
- votes = 4958,
- rating = 8.1,
- genres = listOf("Horror", "Action"),
- status = "Returning Series",
- year = "2024",
- runtime = 45,
- poster_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
- backdrop_url = "/kEl2t3OhXc3Zb9FBh1AuYzRTgZp.jpg",
- aired_episodes = 12,
- id = 84958,
- synced = true,
- created_at = 12345645,
- trakt_id_ = 1232,
- tmdb_id_ = 849583,
- ),
-)
diff --git a/data/similar/api/build.gradle.kts b/data/similar/api/build.gradle.kts
index cc0798de1..28aa509b8 100644
--- a/data/similar/api/build.gradle.kts
+++ b/data/similar/api/build.gradle.kts
@@ -8,13 +8,10 @@ kotlin {
commonMain {
dependencies {
- api(projects.core.networkutil)
api(projects.core.database)
implementation(projects.data.shows.api)
api(libs.coroutines.core)
- api(libs.kotlinx.atomicfu)
- api(libs.store5)
}
}
}
diff --git a/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsDao.kt b/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsDao.kt
index e5a288a6b..fb0c8acf0 100644
--- a/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsDao.kt
+++ b/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsDao.kt
@@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.Flow
interface SimilarShowsDao {
- fun insert(traktId: Long, similarShowId: Long)
+ fun upsert(showId: Long, similarShowId: Long)
fun observeSimilarShows(traktId: Long): Flow>
diff --git a/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsRepository.kt b/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsRepository.kt
index 111ff57c7..f5f373fcf 100644
--- a/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsRepository.kt
+++ b/data/similar/api/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/api/SimilarShowsRepository.kt
@@ -1,12 +1,13 @@
package com.thomaskioko.tvmaniac.similar.api
import com.thomaskioko.tvmaniac.core.db.SimilarShows
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
-import org.mobilenativefoundation.store.store5.StoreReadResponse
interface SimilarShowsRepository {
suspend fun fetchSimilarShows(traktId: Long): List
- fun observeSimilarShows(traktId: Long): Flow>>
+ fun observeSimilarShows(traktId: Long): Flow>>
}
diff --git a/data/similar/implementation/build.gradle.kts b/data/similar/implementation/build.gradle.kts
index c3bd775d3..788559a46 100644
--- a/data/similar/implementation/build.gradle.kts
+++ b/data/similar/implementation/build.gradle.kts
@@ -16,6 +16,8 @@ kotlin {
implementation(libs.kotlinInject.runtime)
implementation(libs.sqldelight.extensions)
+ implementation(libs.kotlinx.atomicfu)
+ implementation(libs.store5)
}
}
diff --git a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/ResponseMapper.kt b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/ResponseMapper.kt
index 37ad2b2b7..e1928c406 100644
--- a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/ResponseMapper.kt
+++ b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/ResponseMapper.kt
@@ -2,12 +2,13 @@ package com.thomaskioko.tvmaniac.similar.implementation
import com.thomaskioko.tvmaniac.core.db.Show
import com.thomaskioko.tvmaniac.core.db.SimilarShows
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.trakt.api.model.TraktShowResponse
fun List.responseToShow(): List {
return map {
SimilarShows(
- trakt_id = it.ids.trakt.toLong(),
+ id = Id(it.ids.trakt.toLong()),
tmdb_id = it.ids.tmdb?.toLong(),
title = it.title,
overview = it.overview ?: "",
@@ -26,7 +27,7 @@ fun List.responseToShow(): List {
fun SimilarShows.toShow(): Show {
return Show(
- trakt_id = trakt_id,
+ id = id,
tmdb_id = tmdb_id,
title = title,
overview = overview,
diff --git a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowStore.kt b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowStore.kt
index b3acf71e2..d44314b13 100644
--- a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowStore.kt
+++ b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowStore.kt
@@ -1,13 +1,13 @@
package com.thomaskioko.tvmaniac.similar.implementation
import com.thomaskioko.tvmaniac.core.db.SimilarShows
-import com.thomaskioko.tvmaniac.core.networkutil.ApiResponse
import com.thomaskioko.tvmaniac.resourcemanager.api.LastRequest
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.shows.api.ShowsDao
import com.thomaskioko.tvmaniac.similar.api.SimilarShowsDao
import com.thomaskioko.tvmaniac.trakt.api.TraktShowsRemoteDataSource
import com.thomaskioko.tvmaniac.util.KermitLogger
+import com.thomaskioko.tvmaniac.util.model.ApiResponse
import com.thomaskioko.tvmaniac.util.model.AppCoroutineScope
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.Fetcher
@@ -23,7 +23,7 @@ class SimilarShowStore(
private val requestManagerRepository: RequestManagerRepository,
private val scope: AppCoroutineScope,
private val logger: KermitLogger,
-) : Store> by StoreBuilder.from, List>(
+) : Store> by StoreBuilder.from(
fetcher = Fetcher.of { id ->
when (val apiResult = remoteDataSource.getSimilarShows(id)) {
@@ -50,11 +50,11 @@ class SimilarShowStore(
writer = { id, list ->
list.forEach {
- showsDao.insert(it.toShow())
+ showsDao.upsert(it.toShow())
- similarShowsDao.insert(
- traktId = id,
- similarShowId = it.trakt_id,
+ similarShowsDao.upsert(
+ similarShowId = it.id.id,
+ showId = id,
)
}
diff --git a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsDaoImpl.kt b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsDaoImpl.kt
index 196e255a5..5d7bad51a 100644
--- a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsDaoImpl.kt
+++ b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsDaoImpl.kt
@@ -4,6 +4,7 @@ import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
import com.thomaskioko.tvmaniac.core.db.SimilarShows
import com.thomaskioko.tvmaniac.core.db.TvManiacDatabase
+import com.thomaskioko.tvmaniac.db.Id
import com.thomaskioko.tvmaniac.similar.api.SimilarShowsDao
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
import kotlinx.coroutines.flow.Flow
@@ -15,23 +16,23 @@ class SimilarShowsDaoImpl(
private val dispatchers: AppCoroutineDispatchers,
) : SimilarShowsDao {
- override fun insert(traktId: Long, similarShowId: Long) {
+ override fun upsert(showId: Long, similarShowId: Long) {
database.similar_showsQueries.transaction {
database.similar_showsQueries.insertOrReplace(
- id = similarShowId,
- trakt_id = traktId,
+ id = Id(similarShowId),
+ similar_show_id = Id(showId),
)
}
}
override fun observeSimilarShows(traktId: Long): Flow> {
- return database.similar_showsQueries.similarShows(trakt_id = traktId)
+ return database.similar_showsQueries.similarShows(Id(traktId))
.asFlow()
.mapToList(dispatchers.io)
}
override fun delete(id: Long) {
- database.similar_showsQueries.delete(id)
+ database.similar_showsQueries.delete(Id(id))
}
override fun deleteAll() {
diff --git a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsRepositoryImpl.kt b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsRepositoryImpl.kt
index 9582d267c..abe793ec4 100644
--- a/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsRepositoryImpl.kt
+++ b/data/similar/implementation/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/implementation/SimilarShowsRepositoryImpl.kt
@@ -4,14 +4,21 @@ import com.thomaskioko.tvmaniac.core.db.SimilarShows
import com.thomaskioko.tvmaniac.resourcemanager.api.RequestManagerRepository
import com.thomaskioko.tvmaniac.similar.api.SimilarShowsRepository
import com.thomaskioko.tvmaniac.util.model.AppCoroutineDispatchers
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import me.tatarka.inject.annotations.Inject
import org.mobilenativefoundation.store.store5.StoreReadRequest
-import org.mobilenativefoundation.store.store5.StoreReadResponse
import org.mobilenativefoundation.store.store5.impl.extensions.get
import kotlin.time.Duration.Companion.days
+@OptIn(ExperimentalCoroutinesApi::class)
@Inject
class SimilarShowsRepositoryImpl(
private val store: SimilarShowStore,
@@ -21,7 +28,7 @@ class SimilarShowsRepositoryImpl(
override suspend fun fetchSimilarShows(traktId: Long): List = store.get(traktId)
- override fun observeSimilarShows(traktId: Long): Flow>> =
+ override fun observeSimilarShows(traktId: Long): Flow>> =
store.stream(
StoreReadRequest.cached(
key = traktId,
@@ -32,5 +39,14 @@ class SimilarShowsRepositoryImpl(
),
),
)
+ .distinctUntilChanged()
+ .flatMapLatest {
+ val data = it.dataOrNull()
+ if (data != null) {
+ flowOf(Either.Right(data))
+ } else {
+ emptyFlow()
+ }
+ }
.flowOn(dispatchers.io)
}
diff --git a/data/similar/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/testing/FakeSimilarShowsRepository.kt b/data/similar/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/testing/FakeSimilarShowsRepository.kt
index 9797886d5..81343e06f 100644
--- a/data/similar/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/testing/FakeSimilarShowsRepository.kt
+++ b/data/similar/testing/src/commonMain/kotlin/com/thomaskioko/tvmaniac/similar/testing/FakeSimilarShowsRepository.kt
@@ -2,21 +2,22 @@ package com.thomaskioko.tvmaniac.similar.testing
import com.thomaskioko.tvmaniac.core.db.SimilarShows
import com.thomaskioko.tvmaniac.similar.api.SimilarShowsRepository
+import com.thomaskioko.tvmaniac.util.model.Either
+import com.thomaskioko.tvmaniac.util.model.Failure
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
-import org.mobilenativefoundation.store.store5.StoreReadResponse
class FakeSimilarShowsRepository : SimilarShowsRepository {
- private var similarShowsResult: Flow>> = flowOf()
+ private var similarShowsResult: Flow>> = flowOf()
- suspend fun setSimilarShowsResult(result: StoreReadResponse