mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Add row for favorite items
This commit is contained in:
parent
d99c947068
commit
ccb79257fd
9 changed files with 334 additions and 24 deletions
|
|
@ -10,6 +10,7 @@ import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
|||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.request.GetItemsRequest
|
||||
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
||||
import java.util.UUID
|
||||
|
|
@ -86,13 +87,33 @@ sealed interface HomeRowConfig {
|
|||
val parentId: UUID,
|
||||
override val viewOptions: HomeRowViewOptions =
|
||||
HomeRowViewOptions(
|
||||
heightDp = (Cards.HEIGHT_2X3_DP * .75f).toInt().let { it - it % 4 },
|
||||
heightDp = Cards.HEIGHT_EPISODE,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
),
|
||||
) : HomeRowConfig {
|
||||
override fun updateViewOptions(viewOptions: HomeRowViewOptions): Genres = this.copy(viewOptions = viewOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Favorites for a specific type
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("Favorite")
|
||||
data class Favorite(
|
||||
val kind: BaseItemKind,
|
||||
override val viewOptions: HomeRowViewOptions =
|
||||
if (kind == BaseItemKind.EPISODE) {
|
||||
HomeRowViewOptions(
|
||||
heightDp = Cards.HEIGHT_EPISODE,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
)
|
||||
} else {
|
||||
HomeRowViewOptions()
|
||||
},
|
||||
) : HomeRowConfig {
|
||||
override fun updateViewOptions(viewOptions: HomeRowViewOptions): Favorite = this.copy(viewOptions = viewOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch by parent ID such as a library, collection, or playlist with optional simple sorting
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
|
|||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.util.GetGenresRequestHandler
|
||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||
import com.github.damontecres.wholphin.util.GetPersonsHandler
|
||||
import com.github.damontecres.wholphin.util.HomeRowLoadingState
|
||||
import com.github.damontecres.wholphin.util.HomeRowLoadingState.Success
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -31,12 +33,15 @@ import org.jellyfin.sdk.api.client.ApiClient
|
|||
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
|
||||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
import org.jellyfin.sdk.model.api.ItemSortBy
|
||||
import org.jellyfin.sdk.model.api.SortOrder
|
||||
import org.jellyfin.sdk.model.api.UserDto
|
||||
import org.jellyfin.sdk.model.api.request.GetGenresRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetItemsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetPersonsRequest
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
|
@ -183,7 +188,19 @@ class HomeSettingsService
|
|||
suspend fun loadCurrentSettings(userId: UUID) {
|
||||
Timber.v("Getting setting for %s", userId)
|
||||
// User local then server/remote otherwise create a default
|
||||
val settings = loadFromLocal(userId) ?: loadFromServer(userId)
|
||||
val settings =
|
||||
try {
|
||||
loadFromLocal(userId)
|
||||
} catch (ex: Exception) {
|
||||
Timber.w(ex, "Error loading local settings")
|
||||
// TODO show toast?
|
||||
null
|
||||
} ?: try {
|
||||
loadFromServer(userId)
|
||||
} catch (ex: Exception) {
|
||||
Timber.w(ex, "Error loading remote settings")
|
||||
null
|
||||
}
|
||||
val resolvedSettings =
|
||||
if (settings != null) {
|
||||
Timber.v("Found settings")
|
||||
|
|
@ -341,6 +358,11 @@ class HomeSettingsService
|
|||
config,
|
||||
)
|
||||
}
|
||||
|
||||
is HomeRowConfig.Favorite -> {
|
||||
val name = context.getString(R.string.favorites) // TODO "Favorite <type>"
|
||||
HomeRowConfigDisplay(id, name, config)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -358,7 +380,7 @@ class HomeSettingsService
|
|||
is HomeRowConfig.ContinueWatching -> {
|
||||
val resume = latestNextUpService.getResume(userDto.id, limit, true)
|
||||
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
title = context.getString(R.string.continue_watching),
|
||||
items = resume,
|
||||
viewOptions = row.viewOptions,
|
||||
|
|
@ -374,7 +396,7 @@ class HomeSettingsService
|
|||
false,
|
||||
)
|
||||
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
title = context.getString(R.string.next_up),
|
||||
items = nextUp,
|
||||
viewOptions = row.viewOptions,
|
||||
|
|
@ -392,7 +414,7 @@ class HomeSettingsService
|
|||
false,
|
||||
)
|
||||
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
title = context.getString(R.string.continue_watching),
|
||||
items =
|
||||
latestNextUpService.buildCombined(
|
||||
|
|
@ -438,7 +460,7 @@ class HomeSettingsService
|
|||
name?.let { context.getString(R.string.genres_in, it) }
|
||||
?: context.getString(R.string.genres)
|
||||
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
title,
|
||||
genres,
|
||||
viewOptions = row.viewOptions,
|
||||
|
|
@ -468,7 +490,7 @@ class HomeSettingsService
|
|||
.content
|
||||
.map { BaseItem.Companion.from(it, api, true) }
|
||||
.let {
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
title,
|
||||
it,
|
||||
row.viewOptions,
|
||||
|
|
@ -500,7 +522,7 @@ class HomeSettingsService
|
|||
.content.items
|
||||
.map { BaseItem.Companion.from(it, api, true) }
|
||||
.let {
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
title,
|
||||
it,
|
||||
row.viewOptions,
|
||||
|
|
@ -528,7 +550,7 @@ class HomeSettingsService
|
|||
.content.items
|
||||
.map { BaseItem(it, true) }
|
||||
.let {
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
name ?: context.getString(R.string.collection),
|
||||
it,
|
||||
row.viewOptions,
|
||||
|
|
@ -555,13 +577,59 @@ class HomeSettingsService
|
|||
.content.items
|
||||
.map { BaseItem(it, true) }
|
||||
.let {
|
||||
HomeRowLoadingState.Success(
|
||||
Success(
|
||||
row.name,
|
||||
it,
|
||||
row.viewOptions,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is HomeRowConfig.Favorite -> {
|
||||
if (row.kind == BaseItemKind.PERSON) {
|
||||
val request =
|
||||
GetPersonsRequest(
|
||||
userId = userDto.id,
|
||||
limit = limit,
|
||||
fields = DefaultItemFields,
|
||||
isFavorite = true,
|
||||
enableImages = true,
|
||||
enableImageTypes = listOf(ImageType.PRIMARY),
|
||||
)
|
||||
GetPersonsHandler
|
||||
.execute(api, request)
|
||||
.content.items
|
||||
.map { BaseItem(it, true) }
|
||||
.let {
|
||||
Success(
|
||||
context.getString(R.string.favorites), // TODO
|
||||
it,
|
||||
row.viewOptions,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val request =
|
||||
GetItemsRequest(
|
||||
userId = userDto.id,
|
||||
recursive = true,
|
||||
limit = limit,
|
||||
fields = DefaultItemFields,
|
||||
includeItemTypes = listOf(row.kind),
|
||||
isFavorite = true,
|
||||
)
|
||||
GetItemsRequestHandler
|
||||
.execute(api, request)
|
||||
.content.items
|
||||
.map { BaseItem(it, false) }
|
||||
.let {
|
||||
Success(
|
||||
context.getString(R.string.favorites), // TODO
|
||||
it,
|
||||
row.viewOptions,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ val SlimItemFields =
|
|||
object Cards {
|
||||
const val HEIGHT_2X3_DP = 172
|
||||
val height2x3 = HEIGHT_2X3_DP.dp
|
||||
val heightEpisode = height2x3 * .75f
|
||||
val HEIGHT_EPISODE = (HEIGHT_2X3_DP * .75f).toInt().let { it - it % 4 }
|
||||
val heightEpisode = HEIGHT_EPISODE.dp
|
||||
val playedPercentHeight = 6.dp
|
||||
val serverUserCircle = height2x3 * .75f
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ sealed interface HomeSettingsDestination : NavKey {
|
|||
data class RowSettings(
|
||||
val rowId: Int,
|
||||
) : HomeSettingsDestination
|
||||
|
||||
data object ChooseFavorite : HomeSettingsDestination
|
||||
|
||||
data object ChooseDiscover : HomeSettingsDestination
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
package com.github.damontecres.wholphin.ui.main.settings
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.focusRestorer
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.tv.material3.ListItem
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
|
||||
@Composable
|
||||
fun HomeSettingsFavoriteList(
|
||||
onClick: (BaseItemKind) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
firstFocus: FocusRequester = remember { FocusRequester() },
|
||||
) {
|
||||
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
||||
Column(modifier = modifier) {
|
||||
Text(
|
||||
text = "Add favorites row...",
|
||||
)
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxHeight()
|
||||
.focusRestorer(firstFocus),
|
||||
) {
|
||||
itemsIndexed(favoriteOptionsList) { index, type ->
|
||||
ListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(favoriteOptions[type]!!),
|
||||
)
|
||||
},
|
||||
onClick = { onClick.invoke(type) },
|
||||
modifier = Modifier.ifElse(index == 0, Modifier.focusRequester(firstFocus)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val favoriteOptions =
|
||||
mapOf(
|
||||
BaseItemKind.MOVIE to R.string.movies,
|
||||
BaseItemKind.SERIES to R.string.tv_shows,
|
||||
BaseItemKind.EPISODE to R.string.episodes,
|
||||
BaseItemKind.VIDEO to R.string.videos,
|
||||
BaseItemKind.PLAYLIST to R.string.playlists,
|
||||
BaseItemKind.PERSON to R.string.people,
|
||||
)
|
||||
val favoriteOptionsList = favoriteOptions.keys.toList()
|
||||
|
|
@ -5,6 +5,8 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
|
|
@ -16,8 +18,10 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.focusRestorer
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.tv.material3.ListItem
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
|
|
@ -26,6 +30,7 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus
|
|||
@Composable
|
||||
fun HomeSettingsLibraryList(
|
||||
libraries: List<Library>,
|
||||
showDiscover: Boolean,
|
||||
onClick: (Library) -> Unit,
|
||||
onClickMeta: (MetaRowType) -> Unit,
|
||||
modifier: Modifier,
|
||||
|
|
@ -44,7 +49,25 @@ fun HomeSettingsLibraryList(
|
|||
.fillMaxHeight()
|
||||
.focusRestorer(firstFocus),
|
||||
) {
|
||||
itemsIndexed(MetaRowType.entries) { index, type ->
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(R.string.continue_watching),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Start,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp, bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
itemsIndexed(
|
||||
listOf(
|
||||
MetaRowType.CONTINUE_WATCHING,
|
||||
MetaRowType.NEXT_UP,
|
||||
MetaRowType.COMBINED_CONTINUE_WATCHING,
|
||||
),
|
||||
) { index, type ->
|
||||
ListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
|
|
@ -56,6 +79,16 @@ fun HomeSettingsLibraryList(
|
|||
}
|
||||
item {
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = stringResource(R.string.library),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Start,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp, bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
itemsIndexed(libraries) { index, library ->
|
||||
ListItem(
|
||||
|
|
@ -67,6 +100,41 @@ fun HomeSettingsLibraryList(
|
|||
modifier = Modifier, // .ifElse(index == 0, Modifier.focusRequester(firstFocus)),
|
||||
)
|
||||
}
|
||||
item {
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = stringResource(R.string.more),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Start,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp, bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
item {
|
||||
ListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
Text(stringResource(MetaRowType.FAVORITES.stringId))
|
||||
},
|
||||
onClick = { onClickMeta.invoke(MetaRowType.FAVORITES) },
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
if (showDiscover) {
|
||||
item {
|
||||
ListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
Text(stringResource(MetaRowType.DISCOVER.stringId))
|
||||
},
|
||||
onClick = { onClickMeta.invoke(MetaRowType.DISCOVER) },
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -77,4 +145,6 @@ enum class MetaRowType(
|
|||
CONTINUE_WATCHING(R.string.continue_watching),
|
||||
NEXT_UP(R.string.next_up),
|
||||
COMBINED_CONTINUE_WATCHING(R.string.combine_continue_next),
|
||||
FAVORITES(R.string.favorites),
|
||||
DISCOVER(R.string.discover),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import com.github.damontecres.wholphin.ui.main.HomePageContent
|
||||
import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.ChooseRowType
|
||||
import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.RowSettings
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
|
@ -38,14 +40,15 @@ fun HomeSettingsPage(
|
|||
var destination by remember { mutableStateOf<HomeSettingsDestination>(HomeSettingsDestination.RowList) }
|
||||
|
||||
val state by viewModel.state.collectAsState()
|
||||
val discoverEnabled by viewModel.discoverEnabled.collectAsState(false)
|
||||
|
||||
BackHandler(destination is HomeSettingsDestination.ChooseRowType) {
|
||||
BackHandler(destination is ChooseRowType) {
|
||||
destination = HomeSettingsDestination.ChooseLibrary
|
||||
}
|
||||
BackHandler(destination is HomeSettingsDestination.ChooseLibrary) {
|
||||
destination = HomeSettingsDestination.RowList
|
||||
}
|
||||
BackHandler(destination is HomeSettingsDestination.RowSettings) {
|
||||
BackHandler(destination is RowSettings) {
|
||||
destination = HomeSettingsDestination.RowList
|
||||
}
|
||||
Row(
|
||||
|
|
@ -72,7 +75,7 @@ fun HomeSettingsPage(
|
|||
onClickMove = viewModel::moveRow,
|
||||
onClickDelete = viewModel::deleteRow,
|
||||
onClick = { index, row ->
|
||||
destination = HomeSettingsDestination.RowSettings(row.id)
|
||||
destination = RowSettings(row.id)
|
||||
scope.launch(ExceptionHandler()) {
|
||||
Timber.v("Scroll to $index")
|
||||
listState.scrollToItem(index)
|
||||
|
|
@ -88,16 +91,32 @@ fun HomeSettingsPage(
|
|||
is HomeSettingsDestination.ChooseLibrary -> {
|
||||
HomeSettingsLibraryList(
|
||||
libraries = state.libraries,
|
||||
onClick = { destination = HomeSettingsDestination.ChooseRowType(it) },
|
||||
showDiscover = discoverEnabled,
|
||||
onClick = { destination = ChooseRowType(it) },
|
||||
onClickMeta = {
|
||||
viewModel.addRow(it)
|
||||
destination = HomeSettingsDestination.RowList
|
||||
when (it) {
|
||||
MetaRowType.CONTINUE_WATCHING,
|
||||
MetaRowType.NEXT_UP,
|
||||
MetaRowType.COMBINED_CONTINUE_WATCHING,
|
||||
-> {
|
||||
viewModel.addRow(it)
|
||||
destination = HomeSettingsDestination.RowList
|
||||
}
|
||||
|
||||
MetaRowType.FAVORITES -> {
|
||||
destination = HomeSettingsDestination.ChooseFavorite
|
||||
}
|
||||
|
||||
MetaRowType.DISCOVER -> {
|
||||
destination = HomeSettingsDestination.ChooseDiscover
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = destModifier,
|
||||
)
|
||||
}
|
||||
|
||||
is HomeSettingsDestination.ChooseRowType -> {
|
||||
is ChooseRowType -> {
|
||||
HomeLibraryRowTypeList(
|
||||
library = dest.library,
|
||||
onClick = {
|
||||
|
|
@ -108,7 +127,7 @@ fun HomeSettingsPage(
|
|||
)
|
||||
}
|
||||
|
||||
is HomeSettingsDestination.RowSettings -> {
|
||||
is RowSettings -> {
|
||||
val row =
|
||||
state.rows
|
||||
.first { it.id == dest.rowId }
|
||||
|
|
@ -124,6 +143,18 @@ fun HomeSettingsPage(
|
|||
modifier = destModifier,
|
||||
)
|
||||
}
|
||||
|
||||
HomeSettingsDestination.ChooseDiscover -> {
|
||||
TODO()
|
||||
}
|
||||
|
||||
HomeSettingsDestination.ChooseFavorite -> {
|
||||
HomeSettingsFavoriteList(
|
||||
onClick = { type ->
|
||||
viewModel.addFavoriteRow(type)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
HomePageContent(
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.focusRestorer
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -57,6 +59,7 @@ fun HomeSettingsRowList(
|
|||
modifier: Modifier,
|
||||
firstFocus: FocusRequester = remember { FocusRequester() },
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
||||
Column(modifier = modifier) {
|
||||
LazyColumn(
|
||||
|
|
@ -148,7 +151,14 @@ fun HomeSettingsRowList(
|
|||
moveDownAllowed = index != state.rows.lastIndex,
|
||||
deleteAllowed = state.rows.size > 1,
|
||||
onClickMove = { onClickMove.invoke(it, index) },
|
||||
onClickDelete = { onClickDelete.invoke(index) },
|
||||
onClickDelete = {
|
||||
if (index != state.rows.lastIndex) {
|
||||
focusManager.moveFocus(FocusDirection.Down)
|
||||
} else {
|
||||
focusManager.moveFocus(FocusDirection.Up)
|
||||
}
|
||||
onClickDelete.invoke(index)
|
||||
},
|
||||
onClick = { onClick.invoke(index, row) },
|
||||
modifier =
|
||||
Modifier
|
||||
|
|
|
|||
|
|
@ -11,11 +11,15 @@ import com.github.damontecres.wholphin.data.ServerRepository
|
|||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.HomePageSettings
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatching
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatchingCombined
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig.NextUp
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||
import com.github.damontecres.wholphin.services.BackdropService
|
||||
import com.github.damontecres.wholphin.services.HomePageResolvedSettings
|
||||
import com.github.damontecres.wholphin.services.HomeRowConfigDisplay
|
||||
import com.github.damontecres.wholphin.services.HomeSettingsService
|
||||
import com.github.damontecres.wholphin.services.SeerrServerRepository
|
||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
|
|
@ -30,6 +34,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.CollectionType
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
|
|
@ -45,11 +50,14 @@ class HomeSettingsViewModel
|
|||
private val userPreferencesService: UserPreferencesService,
|
||||
private val navDrawerItemRepository: NavDrawerItemRepository,
|
||||
private val backdropService: BackdropService,
|
||||
private val seerrServerRepository: SeerrServerRepository,
|
||||
@param:IoCoroutineScope private val ioScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
private val _state = MutableStateFlow(HomePageSettingsState.EMPTY)
|
||||
val state: StateFlow<HomePageSettingsState> = _state
|
||||
|
||||
val discoverEnabled = seerrServerRepository.active
|
||||
|
||||
init {
|
||||
addCloseable { saveToLocal() }
|
||||
viewModelScope.launchIO {
|
||||
|
|
@ -164,7 +172,7 @@ class HomeSettingsViewModel
|
|||
HomeRowConfigDisplay(
|
||||
id = id,
|
||||
title = context.getString(R.string.continue_watching),
|
||||
config = HomeRowConfig.ContinueWatching(),
|
||||
config = ContinueWatching(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +180,7 @@ class HomeSettingsViewModel
|
|||
HomeRowConfigDisplay(
|
||||
id = id,
|
||||
title = context.getString(R.string.continue_watching),
|
||||
config = HomeRowConfig.NextUp(),
|
||||
config = NextUp(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -180,9 +188,17 @@ class HomeSettingsViewModel
|
|||
HomeRowConfigDisplay(
|
||||
id = id,
|
||||
title = context.getString(R.string.combine_continue_next),
|
||||
config = HomeRowConfig.ContinueWatchingCombined(),
|
||||
config = ContinueWatchingCombined(),
|
||||
)
|
||||
}
|
||||
|
||||
MetaRowType.FAVORITES -> {
|
||||
throw IllegalArgumentException("Should use addRow(BaseItemKind) instead")
|
||||
}
|
||||
|
||||
MetaRowType.DISCOVER -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
updateState {
|
||||
it.copy(
|
||||
|
|
@ -246,6 +262,26 @@ class HomeSettingsViewModel
|
|||
}
|
||||
}
|
||||
|
||||
fun addFavoriteRow(type: BaseItemKind) {
|
||||
viewModelScope.launchIO {
|
||||
Timber.v("Adding favorite row for $type")
|
||||
val id = state.value.rows.size
|
||||
val newRow =
|
||||
HomeRowConfigDisplay(
|
||||
id = id,
|
||||
title = context.getString(favoriteOptions[type]!!),
|
||||
config = HomeRowConfig.Favorite(type),
|
||||
)
|
||||
updateState {
|
||||
it.copy(
|
||||
loading = LoadingState.Loading,
|
||||
rows = it.rows.toMutableList().apply { add(newRow) },
|
||||
)
|
||||
}
|
||||
fetchRowData()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateViewOptions(
|
||||
rowId: Int,
|
||||
viewOptions: HomeRowViewOptions,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue