mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
Support requesting 4k media in discover (#685)
## Description If the server support it and the user has permission, allows for requesting 4K media ### Related issues A follow up to #558
This commit is contained in:
parent
4c7c465c67
commit
80670c3e0f
9 changed files with 138 additions and 33 deletions
|
|
@ -52,6 +52,7 @@ import com.github.damontecres.wholphin.ui.Cards
|
|||
import com.github.damontecres.wholphin.ui.cards.DiscoverItemCard
|
||||
import com.github.damontecres.wholphin.ui.cards.ItemRow
|
||||
import com.github.damontecres.wholphin.ui.cards.SeasonCard
|
||||
import com.github.damontecres.wholphin.ui.components.DialogItem
|
||||
import com.github.damontecres.wholphin.ui.components.DialogParams
|
||||
import com.github.damontecres.wholphin.ui.components.DialogPopup
|
||||
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||
|
|
@ -94,10 +95,14 @@ fun DiscoverMovieDetails(
|
|||
val recommended by viewModel.similar.observeAsState(listOf())
|
||||
val loading by viewModel.loading.observeAsState(LoadingState.Loading)
|
||||
val userConfig by viewModel.userConfig.collectAsState(null)
|
||||
val request4kEnabled by viewModel.request4kEnabled.collectAsState(false)
|
||||
|
||||
var overviewDialog by remember { mutableStateOf<ItemDetailsDialogInfo?>(null) }
|
||||
var moreDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||
|
||||
val requestStr = stringResource(R.string.request)
|
||||
val request4kStr = stringResource(R.string.request_4k)
|
||||
|
||||
val moreActions =
|
||||
MoreDialogActions(
|
||||
navigateTo = viewModel::navigateTo,
|
||||
|
|
@ -129,7 +134,28 @@ fun DiscoverMovieDetails(
|
|||
similar = similar,
|
||||
recommended = recommended,
|
||||
requestOnClick = {
|
||||
movie.id?.let { viewModel.request(it) }
|
||||
movie.id?.let { id ->
|
||||
if (request4kEnabled) {
|
||||
moreDialog =
|
||||
DialogParams(
|
||||
fromLongClick = false,
|
||||
title = movie.title + " (${movie.releaseDate ?: ""})",
|
||||
items =
|
||||
listOf(
|
||||
DialogItem(
|
||||
text = requestStr,
|
||||
onClick = { viewModel.request(id, false) },
|
||||
),
|
||||
DialogItem(
|
||||
text = request4kStr,
|
||||
onClick = { viewModel.request(id, true) },
|
||||
),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
viewModel.request(id, false)
|
||||
}
|
||||
}
|
||||
},
|
||||
cancelOnClick = {
|
||||
movie.id?.let { viewModel.cancelRequest(it) }
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ class DiscoverMovieViewModel
|
|||
val recommended = MutableLiveData<List<DiscoverItem>>(listOf())
|
||||
|
||||
val userConfig = seerrServerRepository.current.map { it?.config }
|
||||
val request4kEnabled = seerrServerRepository.current.map { it?.request4kMovieEnabled ?: false }
|
||||
|
||||
init {
|
||||
init()
|
||||
|
|
@ -145,12 +146,15 @@ class DiscoverMovieViewModel
|
|||
navigationManager.navigateTo(destination)
|
||||
}
|
||||
|
||||
fun request(id: Int) {
|
||||
fun request(
|
||||
id: Int,
|
||||
is4k: Boolean,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val request =
|
||||
seerrService.api.requestApi.requestPost(
|
||||
RequestPostRequest(
|
||||
is4k = false,
|
||||
is4k = is4k,
|
||||
mediaId = id,
|
||||
mediaType = RequestPostRequest.MediaType.MOVIE,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -93,9 +93,14 @@ fun DiscoverSeriesDetails(
|
|||
val similar by viewModel.similar.observeAsState(listOf())
|
||||
val recommended by viewModel.recommended.observeAsState(listOf())
|
||||
val userConfig by viewModel.userConfig.collectAsState(null)
|
||||
val request4kEnabled by viewModel.request4kEnabled.collectAsState(false)
|
||||
|
||||
var overviewDialog by remember { mutableStateOf<ItemDetailsDialogInfo?>(null) }
|
||||
var seasonDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||
var moreDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||
|
||||
val requestStr = stringResource(R.string.request)
|
||||
val request4kStr = stringResource(R.string.request_4k)
|
||||
|
||||
when (val state = loading) {
|
||||
is LoadingState.Error -> {
|
||||
|
|
@ -151,7 +156,28 @@ fun DiscoverSeriesDetails(
|
|||
},
|
||||
trailers = listOf(),
|
||||
requestOnClick = {
|
||||
item.id?.let { viewModel.request(it) }
|
||||
item.id?.let { id ->
|
||||
if (request4kEnabled) {
|
||||
moreDialog =
|
||||
DialogParams(
|
||||
fromLongClick = false,
|
||||
title = item.name ?: "",
|
||||
items =
|
||||
listOf(
|
||||
DialogItem(
|
||||
text = requestStr,
|
||||
onClick = { viewModel.request(id, false) },
|
||||
),
|
||||
DialogItem(
|
||||
text = request4kStr,
|
||||
onClick = { viewModel.request(id, true) },
|
||||
),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
viewModel.request(id, false)
|
||||
}
|
||||
}
|
||||
},
|
||||
cancelOnClick = {
|
||||
item.id?.let { viewModel.cancelRequest(it) }
|
||||
|
|
@ -180,6 +206,16 @@ fun DiscoverSeriesDetails(
|
|||
onDismissRequest = { seasonDialog = null },
|
||||
)
|
||||
}
|
||||
moreDialog?.let { params ->
|
||||
DialogPopup(
|
||||
showDialog = true,
|
||||
title = params.title,
|
||||
dialogItems = params.items,
|
||||
onDismissRequest = { moreDialog = null },
|
||||
dismissOnClick = true,
|
||||
waitToLoad = params.fromLongClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val HEADER_ROW = 0
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ class DiscoverSeriesViewModel
|
|||
val recommended = MutableLiveData<List<DiscoverItem>>(listOf())
|
||||
|
||||
val userConfig = seerrServerRepository.current.map { it?.config }
|
||||
val request4kEnabled = seerrServerRepository.current.map { it?.request4kMovieEnabled ?: false }
|
||||
|
||||
init {
|
||||
init()
|
||||
|
|
@ -136,12 +137,15 @@ class DiscoverSeriesViewModel
|
|||
navigationManager.navigateTo(destination)
|
||||
}
|
||||
|
||||
fun request(id: Int) {
|
||||
fun request(
|
||||
id: Int,
|
||||
is4k: Boolean,
|
||||
) {
|
||||
viewModelScope.launchIO {
|
||||
val request =
|
||||
seerrService.api.requestApi.requestPost(
|
||||
RequestPostRequest(
|
||||
is4k = false,
|
||||
is4k = is4k,
|
||||
mediaId = id,
|
||||
mediaType = RequestPostRequest.MediaType.TV,
|
||||
seasons = RequestPostRequest.Seasons.ALL, // TODO handle picking seasons
|
||||
|
|
|
|||
|
|
@ -466,6 +466,12 @@ fun PreferencesContent(
|
|||
}
|
||||
}
|
||||
if (showSeerrServerDialog) {
|
||||
val status by seerrVm.serverConnectionStatus.collectAsState(LoadingState.Pending)
|
||||
LaunchedEffect(status) {
|
||||
if (status == LoadingState.Success) {
|
||||
showSeerrServerDialog = false
|
||||
}
|
||||
}
|
||||
if (seerrIntegrationEnabled) {
|
||||
ConfirmDialog(
|
||||
title = stringResource(R.string.remove_seerr_server),
|
||||
|
|
@ -478,12 +484,6 @@ fun PreferencesContent(
|
|||
)
|
||||
} else {
|
||||
val currentUser by seerrVm.currentUser.observeAsState()
|
||||
val status by seerrVm.serverConnectionStatus.collectAsState(LoadingState.Pending)
|
||||
LaunchedEffect(status) {
|
||||
if (status == LoadingState.Success) {
|
||||
showSeerrServerDialog = false
|
||||
}
|
||||
}
|
||||
AddSeerServerDialog(
|
||||
currentUsername = currentUser?.name,
|
||||
status = status,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.github.damontecres.wholphin.ui.setup.seerr
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.damontecres.wholphin.api.seerr.infrastructure.ClientException
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.data.model.SeerrAuthMethod
|
||||
import com.github.damontecres.wholphin.services.SeerrServerRepository
|
||||
|
|
@ -13,6 +14,7 @@ import jakarta.inject.Inject
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import timber.log.Timber
|
||||
|
||||
@HiltViewModel
|
||||
class SwitchSeerrViewModel
|
||||
|
|
@ -47,12 +49,21 @@ class SwitchSeerrViewModel
|
|||
viewModelScope.launchIO {
|
||||
val url = cleanUrl(url)
|
||||
val result =
|
||||
seerrServerRepository.testConnection(
|
||||
authMethod = SeerrAuthMethod.API_KEY,
|
||||
url = url,
|
||||
username = null,
|
||||
passwordOrApiKey = apiKey,
|
||||
)
|
||||
try {
|
||||
seerrServerRepository.testConnection(
|
||||
authMethod = SeerrAuthMethod.API_KEY,
|
||||
url = url,
|
||||
username = null,
|
||||
passwordOrApiKey = apiKey,
|
||||
)
|
||||
} catch (ex: ClientException) {
|
||||
Timber.w(ex, "Error logging in via API Key")
|
||||
if (ex.statusCode == 401 || ex.statusCode == 403) {
|
||||
LoadingState.Error("Invalid credentials", ex)
|
||||
} else {
|
||||
LoadingState.Error(ex)
|
||||
}
|
||||
}
|
||||
if (result is LoadingState.Success) {
|
||||
seerrServerRepository.addAndChangeServer(url, apiKey)
|
||||
}
|
||||
|
|
@ -69,12 +80,21 @@ class SwitchSeerrViewModel
|
|||
viewModelScope.launchIO {
|
||||
val url = cleanUrl(url)
|
||||
val result =
|
||||
seerrServerRepository.testConnection(
|
||||
authMethod = authMethod,
|
||||
url = url,
|
||||
username = username,
|
||||
passwordOrApiKey = password,
|
||||
)
|
||||
try {
|
||||
seerrServerRepository.testConnection(
|
||||
authMethod = authMethod,
|
||||
url = url,
|
||||
username = username,
|
||||
passwordOrApiKey = password,
|
||||
)
|
||||
} catch (ex: ClientException) {
|
||||
Timber.w(ex, "Error logging in via %s", authMethod)
|
||||
if (ex.statusCode == 401 || ex.statusCode == 403) {
|
||||
LoadingState.Error("Invalid credentials", ex)
|
||||
} else {
|
||||
LoadingState.Error(ex)
|
||||
}
|
||||
}
|
||||
if (result is LoadingState.Success) {
|
||||
seerrServerRepository.addAndChangeServer(url, authMethod, username, password)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue