mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-17 15:32:01 +00:00
feat: support for trakt library items removal from library screen
fixes #962
This commit is contained in:
parent
951cb8f201
commit
daedf05ea5
3 changed files with 64 additions and 12 deletions
|
|
@ -1114,6 +1114,7 @@
|
||||||
<string name="downloads_live_failed">Download failed</string>
|
<string name="downloads_live_failed">Download failed</string>
|
||||||
<string name="downloads_live_paused">Paused %1$s</string>
|
<string name="downloads_live_paused">Paused %1$s</string>
|
||||||
<string name="library_remove_confirm">Remove</string>
|
<string name="library_remove_confirm">Remove</string>
|
||||||
|
<string name="library_remove_from_list_message">Remove %1$s from %2$s?</string>
|
||||||
<string name="library_remove_message">Remove %1$s from your library?</string>
|
<string name="library_remove_message">Remove %1$s from your library?</string>
|
||||||
<string name="library_remove_title">Remove from Library?</string>
|
<string name="library_remove_title">Remove from Library?</string>
|
||||||
<string name="media_movie">Movie</string>
|
<string name="media_movie">Movie</string>
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,14 @@ object LibraryRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun removeFromList(item: LibraryItem, listKey: String) {
|
||||||
|
val desiredMembership = libraryMembershipWithRemovedList(
|
||||||
|
currentMembership = getMembershipSnapshot(item),
|
||||||
|
listKey = listKey,
|
||||||
|
)
|
||||||
|
applyMembershipChanges(item, desiredMembership)
|
||||||
|
}
|
||||||
|
|
||||||
private fun pushToServer() {
|
private fun pushToServer() {
|
||||||
syncScope.launch {
|
syncScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
@ -417,6 +425,14 @@ internal fun libraryMembershipWithLocal(
|
||||||
putAll(traktMembership)
|
putAll(traktMembership)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun libraryMembershipWithRemovedList(
|
||||||
|
currentMembership: Map<String, Boolean>,
|
||||||
|
listKey: String,
|
||||||
|
): Map<String, Boolean> =
|
||||||
|
currentMembership.toMutableMap().apply {
|
||||||
|
this[listKey] = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun LibrarySyncItem.toLibraryItem(): LibraryItem = LibraryItem(
|
private fun LibrarySyncItem.toLibraryItem(): LibraryItem = LibraryItem(
|
||||||
id = contentId,
|
id = contentId,
|
||||||
type = contentType,
|
type = contentType,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import com.nuvio.app.core.ui.NuvioScreen
|
||||||
import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
import com.nuvio.app.core.ui.NuvioNetworkOfflineCard
|
||||||
import com.nuvio.app.core.ui.NuvioScreenHeader
|
import com.nuvio.app.core.ui.NuvioScreenHeader
|
||||||
import com.nuvio.app.core.ui.NuvioStatusModal
|
import com.nuvio.app.core.ui.NuvioStatusModal
|
||||||
|
import com.nuvio.app.core.ui.NuvioToastController
|
||||||
import com.nuvio.app.core.ui.NuvioViewAllPillSize
|
import com.nuvio.app.core.ui.NuvioViewAllPillSize
|
||||||
import com.nuvio.app.core.ui.NuvioShelfSection
|
import com.nuvio.app.core.ui.NuvioShelfSection
|
||||||
import com.nuvio.app.features.home.components.HomeEmptyStateCard
|
import com.nuvio.app.features.home.components.HomeEmptyStateCard
|
||||||
|
|
@ -33,8 +34,15 @@ import com.nuvio.app.features.home.components.HomeSkeletonRow
|
||||||
import com.nuvio.app.features.profiles.ProfileRepository
|
import com.nuvio.app.features.profiles.ProfileRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import nuvio.composeapp.generated.resources.*
|
import nuvio.composeapp.generated.resources.*
|
||||||
|
import org.jetbrains.compose.resources.getString
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
|
private data class LibraryRemovalTarget(
|
||||||
|
val item: LibraryItem,
|
||||||
|
val listKey: String? = null,
|
||||||
|
val listTitle: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryScreen(
|
fun LibraryScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -46,7 +54,7 @@ fun LibraryScreen(
|
||||||
LibraryRepository.uiState
|
LibraryRepository.uiState
|
||||||
}.collectAsStateWithLifecycle()
|
}.collectAsStateWithLifecycle()
|
||||||
val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle()
|
val networkStatusUiState by NetworkStatusRepository.uiState.collectAsStateWithLifecycle()
|
||||||
var pendingRemovalItem by remember { mutableStateOf<LibraryItem?>(null) }
|
var pendingRemovalTarget by remember { mutableStateOf<LibraryRemovalTarget?>(null) }
|
||||||
var observedOfflineState by remember { mutableStateOf(false) }
|
var observedOfflineState by remember { mutableStateOf(false) }
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val isTraktSource = uiState.sourceMode == LibrarySourceMode.TRAKT
|
val isTraktSource = uiState.sourceMode == LibrarySourceMode.TRAKT
|
||||||
|
|
@ -165,9 +173,15 @@ fun LibraryScreen(
|
||||||
sections = uiState.sections,
|
sections = uiState.sections,
|
||||||
onPosterClick = onPosterClick,
|
onPosterClick = onPosterClick,
|
||||||
onSectionViewAllClick = onSectionViewAllClick,
|
onSectionViewAllClick = onSectionViewAllClick,
|
||||||
onPosterLongClick = { item ->
|
onPosterLongClick = { item, section ->
|
||||||
if (!isTraktSource) {
|
pendingRemovalTarget = if (isTraktSource) {
|
||||||
pendingRemovalItem = item
|
LibraryRemovalTarget(
|
||||||
|
item = item,
|
||||||
|
listKey = section.type,
|
||||||
|
listTitle = section.displayTitle,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
LibraryRemovalTarget(item = item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -177,17 +191,38 @@ fun LibraryScreen(
|
||||||
|
|
||||||
NuvioStatusModal(
|
NuvioStatusModal(
|
||||||
title = stringResource(Res.string.library_remove_title),
|
title = stringResource(Res.string.library_remove_title),
|
||||||
message = pendingRemovalItem?.let {
|
message = pendingRemovalTarget?.let { target ->
|
||||||
stringResource(Res.string.library_remove_message, it.name)
|
val listTitle = target.listTitle
|
||||||
|
if (listTitle.isNullOrBlank()) {
|
||||||
|
stringResource(Res.string.library_remove_message, target.item.name)
|
||||||
|
} else {
|
||||||
|
stringResource(Res.string.library_remove_from_list_message, target.item.name, listTitle)
|
||||||
|
}
|
||||||
}.orEmpty(),
|
}.orEmpty(),
|
||||||
isVisible = pendingRemovalItem != null,
|
isVisible = pendingRemovalTarget != null,
|
||||||
confirmText = stringResource(Res.string.library_remove_confirm),
|
confirmText = stringResource(Res.string.library_remove_confirm),
|
||||||
dismissText = stringResource(Res.string.action_cancel),
|
dismissText = stringResource(Res.string.action_cancel),
|
||||||
onConfirm = {
|
onConfirm = {
|
||||||
pendingRemovalItem?.id?.let(LibraryRepository::remove)
|
val target = pendingRemovalTarget
|
||||||
pendingRemovalItem = null
|
pendingRemovalTarget = null
|
||||||
|
target?.let {
|
||||||
|
val listKey = target.listKey
|
||||||
|
if (listKey.isNullOrBlank()) {
|
||||||
|
LibraryRepository.remove(target.item.id)
|
||||||
|
} else {
|
||||||
|
coroutineScope.launch {
|
||||||
|
runCatching {
|
||||||
|
LibraryRepository.removeFromList(target.item, listKey)
|
||||||
|
}.onFailure { error ->
|
||||||
|
NuvioToastController.show(
|
||||||
|
error.message ?: getString(Res.string.trakt_lists_update_failed),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onDismiss = { pendingRemovalItem = null },
|
onDismiss = { pendingRemovalTarget = null },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +230,7 @@ private fun LazyListScope.librarySections(
|
||||||
sections: List<LibrarySection>,
|
sections: List<LibrarySection>,
|
||||||
onPosterClick: ((LibraryItem) -> Unit)?,
|
onPosterClick: ((LibraryItem) -> Unit)?,
|
||||||
onSectionViewAllClick: ((LibrarySection) -> Unit)?,
|
onSectionViewAllClick: ((LibrarySection) -> Unit)?,
|
||||||
onPosterLongClick: (LibraryItem) -> Unit,
|
onPosterLongClick: (LibraryItem, LibrarySection) -> Unit,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = sections,
|
items = sections,
|
||||||
|
|
@ -218,7 +253,7 @@ private fun LazyListScope.librarySections(
|
||||||
HomePosterCard(
|
HomePosterCard(
|
||||||
item = item.toMetaPreview(),
|
item = item.toMetaPreview(),
|
||||||
onClick = onPosterClick?.let { { it(item) } },
|
onClick = onPosterClick?.let { { it(item) } },
|
||||||
onLongClick = { onPosterLongClick(item) },
|
onLongClick = { onPosterLongClick(item, section) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue