mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feat: add Room database entities and DAOs for Episodes, Seasons, and Series
This commit is contained in:
@@ -73,6 +73,8 @@ dependencies {
|
|||||||
implementation(libs.medi3.ui.compose)
|
implementation(libs.medi3.ui.compose)
|
||||||
implementation(libs.androidx.navigation3.runtime)
|
implementation(libs.androidx.navigation3.runtime)
|
||||||
implementation(libs.androidx.navigation3.ui)
|
implementation(libs.androidx.navigation3.ui)
|
||||||
|
implementation(libs.androidx.room.runtime)
|
||||||
|
implementation(libs.androidx.room.ktx)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
@@ -81,4 +83,5 @@ dependencies {
|
|||||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
ksp(libs.hilt.compiler)
|
ksp(libs.hilt.compiler)
|
||||||
|
ksp(libs.androidx.room.compiler)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package hu.bbara.purefin.data.local.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Upsert
|
||||||
|
import hu.bbara.purefin.data.local.entity.EpisodeEntity
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface EpisodeDao {
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
suspend fun upsertEpisode(episode: EpisodeEntity)
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
suspend fun upsertEpisodes(episodes: List<EpisodeEntity>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM episodes WHERE id = :episodeId")
|
||||||
|
suspend fun deleteEpisode(episodeId: UUID)
|
||||||
|
|
||||||
|
@Query("DELETE FROM episodes WHERE seasonId = :seasonId")
|
||||||
|
suspend fun deleteEpisodesForSeason(seasonId: UUID)
|
||||||
|
|
||||||
|
@Query("DELETE FROM episodes WHERE seriesId = :seriesId")
|
||||||
|
suspend fun deleteEpisodesForSeries(seriesId: UUID)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM episodes WHERE id = :episodeId")
|
||||||
|
suspend fun getEpisodeById(episodeId: UUID): EpisodeEntity?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM episodes WHERE seasonId = :seasonId ORDER BY `index` ASC")
|
||||||
|
suspend fun getEpisodesForSeason(seasonId: UUID): List<EpisodeEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM episodes WHERE seriesId = :seriesId ORDER BY seasonId, `index` ASC")
|
||||||
|
suspend fun getEpisodesForSeries(seriesId: UUID): List<EpisodeEntity>
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package hu.bbara.purefin.data.local.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Transaction
|
||||||
|
import androidx.room.Upsert
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeasonEntity
|
||||||
|
import hu.bbara.purefin.data.local.relations.SeasonWithEpisodes
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface SeasonDao {
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
suspend fun upsertSeason(season: SeasonEntity)
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
suspend fun upsertSeasons(seasons: List<SeasonEntity>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM seasons WHERE id = :seasonId")
|
||||||
|
suspend fun deleteSeason(seasonId: UUID)
|
||||||
|
|
||||||
|
@Query("DELETE FROM seasons WHERE seriesId = :seriesId")
|
||||||
|
suspend fun deleteSeasonsForSeries(seriesId: UUID)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM seasons WHERE id = :seasonId")
|
||||||
|
suspend fun getSeasonWithEpisodes(seasonId: UUID): SeasonWithEpisodes?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM seasons WHERE id = :seasonId")
|
||||||
|
suspend fun getSeasonById(seasonId: UUID): SeasonEntity?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM seasons WHERE seriesId = :seriesId ORDER BY `index` ASC")
|
||||||
|
suspend fun getSeasonsForSeries(seriesId: UUID): List<SeasonEntity>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM seasons WHERE seriesId = :seriesId ORDER BY `index` ASC")
|
||||||
|
fun observeSeasonsWithEpisodes(seriesId: UUID): Flow<List<SeasonWithEpisodes>>
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package hu.bbara.purefin.data.local.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Transaction
|
||||||
|
import androidx.room.Upsert
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeriesEntity
|
||||||
|
import hu.bbara.purefin.data.local.relations.SeriesWithSeasonsAndEpisodes
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface SeriesDao {
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
suspend fun upsertSeries(series: SeriesEntity)
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
suspend fun upsertSeries(series: List<SeriesEntity>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM series WHERE id = :seriesId")
|
||||||
|
suspend fun deleteSeries(seriesId: UUID)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM series WHERE id = :seriesId")
|
||||||
|
suspend fun getSeriesWithContent(seriesId: UUID): SeriesWithSeasonsAndEpisodes?
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM series WHERE id = :seriesId")
|
||||||
|
fun observeSeriesWithContent(seriesId: UUID): Flow<SeriesWithSeasonsAndEpisodes?>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM series")
|
||||||
|
fun observeAllSeriesWithContent(): Flow<List<SeriesWithSeasonsAndEpisodes>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM series WHERE id = :seriesId")
|
||||||
|
suspend fun getSeriesById(seriesId: UUID): SeriesEntity?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM series")
|
||||||
|
fun observeSeriesEntities(): Flow<List<SeriesEntity>>
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package hu.bbara.purefin.data.local.db
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
import hu.bbara.purefin.data.local.dao.EpisodeDao
|
||||||
|
import hu.bbara.purefin.data.local.dao.SeasonDao
|
||||||
|
import hu.bbara.purefin.data.local.dao.SeriesDao
|
||||||
|
import hu.bbara.purefin.data.local.entity.EpisodeEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeasonEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeriesEntity
|
||||||
|
|
||||||
|
@Database(
|
||||||
|
entities = [SeriesEntity::class, SeasonEntity::class, EpisodeEntity::class],
|
||||||
|
version = 1,
|
||||||
|
exportSchema = false
|
||||||
|
)
|
||||||
|
@TypeConverters(PurefinTypeConverters::class)
|
||||||
|
abstract class PurefinDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
abstract fun seriesDao(): SeriesDao
|
||||||
|
|
||||||
|
abstract fun seasonDao(): SeasonDao
|
||||||
|
|
||||||
|
abstract fun episodeDao(): EpisodeDao
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package hu.bbara.purefin.data.local.db
|
||||||
|
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import hu.bbara.purefin.data.local.entity.EpisodeCastMemberEntity
|
||||||
|
import java.util.UUID
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
class PurefinTypeConverters {
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromUuid(value: UUID?): String? = value?.toString()
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toUuid(value: String?): UUID? = value?.let(UUID::fromString)
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromCastMembers(value: List<EpisodeCastMemberEntity>?): String? {
|
||||||
|
if (value.isNullOrEmpty()) return null
|
||||||
|
val jsonArray = JSONArray()
|
||||||
|
value.forEach { member ->
|
||||||
|
jsonArray.put(
|
||||||
|
JSONObject().apply {
|
||||||
|
put("name", member.name)
|
||||||
|
put("role", member.role)
|
||||||
|
put("imageUrl", member.imageUrl)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return jsonArray.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toCastMembers(value: String?): List<EpisodeCastMemberEntity> {
|
||||||
|
if (value.isNullOrBlank()) return emptyList()
|
||||||
|
val jsonArray = JSONArray(value)
|
||||||
|
val members = mutableListOf<EpisodeCastMemberEntity>()
|
||||||
|
for (index in 0 until jsonArray.length()) {
|
||||||
|
val jsonObject = jsonArray.optJSONObject(index) ?: continue
|
||||||
|
val imageUrl = when {
|
||||||
|
jsonObject.has("imageUrl") && !jsonObject.isNull("imageUrl") -> jsonObject.optString("imageUrl")
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
members += EpisodeCastMemberEntity(
|
||||||
|
name = jsonObject.optString("name"),
|
||||||
|
role = jsonObject.optString("role"),
|
||||||
|
imageUrl = imageUrl?.ifBlank { null }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package hu.bbara.purefin.data.local.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Room
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import hu.bbara.purefin.data.local.dao.EpisodeDao
|
||||||
|
import hu.bbara.purefin.data.local.dao.SeasonDao
|
||||||
|
import hu.bbara.purefin.data.local.dao.SeriesDao
|
||||||
|
import hu.bbara.purefin.data.local.db.PurefinDatabase
|
||||||
|
import hu.bbara.purefin.data.local.repository.LocalMediaRepository
|
||||||
|
import hu.bbara.purefin.data.local.repository.RoomLocalMediaRepository
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
object DatabaseModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDatabase(
|
||||||
|
@ApplicationContext context: Context
|
||||||
|
): PurefinDatabase {
|
||||||
|
return Room.databaseBuilder(
|
||||||
|
context,
|
||||||
|
PurefinDatabase::class.java,
|
||||||
|
"purefin.db"
|
||||||
|
).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideSeriesDao(database: PurefinDatabase): SeriesDao = database.seriesDao()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideSeasonDao(database: PurefinDatabase): SeasonDao = database.seasonDao()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideEpisodeDao(database: PurefinDatabase): EpisodeDao = database.episodeDao()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideLocalMediaRepository(
|
||||||
|
seriesDao: SeriesDao,
|
||||||
|
seasonDao: SeasonDao,
|
||||||
|
episodeDao: EpisodeDao
|
||||||
|
): LocalMediaRepository = RoomLocalMediaRepository(seriesDao, seasonDao, episodeDao)
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package hu.bbara.purefin.data.local.entity
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "episodes",
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = SeriesEntity::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["seriesId"],
|
||||||
|
onDelete = ForeignKey.CASCADE,
|
||||||
|
onUpdate = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = SeasonEntity::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["seasonId"],
|
||||||
|
onDelete = ForeignKey.CASCADE,
|
||||||
|
onUpdate = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
],
|
||||||
|
indices = [Index(value = ["seriesId"]), Index(value = ["seasonId"])]
|
||||||
|
)
|
||||||
|
data class EpisodeEntity(
|
||||||
|
@PrimaryKey val id: UUID,
|
||||||
|
val seriesId: UUID,
|
||||||
|
val seasonId: UUID,
|
||||||
|
val title: String,
|
||||||
|
val index: Int,
|
||||||
|
val releaseDate: String,
|
||||||
|
val rating: String,
|
||||||
|
val runtime: String,
|
||||||
|
val format: String,
|
||||||
|
val synopsis: String,
|
||||||
|
val heroImageUrl: String,
|
||||||
|
val cast: List<EpisodeCastMemberEntity>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class EpisodeCastMemberEntity(
|
||||||
|
val name: String,
|
||||||
|
val role: String,
|
||||||
|
val imageUrl: String?
|
||||||
|
)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package hu.bbara.purefin.data.local.entity
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "seasons",
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = SeriesEntity::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["seriesId"],
|
||||||
|
onDelete = ForeignKey.CASCADE,
|
||||||
|
onUpdate = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
],
|
||||||
|
indices = [Index(value = ["seriesId"])]
|
||||||
|
)
|
||||||
|
data class SeasonEntity(
|
||||||
|
@PrimaryKey val id: UUID,
|
||||||
|
val seriesId: UUID,
|
||||||
|
val name: String,
|
||||||
|
val index: Int,
|
||||||
|
val episodeCount: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package hu.bbara.purefin.data.local.entity
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Entity(tableName = "series")
|
||||||
|
data class SeriesEntity(
|
||||||
|
@PrimaryKey val id: UUID,
|
||||||
|
val name: String,
|
||||||
|
val synopsis: String,
|
||||||
|
val year: String,
|
||||||
|
val heroImageUrl: String,
|
||||||
|
val seasonCount: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package hu.bbara.purefin.data.local.relations
|
||||||
|
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
import hu.bbara.purefin.data.local.entity.EpisodeEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeasonEntity
|
||||||
|
|
||||||
|
data class SeasonWithEpisodes(
|
||||||
|
@Embedded val season: SeasonEntity,
|
||||||
|
@Relation(
|
||||||
|
parentColumn = "id",
|
||||||
|
entityColumn = "seasonId"
|
||||||
|
)
|
||||||
|
val episodes: List<EpisodeEntity>
|
||||||
|
)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package hu.bbara.purefin.data.local.relations
|
||||||
|
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeasonEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeriesEntity
|
||||||
|
|
||||||
|
data class SeriesWithSeasonsAndEpisodes(
|
||||||
|
@Embedded val series: SeriesEntity,
|
||||||
|
@Relation(
|
||||||
|
entity = SeasonEntity::class,
|
||||||
|
parentColumn = "id",
|
||||||
|
entityColumn = "seriesId"
|
||||||
|
)
|
||||||
|
val seasons: List<SeasonWithEpisodes>
|
||||||
|
)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package hu.bbara.purefin.data.local.repository
|
||||||
|
|
||||||
|
import hu.bbara.purefin.data.model.Episode
|
||||||
|
import hu.bbara.purefin.data.model.Season
|
||||||
|
import hu.bbara.purefin.data.model.Series
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface LocalMediaRepository {
|
||||||
|
|
||||||
|
suspend fun upsertSeries(series: Series)
|
||||||
|
|
||||||
|
suspend fun upsertSeries(seriesList: List<Series>)
|
||||||
|
|
||||||
|
suspend fun getSeries(seriesId: UUID, includeContent: Boolean = true): Series?
|
||||||
|
|
||||||
|
fun observeSeries(seriesId: UUID): Flow<Series?>
|
||||||
|
|
||||||
|
fun observeAllSeries(): Flow<List<Series>>
|
||||||
|
|
||||||
|
suspend fun deleteSeries(seriesId: UUID)
|
||||||
|
|
||||||
|
suspend fun upsertSeason(season: Season)
|
||||||
|
|
||||||
|
suspend fun upsertSeasons(seasons: List<Season>)
|
||||||
|
|
||||||
|
suspend fun getSeason(seasonId: UUID, includeEpisodes: Boolean = true): Season?
|
||||||
|
|
||||||
|
fun observeSeasons(seriesId: UUID): Flow<List<Season>>
|
||||||
|
|
||||||
|
suspend fun deleteSeason(seasonId: UUID)
|
||||||
|
|
||||||
|
suspend fun upsertEpisode(episode: Episode)
|
||||||
|
|
||||||
|
suspend fun upsertEpisodes(episodes: List<Episode>)
|
||||||
|
|
||||||
|
suspend fun getEpisode(episodeId: UUID): Episode?
|
||||||
|
|
||||||
|
suspend fun deleteEpisode(episodeId: UUID)
|
||||||
|
}
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
package hu.bbara.purefin.data.local.repository
|
||||||
|
|
||||||
|
import hu.bbara.purefin.app.content.episode.CastMember
|
||||||
|
import hu.bbara.purefin.data.local.dao.EpisodeDao
|
||||||
|
import hu.bbara.purefin.data.local.dao.SeasonDao
|
||||||
|
import hu.bbara.purefin.data.local.dao.SeriesDao
|
||||||
|
import hu.bbara.purefin.data.local.entity.EpisodeCastMemberEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.EpisodeEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeasonEntity
|
||||||
|
import hu.bbara.purefin.data.local.entity.SeriesEntity
|
||||||
|
import hu.bbara.purefin.data.local.relations.SeasonWithEpisodes
|
||||||
|
import hu.bbara.purefin.data.local.relations.SeriesWithSeasonsAndEpisodes
|
||||||
|
import hu.bbara.purefin.data.model.Episode
|
||||||
|
import hu.bbara.purefin.data.model.Season
|
||||||
|
import hu.bbara.purefin.data.model.Series
|
||||||
|
import java.util.UUID
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class RoomLocalMediaRepository @Inject constructor(
|
||||||
|
private val seriesDao: SeriesDao,
|
||||||
|
private val seasonDao: SeasonDao,
|
||||||
|
private val episodeDao: EpisodeDao
|
||||||
|
) : LocalMediaRepository {
|
||||||
|
|
||||||
|
override suspend fun upsertSeries(series: Series) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
seriesDao.upsertSeries(series.toEntity())
|
||||||
|
upsertSeasonsInternal(series.seasons)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertSeries(seriesList: List<Series>) {
|
||||||
|
if (seriesList.isEmpty()) return
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
seriesDao.upsertSeries(seriesList.map { it.toEntity() })
|
||||||
|
val seasons = seriesList.flatMap { it.seasons }
|
||||||
|
upsertSeasonsInternal(seasons)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSeries(seriesId: UUID, includeContent: Boolean): Series? {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
if (includeContent) {
|
||||||
|
seriesDao.getSeriesWithContent(seriesId)?.toDomain()
|
||||||
|
} else {
|
||||||
|
seriesDao.getSeriesById(seriesId)?.toDomain(emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun observeSeries(seriesId: UUID): Flow<Series?> {
|
||||||
|
return seriesDao.observeSeriesWithContent(seriesId).map { relation ->
|
||||||
|
relation?.toDomain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun observeAllSeries(): Flow<List<Series>> {
|
||||||
|
return seriesDao.observeAllSeriesWithContent().map { relations ->
|
||||||
|
relations.map { it.toDomain() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteSeries(seriesId: UUID) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
seriesDao.deleteSeries(seriesId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertSeason(season: Season) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
upsertSeasonsInternal(listOf(season))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertSeasons(seasons: List<Season>) {
|
||||||
|
if (seasons.isEmpty()) return
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
upsertSeasonsInternal(seasons)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSeason(seasonId: UUID, includeEpisodes: Boolean): Season? {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
if (includeEpisodes) {
|
||||||
|
seasonDao.getSeasonWithEpisodes(seasonId)?.toDomain()
|
||||||
|
} else {
|
||||||
|
seasonDao.getSeasonById(seasonId)?.toDomain(emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun observeSeasons(seriesId: UUID): Flow<List<Season>> {
|
||||||
|
return seasonDao.observeSeasonsWithEpisodes(seriesId).map { relations ->
|
||||||
|
relations.map { it.toDomain() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteSeason(seasonId: UUID) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
seasonDao.deleteSeason(seasonId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertEpisode(episode: Episode) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
episodeDao.upsertEpisode(episode.toEntity())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun upsertEpisodes(episodes: List<Episode>) {
|
||||||
|
if (episodes.isEmpty()) return
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
episodeDao.upsertEpisodes(episodes.map { it.toEntity() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getEpisode(episodeId: UUID): Episode? {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
episodeDao.getEpisodeById(episodeId)?.toDomain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteEpisode(episodeId: UUID) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
episodeDao.deleteEpisode(episodeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun upsertSeasonsInternal(seasons: List<Season>) {
|
||||||
|
if (seasons.isEmpty()) return
|
||||||
|
seasonDao.upsertSeasons(seasons.map { it.toEntity() })
|
||||||
|
val episodes = seasons.flatMap { it.episodes }
|
||||||
|
if (episodes.isNotEmpty()) {
|
||||||
|
episodeDao.upsertEpisodes(episodes.map { it.toEntity() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SeriesEntity.toDomain(seasons: List<Season>): Series = Series(
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
synopsis = synopsis,
|
||||||
|
year = year,
|
||||||
|
heroImageUrl = heroImageUrl,
|
||||||
|
seasonCount = seasonCount,
|
||||||
|
seasons = seasons
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun SeasonEntity.toDomain(episodes: List<Episode>): Season = Season(
|
||||||
|
id = id,
|
||||||
|
seriesId = seriesId,
|
||||||
|
name = name,
|
||||||
|
index = index,
|
||||||
|
episodeCount = episodeCount,
|
||||||
|
episodes = episodes
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun EpisodeEntity.toDomain(): Episode = Episode(
|
||||||
|
id = id,
|
||||||
|
seriesId = seriesId,
|
||||||
|
seasonId = seasonId,
|
||||||
|
title = title,
|
||||||
|
index = index,
|
||||||
|
releaseDate = releaseDate,
|
||||||
|
rating = rating,
|
||||||
|
runtime = runtime,
|
||||||
|
format = format,
|
||||||
|
synopsis = synopsis,
|
||||||
|
heroImageUrl = heroImageUrl,
|
||||||
|
cast = cast.map { it.toDomain() }
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun SeriesWithSeasonsAndEpisodes.toDomain(): Series =
|
||||||
|
series.toDomain(seasons.map { it.toDomain() })
|
||||||
|
|
||||||
|
private fun SeasonWithEpisodes.toDomain(): Season =
|
||||||
|
season.toDomain(episodes.map { it.toDomain() })
|
||||||
|
|
||||||
|
private fun Series.toEntity(): SeriesEntity = SeriesEntity(
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
synopsis = synopsis,
|
||||||
|
year = year,
|
||||||
|
heroImageUrl = heroImageUrl,
|
||||||
|
seasonCount = seasonCount
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Season.toEntity(): SeasonEntity = SeasonEntity(
|
||||||
|
id = id,
|
||||||
|
seriesId = seriesId,
|
||||||
|
name = name,
|
||||||
|
index = index,
|
||||||
|
episodeCount = episodeCount
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Episode.toEntity(): EpisodeEntity = EpisodeEntity(
|
||||||
|
id = id,
|
||||||
|
seriesId = seriesId,
|
||||||
|
seasonId = seasonId,
|
||||||
|
title = title,
|
||||||
|
index = index,
|
||||||
|
releaseDate = releaseDate,
|
||||||
|
rating = rating,
|
||||||
|
runtime = runtime,
|
||||||
|
format = format,
|
||||||
|
synopsis = synopsis,
|
||||||
|
heroImageUrl = heroImageUrl,
|
||||||
|
cast = cast.map { it.toEntity() }
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun EpisodeCastMemberEntity.toDomain(): CastMember = CastMember(
|
||||||
|
name = name,
|
||||||
|
role = role,
|
||||||
|
imageUrl = imageUrl
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun CastMember.toEntity(): EpisodeCastMemberEntity = EpisodeCastMemberEntity(
|
||||||
|
name = name,
|
||||||
|
role = role,
|
||||||
|
imageUrl = imageUrl
|
||||||
|
)
|
||||||
@@ -5,6 +5,8 @@ import java.util.UUID
|
|||||||
|
|
||||||
data class Episode(
|
data class Episode(
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
|
val seriesId: UUID,
|
||||||
|
val seasonId: UUID,
|
||||||
val title: String,
|
val title: String,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
val releaseDate: String,
|
val releaseDate: String,
|
||||||
@@ -13,6 +15,5 @@ data class Episode(
|
|||||||
val format: String,
|
val format: String,
|
||||||
val synopsis: String,
|
val synopsis: String,
|
||||||
val heroImageUrl: String,
|
val heroImageUrl: String,
|
||||||
val cast: List<CastMember>,
|
val cast: List<CastMember>
|
||||||
val season: Season,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import java.util.UUID
|
|||||||
|
|
||||||
data class Season(
|
data class Season(
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
|
val seriesId: UUID,
|
||||||
val name: String,
|
val name: String,
|
||||||
val index: Int,
|
val index: Int,
|
||||||
val episodeCount: Int,
|
val episodeCount: Int,
|
||||||
val episodes: List<Episode>,
|
val episodes: List<Episode>
|
||||||
val series: Series
|
)
|
||||||
)
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ foundation = "1.10.1"
|
|||||||
coil = "3.3.0"
|
coil = "3.3.0"
|
||||||
media3 = "1.9.0"
|
media3 = "1.9.0"
|
||||||
nav3Core = "1.0.0"
|
nav3Core = "1.0.0"
|
||||||
|
room = "2.6.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
@@ -54,6 +55,9 @@ medi3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media
|
|||||||
medi3-ui-compose = { group = "androidx.media3", name = "media3-ui-compose-material3", version.ref = "media3"}
|
medi3-ui-compose = { group = "androidx.media3", name = "media3-ui-compose-material3", version.ref = "media3"}
|
||||||
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
|
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
|
||||||
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }
|
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }
|
||||||
|
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
|
||||||
|
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
|
||||||
|
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
|
||||||
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
|||||||
Reference in New Issue
Block a user