mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
Compare commits
7 Commits
63a8a108e2
...
9a83eb635f
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a83eb635f | |||
| 31c1b0dd92 | |||
| f2c46af410 | |||
| b1ae478f6d | |||
| 132c6feee0 | |||
| 9953c94e86 | |||
| db15bf7e2c |
@@ -17,7 +17,7 @@ android {
|
||||
applicationId = "hu.bbara.purefin"
|
||||
minSdk = 29
|
||||
targetSdk = 36
|
||||
versionCode = 1000005
|
||||
versionCode = 1000008
|
||||
versionName = "0.1"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package hu.bbara.purefin.ui.common.card
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -12,11 +14,22 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.MoreVert
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@@ -26,6 +39,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
|
||||
import hu.bbara.purefin.ui.model.MediaAction
|
||||
|
||||
@Composable
|
||||
fun MediaImageCard(
|
||||
@@ -34,6 +48,7 @@ fun MediaImageCard(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitle: String? = null,
|
||||
popupActions: List<MediaAction> = emptyList(),
|
||||
imageModifier: Modifier = Modifier,
|
||||
shapeSize: Dp = 12.dp,
|
||||
imageAspectRatio: Float = 16f / 10f,
|
||||
@@ -45,6 +60,8 @@ fun MediaImageCard(
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
val shape = RoundedCornerShape(shapeSize)
|
||||
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
Card(
|
||||
onClick = onClick,
|
||||
shape = shape,
|
||||
@@ -67,26 +84,55 @@ fun MediaImageCard(
|
||||
)
|
||||
imageOverlay()
|
||||
}
|
||||
Column(modifier = Modifier.padding(textPadding)) {
|
||||
Text(
|
||||
text = title,
|
||||
style = titleStyle,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
subtitle
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?.let { text ->
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = text,
|
||||
style = subtitleStyle,
|
||||
color = scheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column(modifier = Modifier.padding(textPadding)) {
|
||||
Text(
|
||||
text = title,
|
||||
style = titleStyle,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
subtitle
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?.let { text ->
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = text,
|
||||
style = subtitleStyle,
|
||||
color = scheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
if (popupActions.isNotEmpty()) {
|
||||
Box() {
|
||||
IconButton(
|
||||
onClick = { expanded = !expanded },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.MoreVert,
|
||||
contentDescription = "More actions"
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
) {
|
||||
popupActions.forEach { action ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = action.name) },
|
||||
onClick = action.onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package hu.bbara.purefin.ui.model
|
||||
|
||||
data class MediaAction(
|
||||
val name: String,
|
||||
val onClick: () -> Unit
|
||||
)
|
||||
@@ -91,6 +91,7 @@ fun AppScreen(
|
||||
library.name
|
||||
)
|
||||
},
|
||||
onMarkWatched = viewModel::markAsWatched,
|
||||
onProfileClick = {},
|
||||
onCheckForUpdates = { updateViewModel.checkForUpdates() },
|
||||
isCheckingForUpdates = isCheckingForUpdates,
|
||||
|
||||
@@ -26,6 +26,7 @@ fun HomeScreen(
|
||||
onRefresh: () -> Unit,
|
||||
onMediaSelected: (MediaUiModel) -> Unit,
|
||||
onLibrarySelected: (LibraryUiModel) -> Unit,
|
||||
onMarkWatched: (MediaUiModel, Boolean) -> Unit,
|
||||
onProfileClick: () -> Unit,
|
||||
onCheckForUpdates: () -> Unit,
|
||||
isCheckingForUpdates: Boolean,
|
||||
@@ -71,6 +72,7 @@ fun HomeScreen(
|
||||
onMediaSelected = onMediaSelected,
|
||||
onLibrarySelected = onLibrarySelected,
|
||||
onBrowseLibrariesClick = { onTabSelected(1) },
|
||||
onMarkAsWatched = onMarkWatched,
|
||||
modifier = Modifier.padding(innerPadding)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,16 +20,12 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonColors
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import hu.bbara.purefin.navigation.HOME_SEARCH_SHARED_BOUNDS_KEY
|
||||
import hu.bbara.purefin.navigation.LocalNavSharedAnimatedVisibilityScope
|
||||
import hu.bbara.purefin.navigation.LocalSharedTransitionScope
|
||||
@@ -71,14 +67,7 @@ fun DefaultTopBar(
|
||||
}
|
||||
) {
|
||||
PurefinLogo(
|
||||
modifier = Modifier.size(84.dp),
|
||||
)
|
||||
Text(
|
||||
text = "PureFin",
|
||||
fontSize = 32.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontStyle = FontStyle.Italic,
|
||||
color = scheme.primary
|
||||
modifier = Modifier.size(56.dp),
|
||||
)
|
||||
}
|
||||
if (rightActions != null) {
|
||||
|
||||
@@ -42,6 +42,7 @@ fun HomeContent(
|
||||
onMediaSelected: (MediaUiModel) -> Unit,
|
||||
onLibrarySelected: (LibraryUiModel) -> Unit,
|
||||
onBrowseLibrariesClick: () -> Unit,
|
||||
onMarkAsWatched: (MediaUiModel, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
@@ -105,6 +106,7 @@ fun HomeContent(
|
||||
item(key = "continue-watching") {
|
||||
ContinueWatchingSection(
|
||||
items = continueWatching,
|
||||
onMarkAsWatched = onMarkAsWatched,
|
||||
onMediaSelected = onMediaSelected
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import hu.bbara.purefin.ui.common.bar.MediaProgressBar
|
||||
import hu.bbara.purefin.ui.common.card.MediaImageCard
|
||||
import hu.bbara.purefin.ui.common.media.homeMediaSharedBoundsSource
|
||||
import hu.bbara.purefin.ui.common.media.rememberHomeMediaSharedBoundsClick
|
||||
import hu.bbara.purefin.ui.model.MediaAction
|
||||
import hu.bbara.purefin.ui.model.MediaUiModel
|
||||
|
||||
@Composable
|
||||
@@ -22,6 +23,7 @@ internal fun ContinueWatchingCard(
|
||||
item: MediaUiModel,
|
||||
sharedBoundsKey: String,
|
||||
onMediaSelected: (MediaUiModel) -> Unit,
|
||||
onMarkAsWatched: (MediaUiModel, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
@@ -34,6 +36,16 @@ internal fun ContinueWatchingCard(
|
||||
title = item.primaryText,
|
||||
subtitle = item.secondaryText,
|
||||
onClick = onClick,
|
||||
popupActions = listOf(
|
||||
MediaAction(
|
||||
name = "Mark as watched",
|
||||
onClick = { onMarkAsWatched(item, true) }
|
||||
),
|
||||
MediaAction(
|
||||
name = "Mark as unwatched",
|
||||
onClick = { onMarkAsWatched(item, false) }
|
||||
)
|
||||
),
|
||||
imageModifier = Modifier.homeMediaSharedBoundsSource(sharedBoundsKey),
|
||||
shapeSize = 26.dp,
|
||||
imageAspectRatio = 16f / 9f,
|
||||
|
||||
@@ -21,6 +21,7 @@ import hu.bbara.purefin.ui.model.MediaUiModel
|
||||
fun ContinueWatchingSection(
|
||||
items: List<MediaUiModel>,
|
||||
onMediaSelected: (MediaUiModel) -> Unit,
|
||||
onMarkAsWatched: (MediaUiModel, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (items.isEmpty()) return
|
||||
@@ -47,7 +48,8 @@ fun ContinueWatchingSection(
|
||||
ContinueWatchingCard(
|
||||
item = item,
|
||||
sharedBoundsKey = homeMediaSharedBoundsKey("continue-$index", item.id),
|
||||
onMediaSelected = onMediaSelected
|
||||
onMediaSelected = onMediaSelected,
|
||||
onMarkAsWatched = onMarkAsWatched
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
@@ -98,7 +97,7 @@ fun SearchScreen(
|
||||
Modifier
|
||||
}
|
||||
|
||||
SearchFullScreenContent(
|
||||
SearchScreenContent(
|
||||
query = query,
|
||||
searchResults = searchResults,
|
||||
genres = genres.sortedBy { it.name },
|
||||
@@ -128,7 +127,7 @@ fun SearchScreen(
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun SearchFullScreenContent(
|
||||
private fun SearchScreenContent(
|
||||
query: String,
|
||||
searchResults: List<SearchResult>,
|
||||
genres: List<Genre>,
|
||||
@@ -149,8 +148,6 @@ private fun SearchFullScreenContent(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(scheme.background)
|
||||
.statusBarsPadding()
|
||||
.padding(top = 24.dp)
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -219,10 +216,7 @@ private fun SearchResults(
|
||||
@Composable
|
||||
private fun SearchHeader(
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
|
||||
DefaultTopBar(
|
||||
leftActions = {
|
||||
DefaultTopBarIconButton(
|
||||
@@ -477,11 +471,11 @@ private fun GenreChip(
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun SearchFullScreenPreview() {
|
||||
private fun SearchScreenPreview() {
|
||||
var query by rememberSaveable { mutableStateOf("du") }
|
||||
|
||||
AppTheme {
|
||||
SearchFullScreenContent(
|
||||
SearchScreenContent(
|
||||
query = query,
|
||||
searchResults = previewSearchResults,
|
||||
genres = previewGenres,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="600dp"
|
||||
android:height="552dp"
|
||||
android:viewportWidth="600"
|
||||
android:viewportHeight="552">
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.075"
|
||||
android:scaleY="-0.075"
|
||||
android:translateX="75"
|
||||
android:translateY="483">
|
||||
android:scaleX="0.01231"
|
||||
android:scaleY="-0.01231"
|
||||
android:translateX="15.8"
|
||||
android:translateY="88.3">
|
||||
|
||||
<path
|
||||
android:fillColor="#7c42f0"
|
||||
|
||||
@@ -7,6 +7,7 @@ import hu.bbara.purefin.data.HomeRepository
|
||||
import hu.bbara.purefin.data.LocalMediaRepository
|
||||
import hu.bbara.purefin.data.UserSessionRepository
|
||||
import hu.bbara.purefin.download.MediaDownloadController
|
||||
import hu.bbara.purefin.jellyfin.JellyfinMediaMetadataUpdater
|
||||
import hu.bbara.purefin.model.LibraryKind
|
||||
import hu.bbara.purefin.model.Media
|
||||
import hu.bbara.purefin.navigation.EpisodeDto
|
||||
@@ -34,8 +35,9 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class AppViewModel @Inject constructor(
|
||||
private val homeRepository: HomeRepository,
|
||||
private val mediaCatalogReader: LocalMediaRepository,
|
||||
private val localMediaRepository: LocalMediaRepository,
|
||||
private val userSessionRepository: UserSessionRepository,
|
||||
private val jellyfinMediaMetadataUpdater: JellyfinMediaMetadataUpdater,
|
||||
private val navigationManager: NavigationManager,
|
||||
private val mediaDownloadManager: MediaDownloadController,
|
||||
) : ViewModel() {
|
||||
@@ -59,8 +61,8 @@ class AppViewModel @Inject constructor(
|
||||
posterUrl = it.posterUrl,
|
||||
size = it.size,
|
||||
isEmpty = when (it.type) {
|
||||
LibraryKind.MOVIES -> mediaCatalogReader.movies.value.isEmpty()
|
||||
LibraryKind.SERIES -> mediaCatalogReader.series.value.isEmpty()
|
||||
LibraryKind.MOVIES -> localMediaRepository.movies.value.isEmpty()
|
||||
LibraryKind.SERIES -> localMediaRepository.series.value.isEmpty()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -68,9 +70,9 @@ class AppViewModel @Inject constructor(
|
||||
|
||||
val suggestions = combine(
|
||||
homeRepository.suggestions,
|
||||
mediaCatalogReader.movies,
|
||||
mediaCatalogReader.series,
|
||||
mediaCatalogReader.episodes
|
||||
localMediaRepository.movies,
|
||||
localMediaRepository.series,
|
||||
localMediaRepository.episodes
|
||||
) { list, moviesMap, seriesMap, episodesMap ->
|
||||
list.mapNotNull { media ->
|
||||
when (media) {
|
||||
@@ -94,8 +96,8 @@ class AppViewModel @Inject constructor(
|
||||
|
||||
val continueWatching = combine(
|
||||
homeRepository.continueWatching,
|
||||
mediaCatalogReader.movies,
|
||||
mediaCatalogReader.episodes
|
||||
localMediaRepository.movies,
|
||||
localMediaRepository.episodes
|
||||
) { list, moviesMap, episodesMap ->
|
||||
list.mapNotNull { media ->
|
||||
when (media) {
|
||||
@@ -116,7 +118,7 @@ class AppViewModel @Inject constructor(
|
||||
|
||||
val nextUp = combine(
|
||||
homeRepository.nextUp,
|
||||
mediaCatalogReader.episodes
|
||||
localMediaRepository.episodes
|
||||
) { list, episodesMap ->
|
||||
list.mapNotNull { media ->
|
||||
when (media) {
|
||||
@@ -134,9 +136,9 @@ class AppViewModel @Inject constructor(
|
||||
|
||||
val latestLibraryContent = combine(
|
||||
homeRepository.latestLibraryContent,
|
||||
mediaCatalogReader.movies,
|
||||
mediaCatalogReader.series,
|
||||
mediaCatalogReader.episodes
|
||||
localMediaRepository.movies,
|
||||
localMediaRepository.series,
|
||||
localMediaRepository.episodes
|
||||
) { libraryMap, moviesMap, seriesMap, episodesMap ->
|
||||
libraryMap.mapValues { (_, items) ->
|
||||
items.mapNotNull { media ->
|
||||
@@ -162,6 +164,12 @@ class AppViewModel @Inject constructor(
|
||||
initialValue = emptyMap()
|
||||
)
|
||||
|
||||
fun markAsWatched(mediaUiModel: MediaUiModel, watched: Boolean) {
|
||||
viewModelScope.launch {
|
||||
jellyfinMediaMetadataUpdater.markAsWatched(mediaUiModel.id, watched)
|
||||
}
|
||||
}
|
||||
|
||||
fun onLibrarySelected(id: UUID, name: String) {
|
||||
viewModelScope.launch {
|
||||
navigationManager.navigate(Route.LibraryRoute(library = LibraryDto(id = id, name = name)))
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package hu.bbara.purefin.jellyfin
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
interface JellyfinMediaMetadataUpdater {
|
||||
suspend fun markAsWatched(mediaId: UUID, watched: Boolean)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package hu.bbara.purefin.data.jellyfin
|
||||
|
||||
import hu.bbara.purefin.data.jellyfin.client.JellyfinApiClient
|
||||
import hu.bbara.purefin.jellyfin.JellyfinMediaMetadataUpdater
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
class JellyfinMediaMetadataUpdaterImpl @Inject constructor(
|
||||
private val jellyfinApiClient: JellyfinApiClient
|
||||
) : JellyfinMediaMetadataUpdater {
|
||||
|
||||
override suspend fun markAsWatched(mediaId: UUID, watched: Boolean) {
|
||||
if (watched) {
|
||||
jellyfinApiClient.markAsWatched(mediaId)
|
||||
} else {
|
||||
jellyfinApiClient.markAsUnwatched(mediaId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,6 +322,30 @@ class JellyfinApiClient @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun markAsWatched(mediaId: UUID) = withContext(Dispatchers.IO) {
|
||||
logApiFailure("markAsWatched($mediaId)") {
|
||||
if (!ensureConfigured()) {
|
||||
return@logApiFailure
|
||||
}
|
||||
api.playStateApi.markPlayedItem(
|
||||
itemId = mediaId,
|
||||
userId = getUserId(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun markAsUnwatched(mediaId: UUID) = withContext(Dispatchers.IO) {
|
||||
logApiFailure("markAsUnwatched($mediaId)") {
|
||||
if (!ensureConfigured()) {
|
||||
return@logApiFailure
|
||||
}
|
||||
api.playStateApi.markUnplayedItem(
|
||||
itemId = mediaId,
|
||||
userId = getUserId(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getMediaSources(mediaId: UUID): List<MediaSourceInfo> = withContext(Dispatchers.IO) {
|
||||
logApiFailure("getMediaSources($mediaId)") {
|
||||
if (!ensureConfigured()) {
|
||||
|
||||
@@ -12,7 +12,9 @@ import hu.bbara.purefin.data.SearchManager
|
||||
import hu.bbara.purefin.data.catalog.InMemoryAppContentRepository
|
||||
import hu.bbara.purefin.data.catalog.InMemoryLocalMediaRepository
|
||||
import hu.bbara.purefin.data.catalog.OfflineLocalMediaRepository
|
||||
import hu.bbara.purefin.data.jellyfin.JellyfinMediaMetadataUpdaterImpl
|
||||
import hu.bbara.purefin.data.jellyfin.SearchManagerImpl
|
||||
import hu.bbara.purefin.jellyfin.JellyfinMediaMetadataUpdater
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@@ -29,6 +31,9 @@ abstract class MediaRepositoryModule {
|
||||
@Binds
|
||||
abstract fun bindHomeRepository(impl: InMemoryAppContentRepository): HomeRepository
|
||||
|
||||
@Binds
|
||||
abstract fun bindJellyfinMediaMetadataUpdater(impl: JellyfinMediaMetadataUpdaterImpl): JellyfinMediaMetadataUpdater
|
||||
|
||||
@Binds
|
||||
abstract fun bindSearchManager(impl: SearchManagerImpl): SearchManager
|
||||
}
|
||||
Reference in New Issue
Block a user