refactor: modularize app into multi-module architecture

This commit is contained in:
2026-02-21 00:15:51 +01:00
parent 8601ef0236
commit 7333781f83
123 changed files with 668 additions and 404 deletions

2
.gitignore vendored
View File

@@ -9,7 +9,7 @@
/.idea/navEditor.xml /.idea/navEditor.xml
/.idea/assetWizardSettings.xml /.idea/assetWizardSettings.xml
.DS_Store .DS_Store
/build **/build
/captures /captures
.externalNativeBuild .externalNativeBuild
.cxx .cxx

View File

@@ -47,6 +47,11 @@ kotlin {
} }
dependencies { dependencies {
implementation(project(":core:model"))
implementation(project(":core:data"))
implementation(project(":feature:download"))
implementation(project(":core:player"))
implementation(project(":feature:shared"))
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.lifecycle.viewmodel.compose)

View File

@@ -33,7 +33,7 @@
android:exported="false" android:exported="false"
android:theme="@style/Theme.Purefin" /> android:theme="@style/Theme.Purefin" />
<service <service
android:name=".download.PurefinDownloadService" android:name="hu.bbara.purefin.feature.download.PurefinDownloadService"
android:exported="false" android:exported="false"
android:foregroundServiceType="dataSync" /> android:foregroundServiceType="dataSync" />
</application> </application>

View File

@@ -31,15 +31,15 @@ import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import coil3.request.crossfade import coil3.request.crossfade
import coil3.util.DebugLogger import coil3.util.DebugLogger
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import hu.bbara.purefin.client.JellyfinApiClient
import hu.bbara.purefin.client.JellyfinAuthInterceptor
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.core.data.client.JellyfinApiClient
import hu.bbara.purefin.core.data.client.JellyfinAuthInterceptor
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
import hu.bbara.purefin.core.data.navigation.NavigationCommand
import hu.bbara.purefin.core.data.navigation.NavigationManager
import hu.bbara.purefin.core.data.navigation.Route
import hu.bbara.purefin.core.data.session.UserSessionRepository
import hu.bbara.purefin.login.ui.LoginScreen import hu.bbara.purefin.login.ui.LoginScreen
import hu.bbara.purefin.navigation.LocalNavigationManager
import hu.bbara.purefin.navigation.NavigationCommand
import hu.bbara.purefin.navigation.NavigationManager
import hu.bbara.purefin.navigation.Route
import hu.bbara.purefin.session.UserSessionRepository
import hu.bbara.purefin.ui.theme.AppTheme import hu.bbara.purefin.ui.theme.AppTheme
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.OkHttpClient import okhttp3.OkHttpClient

View File

@@ -1,14 +1,14 @@
package hu.bbara.purefin.app.content package hu.bbara.purefin.app.content
import hu.bbara.purefin.app.content.episode.EpisodeUiModel import hu.bbara.purefin.feature.shared.content.episode.EpisodeUiModel
import hu.bbara.purefin.app.content.movie.MovieUiModel import hu.bbara.purefin.feature.shared.content.movie.MovieUiModel
import hu.bbara.purefin.app.content.series.SeriesCastMemberUiModel import hu.bbara.purefin.feature.shared.content.series.SeriesCastMemberUiModel
import hu.bbara.purefin.app.content.series.SeriesEpisodeUiModel import hu.bbara.purefin.feature.shared.content.series.SeriesEpisodeUiModel
import hu.bbara.purefin.app.content.series.SeriesSeasonUiModel import hu.bbara.purefin.feature.shared.content.series.SeriesSeasonUiModel
import hu.bbara.purefin.app.content.series.SeriesUiModel import hu.bbara.purefin.feature.shared.content.series.SeriesUiModel
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
import hu.bbara.purefin.app.content.episode.CastMember as EpisodeCastMember import hu.bbara.purefin.feature.shared.content.episode.CastMember as EpisodeCastMember
import hu.bbara.purefin.app.content.movie.CastMember as MovieCastMember import hu.bbara.purefin.feature.shared.content.movie.CastMember as MovieCastMember
object ContentMockData { object ContentMockData {
fun series(): SeriesUiModel { fun series(): SeriesUiModel {

View File

@@ -37,7 +37,7 @@ import hu.bbara.purefin.common.ui.components.GhostIconButton
import hu.bbara.purefin.common.ui.components.MediaActionButton import hu.bbara.purefin.common.ui.components.MediaActionButton
import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings
import hu.bbara.purefin.common.ui.components.MediaResumeButton import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.player.PlayerActivity import hu.bbara.purefin.player.PlayerActivity
@Composable @Composable

View File

@@ -16,8 +16,9 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaHero import hu.bbara.purefin.common.ui.components.MediaHero
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.data.navigation.EpisodeDto
import hu.bbara.purefin.navigation.EpisodeDto import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.feature.shared.content.episode.EpisodeScreenViewModel
@Composable @Composable
fun EpisodeScreen( fun EpisodeScreen(

View File

@@ -39,7 +39,8 @@ import hu.bbara.purefin.common.ui.components.GhostIconButton
import hu.bbara.purefin.common.ui.components.MediaActionButton import hu.bbara.purefin.common.ui.components.MediaActionButton
import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings
import hu.bbara.purefin.common.ui.components.MediaResumeButton import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.download.DownloadState import hu.bbara.purefin.feature.download.DownloadState
import hu.bbara.purefin.feature.shared.content.movie.MovieUiModel
import hu.bbara.purefin.player.PlayerActivity import hu.bbara.purefin.player.PlayerActivity
@Composable @Composable

View File

@@ -22,8 +22,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.app.content.ContentMockData import hu.bbara.purefin.app.content.ContentMockData
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaHero import hu.bbara.purefin.common.ui.components.MediaHero
import hu.bbara.purefin.download.DownloadState import hu.bbara.purefin.core.data.navigation.MovieDto
import hu.bbara.purefin.navigation.MovieDto import hu.bbara.purefin.feature.download.DownloadState
import hu.bbara.purefin.feature.shared.content.movie.MovieScreenViewModel
import hu.bbara.purefin.feature.shared.content.movie.MovieUiModel
@Composable @Composable
fun MovieScreen( fun MovieScreen(

View File

@@ -53,10 +53,11 @@ import hu.bbara.purefin.common.ui.components.MediaActionButton
import hu.bbara.purefin.common.ui.components.MediaProgressBar import hu.bbara.purefin.common.ui.components.MediaProgressBar
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.common.ui.components.WatchStateIndicator import hu.bbara.purefin.common.ui.components.WatchStateIndicator
import hu.bbara.purefin.data.model.CastMember import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Season import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.Series
import hu.bbara.purefin.feature.shared.content.series.SeriesViewModel
@Composable @Composable
internal fun SeriesTopBar( internal fun SeriesTopBar(

View File

@@ -24,9 +24,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.MediaSynopsis import hu.bbara.purefin.common.ui.MediaSynopsis
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaHero import hu.bbara.purefin.common.ui.components.MediaHero
import hu.bbara.purefin.data.model.Season import hu.bbara.purefin.core.data.navigation.SeriesDto
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.navigation.SeriesDto import hu.bbara.purefin.core.model.Series
import hu.bbara.purefin.feature.shared.content.series.SeriesViewModel
@Composable @Composable
fun SeriesScreen( fun SeriesScreen(

View File

@@ -1,7 +1,7 @@
package hu.bbara.purefin.app.home package hu.bbara.purefin.app.home
import androidx.navigation3.runtime.EntryProviderScope import androidx.navigation3.runtime.EntryProviderScope
import hu.bbara.purefin.navigation.Route import hu.bbara.purefin.core.data.navigation.Route
/** /**
* Navigation 3 entry definition for the Home section. * Navigation 3 entry definition for the Home section.

View File

@@ -25,6 +25,7 @@ import hu.bbara.purefin.app.home.ui.HomeDrawerContent
import hu.bbara.purefin.app.home.ui.HomeMockData import hu.bbara.purefin.app.home.ui.HomeMockData
import hu.bbara.purefin.app.home.ui.HomeNavItem import hu.bbara.purefin.app.home.ui.HomeNavItem
import hu.bbara.purefin.app.home.ui.HomeTopBar import hu.bbara.purefin.app.home.ui.HomeTopBar
import hu.bbara.purefin.feature.shared.home.HomePageViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.CollectionType
@@ -74,7 +75,7 @@ fun HomePage(
primaryNavItems = libraryNavItems, primaryNavItems = libraryNavItems,
secondaryNavItems = HomeMockData.secondaryNavItems, secondaryNavItems = HomeMockData.secondaryNavItems,
user = HomeMockData.user, user = HomeMockData.user,
onLibrarySelected = viewModel::onLibrarySelected, onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.label) },
onLogout = viewModel::logout onLogout = viewModel::logout
) )
} }

View File

@@ -10,6 +10,10 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.feature.shared.home.ContinueWatchingItem
import hu.bbara.purefin.feature.shared.home.LibraryItem
import hu.bbara.purefin.feature.shared.home.NextUpItem
import hu.bbara.purefin.feature.shared.home.PosterItem
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
@Composable @Composable

View File

@@ -1,85 +1,7 @@
package hu.bbara.purefin.app.home.ui package hu.bbara.purefin.app.home.ui
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import hu.bbara.purefin.data.model.Episode
import hu.bbara.purefin.data.model.Movie
import hu.bbara.purefin.data.model.Series
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
data class ContinueWatchingItem(
val type: BaseItemKind,
val movie: Movie? = null,
val episode: Episode? = null
) {
val id: UUID = when (type) {
BaseItemKind.MOVIE -> movie!!.id
BaseItemKind.EPISODE -> episode!!.id
else -> throw UnsupportedOperationException("Unsupported item type: $type")
}
val primaryText: String = when (type) {
BaseItemKind.MOVIE -> movie!!.title
BaseItemKind.EPISODE -> episode!!.title
else -> throw UnsupportedOperationException("Unsupported item type: $type")
}
val secondaryText: String = when (type) {
BaseItemKind.MOVIE -> movie!!.year
BaseItemKind.EPISODE -> episode!!.releaseDate
else -> throw UnsupportedOperationException("Unsupported item type: $type")
}
val progress: Double = when (type) {
BaseItemKind.MOVIE -> movie!!.progress ?: 0.0
BaseItemKind.EPISODE -> episode!!.progress ?: 0.0
else -> throw UnsupportedOperationException("Unsupported item type: $type")
}
}
data class NextUpItem(
val episode: Episode
) {
val id: UUID = episode.id
val primaryText: String = episode.title
val secondaryText: String = episode.releaseDate
}
data class LibraryItem(
val id: UUID,
val name: String,
val type: CollectionType,
val isEmpty: Boolean
)
data class PosterItem(
val type: BaseItemKind,
val movie: Movie? = null,
val series: Series? = null,
val episode: Episode? = null
) {
val id: UUID = when (type) {
BaseItemKind.MOVIE -> movie!!.id
BaseItemKind.EPISODE -> episode!!.id
BaseItemKind.SERIES -> series!!.id
else -> throw IllegalArgumentException("Invalid type: $type")
}
val title: String = when (type) {
BaseItemKind.MOVIE -> movie!!.title
BaseItemKind.EPISODE -> episode!!.title
BaseItemKind.SERIES -> series!!.name
else -> throw IllegalArgumentException("Invalid type: $type")
}
val imageUrl: String = when (type) {
BaseItemKind.MOVIE -> movie!!.heroImageUrl
BaseItemKind.EPISODE -> episode!!.heroImageUrl
BaseItemKind.SERIES -> series!!.heroImageUrl
else -> throw IllegalArgumentException("Invalid type: $type")
}
fun watched() = when (type) {
BaseItemKind.MOVIE -> movie!!.watched
BaseItemKind.EPISODE -> episode!!.watched
else -> throw IllegalArgumentException("Invalid type: $type")
}
}
data class HomeNavItem( data class HomeNavItem(
val id: UUID, val id: UUID,

View File

@@ -40,6 +40,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil3.request.ImageRequest import coil3.request.ImageRequest
import hu.bbara.purefin.common.ui.PosterCard import hu.bbara.purefin.common.ui.PosterCard
import hu.bbara.purefin.feature.shared.home.ContinueWatchingItem
import hu.bbara.purefin.feature.shared.home.NextUpItem
import hu.bbara.purefin.feature.shared.home.PosterItem
import hu.bbara.purefin.common.ui.components.MediaProgressBar import hu.bbara.purefin.common.ui.components.MediaProgressBar
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.player.PlayerActivity import hu.bbara.purefin.player.PlayerActivity

View File

@@ -21,11 +21,11 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.app.home.ui.PosterItem
import hu.bbara.purefin.app.library.LibraryViewModel
import hu.bbara.purefin.common.ui.PosterCard import hu.bbara.purefin.common.ui.PosterCard
import hu.bbara.purefin.common.ui.components.PurefinIconButton import hu.bbara.purefin.common.ui.components.PurefinIconButton
import hu.bbara.purefin.navigation.LibraryDto import hu.bbara.purefin.core.data.navigation.LibraryDto
import hu.bbara.purefin.feature.shared.home.PosterItem
import hu.bbara.purefin.feature.shared.library.LibraryViewModel
@Composable @Composable
fun LibraryScreen( fun LibraryScreen(

View File

@@ -34,7 +34,7 @@ import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.data.model.CastMember import hu.bbara.purefin.core.model.CastMember
@Composable @Composable
fun MediaMetaChip( fun MediaMetaChip(

View File

@@ -23,10 +23,10 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil3.request.ImageRequest import coil3.request.ImageRequest
import hu.bbara.purefin.app.home.ui.PosterItem
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.common.ui.components.UnwatchedEpisodeIndicator import hu.bbara.purefin.common.ui.components.UnwatchedEpisodeIndicator
import hu.bbara.purefin.common.ui.components.WatchStateIndicator import hu.bbara.purefin.common.ui.components.WatchStateIndicator
import hu.bbara.purefin.feature.shared.home.PosterItem
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
@@ -49,11 +49,10 @@ fun PosterCard(
when (posterItem.type) { when (posterItem.type) {
BaseItemKind.MOVIE -> onMovieSelected(posterItem.id) BaseItemKind.MOVIE -> onMovieSelected(posterItem.id)
BaseItemKind.SERIES -> onSeriesSelected(posterItem.id) BaseItemKind.SERIES -> onSeriesSelected(posterItem.id)
BaseItemKind.EPISODE -> onEpisodeSelected( BaseItemKind.EPISODE -> {
posterItem.episode!!.seriesId, val ep = posterItem.episode!!
posterItem.episode.seasonId, onEpisodeSelected(ep.seriesId, ep.seasonId, ep.id)
posterItem.episode.id }
)
else -> {} else -> {}
} }
} }
@@ -79,20 +78,26 @@ fun PosterCard(
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
when (item.type) { when (item.type) {
BaseItemKind.MOVIE -> WatchStateIndicator( BaseItemKind.MOVIE -> {
val m = item.movie!!
WatchStateIndicator(
size = 28, size = 28,
modifier = Modifier.align(Alignment.TopEnd) modifier = Modifier.align(Alignment.TopEnd)
.padding(8.dp), .padding(8.dp),
watched = item.movie!!.watched, watched = m.watched,
started = (item.movie.progress ?: 0.0) > 0 started = (m.progress ?: 0.0) > 0
) )
BaseItemKind.EPISODE -> WatchStateIndicator( }
BaseItemKind.EPISODE -> {
val ep = item.episode!!
WatchStateIndicator(
size = 28, size = 28,
modifier = Modifier.align(Alignment.TopEnd) modifier = Modifier.align(Alignment.TopEnd)
.padding(8.dp), .padding(8.dp),
watched = item.episode!!.watched, watched = ep.watched,
started = (item.episode.progress ?: 0.0) > 0 started = (ep.progress ?: 0.0) > 0
) )
}
BaseItemKind.SERIES -> UnwatchedEpisodeIndicator( BaseItemKind.SERIES -> UnwatchedEpisodeIndicator(
size = 28, size = 28,
modifier = Modifier.align(Alignment.TopEnd) modifier = Modifier.align(Alignment.TopEnd)

View File

@@ -41,7 +41,7 @@ import hu.bbara.purefin.common.ui.PurefinComplexTextField
import hu.bbara.purefin.common.ui.PurefinPasswordField import hu.bbara.purefin.common.ui.PurefinPasswordField
import hu.bbara.purefin.common.ui.PurefinTextButton import hu.bbara.purefin.common.ui.PurefinTextButton
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.login.viewmodel.LoginViewModel import hu.bbara.purefin.feature.shared.login.LoginViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable

View File

@@ -6,6 +6,7 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.multibindings.IntoSet import dagger.multibindings.IntoSet
import hu.bbara.purefin.core.data.navigation.Route
@Module @Module
@InstallIn(ActivityRetainedComponent::class) @InstallIn(ActivityRetainedComponent::class)

View File

@@ -6,6 +6,7 @@ import hu.bbara.purefin.app.content.movie.MovieScreen
import hu.bbara.purefin.app.content.series.SeriesScreen import hu.bbara.purefin.app.content.series.SeriesScreen
import hu.bbara.purefin.app.home.HomePage import hu.bbara.purefin.app.home.HomePage
import hu.bbara.purefin.app.library.ui.LibraryScreen import hu.bbara.purefin.app.library.ui.LibraryScreen
import hu.bbara.purefin.core.data.navigation.Route
import hu.bbara.purefin.login.ui.LoginScreen import hu.bbara.purefin.login.ui.LoginScreen
fun EntryProviderScope<Route>.appRouteEntryBuilder() { fun EntryProviderScope<Route>.appRouteEntryBuilder() {

View File

@@ -11,8 +11,8 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import hu.bbara.purefin.core.player.viewmodel.PlayerViewModel
import hu.bbara.purefin.player.ui.PlayerScreen import hu.bbara.purefin.player.ui.PlayerScreen
import hu.bbara.purefin.player.viewmodel.PlayerViewModel
import hu.bbara.purefin.ui.theme.AppTheme import hu.bbara.purefin.ui.theme.AppTheme
@AndroidEntryPoint @AndroidEntryPoint

View File

@@ -1,4 +0,0 @@
package hu.bbara.purefin.player.stream
class MediaSourceSelector {
}

View File

@@ -39,6 +39,7 @@ import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import hu.bbara.purefin.common.ui.components.EmptyValueTimedVisibility import hu.bbara.purefin.common.ui.components.EmptyValueTimedVisibility
import hu.bbara.purefin.common.ui.components.ValueChangeTimedVisibility import hu.bbara.purefin.common.ui.components.ValueChangeTimedVisibility
import hu.bbara.purefin.core.player.viewmodel.PlayerViewModel
import hu.bbara.purefin.player.ui.components.PersistentOverlayContainer import hu.bbara.purefin.player.ui.components.PersistentOverlayContainer
import hu.bbara.purefin.player.ui.components.PlayerAdjustmentIndicator import hu.bbara.purefin.player.ui.components.PlayerAdjustmentIndicator
import hu.bbara.purefin.player.ui.components.PlayerControlsOverlay import hu.bbara.purefin.player.ui.components.PlayerControlsOverlay
@@ -46,7 +47,6 @@ import hu.bbara.purefin.player.ui.components.PlayerGesturesLayer
import hu.bbara.purefin.player.ui.components.PlayerLoadingErrorEndCard import hu.bbara.purefin.player.ui.components.PlayerLoadingErrorEndCard
import hu.bbara.purefin.player.ui.components.PlayerQueuePanel import hu.bbara.purefin.player.ui.components.PlayerQueuePanel
import hu.bbara.purefin.player.ui.components.rememberPersistentOverlayController import hu.bbara.purefin.player.ui.components.rememberPersistentOverlayController
import hu.bbara.purefin.player.viewmodel.PlayerViewModel
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.roundToInt import kotlin.math.roundToInt

View File

@@ -37,8 +37,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.common.ui.components.GhostIconButton import hu.bbara.purefin.common.ui.components.GhostIconButton
import hu.bbara.purefin.common.ui.components.PurefinIconButton import hu.bbara.purefin.common.ui.components.PurefinIconButton
import hu.bbara.purefin.player.model.PlayerUiState import hu.bbara.purefin.core.player.model.PlayerUiState
import hu.bbara.purefin.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
@Composable @Composable
fun PlayerControlsOverlay( fun PlayerControlsOverlay(

View File

@@ -19,7 +19,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.player.model.PlayerUiState import hu.bbara.purefin.core.player.model.PlayerUiState
@Composable @Composable
fun PlayerLoadingErrorEndCard( fun PlayerLoadingErrorEndCard(

View File

@@ -31,7 +31,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.player.model.PlayerUiState import hu.bbara.purefin.core.player.model.PlayerUiState
@Composable @Composable
fun PlayerQueuePanel( fun PlayerQueuePanel(

View File

@@ -16,8 +16,8 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.player.model.MarkerType import hu.bbara.purefin.core.player.model.MarkerType
import hu.bbara.purefin.player.model.TimedMarker import hu.bbara.purefin.core.player.model.TimedMarker
@Composable @Composable
fun PlayerSeekBar( fun PlayerSeekBar(

View File

@@ -27,7 +27,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import hu.bbara.purefin.common.ui.components.PurefinIconButton import hu.bbara.purefin.common.ui.components.PurefinIconButton
import hu.bbara.purefin.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
@Composable @Composable
fun QualitySelectionButton( fun QualitySelectionButton(

View File

@@ -1,8 +1,10 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.ksp) apply false alias(libs.plugins.ksp) apply false
alias(libs.plugins.hilt) apply false alias(libs.plugins.hilt) apply false
} }

View File

@@ -0,0 +1,52 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
}
android {
namespace = "hu.bbara.purefin.core.data"
compileSdk = 36
defaultConfig {
minSdk = 29
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures {
compose = true
}
}
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
dependencies {
implementation(project(":core:model"))
implementation(libs.jellyfin.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.hilt)
ksp(libs.hilt.compiler)
implementation(libs.datastore)
implementation(libs.okhttp)
implementation(libs.logging.interceptor)
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.navigation3.runtime)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
}

View File

@@ -1,13 +1,14 @@
package hu.bbara.purefin.data package hu.bbara.purefin.core.data
import hu.bbara.purefin.data.local.room.OfflineRepository import hu.bbara.purefin.core.data.local.room.OfflineRepository
import hu.bbara.purefin.data.local.room.OnlineRepository import hu.bbara.purefin.core.data.local.room.OnlineRepository
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.data.session.UserSessionRepository
import hu.bbara.purefin.data.model.Library import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Media import hu.bbara.purefin.core.model.Library
import hu.bbara.purefin.data.model.Movie import hu.bbara.purefin.core.model.Media
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.MediaRepositoryState
import hu.bbara.purefin.session.UserSessionRepository import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.core.model.Series
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi

View File

@@ -1,20 +1,21 @@
package hu.bbara.purefin.data package hu.bbara.purefin.core.data
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import hu.bbara.purefin.client.JellyfinApiClient import hu.bbara.purefin.core.data.cache.CachedMediaItem
import hu.bbara.purefin.data.cache.CachedMediaItem import hu.bbara.purefin.core.data.cache.HomeCache
import hu.bbara.purefin.data.cache.HomeCache import hu.bbara.purefin.core.data.client.JellyfinApiClient
import hu.bbara.purefin.data.local.room.OfflineDatabase import hu.bbara.purefin.core.data.image.JellyfinImageHelper
import hu.bbara.purefin.data.local.room.OfflineRoomMediaLocalDataSource import hu.bbara.purefin.core.data.local.room.OfflineDatabase
import hu.bbara.purefin.data.local.room.RoomMediaLocalDataSource import hu.bbara.purefin.core.data.local.room.OfflineRoomMediaLocalDataSource
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.data.local.room.RoomMediaLocalDataSource
import hu.bbara.purefin.data.model.Library import hu.bbara.purefin.core.data.session.UserSessionRepository
import hu.bbara.purefin.data.model.Media import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Movie import hu.bbara.purefin.core.model.Library
import hu.bbara.purefin.data.model.Season import hu.bbara.purefin.core.model.Media
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.MediaRepositoryState
import hu.bbara.purefin.image.JellyfinImageHelper import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.session.UserSessionRepository import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.core.model.Series
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View File

@@ -1,10 +1,11 @@
package hu.bbara.purefin.data package hu.bbara.purefin.core.data
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Library import hu.bbara.purefin.core.model.Library
import hu.bbara.purefin.data.model.Media import hu.bbara.purefin.core.model.Media
import hu.bbara.purefin.data.model.Movie import hu.bbara.purefin.core.model.MediaRepositoryState
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.core.model.Series
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import java.util.UUID import java.util.UUID

View File

@@ -1,11 +1,11 @@
package hu.bbara.purefin.data package hu.bbara.purefin.core.data
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import hu.bbara.purefin.data.local.room.OnlineRepository import hu.bbara.purefin.core.data.local.room.OfflineRepository
import hu.bbara.purefin.data.local.room.OfflineRepository import hu.bbara.purefin.core.data.local.room.OnlineRepository
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)

View File

@@ -1,12 +1,13 @@
package hu.bbara.purefin.data package hu.bbara.purefin.core.data
import hu.bbara.purefin.data.local.room.OfflineDatabase import hu.bbara.purefin.core.data.local.room.OfflineDatabase
import hu.bbara.purefin.data.local.room.OfflineRoomMediaLocalDataSource import hu.bbara.purefin.core.data.local.room.OfflineRoomMediaLocalDataSource
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Library import hu.bbara.purefin.core.model.Library
import hu.bbara.purefin.data.model.Media import hu.bbara.purefin.core.model.Media
import hu.bbara.purefin.data.model.Movie import hu.bbara.purefin.core.model.MediaRepositoryState
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.core.model.Series
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.cache package hu.bbara.purefin.core.data.cache
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.cache package hu.bbara.purefin.core.data.cache
import android.content.Context import android.content.Context
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.cache package hu.bbara.purefin.core.data.cache
import androidx.datastore.core.CorruptionException import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer import androidx.datastore.core.Serializer

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.client package hu.bbara.purefin.core.data.client
import android.media.MediaCodecList import android.media.MediaCodecList
import android.util.Log import android.util.Log

View File

@@ -1,6 +1,5 @@
package hu.bbara.purefin.client package hu.bbara.purefin.core.data.client
import android.media.MediaCodecInfo
import android.media.MediaCodecList import android.media.MediaCodecList
import android.util.Log import android.util.Log

View File

@@ -1,9 +1,9 @@
package hu.bbara.purefin.client package hu.bbara.purefin.core.data.client
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import hu.bbara.purefin.session.UserSessionRepository import hu.bbara.purefin.core.data.session.UserSessionRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext

View File

@@ -1,6 +1,6 @@
package hu.bbara.purefin.client package hu.bbara.purefin.core.data.client
import hu.bbara.purefin.session.UserSessionRepository import hu.bbara.purefin.core.data.session.UserSessionRepository
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob

View File

@@ -1,6 +1,6 @@
package hu.bbara.purefin.domain.usecase package hu.bbara.purefin.core.data.domain.usecase
import hu.bbara.purefin.data.MediaRepository import hu.bbara.purefin.core.data.MediaRepository
import javax.inject.Inject import javax.inject.Inject
class RefreshHomeDataUseCase @Inject constructor( class RefreshHomeDataUseCase @Inject constructor(

View File

@@ -1,6 +1,6 @@
package hu.bbara.purefin.domain.usecase package hu.bbara.purefin.core.data.domain.usecase
import hu.bbara.purefin.data.MediaRepository import hu.bbara.purefin.core.data.MediaRepository
import java.util.UUID import java.util.UUID
import javax.inject.Inject import javax.inject.Inject

View File

@@ -1,10 +1,10 @@
package hu.bbara.purefin.image package hu.bbara.purefin.core.data.image
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import hu.bbara.purefin.client.JellyfinAuthInterceptor import hu.bbara.purefin.core.data.client.JellyfinAuthInterceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import javax.inject.Singleton import javax.inject.Singleton

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.image package hu.bbara.purefin.core.data.image
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.ImageType

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Index import androidx.room.Index

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import javax.inject.Qualifier import javax.inject.Qualifier

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey

View File

@@ -1,14 +1,15 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import hu.bbara.purefin.data.local.room.dao.CastMemberDao import hu.bbara.purefin.core.data.local.room.dao.CastMemberDao
import hu.bbara.purefin.data.local.room.dao.EpisodeDao import hu.bbara.purefin.core.data.local.room.dao.EpisodeDao
import hu.bbara.purefin.data.local.room.dao.MovieDao import hu.bbara.purefin.core.data.local.room.dao.LibraryDao
import hu.bbara.purefin.data.local.room.dao.SeasonDao import hu.bbara.purefin.core.data.local.room.dao.MovieDao
import hu.bbara.purefin.data.local.room.dao.SeriesDao import hu.bbara.purefin.core.data.local.room.dao.SeasonDao
import hu.bbara.purefin.data.local.room.dao.LibraryDao import hu.bbara.purefin.core.data.local.room.dao.SeriesDao
@Database( @Database(
entities = [ entities = [
MovieEntity::class, MovieEntity::class,

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
@@ -7,12 +7,12 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import hu.bbara.purefin.data.local.room.dao.CastMemberDao import hu.bbara.purefin.core.data.local.room.dao.CastMemberDao
import hu.bbara.purefin.data.local.room.dao.EpisodeDao import hu.bbara.purefin.core.data.local.room.dao.EpisodeDao
import hu.bbara.purefin.data.local.room.dao.LibraryDao import hu.bbara.purefin.core.data.local.room.dao.LibraryDao
import hu.bbara.purefin.data.local.room.dao.MovieDao import hu.bbara.purefin.core.data.local.room.dao.MovieDao
import hu.bbara.purefin.data.local.room.dao.SeasonDao import hu.bbara.purefin.core.data.local.room.dao.SeasonDao
import hu.bbara.purefin.data.local.room.dao.SeriesDao import hu.bbara.purefin.core.data.local.room.dao.SeriesDao
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey

View File

@@ -1,14 +1,14 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import hu.bbara.purefin.data.local.room.dao.CastMemberDao import hu.bbara.purefin.core.data.local.room.dao.CastMemberDao
import hu.bbara.purefin.data.local.room.dao.EpisodeDao import hu.bbara.purefin.core.data.local.room.dao.EpisodeDao
import hu.bbara.purefin.data.local.room.dao.MovieDao import hu.bbara.purefin.core.data.local.room.dao.LibraryDao
import hu.bbara.purefin.data.local.room.dao.SeasonDao import hu.bbara.purefin.core.data.local.room.dao.MovieDao
import hu.bbara.purefin.data.local.room.dao.SeriesDao import hu.bbara.purefin.core.data.local.room.dao.SeasonDao
import hu.bbara.purefin.data.local.room.dao.LibraryDao import hu.bbara.purefin.core.data.local.room.dao.SeriesDao
@Database( @Database(
entities = [ entities = [

View File

@@ -1,23 +1,22 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.withTransaction import androidx.room.withTransaction
import hu.bbara.purefin.data.local.room.dao.CastMemberDao import hu.bbara.purefin.core.data.local.room.dao.CastMemberDao
import hu.bbara.purefin.data.local.room.dao.EpisodeDao import hu.bbara.purefin.core.data.local.room.dao.EpisodeDao
import hu.bbara.purefin.data.local.room.dao.LibraryDao import hu.bbara.purefin.core.data.local.room.dao.LibraryDao
import hu.bbara.purefin.data.local.room.dao.MovieDao import hu.bbara.purefin.core.data.local.room.dao.MovieDao
import hu.bbara.purefin.data.local.room.dao.SeasonDao import hu.bbara.purefin.core.data.local.room.dao.SeasonDao
import hu.bbara.purefin.data.local.room.dao.SeriesDao import hu.bbara.purefin.core.data.local.room.dao.SeriesDao
import hu.bbara.purefin.data.model.CastMember import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Library import hu.bbara.purefin.core.model.Library
import hu.bbara.purefin.data.model.Movie import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.data.model.Season import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.Series
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.CollectionType
import java.util.UUID import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton

View File

@@ -1,24 +1,23 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.withTransaction import androidx.room.withTransaction
import hu.bbara.purefin.data.local.room.dao.CastMemberDao import hu.bbara.purefin.core.data.local.room.dao.CastMemberDao
import hu.bbara.purefin.data.local.room.dao.EpisodeDao import hu.bbara.purefin.core.data.local.room.dao.EpisodeDao
import hu.bbara.purefin.data.local.room.dao.LibraryDao import hu.bbara.purefin.core.data.local.room.dao.LibraryDao
import hu.bbara.purefin.data.local.room.dao.MovieDao import hu.bbara.purefin.core.data.local.room.dao.MovieDao
import hu.bbara.purefin.data.local.room.dao.SeasonDao import hu.bbara.purefin.core.data.local.room.dao.SeasonDao
import hu.bbara.purefin.data.local.room.dao.SeriesDao import hu.bbara.purefin.core.data.local.room.dao.SeriesDao
import hu.bbara.purefin.data.model.CastMember import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.data.model.Library import hu.bbara.purefin.core.model.Library
import hu.bbara.purefin.data.model.Movie import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.data.model.Season import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.data.model.Series import hu.bbara.purefin.core.model.Series
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.CollectionType
import java.util.UUID import java.util.UUID
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.collections.map
@Singleton @Singleton
class RoomMediaLocalDataSource( class RoomMediaLocalDataSource(

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Relation import androidx.room.Relation

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.local.room package hu.bbara.purefin.core.data.local.room
import androidx.room.TypeConverter import androidx.room.TypeConverter
import java.util.UUID import java.util.UUID

View File

@@ -1,9 +1,9 @@
package hu.bbara.purefin.data.local.room.dao package hu.bbara.purefin.core.data.local.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import androidx.room.Upsert import androidx.room.Upsert
import hu.bbara.purefin.data.local.room.CastMemberEntity import hu.bbara.purefin.core.data.local.room.CastMemberEntity
import java.util.UUID import java.util.UUID
@Dao @Dao

View File

@@ -1,9 +1,9 @@
package hu.bbara.purefin.data.local.room.dao package hu.bbara.purefin.core.data.local.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import androidx.room.Upsert import androidx.room.Upsert
import hu.bbara.purefin.data.local.room.EpisodeEntity import hu.bbara.purefin.core.data.local.room.EpisodeEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import java.util.UUID import java.util.UUID

View File

@@ -1,10 +1,10 @@
package hu.bbara.purefin.data.local.room.dao package hu.bbara.purefin.core.data.local.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import androidx.room.Upsert import androidx.room.Upsert
import hu.bbara.purefin.data.local.room.LibraryEntity import hu.bbara.purefin.core.data.local.room.LibraryEntity
import hu.bbara.purefin.data.local.room.LibraryWithContent import hu.bbara.purefin.core.data.local.room.LibraryWithContent
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao

View File

@@ -1,9 +1,9 @@
package hu.bbara.purefin.data.local.room.dao package hu.bbara.purefin.core.data.local.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import androidx.room.Upsert import androidx.room.Upsert
import hu.bbara.purefin.data.local.room.MovieEntity import hu.bbara.purefin.core.data.local.room.MovieEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import java.util.UUID import java.util.UUID

View File

@@ -1,9 +1,9 @@
package hu.bbara.purefin.data.local.room.dao package hu.bbara.purefin.core.data.local.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import androidx.room.Upsert import androidx.room.Upsert
import hu.bbara.purefin.data.local.room.SeasonEntity import hu.bbara.purefin.core.data.local.room.SeasonEntity
import java.util.UUID import java.util.UUID
@Dao @Dao

View File

@@ -1,11 +1,11 @@
package hu.bbara.purefin.data.local.room.dao package hu.bbara.purefin.core.data.local.room.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import androidx.room.Transaction import androidx.room.Transaction
import androidx.room.Upsert import androidx.room.Upsert
import hu.bbara.purefin.data.local.room.SeriesEntity import hu.bbara.purefin.core.data.local.room.SeriesEntity
import hu.bbara.purefin.data.local.room.SeriesWithSeasonsAndEpisodes import hu.bbara.purefin.core.data.local.room.SeriesWithSeasonsAndEpisodes
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import java.util.UUID import java.util.UUID

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.model.serializer.UUIDSerializer import org.jellyfin.sdk.model.serializer.UUIDSerializer

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.model.serializer.UUIDSerializer import org.jellyfin.sdk.model.serializer.UUIDSerializer

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.staticCompositionLocalOf

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.NavKey
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.navigation package hu.bbara.purefin.core.data.navigation
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.model.serializer.UUIDSerializer import org.jellyfin.sdk.model.serializer.UUIDSerializer

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.session package hu.bbara.purefin.core.data.session
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.model.serializer.UUIDSerializer import org.jellyfin.sdk.model.serializer.UUIDSerializer

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.session package hu.bbara.purefin.core.data.session
import android.content.Context import android.content.Context
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.session package hu.bbara.purefin.core.data.session
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.session package hu.bbara.purefin.core.data.session
import androidx.datastore.core.CorruptionException import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer import androidx.datastore.core.Serializer

View File

@@ -0,0 +1,30 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "hu.bbara.purefin.core.model"
compileSdk = 36
defaultConfig {
minSdk = 29
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
dependencies {
implementation(libs.jellyfin.core)
}

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
data class CastMember( data class CastMember(
val name: String, val name: String,

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
import java.util.UUID import java.util.UUID

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.CollectionType
import java.util.UUID import java.util.UUID

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
import java.util.UUID import java.util.UUID

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data package hu.bbara.purefin.core.model
sealed interface MediaRepositoryState { sealed interface MediaRepositoryState {
data object Loading : MediaRepositoryState data object Loading : MediaRepositoryState

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
import java.util.UUID import java.util.UUID

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
import java.util.UUID import java.util.UUID
@@ -10,5 +10,4 @@ data class Season(
val unwatchedEpisodeCount: Int, val unwatchedEpisodeCount: Int,
val episodeCount: Int, val episodeCount: Int,
val episodes: List<Episode> val episodes: List<Episode>
) { )
}

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.data.model package hu.bbara.purefin.core.model
import java.util.UUID import java.util.UUID
@@ -13,5 +13,4 @@ data class Series(
val seasonCount: Int, val seasonCount: Int,
val seasons: List<Season>, val seasons: List<Season>,
val cast: List<CastMember> val cast: List<CastMember>
) { )
}

View File

@@ -0,0 +1,42 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
}
android {
namespace = "hu.bbara.purefin.core.player"
compileSdk = 36
defaultConfig {
minSdk = 29
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
dependencies {
implementation(project(":core:model"))
implementation(project(":core:data"))
implementation(libs.hilt)
ksp(libs.hilt.compiler)
implementation(libs.medi3.exoplayer)
implementation(libs.media3.datasource.okhttp)
implementation(libs.datastore)
implementation(libs.kotlinx.serialization.json)
implementation(libs.jellyfin.core)
implementation(libs.okhttp)
}

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.data package hu.bbara.purefin.core.player.data
import android.util.Log import android.util.Log
import androidx.annotation.OptIn import androidx.annotation.OptIn
@@ -9,9 +9,9 @@ import androidx.media3.common.MediaMetadata
import androidx.media3.common.MimeTypes import androidx.media3.common.MimeTypes
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import dagger.hilt.android.scopes.ViewModelScoped import dagger.hilt.android.scopes.ViewModelScoped
import hu.bbara.purefin.client.JellyfinApiClient import hu.bbara.purefin.core.data.client.JellyfinApiClient
import hu.bbara.purefin.image.JellyfinImageHelper import hu.bbara.purefin.core.data.image.JellyfinImageHelper
import hu.bbara.purefin.session.UserSessionRepository import hu.bbara.purefin.core.data.session.UserSessionRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.manager package hu.bbara.purefin.core.player.manager
import androidx.annotation.OptIn import androidx.annotation.OptIn
import androidx.media3.common.C import androidx.media3.common.C
@@ -9,14 +9,13 @@ import androidx.media3.common.TrackSelectionOverride
import androidx.media3.common.Tracks import androidx.media3.common.Tracks
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import dagger.hilt.android.scopes.ViewModelScoped import dagger.hilt.android.scopes.ViewModelScoped
import hu.bbara.purefin.player.model.QueueItemUi import hu.bbara.purefin.core.player.model.QueueItemUi
import hu.bbara.purefin.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
import hu.bbara.purefin.player.model.TrackType import hu.bbara.purefin.core.player.model.TrackType
import hu.bbara.purefin.player.preference.AudioTrackProperties import hu.bbara.purefin.core.player.preference.AudioTrackProperties
import hu.bbara.purefin.player.preference.SubtitleTrackProperties import hu.bbara.purefin.core.player.preference.SubtitleTrackProperties
import hu.bbara.purefin.player.preference.TrackMatcher import hu.bbara.purefin.core.player.preference.TrackMatcher
import hu.bbara.purefin.player.preference.TrackPreferencesRepository import hu.bbara.purefin.core.player.preference.TrackPreferencesRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -29,6 +28,7 @@ import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
/** /**
* Encapsulates the Media3 [Player] wiring and exposes reactive updates for the UI layer. * Encapsulates the Media3 [Player] wiring and exposes reactive updates for the UI layer.

View File

@@ -1,9 +1,9 @@
package hu.bbara.purefin.player.manager package hu.bbara.purefin.core.player.manager
import android.util.Log import android.util.Log
import dagger.hilt.android.scopes.ViewModelScoped import dagger.hilt.android.scopes.ViewModelScoped
import hu.bbara.purefin.client.JellyfinApiClient import hu.bbara.purefin.core.data.client.JellyfinApiClient
import hu.bbara.purefin.domain.usecase.UpdateWatchProgressUseCase import hu.bbara.purefin.core.data.domain.usecase.UpdateWatchProgressUseCase
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job

View File

@@ -1,12 +1,12 @@
package hu.bbara.purefin.player.manager package hu.bbara.purefin.core.player.manager
import androidx.annotation.OptIn import androidx.annotation.OptIn
import androidx.media3.common.C import androidx.media3.common.C
import androidx.media3.common.Format import androidx.media3.common.Format
import androidx.media3.common.Tracks import androidx.media3.common.Tracks
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import hu.bbara.purefin.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
import hu.bbara.purefin.player.model.TrackType import hu.bbara.purefin.core.player.model.TrackType
import javax.inject.Inject import javax.inject.Inject
data class TrackSelectionState( data class TrackSelectionState(

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.model package hu.bbara.purefin.core.player.model
data class PlayerUiState( data class PlayerUiState(
val isPlaying: Boolean = false, val isPlaying: Boolean = false,

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.model package hu.bbara.purefin.core.player.model
import android.net.Uri import android.net.Uri
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.module package hu.bbara.purefin.core.player.module
import android.app.Application import android.app.Application
import androidx.annotation.OptIn import androidx.annotation.OptIn

View File

@@ -1,7 +1,7 @@
package hu.bbara.purefin.player.preference package hu.bbara.purefin.core.player.preference
import hu.bbara.purefin.player.model.TrackOption import hu.bbara.purefin.core.player.model.TrackOption
import hu.bbara.purefin.player.model.TrackType import hu.bbara.purefin.core.player.model.TrackType
import javax.inject.Inject import javax.inject.Inject
class TrackMatcher @Inject constructor() { class TrackMatcher @Inject constructor() {

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.preference package hu.bbara.purefin.core.player.preference
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.preference package hu.bbara.purefin.core.player.preference
import android.content.Context import android.content.Context
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.player.preference package hu.bbara.purefin.core.player.preference
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow

Some files were not shown because too many files have changed in this diff Show More