mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Merge branch 'main' into develop/jellyseerr
This commit is contained in:
commit
cf73239c46
40 changed files with 1333 additions and 502 deletions
|
|
@ -23,8 +23,9 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
|
||||
|
|
@ -46,6 +47,7 @@ import com.github.damontecres.wholphin.services.ImageUrlService
|
|||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.PlaybackLifecycleObserver
|
||||
import com.github.damontecres.wholphin.services.RefreshRateService
|
||||
import com.github.damontecres.wholphin.services.ServerEventListener
|
||||
import com.github.damontecres.wholphin.services.SetupDestination
|
||||
import com.github.damontecres.wholphin.services.SetupNavigationManager
|
||||
import com.github.damontecres.wholphin.services.UpdateChecker
|
||||
|
|
@ -113,6 +115,14 @@ class MainActivity : AppCompatActivity() {
|
|||
@Inject
|
||||
lateinit var tvProviderSchedulerService: TvProviderSchedulerService
|
||||
|
||||
// Note: unused but injected to ensure it is created
|
||||
@Inject
|
||||
lateinit var serverEventListener: ServerEventListener
|
||||
|
||||
// Note: unused but injected to ensure it is created
|
||||
@Inject
|
||||
lateinit var datePlayedInvalidationService: DatePlayedInvalidationService
|
||||
|
||||
private var signInAuto = true
|
||||
|
||||
@OptIn(ExperimentalTvMaterial3Api::class)
|
||||
|
|
@ -232,13 +242,12 @@ class MainActivity : AppCompatActivity() {
|
|||
var showContent by remember {
|
||||
mutableStateOf(true)
|
||||
}
|
||||
if (!preferences.appPreferences.signInAutomatically) {
|
||||
LifecycleStartEffect(Unit) {
|
||||
onStopOrDispose {
|
||||
showContent = false
|
||||
}
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
|
||||
if (!preferences.appPreferences.signInAutomatically) {
|
||||
showContent = false
|
||||
}
|
||||
}
|
||||
|
||||
if (showContent) {
|
||||
ApplicationContent(
|
||||
user = current.user,
|
||||
|
|
|
|||
|
|
@ -14,4 +14,5 @@ data class LocalTrailer(
|
|||
data class RemoteTrailer(
|
||||
override val name: String,
|
||||
val url: String,
|
||||
val subtitle: String?,
|
||||
) : Trailer
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ class PlaybackLifecycleObserver
|
|||
private var wasPlaying: Boolean? = null
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
val lastDest = navigationManager.backStack.lastOrNull()
|
||||
if (lastDest is Destination.Playback || lastDest is Destination.PlaybackList) {
|
||||
navigationManager.goBack()
|
||||
}
|
||||
wasPlaying = null
|
||||
}
|
||||
|
||||
|
|
@ -40,9 +44,6 @@ class PlaybackLifecycleObserver
|
|||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
if (navigationManager.backStack.lastOrNull() is Destination.Playback) {
|
||||
navigationManager.goBack()
|
||||
}
|
||||
themeSongPlayer.stop()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,13 +95,13 @@ class RefreshRateService
|
|||
} catch (ex: InterruptedException) {
|
||||
Timber.w(ex, "Exception waiting for refresh rate switch")
|
||||
}
|
||||
val targetRate = (targetMode.refreshRate * 100).roundToInt()
|
||||
val targetRate = (targetMode.refreshRate * 1000).roundToInt()
|
||||
val isSeamless =
|
||||
targetRate == (display.mode.refreshRate * 100).roundToInt() ||
|
||||
targetRate == (currentDisplayMode.refreshRate * 1000).roundToInt() ||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
display.mode.alternativeRefreshRates
|
||||
.map { (it * 100).roundToInt() }
|
||||
.any { targetRate % it == 0 }
|
||||
currentDisplayMode.alternativeRefreshRates
|
||||
.map { (it * 1000).roundToInt() }
|
||||
.any { it % targetRate == 0 }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,9 @@ class ThemeSongPlayer
|
|||
}
|
||||
|
||||
fun stop() {
|
||||
Timber.v("Stopping theme song")
|
||||
player.stop()
|
||||
if (player.isPlaying) {
|
||||
Timber.v("Stopping theme song")
|
||||
player.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,31 +22,53 @@ class TrailerService
|
|||
@param:ApplicationContext private val context: Context,
|
||||
private val api: ApiClient,
|
||||
) {
|
||||
suspend fun getTrailers(item: BaseItem): List<Trailer> {
|
||||
val remoteTrailers =
|
||||
item.data.remoteTrailers
|
||||
?.mapNotNull { t ->
|
||||
t.url?.let { url ->
|
||||
val name =
|
||||
t.name
|
||||
// TODO would be nice to clean up the trailer name
|
||||
fun getRemoteTrailers(item: BaseItem): List<Trailer> =
|
||||
item.data.remoteTrailers
|
||||
?.mapNotNull { t ->
|
||||
t.url?.let { url ->
|
||||
val name =
|
||||
t.name
|
||||
// TODO would be nice to clean up the trailer name
|
||||
// ?.replace(item.name ?: "", "")
|
||||
// ?.removePrefix(" - ")
|
||||
?: context.getString(R.string.trailer)
|
||||
RemoteTrailer(name, url)
|
||||
}
|
||||
}.orEmpty()
|
||||
.sortedBy { it.name }
|
||||
val localTrailerCount = item.data.localTrailerCount ?: 0
|
||||
?: context.getString(R.string.trailer)
|
||||
val subtitle =
|
||||
when (url.toUri().host) {
|
||||
"youtube.com", "www.youtube.com" -> "YouTube"
|
||||
else -> null
|
||||
}
|
||||
RemoteTrailer(name, url, subtitle)
|
||||
}
|
||||
}.orEmpty()
|
||||
.sortedWith(
|
||||
compareBy(
|
||||
{
|
||||
// Try to show official trailers first & teasers last
|
||||
when {
|
||||
it.name.contains("Official Trailer", true) -> 0
|
||||
it.name.contains("Official Theatrical Trailer", true) -> 0
|
||||
it.name.contains("Teaser", true) -> 10
|
||||
it.name.contains("Trailer", true) -> 1
|
||||
else -> 5
|
||||
}
|
||||
},
|
||||
{
|
||||
it.name
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
suspend fun getLocalTrailers(item: BaseItem): List<Trailer> {
|
||||
val localTrailerCount = item.data.localTrailerCount ?: return emptyList()
|
||||
val localTrailers =
|
||||
if (localTrailerCount > 0) {
|
||||
api.userLibraryApi.getLocalTrailers(item.id).content.map {
|
||||
LocalTrailer(BaseItem.Companion.from(it, api))
|
||||
LocalTrailer(BaseItem.from(it, api))
|
||||
}
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
return localTrailers + remoteTrailers
|
||||
return localTrailers
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -28,9 +28,7 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.media3.common.Player
|
||||
import coil3.request.ErrorResult
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
|
|
@ -182,10 +180,10 @@ fun RequestOrRestoreFocus(
|
|||
debugKey?.let { Timber.v("RequestOrRestoreFocus: %s", it) }
|
||||
focusRequester.tryRequestFocus()
|
||||
}
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||
debugKey?.let { Timber.v("RequestOrRestoreFocus onResume: %s", it) }
|
||||
focusRequester.tryRequestFocus()
|
||||
}
|
||||
// LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||
// debugKey?.let { Timber.v("RequestOrRestoreFocus onResume: %s", it) }
|
||||
// focusRequester.tryRequestFocus()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ class CollectionFolderViewModel
|
|||
context.getString(R.string.error_loading_collection, itemId),
|
||||
) + Dispatchers.IO,
|
||||
) {
|
||||
super.itemId = itemId
|
||||
itemId.toUUIDOrNull()?.let {
|
||||
fetchItem(it)
|
||||
}
|
||||
|
|
@ -206,7 +207,7 @@ class CollectionFolderViewModel
|
|||
) {
|
||||
if (collectionFilter.useSavedLibraryDisplayInfo) {
|
||||
serverRepository.currentUser.value?.let { user ->
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
viewModelScope.launchIO {
|
||||
val libraryDisplayInfo =
|
||||
LibraryDisplayInfo(
|
||||
userId = user.rowId,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.gestures.scrollBy
|
|||
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.fillMaxWidth
|
||||
|
|
@ -239,47 +240,48 @@ fun DialogPopupContent(
|
|||
) {
|
||||
val elevatedContainerColor =
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(elevation)
|
||||
LazyColumn(
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier =
|
||||
modifier
|
||||
// .widthIn(min = 520.dp, max = 300.dp)
|
||||
// .dialogFocusable()
|
||||
.graphicsLayer {
|
||||
this.clip = true
|
||||
this.shape = RoundedCornerShape(28.0.dp)
|
||||
}.drawBehind { drawRect(color = elevatedContainerColor) }
|
||||
.padding(PaddingValues(24.dp)),
|
||||
) {
|
||||
stickyHeader {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
items(dialogItems) {
|
||||
when (it) {
|
||||
is DialogItemDivider -> {
|
||||
HorizontalDivider(Modifier.height(16.dp))
|
||||
}
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
LazyColumn(
|
||||
modifier = Modifier,
|
||||
) {
|
||||
items(dialogItems) {
|
||||
when (it) {
|
||||
is DialogItemDivider -> {
|
||||
HorizontalDivider(Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
is DialogItem -> {
|
||||
ListItem(
|
||||
selected = false,
|
||||
enabled = !waiting && it.enabled,
|
||||
onClick = {
|
||||
if (dismissOnClick) {
|
||||
onDismissRequest.invoke()
|
||||
}
|
||||
it.onClick.invoke()
|
||||
},
|
||||
headlineContent = it.headlineContent,
|
||||
overlineContent = it.overlineContent,
|
||||
supportingContent = it.supportingContent,
|
||||
leadingContent = it.leadingContent,
|
||||
trailingContent = it.trailingContent,
|
||||
modifier = Modifier,
|
||||
)
|
||||
is DialogItem -> {
|
||||
ListItem(
|
||||
selected = false,
|
||||
enabled = !waiting && it.enabled,
|
||||
onClick = {
|
||||
if (dismissOnClick) {
|
||||
onDismissRequest.invoke()
|
||||
}
|
||||
it.onClick.invoke()
|
||||
},
|
||||
headlineContent = it.headlineContent,
|
||||
overlineContent = it.overlineContent,
|
||||
supportingContent = it.supportingContent,
|
||||
leadingContent = it.leadingContent,
|
||||
trailingContent = it.trailingContent,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ import androidx.compose.material.icons.filled.MoreVert
|
|||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
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.focus.FocusRequester
|
||||
|
|
@ -40,6 +43,7 @@ import androidx.tv.material3.Icon
|
|||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.Trailer
|
||||
import com.github.damontecres.wholphin.ui.FontAwesome
|
||||
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
||||
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
||||
|
|
@ -59,10 +63,12 @@ fun ExpandablePlayButtons(
|
|||
resumePosition: Duration,
|
||||
watched: Boolean,
|
||||
favorite: Boolean,
|
||||
trailers: List<Trailer>?,
|
||||
playOnClick: (position: Duration) -> Unit,
|
||||
watchOnClick: () -> Unit,
|
||||
favoriteOnClick: () -> Unit,
|
||||
moreOnClick: () -> Unit,
|
||||
trailerOnClick: (Trailer) -> Unit,
|
||||
buttonOnFocusChanged: (FocusState) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -134,6 +140,16 @@ fun ExpandablePlayButtons(
|
|||
)
|
||||
}
|
||||
|
||||
if (trailers != null) {
|
||||
item("trailers") {
|
||||
TrailerButton(
|
||||
trailers = trailers,
|
||||
trailerOnClick = trailerOnClick,
|
||||
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// More button
|
||||
item("more") {
|
||||
ExpandablePlayButton(
|
||||
|
|
@ -229,6 +245,7 @@ fun ExpandableFaButton(
|
|||
),
|
||||
contentPadding = DefaultButtonPadding,
|
||||
interactionSource = interactionSource,
|
||||
enabled = enabled,
|
||||
) {
|
||||
Box(
|
||||
modifier =
|
||||
|
|
@ -255,6 +272,42 @@ fun ExpandableFaButton(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TrailerButton(
|
||||
trailers: List<Trailer>,
|
||||
trailerOnClick: (Trailer) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
ExpandableFaButton(
|
||||
title =
|
||||
if (trailers.isEmpty()) {
|
||||
R.string.no_trailers
|
||||
} else if (trailers.size == 1) {
|
||||
R.string.play_trailer
|
||||
} else {
|
||||
R.string.trailers
|
||||
},
|
||||
iconStringRes = R.string.fa_film,
|
||||
enabled = trailers.isNotEmpty(),
|
||||
onClick = {
|
||||
if (trailers.size == 1) {
|
||||
trailerOnClick.invoke(trailers.first())
|
||||
} else {
|
||||
showDialog = true
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
if (showDialog) {
|
||||
TrailerDialog(
|
||||
onDismissRequest = { showDialog = false },
|
||||
trailers = trailers,
|
||||
onClick = trailerOnClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewTvSpec
|
||||
@Composable
|
||||
private fun ExpandablePlayButtonsPreview() {
|
||||
|
|
@ -268,6 +321,8 @@ private fun ExpandablePlayButtonsPreview() {
|
|||
favoriteOnClick = {},
|
||||
moreOnClick = {},
|
||||
buttonOnFocusChanged = {},
|
||||
trailers = listOf(),
|
||||
trailerOnClick = {},
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.github.damontecres.wholphin.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.LocalTrailer
|
||||
import com.github.damontecres.wholphin.data.model.RemoteTrailer
|
||||
import com.github.damontecres.wholphin.data.model.Trailer
|
||||
|
||||
@Composable
|
||||
fun TrailerDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
trailers: List<Trailer>,
|
||||
onClick: (Trailer) -> Unit,
|
||||
) {
|
||||
val trailersStr = stringResource(R.string.play_trailer)
|
||||
val localStr = stringResource(R.string.local)
|
||||
val externalStr = stringResource(R.string.external_track)
|
||||
val params =
|
||||
remember(trailers) {
|
||||
DialogParams(
|
||||
fromLongClick = false,
|
||||
title = trailersStr,
|
||||
items =
|
||||
trailers.map { trailer ->
|
||||
DialogItem(
|
||||
headlineContent = {
|
||||
Text(trailer.name)
|
||||
},
|
||||
supportingContent = {
|
||||
val subtitle =
|
||||
when (trailer) {
|
||||
is LocalTrailer -> localStr
|
||||
is RemoteTrailer -> trailer.subtitle ?: externalStr
|
||||
}
|
||||
Text(
|
||||
text = subtitle,
|
||||
)
|
||||
},
|
||||
onClick = { onClick.invoke(trailer) },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
DialogPopup(
|
||||
params = params,
|
||||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
|
|
@ -196,210 +196,224 @@ fun <T : CardGridItem> CardGrid(
|
|||
}
|
||||
}
|
||||
|
||||
var longPressing by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
// horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxSize()
|
||||
.onKeyEvent {
|
||||
if (DEBUG) Timber.d("onKeyEvent: ${it.nativeKeyEvent}")
|
||||
if (useBackToJump && it.key == Key.Back && it.nativeKeyEvent.isLongPress) {
|
||||
longPressing = true
|
||||
val newPosition = previouslyFocusedIndex
|
||||
if (DEBUG) Timber.d("Back long pressed: newPosition=$newPosition")
|
||||
if (newPosition > 0) {
|
||||
focusOn(newPosition)
|
||||
scope.launch(ExceptionHandler()) {
|
||||
gridState.scrollToItem(newPosition, -columns)
|
||||
firstFocus.tryRequestFocus()
|
||||
}
|
||||
}
|
||||
return@onKeyEvent true
|
||||
} else if (it.type == KeyEventType.KeyUp) {
|
||||
if (longPressing && it.key == Key.Back) {
|
||||
longPressing = false
|
||||
return@onKeyEvent true
|
||||
}
|
||||
longPressing = false
|
||||
}
|
||||
if (it.type != KeyEventType.KeyUp) {
|
||||
return@onKeyEvent false
|
||||
} else if (useBackToJump && it.key == Key.Back && focusedIndex > 0) {
|
||||
jumpToTop()
|
||||
return@onKeyEvent true
|
||||
} else if (isPlayKeyUp(it)) {
|
||||
val item = pager.getOrNull(focusedIndex)
|
||||
if (item?.playable == true) {
|
||||
Timber.v("Clicked play on ${item.id}")
|
||||
onClickPlay.invoke(focusedIndex, item)
|
||||
}
|
||||
return@onKeyEvent true
|
||||
} else if (useJumpRemoteButtons && isForwardButton(it)) {
|
||||
jump(jump1)
|
||||
return@onKeyEvent true
|
||||
} else if (useJumpRemoteButtons && isBackwardButton(it)) {
|
||||
jump(-jump1)
|
||||
return@onKeyEvent true
|
||||
} else {
|
||||
return@onKeyEvent false
|
||||
}
|
||||
},
|
||||
) {
|
||||
if (showJumpButtons && pager.isNotEmpty()) {
|
||||
JumpButtons(
|
||||
jump1 = jump1,
|
||||
jump2 = jump2,
|
||||
jumpClick = { jump(it) },
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
if (pager.isEmpty()) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = modifier.fillMaxSize(),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.no_results),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(columns),
|
||||
horizontalArrangement = Arrangement.spacedBy(spacing),
|
||||
verticalArrangement = Arrangement.spacedBy(spacing),
|
||||
state = gridState,
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.focusGroup()
|
||||
.focusRestorer(firstFocus)
|
||||
.focusProperties {
|
||||
onExit = {
|
||||
// Leaving the grid, so "forget" the position
|
||||
// focusedIndex = -1
|
||||
}
|
||||
onEnter = {
|
||||
if (focusedIndex < 0 && gridState.firstVisibleItemIndex <= startPosition) {
|
||||
focusedIndex = startPosition
|
||||
} else {
|
||||
var longPressing by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
// horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxSize()
|
||||
.onKeyEvent {
|
||||
if (DEBUG) Timber.d("onKeyEvent: ${it.nativeKeyEvent}")
|
||||
if (useBackToJump && it.key == Key.Back && it.nativeKeyEvent.isLongPress) {
|
||||
longPressing = true
|
||||
val newPosition = previouslyFocusedIndex
|
||||
if (DEBUG) Timber.d("Back long pressed: newPosition=$newPosition")
|
||||
if (newPosition > 0) {
|
||||
focusOn(newPosition)
|
||||
scope.launch(ExceptionHandler()) {
|
||||
gridState.scrollToItem(newPosition, -columns)
|
||||
firstFocus.tryRequestFocus()
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
items(pager.size) { index ->
|
||||
val mod =
|
||||
if ((index == focusedIndex) or (focusedIndex < 0 && index == 0)) {
|
||||
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
|
||||
Modifier
|
||||
.focusRequester(firstFocus)
|
||||
.focusRequester(gridFocusRequester)
|
||||
.focusRequester(alphabetFocusRequester)
|
||||
} else {
|
||||
Modifier
|
||||
return@onKeyEvent true
|
||||
} else if (it.type == KeyEventType.KeyUp) {
|
||||
if (longPressing && it.key == Key.Back) {
|
||||
longPressing = false
|
||||
return@onKeyEvent true
|
||||
}
|
||||
longPressing = false
|
||||
}
|
||||
val item = pager[index]
|
||||
cardContent(
|
||||
item,
|
||||
{
|
||||
if (item != null) {
|
||||
focusedIndex = index
|
||||
onClickItem.invoke(index, item)
|
||||
if (it.type != KeyEventType.KeyUp) {
|
||||
return@onKeyEvent false
|
||||
} else if (useBackToJump && it.key == Key.Back && focusedIndex > 0) {
|
||||
jumpToTop()
|
||||
return@onKeyEvent true
|
||||
} else if (isPlayKeyUp(it)) {
|
||||
val item = pager.getOrNull(focusedIndex)
|
||||
if (item?.playable == true) {
|
||||
Timber.v("Clicked play on ${item.id}")
|
||||
onClickPlay.invoke(focusedIndex, item)
|
||||
}
|
||||
},
|
||||
{ if (item != null) onLongClickItem.invoke(index, item) },
|
||||
mod
|
||||
.ifElse(index == 0, Modifier.focusRequester(zeroFocus))
|
||||
.onFocusChanged { focusState ->
|
||||
if (DEBUG) {
|
||||
Timber.v(
|
||||
"$index isFocused=${focusState.isFocused}",
|
||||
)
|
||||
return@onKeyEvent true
|
||||
} else if (useJumpRemoteButtons && isForwardButton(it)) {
|
||||
jump(jump1)
|
||||
return@onKeyEvent true
|
||||
} else if (useJumpRemoteButtons && isBackwardButton(it)) {
|
||||
jump(-jump1)
|
||||
return@onKeyEvent true
|
||||
} else {
|
||||
return@onKeyEvent false
|
||||
}
|
||||
},
|
||||
) {
|
||||
if (showJumpButtons && pager.isNotEmpty()) {
|
||||
JumpButtons(
|
||||
jump1 = jump1,
|
||||
jump2 = jump2,
|
||||
jumpClick = { jump(it) },
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(columns),
|
||||
horizontalArrangement = Arrangement.spacedBy(spacing),
|
||||
verticalArrangement = Arrangement.spacedBy(spacing),
|
||||
state = gridState,
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.focusGroup()
|
||||
.focusRestorer(firstFocus)
|
||||
.focusProperties {
|
||||
onExit = {
|
||||
// Leaving the grid, so "forget" the position
|
||||
// focusedIndex = -1
|
||||
}
|
||||
if (focusState.isFocused) {
|
||||
// Focused, so set that up
|
||||
focusOn(index)
|
||||
positionCallback?.invoke(columns, index)
|
||||
} else if (focusedIndex == index) {
|
||||
onEnter = {
|
||||
if (focusedIndex < 0 && gridState.firstVisibleItemIndex <= startPosition) {
|
||||
focusedIndex = startPosition
|
||||
}
|
||||
}
|
||||
},
|
||||
) {
|
||||
items(pager.size) { index ->
|
||||
val mod =
|
||||
if ((index == focusedIndex) or (focusedIndex < 0 && index == 0)) {
|
||||
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
|
||||
Modifier
|
||||
.focusRequester(firstFocus)
|
||||
.focusRequester(gridFocusRequester)
|
||||
.focusRequester(alphabetFocusRequester)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
val item = pager[index]
|
||||
cardContent(
|
||||
item,
|
||||
{
|
||||
if (item != null) {
|
||||
focusedIndex = index
|
||||
onClickItem.invoke(index, item)
|
||||
}
|
||||
},
|
||||
{ if (item != null) onLongClickItem.invoke(index, item) },
|
||||
mod
|
||||
.ifElse(index == 0, Modifier.focusRequester(zeroFocus))
|
||||
.onFocusChanged { focusState ->
|
||||
if (DEBUG) {
|
||||
Timber.v(
|
||||
"$index isFocused=${focusState.isFocused}",
|
||||
)
|
||||
}
|
||||
if (focusState.isFocused) {
|
||||
// Focused, so set that up
|
||||
focusOn(index)
|
||||
positionCallback?.invoke(columns, index)
|
||||
} else if (focusedIndex == index) {
|
||||
// savedFocusedIndex = index
|
||||
// // Was focused on this, so mark unfocused
|
||||
// focusedIndex = -1
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pager.isEmpty()) {
|
||||
if (pager.isEmpty()) {
|
||||
// focusedIndex = -1
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
text = stringResource(R.string.no_results),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Text(
|
||||
text = stringResource(R.string.no_results),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (showFooter) {
|
||||
// Footer
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.background(AppColors.TransparentBlack50),
|
||||
) {
|
||||
val index = (focusedIndex + 1).takeIf { it > 0 } ?: "?"
|
||||
if (showFooter) {
|
||||
// Footer
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.background(AppColors.TransparentBlack50),
|
||||
) {
|
||||
val index = (focusedIndex + 1).takeIf { it > 0 } ?: "?"
|
||||
// if (focusedIndex >= 0) {
|
||||
// focusedIndex + 1
|
||||
// } else {
|
||||
// max(savedFocusedIndex, focusedIndexOnExit) + 1
|
||||
// }
|
||||
Text(
|
||||
modifier = Modifier.padding(4.dp),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
text = "$index / ${pager.size}",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(4.dp),
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
text = "$index / ${pager.size}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val context = LocalContext.current
|
||||
val letters = context.getString(R.string.jump_letters)
|
||||
// Letters
|
||||
val currentLetter =
|
||||
remember(focusedIndex) {
|
||||
pager
|
||||
.getOrNull(focusedIndex)
|
||||
?.sortName
|
||||
?.first()
|
||||
?.uppercaseChar()
|
||||
?.let {
|
||||
if (it >= '0' && it <= '9') {
|
||||
'#'
|
||||
} else if (it >= 'A' && it <= 'Z') {
|
||||
it
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
?: letters[0]
|
||||
}
|
||||
if (showLetterButtons && pager.isNotEmpty()) {
|
||||
AlphabetButtons(
|
||||
letters = letters,
|
||||
currentLetter = currentLetter,
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(end = 16.dp),
|
||||
// Add end padding to push away from edge
|
||||
letterClicked = { letter ->
|
||||
scope.launch(ExceptionHandler()) {
|
||||
val jumpPosition =
|
||||
withContext(Dispatchers.IO) {
|
||||
letterPosition.invoke(letter)
|
||||
val context = LocalContext.current
|
||||
val letters = context.getString(R.string.jump_letters)
|
||||
// Letters
|
||||
val currentLetter =
|
||||
remember(focusedIndex) {
|
||||
pager
|
||||
.getOrNull(focusedIndex)
|
||||
?.sortName
|
||||
?.first()
|
||||
?.uppercaseChar()
|
||||
?.let {
|
||||
if (it >= '0' && it <= '9') {
|
||||
'#'
|
||||
} else if (it >= 'A' && it <= 'Z') {
|
||||
it
|
||||
} else {
|
||||
null
|
||||
}
|
||||
Timber.d("Alphabet jump to $jumpPosition")
|
||||
if (jumpPosition >= 0) {
|
||||
pager.getOrNull(jumpPosition)
|
||||
gridState.scrollToItem(jumpPosition)
|
||||
focusOn(jumpPosition)
|
||||
alphabetFocus = true
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
?: letters[0]
|
||||
}
|
||||
if (showLetterButtons && pager.isNotEmpty()) {
|
||||
AlphabetButtons(
|
||||
letters = letters,
|
||||
currentLetter = currentLetter,
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(end = 16.dp),
|
||||
// Add end padding to push away from edge
|
||||
letterClicked = { letter ->
|
||||
scope.launch(ExceptionHandler()) {
|
||||
val jumpPosition =
|
||||
withContext(Dispatchers.IO) {
|
||||
letterPosition.invoke(letter)
|
||||
}
|
||||
Timber.d("Alphabet jump to $jumpPosition")
|
||||
if (jumpPosition >= 0) {
|
||||
pager.getOrNull(jumpPosition)
|
||||
gridState.scrollToItem(jumpPosition)
|
||||
focusOn(jumpPosition)
|
||||
alphabetFocus = true
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ abstract class ItemViewModel(
|
|||
) : ViewModel() {
|
||||
val item = MutableLiveData<BaseItem?>(null)
|
||||
lateinit var itemId: String
|
||||
lateinit var itemUuid: UUID
|
||||
var itemUuid: UUID? = null
|
||||
|
||||
suspend fun fetchItem(itemId: UUID): BaseItem =
|
||||
withContext(Dispatchers.IO) {
|
||||
|
|
|
|||
|
|
@ -155,8 +155,10 @@ class PersonViewModel
|
|||
|
||||
fun setFavorite(favorite: Boolean) {
|
||||
viewModelScope.launchIO {
|
||||
favoriteWatchManager.setFavorite(itemUuid, favorite)
|
||||
fetchAndSetItem(itemUuid)
|
||||
itemUuid?.let {
|
||||
favoriteWatchManager.setFavorite(it, favorite)
|
||||
fetchAndSetItem(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
|
|
@ -112,12 +111,12 @@ fun EpisodeDetails(
|
|||
|
||||
LoadingState.Success -> {
|
||||
item?.let { ep ->
|
||||
LifecycleStartEffect(destination.itemId) {
|
||||
LifecycleResumeEffect(destination.itemId) {
|
||||
viewModel.maybePlayThemeSong(
|
||||
destination.itemId,
|
||||
preferences.appPreferences.interfacePreferences.playThemeSongs,
|
||||
)
|
||||
onStopOrDispose {
|
||||
onPauseOrDispose {
|
||||
viewModel.release()
|
||||
}
|
||||
}
|
||||
|
|
@ -335,6 +334,8 @@ fun EpisodeDetailsContent(
|
|||
}
|
||||
}
|
||||
},
|
||||
trailers = null,
|
||||
trailerOnClick = {},
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.relocation.BringIntoViewRequester
|
||||
import androidx.compose.foundation.relocation.bringIntoViewRequester
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -23,25 +20,18 @@ import androidx.compose.runtime.setValue
|
|||
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.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.data.ExtrasItem
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.Chapter
|
||||
import com.github.damontecres.wholphin.data.model.LocalTrailer
|
||||
import com.github.damontecres.wholphin.data.model.Person
|
||||
import com.github.damontecres.wholphin.data.model.RemoteTrailer
|
||||
import com.github.damontecres.wholphin.data.model.Trailer
|
||||
import com.github.damontecres.wholphin.data.model.aspectRatioFloat
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
|
|
@ -143,12 +133,12 @@ fun MovieDetails(
|
|||
|
||||
LoadingState.Success -> {
|
||||
item?.let { movie ->
|
||||
LifecycleStartEffect(destination.itemId) {
|
||||
LifecycleResumeEffect(destination.itemId) {
|
||||
viewModel.maybePlayThemeSong(
|
||||
destination.itemId,
|
||||
preferences.appPreferences.interfacePreferences.playThemeSongs,
|
||||
)
|
||||
onStopOrDispose {
|
||||
onPauseOrDispose {
|
||||
viewModel.release()
|
||||
}
|
||||
}
|
||||
|
|
@ -437,6 +427,11 @@ fun MovieDetailsContent(
|
|||
}
|
||||
}
|
||||
},
|
||||
trailers = trailers,
|
||||
trailerOnClick = {
|
||||
position = TRAILER_ROW
|
||||
trailerOnClick.invoke(it)
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -464,21 +459,6 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (trailers.isNotEmpty()) {
|
||||
item {
|
||||
TrailerRow(
|
||||
trailers = trailers,
|
||||
onClickTrailer = {
|
||||
position = TRAILER_ROW
|
||||
trailerOnClick.invoke(it)
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequesters[TRAILER_ROW]),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (chapters.isNotEmpty()) {
|
||||
item {
|
||||
ChapterRow(
|
||||
|
|
@ -546,78 +526,3 @@ fun MovieDetailsContent(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TrailerRow(
|
||||
trailers: List<Trailer>,
|
||||
onClickTrailer: (Trailer) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val state = rememberLazyListState()
|
||||
val firstFocus = remember { FocusRequester() }
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = modifier,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.trailers),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
LazyRow(
|
||||
state = state,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 8.dp),
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.focusRestorer(firstFocus),
|
||||
) {
|
||||
itemsIndexed(trailers) { index, item ->
|
||||
val cardModifier =
|
||||
if (index == 0) {
|
||||
Modifier.focusRequester(firstFocus)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
when (item) {
|
||||
is LocalTrailer -> {
|
||||
SeasonCard(
|
||||
item = item.baseItem,
|
||||
onClick = { onClickTrailer.invoke(item) },
|
||||
onLongClick = {},
|
||||
imageHeight = Cards.height2x3,
|
||||
imageWidth = Dp.Unspecified,
|
||||
showImageOverlay = false,
|
||||
modifier = cardModifier,
|
||||
)
|
||||
}
|
||||
|
||||
is RemoteTrailer -> {
|
||||
val subtitle =
|
||||
when (item.url.toUri().host) {
|
||||
"youtube.com", "www.youtube.com" -> "YouTube"
|
||||
else -> null
|
||||
}
|
||||
SeasonCard(
|
||||
title = item.name,
|
||||
subtitle = subtitle,
|
||||
name = item.name,
|
||||
imageUrl = null,
|
||||
isFavorite = false,
|
||||
isPlayed = false,
|
||||
unplayedItemCount = 0,
|
||||
playedPercentage = 0.0,
|
||||
onClick = { onClickTrailer.invoke(item) },
|
||||
onLongClick = {},
|
||||
modifier = cardModifier,
|
||||
showImageOverlay = false,
|
||||
imageHeight = Cards.height2x3,
|
||||
imageWidth = Dp.Unspecified,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.github.damontecres.wholphin.services.TrailerService
|
|||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
|
|
@ -116,16 +117,19 @@ class MovieViewModel
|
|||
item,
|
||||
userPreferencesService.getCurrent(),
|
||||
)
|
||||
val remoteTrailers = trailerService.getRemoteTrailers(item)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.item.value = item
|
||||
chosenStreams.value = result
|
||||
this@MovieViewModel.trailers.value = remoteTrailers
|
||||
loading.value = LoadingState.Success
|
||||
backdropService.submit(item)
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
val trailers = trailerService.getTrailers(item)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.trailers.value = trailers
|
||||
trailerService.getLocalTrailers(item).letNotEmpty { localTrailers ->
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.trailers.value = localTrailers + remoteTrailers
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ fun FocusedEpisodeFooter(
|
|||
watchOnClick = watchOnClick,
|
||||
favoriteOnClick = favoriteOnClick,
|
||||
buttonOnFocusChanged = buttonOnFocusChanged,
|
||||
trailers = null,
|
||||
trailerOnClick = {},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
|
|
@ -62,6 +62,7 @@ import com.github.damontecres.wholphin.ui.components.LoadingPage
|
|||
import com.github.damontecres.wholphin.ui.components.Optional
|
||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||
import com.github.damontecres.wholphin.ui.components.SeriesQuickDetails
|
||||
import com.github.damontecres.wholphin.ui.components.TrailerButton
|
||||
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
|
||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
|
||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
|
||||
|
|
@ -70,7 +71,6 @@ import com.github.damontecres.wholphin.ui.detail.PlaylistDialog
|
|||
import com.github.damontecres.wholphin.ui.detail.PlaylistLoadingState
|
||||
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome
|
||||
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForPerson
|
||||
import com.github.damontecres.wholphin.ui.detail.movie.TrailerRow
|
||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.rememberInt
|
||||
|
|
@ -124,12 +124,12 @@ fun SeriesDetails(
|
|||
|
||||
LoadingState.Success -> {
|
||||
item?.let { item ->
|
||||
LifecycleStartEffect(destination.itemId) {
|
||||
LifecycleResumeEffect(destination.itemId) {
|
||||
viewModel.maybePlayThemeSong(
|
||||
destination.itemId,
|
||||
preferences.appPreferences.interfacePreferences.playThemeSongs,
|
||||
)
|
||||
onStopOrDispose {
|
||||
onPauseOrDispose {
|
||||
viewModel.release()
|
||||
}
|
||||
}
|
||||
|
|
@ -411,6 +411,18 @@ fun SeriesDetailsContent(
|
|||
}
|
||||
},
|
||||
)
|
||||
TrailerButton(
|
||||
trailers = trailers,
|
||||
trailerOnClick = trailerOnClick,
|
||||
modifier =
|
||||
Modifier.onFocusChanged {
|
||||
if (it.isFocused) {
|
||||
scope.launch(ExceptionHandler()) {
|
||||
bringIntoViewRequester.bringIntoView()
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
|
|
@ -472,21 +484,6 @@ fun SeriesDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (trailers.isNotEmpty()) {
|
||||
item {
|
||||
TrailerRow(
|
||||
trailers = trailers,
|
||||
onClickTrailer = {
|
||||
position = TRAILER_ROW
|
||||
trailerOnClick.invoke(it)
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequesters[TRAILER_ROW]),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (extras.isNotEmpty()) {
|
||||
item {
|
||||
ExtrasRow(
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import androidx.lifecycle.map
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.RequestOrRestoreFocus
|
||||
import com.github.damontecres.wholphin.ui.components.DialogParams
|
||||
import com.github.damontecres.wholphin.ui.components.DialogPopup
|
||||
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||
|
|
@ -37,7 +38,6 @@ import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItems
|
|||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.rememberInt
|
||||
import com.github.damontecres.wholphin.ui.seasonEpisode
|
||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||
import com.github.damontecres.wholphin.util.LoadingState
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.serialization.Serializable
|
||||
|
|
@ -158,19 +158,21 @@ fun SeriesOverview(
|
|||
LoadingState.Success -> {
|
||||
series?.let { series ->
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
RequestOrRestoreFocus(
|
||||
when (rowFocused) {
|
||||
EPISODE_ROW -> episodeRowFocusRequester.tryRequestFocus()
|
||||
CAST_AND_CREW_ROW -> castCrewRowFocusRequester.tryRequestFocus()
|
||||
GUEST_STAR_ROW -> guestStarRowFocusRequester.tryRequestFocus()
|
||||
}
|
||||
}
|
||||
LifecycleStartEffect(destination.itemId) {
|
||||
EPISODE_ROW -> episodeRowFocusRequester
|
||||
CAST_AND_CREW_ROW -> castCrewRowFocusRequester
|
||||
GUEST_STAR_ROW -> guestStarRowFocusRequester
|
||||
else -> episodeRowFocusRequester
|
||||
},
|
||||
"series_overview",
|
||||
)
|
||||
LifecycleResumeEffect(destination.itemId) {
|
||||
viewModel.maybePlayThemeSong(
|
||||
destination.itemId,
|
||||
preferences.appPreferences.interfacePreferences.playThemeSongs,
|
||||
)
|
||||
onStopOrDispose {
|
||||
onPauseOrDispose {
|
||||
viewModel.release()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ import com.github.damontecres.wholphin.data.model.BaseItem
|
|||
import com.github.damontecres.wholphin.data.model.Person
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.AspectRatios
|
||||
import com.github.damontecres.wholphin.ui.RequestOrRestoreFocus
|
||||
import com.github.damontecres.wholphin.ui.cards.BannerCard
|
||||
import com.github.damontecres.wholphin.ui.cards.PersonRow
|
||||
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||
|
|
@ -107,6 +106,7 @@ fun SeriesOverviewContent(
|
|||
|
||||
val scrollState = rememberScrollState()
|
||||
val scrollConnection = rememberDelayedNestedScroll()
|
||||
var requestFocusAfterSeason by remember { mutableStateOf(false) }
|
||||
Box(
|
||||
modifier =
|
||||
modifier
|
||||
|
|
@ -147,6 +147,7 @@ fun SeriesOverviewContent(
|
|||
onClick = {
|
||||
selectedTabIndex = it
|
||||
onChangeSeason.invoke(it)
|
||||
requestFocusAfterSeason = true
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
|
|
@ -181,8 +182,14 @@ fun SeriesOverviewContent(
|
|||
}
|
||||
|
||||
is EpisodeList.Success -> {
|
||||
if (requestFocusAfterSeason) {
|
||||
// Changing seasons, so move focus once the new episodes are loaded
|
||||
LaunchedEffect(Unit) {
|
||||
firstItemFocusRequester.tryRequestFocus()
|
||||
requestFocusAfterSeason = false
|
||||
}
|
||||
}
|
||||
val state = rememberLazyListState(position.episodeRowIndex)
|
||||
RequestOrRestoreFocus(firstItemFocusRequester)
|
||||
|
||||
LazyRow(
|
||||
state = state,
|
||||
|
|
|
|||
|
|
@ -165,8 +165,9 @@ class SeriesViewModel
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
val remoteTrailers = trailerService.getRemoteTrailers(item)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@SeriesViewModel.trailers.value = remoteTrailers
|
||||
this@SeriesViewModel.position.update {
|
||||
it.copy(
|
||||
episodeRowIndex =
|
||||
|
|
@ -179,9 +180,10 @@ class SeriesViewModel
|
|||
}
|
||||
if (seriesPageType == SeriesPageType.DETAILS) {
|
||||
viewModelScope.launchIO {
|
||||
val trailers = trailerService.getTrailers(item)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@SeriesViewModel.trailers.value = trailers
|
||||
trailerService.getLocalTrailers(item).letNotEmpty { localTrailers ->
|
||||
withContext(Dispatchers.Main) {
|
||||
this@SeriesViewModel.trailers.value = localTrailers + remoteTrailers
|
||||
}
|
||||
}
|
||||
}
|
||||
viewModelScope.launchIO {
|
||||
|
|
@ -221,9 +223,6 @@ class SeriesViewModel
|
|||
) {
|
||||
viewModelScope.launchIO {
|
||||
themeSongPlayer.playThemeFor(seriesId, playThemeSongs)
|
||||
addCloseable {
|
||||
themeSongPlayer.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ fun HomePageContent(
|
|||
|
||||
val listState = rememberLazyListState()
|
||||
val rowFocusRequesters = remember(homeRows.size) { List(homeRows.size) { FocusRequester() } }
|
||||
var focused by remember { mutableStateOf(false) }
|
||||
var focused by rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(homeRows) {
|
||||
if (!focused) {
|
||||
homeRows
|
||||
|
|
@ -246,6 +246,8 @@ fun HomePageContent(
|
|||
listState.animateScrollToItem(position.row)
|
||||
focused = true
|
||||
}
|
||||
} else {
|
||||
rowFocusRequesters.getOrNull(position.row)?.tryRequestFocus()
|
||||
}
|
||||
}
|
||||
LaunchedEffect(position) {
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ class PlaybackViewModel
|
|||
internal lateinit var item: BaseItem
|
||||
internal var forceTranscoding: Boolean = false
|
||||
private var activityListener: TrackActivityPlaybackListener? = null
|
||||
private val jobs = mutableListOf<Job>()
|
||||
|
||||
val nextUp = MutableLiveData<BaseItem?>()
|
||||
private var isPlaylist = false
|
||||
|
|
@ -166,20 +167,22 @@ class PlaybackViewModel
|
|||
val subtitleSearchLanguage = MutableLiveData<String>(Locale.current.language)
|
||||
|
||||
init {
|
||||
viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() }
|
||||
player.addListener(this)
|
||||
(player as? ExoPlayer)?.addAnalyticsListener(this)
|
||||
addCloseable { player.removeListener(this@PlaybackViewModel) }
|
||||
addCloseable { (player as? ExoPlayer)?.removeAnalyticsListener(this@PlaybackViewModel) }
|
||||
addCloseable {
|
||||
player.removeListener(this@PlaybackViewModel)
|
||||
(player as? ExoPlayer)?.removeAnalyticsListener(this@PlaybackViewModel)
|
||||
|
||||
this@PlaybackViewModel.activityListener?.let {
|
||||
it.release()
|
||||
player.removeListener(it)
|
||||
}
|
||||
jobs.forEach { it.cancel() }
|
||||
player.release()
|
||||
}
|
||||
addCloseable { player.release() }
|
||||
subscribe()
|
||||
listenForTranscodeReason()
|
||||
viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() }
|
||||
player.addListener(this)
|
||||
(player as? ExoPlayer)?.addAnalyticsListener(this)
|
||||
jobs.add(subscribe())
|
||||
jobs.add(listenForTranscodeReason())
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -874,7 +877,7 @@ class PlaybackViewModel
|
|||
}
|
||||
}
|
||||
|
||||
private fun listenForTranscodeReason() {
|
||||
private fun listenForTranscodeReason(): Job =
|
||||
viewModelScope.launchIO {
|
||||
currentPlayback.collectLatest {
|
||||
if (it != null) {
|
||||
|
|
@ -905,7 +908,6 @@ class PlaybackViewModel
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var lastInteractionDate: Date = Date()
|
||||
|
||||
|
|
@ -1026,11 +1028,13 @@ class PlaybackViewModel
|
|||
}
|
||||
|
||||
fun release() {
|
||||
Timber.v("release")
|
||||
activityListener?.release()
|
||||
player.release()
|
||||
activityListener = null
|
||||
}
|
||||
|
||||
fun subscribe() {
|
||||
fun subscribe(): Job =
|
||||
api.webSocket
|
||||
.subscribe<PlaystateMessage>()
|
||||
.onEach { message ->
|
||||
|
|
@ -1085,7 +1089,6 @@ class PlaybackViewModel
|
|||
}
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically update [currentMediaInfo]
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ class MpvPlayer(
|
|||
Timber.v("config-dir=${context.filesDir.path}")
|
||||
MPVLib.addLogObserver(mpvLogger)
|
||||
|
||||
Timber.v("Creating MPVLib")
|
||||
MPVLib.create(context)
|
||||
MPVLib.setOptionString("config", "yes")
|
||||
MPVLib.setOptionString("config-dir", context.filesDir.path)
|
||||
|
|
@ -127,6 +128,7 @@ class MpvPlayer(
|
|||
MPVLib.setOptionString("demuxer-max-bytes", "${cacheMegs * 1024 * 1024}")
|
||||
MPVLib.setOptionString("demuxer-max-back-bytes", "${cacheMegs * 1024 * 1024}")
|
||||
|
||||
Timber.v("Initializing MPVLib")
|
||||
MPVLib.initialize()
|
||||
|
||||
MPVLib.setOptionString("force-window", "no")
|
||||
|
|
@ -466,7 +468,6 @@ class MpvPlayer(
|
|||
override fun clearVideoSurfaceHolder(surfaceHolder: SurfaceHolder?): Unit = throw UnsupportedOperationException()
|
||||
|
||||
override fun setVideoSurfaceView(surfaceView: SurfaceView?) {
|
||||
throwIfReleased()
|
||||
if (DEBUG) Timber.v("setVideoSurfaceView")
|
||||
val surface = surfaceView?.holder?.surface
|
||||
if (surface != null && surface.isValid) {
|
||||
|
|
@ -635,9 +636,9 @@ class MpvPlayer(
|
|||
val title = it.label ?: "External Subtitles"
|
||||
Timber.v("Adding external subtitle track '$title'")
|
||||
if (it.language.isNotNullOrBlank()) {
|
||||
MPVLib.command(arrayOf("sub-add", url, "auto", title, it.language!!))
|
||||
MPVLib.command(arrayOf("sub-add", url, "select", title, it.language!!))
|
||||
} else {
|
||||
MPVLib.command(arrayOf("sub-add", url, "auto", title))
|
||||
MPVLib.command(arrayOf("sub-add", url, "select", title))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -837,7 +838,18 @@ class MpvPlayer(
|
|||
|
||||
override fun handleMessage(msg: Message): Boolean {
|
||||
val cmd = MpvCommand.entries[msg.what]
|
||||
Timber.v("handleMessage: cmd=$cmd")
|
||||
Timber.d("handleMessage: cmd=$cmd")
|
||||
if (isReleased && cmd != MpvCommand.DESTROY) {
|
||||
Timber.w("Player is released, ignoring command %s", cmd)
|
||||
return true
|
||||
}
|
||||
if (surface == null && !cmd.isLifecycle) {
|
||||
// If libmpv isn't ready, re-enqueue the messages
|
||||
// Note: this means nothing will play until it is attached to a surface,
|
||||
// so MpvPlayer can't be used for background audio/music playback
|
||||
Timber.v("MPV is not initialized/attached yet, requeue cmd %s", cmd)
|
||||
internalHandler.sendMessageDelayed(Message.obtain(msg), 50)
|
||||
}
|
||||
when (cmd) {
|
||||
MpvCommand.PLAY_PAUSE -> {
|
||||
val playWhenReady = msg.obj as Boolean
|
||||
|
|
@ -894,6 +906,7 @@ class MpvPlayer(
|
|||
MPVLib.detachSurface()
|
||||
MPVLib.setPropertyString("vo", "null")
|
||||
MPVLib.setPropertyString("force-window", "no")
|
||||
Timber.d("Detached surface")
|
||||
}
|
||||
if (surface != null) {
|
||||
MPVLib.attachSurface(surface)
|
||||
|
|
@ -1035,14 +1048,16 @@ private data class MediaAndPosition(
|
|||
val startPositionMs: Long,
|
||||
)
|
||||
|
||||
enum class MpvCommand {
|
||||
PLAY_PAUSE,
|
||||
SEEK,
|
||||
SET_TRACK_SELECTION,
|
||||
SET_SPEED,
|
||||
SET_SUBTITLE_DELAY,
|
||||
LOAD_FILE,
|
||||
ATTACH_SURFACE,
|
||||
INITIALIZE,
|
||||
DESTROY,
|
||||
enum class MpvCommand(
|
||||
val isLifecycle: Boolean,
|
||||
) {
|
||||
PLAY_PAUSE(false),
|
||||
SEEK(false),
|
||||
SET_TRACK_SELECTION(false),
|
||||
SET_SPEED(false),
|
||||
SET_SUBTITLE_DELAY(false),
|
||||
LOAD_FILE(false),
|
||||
ATTACH_SURFACE(true),
|
||||
INITIALIZE(true),
|
||||
DESTROY(true),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ fun createDeviceProfile(
|
|||
"main",
|
||||
"baseline",
|
||||
"constrained baseline",
|
||||
if (supportsAVCHigh10) "main 10" else null,
|
||||
if (supportsAVCHigh10) "high 10" else null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@
|
|||
<string name="send_app_logs_summary">Nützlich zum Debuggen</string>
|
||||
<string name="send_crash_reports">Sende Absturzmeldung</string>
|
||||
<string name="skip_back_on_resume_preference">Zurückspringen wenn wiedergabe fortgesetzt wird</string>
|
||||
<string name="skip_commercials_behavior">Überspringe Werbung verhalten</string>
|
||||
<string name="skip_commercials_behavior">Werbung überspringen</string>
|
||||
<string name="skip_forward_preference">Vorspringen</string>
|
||||
<string name="skip_intro_behavior">Überspringe Intro verhalten</string>
|
||||
<string name="skip_outro_behavior">Überspringe Outro verhalten</string>
|
||||
|
|
@ -286,4 +286,39 @@
|
|||
<string name="remove">Entfernen</string>
|
||||
<string name="dolby_vision">Dolby Vision</string>
|
||||
<string name="dolby_atmos">Dolby Atmos</string>
|
||||
<string name="ends_at">Endet um %1$s</string>
|
||||
<string name="enter_server_address">Server Adresse eingeben</string>
|
||||
<string name="no_servers_found">Keine Server gefunden</string>
|
||||
<string name="media_information">Medieninformation</string>
|
||||
<string name="played">Abgespielt</string>
|
||||
<string name="mpv_use_gpu_next">MPV: Benutze gpu-next</string>
|
||||
<string name="mpv_conf">mpv.conf bearbeiten</string>
|
||||
<string name="discard_change">Änderungen verwerfen?</string>
|
||||
<string name="subtitle_margin">Abstand</string>
|
||||
<string name="enter_pin">PIN Eingeben</string>
|
||||
<string name="sign_in_auto">Automatisch anmelden</string>
|
||||
<string name="require_pin_code">Profil benötigt PIN</string>
|
||||
<string name="confirm_pin">PIN bestätigen</string>
|
||||
<string name="incorrect">Falsch</string>
|
||||
<string name="pin_too_short">PIN muss 4 Zeichen oder länger sein</string>
|
||||
<string name="will_remove_pin">PIN wird entfernt</string>
|
||||
<string name="view_options">Anzeigeoptionen</string>
|
||||
<string name="columns">Spalten</string>
|
||||
<string name="spacing">Abstände</string>
|
||||
<string name="aspect_ratio">Seitenverhältnis</string>
|
||||
<string name="show_details">Details anzeigen</string>
|
||||
<string name="image_type">Bild Typ</string>
|
||||
<string name="automatic">Automatisch</string>
|
||||
<string name="username_or_password">Verwende Benutzername/Passwort</string>
|
||||
<string name="login">Anmelden</string>
|
||||
<string name="title">Titel</string>
|
||||
<string name="profile">Profil</string>
|
||||
<string name="resolution">Auflösung</string>
|
||||
<string name="framerate">Bildrate</string>
|
||||
<string name="language">Sprache</string>
|
||||
<string name="channels">Kanäle</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="no">Nein</string>
|
||||
<string name="show_titles">Titel anzeigen</string>
|
||||
<string name="live_tv_repeat">Wiederholen</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="add_favorite">Favorito</string>
|
||||
<string name="add_server">Agregar servidor</string>
|
||||
<string name="add_user">Agregar usuario</string>
|
||||
<string name="add_favorite">Añadir a Favoritos</string>
|
||||
<string name="add_server">Añadir servidor</string>
|
||||
<string name="add_user">Añadir usuario</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="birthplace">Lugar de nacimiento</string>
|
||||
<string name="bitrate">Tasa de bits</string>
|
||||
|
|
@ -170,8 +170,8 @@
|
|||
</plurals>
|
||||
<plurals name="theme_songs">
|
||||
<item quantity="one">Canciones principales</item>
|
||||
<item quantity="many"></item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="many"/>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="theme_videos">
|
||||
<item quantity="one">Vídeos temáticos</item>
|
||||
|
|
@ -303,4 +303,76 @@
|
|||
<string name="font">Fuente</string>
|
||||
<string name="background">Fondo</string>
|
||||
<string name="official_rating">Clasificación parental</string>
|
||||
<string name="ends_at">Termina en %1$s</string>
|
||||
<string name="enter_server_address">Introduzca la dirección del servidor</string>
|
||||
<string name="no_servers_found">No se encontraron servidores</string>
|
||||
<string name="media_information">Información multimedia</string>
|
||||
<string name="mpv_use_gpu_next">MPV: Usar gpu-next</string>
|
||||
<string name="mpv_conf">Editar mpv.conf</string>
|
||||
<string name="discard_change">¿Descartar los cambios?</string>
|
||||
<string name="subtitle_margin">Margen</string>
|
||||
<string name="verbose_logging">Registro detallado</string>
|
||||
<string name="enter_pin">Introducir PIN</string>
|
||||
<string name="sign_in_auto">Iniciar sesión automáticamente</string>
|
||||
<string name="use_server_credentials">Iniciar sesión a través del servidor</string>
|
||||
<string name="press_enter_to_confirm">Pulsa el centro para confirmar</string>
|
||||
<string name="require_pin_code">Requerir PIN para el perfil</string>
|
||||
<string name="confirm_pin">Confirmar PIN</string>
|
||||
<string name="incorrect">Incorrecto</string>
|
||||
<string name="pin_too_short">El PIN debe tener 4 teclas o más</string>
|
||||
<string name="will_remove_pin">Se eliminará el PIN</string>
|
||||
<string name="image_cache_size">Tamaño de la caché de disco de imágenes (MB)</string>
|
||||
<string name="view_options">Opciones de visualización</string>
|
||||
<string name="columns">Columnas</string>
|
||||
<string name="spacing">Espaciado</string>
|
||||
<string name="aspect_ratio">Relación de aspecto</string>
|
||||
<string name="show_details">Mostrar detalles</string>
|
||||
<string name="image_type">Tipo de imagen</string>
|
||||
<string name="cast_and_crew"><![CDATA[Reparto y equipo]]></string>
|
||||
<string name="guest_stars">Estrellas invitadas</string>
|
||||
<string name="edge_size">Tamaño del borde</string>
|
||||
<string name="refresh_rate_switching">Cambio de frecuencia de actualización</string>
|
||||
<string name="automatic">Automático</string>
|
||||
<string name="username_or_password">Usar nombre de usuario/contraseña</string>
|
||||
<string name="login">Iniciar sesión</string>
|
||||
<string name="general">General</string>
|
||||
<string name="container">Contenedor</string>
|
||||
<string name="title">Título</string>
|
||||
<string name="codec">Codec</string>
|
||||
<string name="profile">Perfil</string>
|
||||
<string name="level">Nivel</string>
|
||||
<string name="resolution">Resolución</string>
|
||||
<string name="anamorphic">Anamórfico</string>
|
||||
<string name="interlaced">Entrelazado</string>
|
||||
<string name="framerate">Frecuencia de fotogramas</string>
|
||||
<string name="bit_depth">Profundidad de bits</string>
|
||||
<string name="video_range">Rango de vídeo</string>
|
||||
<string name="video_range_type">Tipo de rango de vídeo</string>
|
||||
<string name="color_space">Espacio de color</string>
|
||||
<string name="color_transfer">Transferencia de color</string>
|
||||
<string name="color_primaries">Primarias de color</string>
|
||||
<string name="pixel_format">Formato de píxel</string>
|
||||
<string name="ref_frames">Fotogramas de referencia</string>
|
||||
<string name="nal">NAL</string>
|
||||
<string name="language">Idioma</string>
|
||||
<string name="layout">Distribución</string>
|
||||
<string name="channels">Canales</string>
|
||||
<string name="sample_rate">Frecuencia de muestreo</string>
|
||||
<string name="avc">AVC</string>
|
||||
<string name="yes">Sí</string>
|
||||
<string name="no">No</string>
|
||||
<string name="sdr">SDR</string>
|
||||
<string name="hdr">HDR</string>
|
||||
<string name="hdr10">HDR10</string>
|
||||
<string name="hdr10_plus">HDR10+</string>
|
||||
<string name="hlg">HLG</string>
|
||||
<string name="bit_unit">bit</string>
|
||||
<string name="sample_rate_unit">Hz</string>
|
||||
<string name="show_titles">Mostrar títulos</string>
|
||||
<string name="live_tv_repeat">Repetir</string>
|
||||
<string name="favorite_channels_at_beginning">Mostrar primero los canales favoritos</string>
|
||||
<string name="sort_channels_recently_watched">Ordenar los canales por vistos recientemente</string>
|
||||
<string name="color_code_programs">Programas codificados por colores</string>
|
||||
<string name="subtitle_delay">Retardo de subtítulos</string>
|
||||
<string name="backdrop_display">Estilo del fondo</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -358,4 +358,5 @@
|
|||
<string name="enter_server_address">Sisesta serveri aadress</string>
|
||||
<string name="no_servers_found">Ühtegi serverit ei leidu</string>
|
||||
<string name="backdrop_display">Tausta dekoratsioon</string>
|
||||
<string name="ends_at">Lõppeb kell %1$s</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -370,4 +370,9 @@
|
|||
<string name="ref_frames">Images de référence</string>
|
||||
<string name="sort_channels_recently_watched">Trier les chaînes par date de visionnage</string>
|
||||
<string name="color_code_programs">Classer les programmes par code couleur</string>
|
||||
<string name="ends_at">Terminera à %1$s</string>
|
||||
<string name="enter_server_address">Entrez l\'adresse du serveur</string>
|
||||
<string name="no_servers_found">Aucun serveur trouvé</string>
|
||||
<string name="subtitle_delay">Décalage des sous-titres</string>
|
||||
<string name="backdrop_display">Style d\'arrière-plan</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about">Névjegy</string>
|
||||
<string name="add_favorite">Kedvenc</string>
|
||||
<string name="add_favorite">Hozzáadás kedvencekhez</string>
|
||||
<string name="add_server">Szerver hozzáadása</string>
|
||||
<string name="add_user">Felhasználó hozzáadása</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="audio">Hang</string>
|
||||
<string name="birthplace">Születési hely</string>
|
||||
<string name="bitrate">Bitráta</string>
|
||||
<string name="born">Született</string>
|
||||
<string name="cancel">Mégse</string>
|
||||
<string name="chapters">Fejezetek</string>
|
||||
<string name="choose_stream">Válassz %1$s</string>
|
||||
<string name="clear_image_cache">Kép gyorsítótár törlése</string>
|
||||
<string name="choose_stream">%1$s kiválasztása</string>
|
||||
<string name="clear_image_cache">Képgyorsítótár törlése</string>
|
||||
<string name="collection">Gyűjtemény</string>
|
||||
<string name="collections">Gyűjtemények</string>
|
||||
<string name="community_rating">Közösségi értékelés</string>
|
||||
<string name="compose_error_message_title">Hiba történt! Nyomd meg a gombot, hogy elküldd a naplófájlokat a szervernek.</string>
|
||||
<string name="compose_error_message_title">Hiba történt! Nyomja meg a gombot, hogy elküldje a naplófájlokat a szervernek.</string>
|
||||
<string name="confirm">Megerősít</string>
|
||||
<string name="critic_rating">Kritikusi értékelés</string>
|
||||
<string name="decimal_seconds">%.1f másodperc</string>
|
||||
<string name="default_track">Alapértelmezett</string>
|
||||
<string name="delete">Törlés</string>
|
||||
<string name="directed_by">Rendezte %1$s</string>
|
||||
<string name="directed_by">Rendezte: %1$s</string>
|
||||
<string name="director">Rendező</string>
|
||||
<string name="disabled">Letiltva</string>
|
||||
<string name="discovered_servers">Felfedezett szerverek</string>
|
||||
<string name="download_and_update"><![CDATA[Letöltés & Frissítés]]></string>
|
||||
<string name="downloading">Letöltés folyamatban…</string>
|
||||
<string name="enabled">Engedélyezve</string>
|
||||
<string name="enter_server_url">Add meg a szerver IP-t vagy URL-t</string>
|
||||
<string name="enter_server_url">Adja meg a szerver IP-t vagy URL-t</string>
|
||||
<string name="episodes">Epizódok</string>
|
||||
<string name="error_loading_collection">Hiba a gyűjtemény betöltése során: %1$s</string>
|
||||
<string name="error_loading_collection">Hiba a következő gyűjtemény betöltése során: %1$s</string>
|
||||
<string name="external_track">Külső</string>
|
||||
<string name="favorites">Kedvencek</string>
|
||||
<string name="active_recordings">Aktív felvételek</string>
|
||||
|
|
@ -38,28 +38,28 @@
|
|||
<string name="cancel_series_recording">Sorozatfelvétel leállítása</string>
|
||||
<string name="commercial">Reklám</string>
|
||||
<string name="continue_watching">Megtekintés folytatása</string>
|
||||
<string name="died">Halott</string>
|
||||
<string name="died">Elhunyt</string>
|
||||
<string name="file_size">Méret</string>
|
||||
<string name="forced_track">Kényszerített</string>
|
||||
<string name="forced_track">Kiegészítő</string>
|
||||
<string name="genres">Műfajok</string>
|
||||
<string name="go_to_series">Ugrás a sorozathoz</string>
|
||||
<string name="go_to">Ugrás</string>
|
||||
<string name="go_to">Ugrás ide:</string>
|
||||
<string name="hide_controller_timeout">Lejátszási gombok elrejtése</string>
|
||||
<string name="hide_debug_info">Hibajavítási infó elrejtése</string>
|
||||
<string name="hide_debug_info">Hibakeresési infó elrejtése</string>
|
||||
<string name="hide">Elrejt</string>
|
||||
<string name="home">Kezdőlap</string>
|
||||
<string name="immediate">Azonnal</string>
|
||||
<string name="intro">Intro</string>
|
||||
<string name="intro">Intró</string>
|
||||
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
|
||||
<string name="library">Könyvtár</string>
|
||||
<string name="license_info">Lincenc információk</string>
|
||||
<string name="live_tv">Élő TV</string>
|
||||
<string name="loading">Betöltés…</string>
|
||||
<string name="mark_entire_series_as_played">Megjelölöd az egész sorozatot megnézettként?</string>
|
||||
<string name="mark_entire_series_as_unplayed">Megjelölöd az egész sorozatot megnézetlenként?</string>
|
||||
<string name="mark_entire_series_as_played">Megjelöli az egész sorozatot megnézettként?</string>
|
||||
<string name="mark_entire_series_as_unplayed">Megjelöli az egész sorozatot megnézetlenként?</string>
|
||||
<string name="mark_unwatched">Jelölés megnézetlenként</string>
|
||||
<string name="mark_watched">Jelölés megnézettként</string>
|
||||
<string name="max_bitrate">Max bitráta</string>
|
||||
<string name="max_bitrate">Maximális bitráta</string>
|
||||
<string name="more_like_this">Hasonlóak</string>
|
||||
<string name="more">Továbbiak</string>
|
||||
<string name="movies">Filmek</string>
|
||||
|
|
@ -70,15 +70,15 @@
|
|||
<string name="no_scheduled_recordings">Nincs időzített felvétel</string>
|
||||
<string name="no_update_available">Nincs elérhető frissítés</string>
|
||||
<string name="none">Nincs</string>
|
||||
<string name="outro">Outro</string>
|
||||
<string name="outro">Stáblista</string>
|
||||
<string name="path">Elérési út</string>
|
||||
<string name="people">Emberek</string>
|
||||
<string name="people">Stábtagok</string>
|
||||
<string name="play_count">Lejátszások száma</string>
|
||||
<string name="play_from_here">Lejátszás innen</string>
|
||||
<string name="play">Lejátszás</string>
|
||||
<string name="playback_debug_info">Lejátszás hibakeresési adatainak mutatása</string>
|
||||
<string name="playback_speed">Lejátszási sebesség</string>
|
||||
<string name="playback">Visszajátszás</string>
|
||||
<string name="playback">Lejátszás</string>
|
||||
<string name="playlist">Lejátszási lista</string>
|
||||
<string name="playlists">Lejátszási listák</string>
|
||||
<string name="preview">Előnézet</string>
|
||||
|
|
@ -87,9 +87,9 @@
|
|||
<string name="recently_added_in">Nemrég hozzáadva: %1$s</string>
|
||||
<string name="recently_added">Nemrég hozzáadott</string>
|
||||
<string name="recently_recorded">Nemrég rögzített</string>
|
||||
<string name="recently_released">Nemrég kiadott</string>
|
||||
<string name="recently_released">Nemrég megjelent</string>
|
||||
<string name="recommended">Ajánlott</string>
|
||||
<string name="record_program">Program felvétele</string>
|
||||
<string name="record_program">Műsor felvétele</string>
|
||||
<string name="record_series">Sorozat felvétele</string>
|
||||
<string name="remove_favorite">Törlés a kedvencekből</string>
|
||||
<string name="restart">Újraindítás</string>
|
||||
|
|
@ -100,117 +100,263 @@
|
|||
<string name="searching">Keresés…</string>
|
||||
<string name="select_server">Szerver kiválasztása</string>
|
||||
<string name="select_user">Felhasználó kiválasztása</string>
|
||||
<string name="show_debug_info">Hibakeresési info megjelenítése</string>
|
||||
<string name="show_debug_info">Hibakeresési infó megjelenítése</string>
|
||||
<string name="show_next_up_when">Következő mutatása</string>
|
||||
<string name="show">Megmutat</string>
|
||||
<string name="shuffle">Véletlenszerű</string>
|
||||
<string name="skip">Átugrás</string>
|
||||
<string name="sort_by_date_added">Hozzáadva</string>
|
||||
<string name="sort_by_date_added">Hozzáadás dátuma</string>
|
||||
<string name="sort_by_date_episode_added">Epizód hozzáadásának dátuma</string>
|
||||
<string name="sort_by_date_played">Lejátszás dátuma</string>
|
||||
<string name="sort_by_date_released">Megjelenés dátuma</string>
|
||||
<string name="sort_by_name">Név</string>
|
||||
<string name="sort_by_random">Random</string>
|
||||
<string name="sort_by_random">Véletlenszerűen</string>
|
||||
<string name="studios">Stúdiók</string>
|
||||
<string name="submit">Beküld</string>
|
||||
<string name="subtitle_download_too_long">A letöltés sok időt vesz igénybe, előfordulhat, hogy újra kell indítanod a lejátszást</string>
|
||||
<string name="subtitle_download_too_long">A letöltés sok időt vesz igénybe, előfordulhat, hogy újra kell indítani a lejátszást</string>
|
||||
<string name="subtitle">Felirat</string>
|
||||
<string name="subtitles">Feliratok</string>
|
||||
<string name="suggestions">Ajánlások</string>
|
||||
<string name="switch_servers">Váltás szerverek között</string>
|
||||
<string name="switch_servers">Váltás másik szerverre</string>
|
||||
<string name="switch_user">Váltás</string>
|
||||
<string name="top_unwatched">Legjobbra értékelt nem megtekintett</string>
|
||||
<string name="top_unwatched">Legjobbra értékelt, nem megnézett</string>
|
||||
<string name="trailer">Előzetes</string>
|
||||
<plurals name="trailers">
|
||||
<item quantity="one">Előzetesek</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="tv_dvr_schedule">DVR Időzítés</string>
|
||||
<string name="tv_guide">Műsorújság</string>
|
||||
<string name="tv_season">Évad</string>
|
||||
<string name="tv_seasons">Évadok</string>
|
||||
<string name="tv_shows">Sorozatok</string>
|
||||
<string name="ui_interface">Felület</string>
|
||||
<string name="ui_interface">Kezelőfelület</string>
|
||||
<string name="unknown">Ismeretlen</string>
|
||||
<string name="updates">Frissítések</string>
|
||||
<string name="version">Verzió</string>
|
||||
<string name="video_scale">Képarány</string>
|
||||
<string name="video_scale">Kép méretezése</string>
|
||||
<string name="video">Videó</string>
|
||||
<string name="videos">Videók</string>
|
||||
<string name="watch_live">Nézd élőben</string>
|
||||
<string name="watch_live">Nézze élőben</string>
|
||||
<string name="years_old">%1$d éves</string>
|
||||
<string name="play_with_transcoding">Lejátszás átalakítással</string>
|
||||
<string name="show_clock">Aktuális idő mutatása</string>
|
||||
<string name="aired_episode_order">Sorrend epízód vetítése alapján</string>
|
||||
<string name="aired_episode_order">Sorrend epizód vetítése alapján</string>
|
||||
<string name="create_playlist">Új lejátszási lista létrehozása</string>
|
||||
<string name="add_to_playlist">Hozzáadás lejátszási listához</string>
|
||||
<string name="one_click_pause">Szüneteltetés egy klikkel</string>
|
||||
<string name="one_click_pause_summary_on">Nyomd a D-Pad közepét megállításhoz/lejátszáshoz</string>
|
||||
<string name="one_click_pause_summary_on">Nyomja le a D-Pad közepét megállításhoz/lejátszáshoz</string>
|
||||
<string name="italic_font">Dőlt betűk</string>
|
||||
<string name="font">Betűtípus</string>
|
||||
<string name="background">Háttérszín</string>
|
||||
<string name="font">Betűk stílusa</string>
|
||||
<string name="background">Háttér</string>
|
||||
<string name="success">Sikeres</string>
|
||||
<string name="official_rating">Szülői besorolás</string>
|
||||
<string name="runtime_sort">Műsoridő</string>
|
||||
<string name="official_rating">Korhatár-besorolás</string>
|
||||
<string name="runtime_sort">Hossz</string>
|
||||
<string name="extras">Extrák</string>
|
||||
<plurals name="other_extras">
|
||||
<item quantity="one">Egyéb</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="other">Egyebek</item>
|
||||
</plurals>
|
||||
<plurals name="behind_the_scenes">
|
||||
<item quantity="one">Színfalak mögött</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="theme_songs">
|
||||
<item quantity="one">Téma zenék</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Főcímdal</item>
|
||||
<item quantity="other">Főcímdalok</item>
|
||||
</plurals>
|
||||
<plurals name="theme_videos">
|
||||
<item quantity="one">Téma videók</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Téma videó</item>
|
||||
<item quantity="other">Téma videók</item>
|
||||
</plurals>
|
||||
<plurals name="clips">
|
||||
<item quantity="one">Klippek</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Klip</item>
|
||||
<item quantity="other">Klipek</item>
|
||||
</plurals>
|
||||
<plurals name="deleted_scenes">
|
||||
<item quantity="one">Törölt jelenetek</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Törölt jelenet</item>
|
||||
<item quantity="other">Törölt jelenetek</item>
|
||||
</plurals>
|
||||
<plurals name="interviews">
|
||||
<item quantity="one">Interjúk</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Interjú</item>
|
||||
<item quantity="other">Interjúk</item>
|
||||
</plurals>
|
||||
<plurals name="scenes">
|
||||
<item quantity="one">Jelenetek</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Jelenet</item>
|
||||
<item quantity="other">Jelenetek</item>
|
||||
</plurals>
|
||||
<plurals name="samples">
|
||||
<item quantity="one">Minták</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Minta</item>
|
||||
<item quantity="other">Minták</item>
|
||||
</plurals>
|
||||
<plurals name="featurettes">
|
||||
<item quantity="one">Rövidfilmek</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Rövidfilm</item>
|
||||
<item quantity="other">Rövidfilmek</item>
|
||||
</plurals>
|
||||
<plurals name="shorts">
|
||||
<item quantity="one">Rövidek</item>
|
||||
<item quantity="other"></item>
|
||||
<item quantity="one">Rövid</item>
|
||||
<item quantity="other">Rövidek</item>
|
||||
</plurals>
|
||||
<plurals name="downloads">
|
||||
<item quantity="one">%s letöltés</item>
|
||||
<item quantity="other">%s letöltések</item>
|
||||
<item quantity="other">%s letöltés</item>
|
||||
</plurals>
|
||||
<plurals name="hours">
|
||||
<item quantity="one">%d óra</item>
|
||||
<item quantity="other">%d órák</item>
|
||||
<item quantity="other">%d óra</item>
|
||||
</plurals>
|
||||
<plurals name="items">
|
||||
<item quantity="one">%d elem</item>
|
||||
<item quantity="other">%d elemek</item>
|
||||
<item quantity="other">%d elem</item>
|
||||
</plurals>
|
||||
<plurals name="seconds">
|
||||
<item quantity="one">%d másodperc</item>
|
||||
<item quantity="other">%d másodpercek</item>
|
||||
<item quantity="other">%d másodperc</item>
|
||||
</plurals>
|
||||
<string name="ends_at">%1$s-kor ér véget</string>
|
||||
<string name="no_servers_found">Nem található szerver</string>
|
||||
<string name="recap">Összefoglaló</string>
|
||||
<string name="media_information">Médiainformáció</string>
|
||||
<string name="ac3_supported">A készülék támogatja az AC3/Dolby Digital formátumot</string>
|
||||
<string name="advanced_settings">Haladó beállítások</string>
|
||||
<string name="advanced_ui">Haladó kezelőfelület-beállítások</string>
|
||||
<string name="app_theme">Alkalmazás témája</string>
|
||||
<string name="auto_check_for_updates">Frissítések automatikus keresése</string>
|
||||
<string name="auto_play_next_delay">Késleltetés a következő elem lejátszása előtt</string>
|
||||
<string name="auto_play_next">Következő elem automatikus lejátszása</string>
|
||||
<string name="check_for_updates">Frissítések keresése</string>
|
||||
<string name="combine_continue_next_summary">Csak sorozatok esetén</string>
|
||||
<string name="direct_play_ass">ASS feliratok közvetlen lejátszása</string>
|
||||
<string name="direct_play_pgs">PGS feliratok közvetlen lejátszása</string>
|
||||
<string name="downmix_stereo">Mindig konvertálja sztereóvá</string>
|
||||
<string name="ffmpeg_extension_pref">FFmpeg dekóder modul használata</string>
|
||||
<string name="global_content_scale">Tartalom alapértelmezett méretezése</string>
|
||||
<string name="install_update">Frissítés telepítése</string>
|
||||
<string name="installed_version">Telepített verzió</string>
|
||||
<string name="max_homepage_items">Maximális elemek soronként a kezdőlapon</string>
|
||||
<string name="nav_drawer_pins_summary">Válassza ki az alapértelmezett elemeket, amelyek megjelennek, a többi el lesz rejtve</string>
|
||||
<string name="nav_drawer_pins">Navigációs menü elemeinek testreszabása</string>
|
||||
<string name="nav_drawer_switch_on_focus_summary_off">Kattintson az oldalak közti váltáshoz</string>
|
||||
<string name="pass_out_protection">Automatikus leállítás inaktivitás esetén</string>
|
||||
<string name="play_theme_music">Főcímdal lejátszása</string>
|
||||
<string name="remember_selected_tab">Kiválasztott lapok megjegyzése</string>
|
||||
<string name="rewatch_next_up">Újranézés engedélyezése a Következő menüben</string>
|
||||
<string name="seek_bar_steps">Előre/hátra ugrás intervallum</string>
|
||||
<string name="send_app_logs_summary">Hibakereséshez hasznos</string>
|
||||
<string name="send_app_logs">Naplófájlok küldése a jelenlegi szerverre</string>
|
||||
<string name="send_crash_reports_summary">Megpróbálja elküldeni az legutóbb csatlakozott szerverre</string>
|
||||
<string name="send_crash_reports">Összeomlási napló küldése</string>
|
||||
<string name="settings">Beállítások</string>
|
||||
<string name="skip_back_on_resume_preference">Visszaugrás a lejátszás folytatásakor</string>
|
||||
<string name="skip_back_preference">Visszaugrás</string>
|
||||
<string name="skip_commercials_behavior">Reklám-átugrás viselkedés</string>
|
||||
<string name="skip_forward_preference">Előreugrás</string>
|
||||
<string name="skip_intro_behavior">Intró-átugrás viselkedés</string>
|
||||
<string name="skip_outro_behavior">Stáblista-átugrás viselkedés</string>
|
||||
<string name="skip_previews_behavior">Előzetes-átugrás viselkedés</string>
|
||||
<string name="skip_recap_behavior">Összefoglaló-átugrás viselkedés</string>
|
||||
<string name="update_available">Frissítés érhető el</string>
|
||||
<string name="update_url_summary">Az alkalmazás frissítéseinek ellenőrzésére használt URL</string>
|
||||
<string name="update_url">Frissítés URL</string>
|
||||
<string name="font_size">Betűméret</string>
|
||||
<string name="font_color">Betűszín</string>
|
||||
<string name="font_opacity">Betűk áttetszősége</string>
|
||||
<string name="edge_style">Szegély stílusa</string>
|
||||
<string name="edge_color">Szegély színe</string>
|
||||
<string name="background_opacity">Háttér áttetszősége</string>
|
||||
<string name="background_style">Háttér típusa</string>
|
||||
<string name="subtitle_style">Felirat stílusa</string>
|
||||
<string name="background_color">Háttér színe</string>
|
||||
<string name="reset">Visszaállítás</string>
|
||||
<string name="bold_font">Félkövér betűk</string>
|
||||
<string name="mpv_hardware_decoding">MPV: hardveres dekódolás használata</string>
|
||||
<string name="disable_if_crash">Tiltsa le, ha összeomlást tapasztal</string>
|
||||
<string name="mpv_options">MPV beállítások</string>
|
||||
<string name="exoplayer_options">ExoPlayer beállítások</string>
|
||||
<string name="skip_segment_unknown">Szegmens átugrása</string>
|
||||
<string name="skip_segment_commercial">Reklám átugrása</string>
|
||||
<string name="skip_segment_preview">Előzetes átugrása</string>
|
||||
<string name="skip_segment_recap">Összefoglaló átugrása</string>
|
||||
<string name="skip_segment_outro">Stáblista átugrása</string>
|
||||
<string name="skip_segment_intro">Intró átugrása</string>
|
||||
<string name="played">Lejátszott</string>
|
||||
<string name="filter">Szűrő</string>
|
||||
<string name="year">Év</string>
|
||||
<string name="decade">Évtized</string>
|
||||
<string name="remove">Eltávolítás</string>
|
||||
<string name="dolby_vision">Dolby Vision</string>
|
||||
<string name="dolby_atmos">Dolby Atmos</string>
|
||||
<string name="mpv_use_gpu_next">MPV: gpu-next használata</string>
|
||||
<string name="mpv_conf">mpv.conf szerkesztése</string>
|
||||
<string name="discard_change">Elveti a változtatásokat?</string>
|
||||
<string name="subtitle_margin">Függőleges eltolás</string>
|
||||
<string name="verbose_logging">Részletes naplózás</string>
|
||||
<string name="enter_pin">Adja meg a PIN-kódot</string>
|
||||
<string name="sign_in_auto">Automatikus bejelentkezés</string>
|
||||
<string name="use_server_credentials">Bejelentkezés szerveren keresztül</string>
|
||||
<string name="press_enter_to_confirm">Nyomja meg a középső gombot a megerősítéshez</string>
|
||||
<string name="require_pin_code">Kérjen PIN-kódot a profillal történő bejelentkezéshez</string>
|
||||
<string name="confirm_pin">PIN-kód megerősítése</string>
|
||||
<string name="incorrect">Helytelen</string>
|
||||
<string name="pin_too_short">A PIN-kódnak legalább 4 karakterből kell állnia</string>
|
||||
<string name="will_remove_pin">PIN-kód eltávolítása</string>
|
||||
<string name="view_options">Nézetbeállítások</string>
|
||||
<string name="columns">Oszlopok</string>
|
||||
<string name="spacing">Helyköz</string>
|
||||
<string name="aspect_ratio">Képarány</string>
|
||||
<string name="show_details">Részletek mutatása</string>
|
||||
<string name="image_type">Kép típusa</string>
|
||||
<string name="guest_stars">Vendégszereplők</string>
|
||||
<string name="edge_size">Szegély mérete</string>
|
||||
<string name="refresh_rate_switching">Tartalomhoz igazodó képfrissítési gyakoriság</string>
|
||||
<string name="automatic">Automatikus</string>
|
||||
<string name="username_or_password">Felhasználónév/jelszó használata</string>
|
||||
<string name="login">Bejelentkezés</string>
|
||||
<string name="general">Általános</string>
|
||||
<string name="container">Konténer</string>
|
||||
<string name="title">Cím</string>
|
||||
<string name="codec">Kodek</string>
|
||||
<string name="profile">Profil</string>
|
||||
<string name="level">Szint</string>
|
||||
<string name="resolution">Felbontás</string>
|
||||
<string name="anamorphic">Anamorfikus</string>
|
||||
<string name="interlaced">Váltottsoros</string>
|
||||
<string name="framerate">Képfrissítés</string>
|
||||
<string name="bit_depth">Színmélység</string>
|
||||
<string name="video_range">Feketeszint tartomány</string>
|
||||
<string name="video_range_type">Feketeszint tartomány típusa</string>
|
||||
<string name="color_space">Színtér</string>
|
||||
<string name="color_transfer">Színátviteli jellemző</string>
|
||||
<string name="color_primaries">Alapszínek</string>
|
||||
<string name="pixel_format">Pixelformátum</string>
|
||||
<string name="ref_frames">Referencia-képkockák</string>
|
||||
<string name="nal">NAL</string>
|
||||
<string name="language">Nyelv</string>
|
||||
<string name="layout">Elrendezés</string>
|
||||
<string name="channels">Csatornák</string>
|
||||
<string name="sample_rate">Mintavételezés</string>
|
||||
<string name="avc">AVC</string>
|
||||
<string name="yes">Igen</string>
|
||||
<string name="no">Nem</string>
|
||||
<string name="sdr">SDR</string>
|
||||
<string name="hdr">HDR</string>
|
||||
<string name="hdr10">HDR10</string>
|
||||
<string name="hdr10_plus">HDR10+</string>
|
||||
<string name="hlg">HLG</string>
|
||||
<string name="bit_unit">bit</string>
|
||||
<string name="sample_rate_unit">Hz</string>
|
||||
<string name="show_titles">Címek mutatása</string>
|
||||
<string name="live_tv_repeat">Ismétlés</string>
|
||||
<string name="favorite_channels_at_beginning">A kedvenc csatornákat mutassa először</string>
|
||||
<string name="sort_channels_recently_watched">Legutóbb nézett csatornák előre sorolása</string>
|
||||
<string name="color_code_programs">Műsorok kategória szerinti színezése</string>
|
||||
<string name="subtitle_delay">Felirat késleltetése</string>
|
||||
<string name="backdrop_display">Háttér stílusa</string>
|
||||
<string name="enter_server_address">Adja meg a szerver címét</string>
|
||||
<string name="combine_continue_next"><![CDATA[Folytatás & Következő menü összevonása]]></string>
|
||||
<string name="player_backend">Lejátszás backend</string>
|
||||
<string name="image_cache_size">Kép gyorsítótár méret (MB)</string>
|
||||
<string name="cast_and_crew"><![CDATA[Stábtagok]]></string>
|
||||
<string name="nav_drawer_switch_on_focus">Navigációs menü oldalainak váltása fókusznál</string>
|
||||
<string name="playback_overrides">Lejátszás felülbírálatai</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -332,4 +332,8 @@
|
|||
<string name="resolution">Resolusi</string>
|
||||
<string name="sample_rate">Sampel rate</string>
|
||||
<string name="spacing">Jarak</string>
|
||||
<string name="ends_at">Berakhir pada %1$s</string>
|
||||
<string name="enter_server_address">Masukkan alamat server</string>
|
||||
<string name="no_servers_found">Server tidak ditemukan</string>
|
||||
<string name="subtitle_delay">Penundaan subtitel</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -371,4 +371,8 @@
|
|||
<string name="sort_channels_recently_watched">Ordina canali per ultimo guardato</string>
|
||||
<string name="color_code_programs">Codifica colori per i programmi</string>
|
||||
<string name="subtitle_delay">Ritardo sottotitoli</string>
|
||||
<string name="enter_server_address">Inserisci indirizzo server</string>
|
||||
<string name="no_servers_found">Nessun server trovato</string>
|
||||
<string name="backdrop_display">Stile backdrop</string>
|
||||
<string name="ends_at">Termina alle %1$s</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about">אודות</string>
|
||||
<string name="active_recordings">הקלטות פעילות</string>
|
||||
<string name="add_favorite">הוספה למועדפים</string>
|
||||
<string name="add_server">הוסף שרת</string>
|
||||
<string name="add_user">הוסף משתמש</string>
|
||||
<string name="audio">שמע</string>
|
||||
<string name="birthplace">מקום לידה</string>
|
||||
<string name="bitrate">קצב נתונים</string>
|
||||
<string name="cancel_recording">בטל הקלטה</string>
|
||||
<string name="cancel_series_recording">בטל הקלטת סדרה</string>
|
||||
<string name="cancel">בטל</string>
|
||||
<string name="chapters">פרקים</string>
|
||||
<string name="clear_image_cache">נקה זיכרון מטמון</string>
|
||||
<string name="collection">אוסף</string>
|
||||
<string name="collections">אוספים</string>
|
||||
<string name="commercial">מסחרי</string>
|
||||
<string name="community_rating">דירוג קהילתי</string>
|
||||
<string name="compose_error_message_title">אירעה שגיאה! לחץ על הכפתור על מנת לשלוח יומני אירועים לשרת שלך.</string>
|
||||
<string name="confirm">לאשר</string>
|
||||
<string name="continue_watching">המשך צפייה</string>
|
||||
<string name="critic_rating">דירוג מבקרים</string>
|
||||
<string name="decimal_seconds">%.1f שניות</string>
|
||||
<string name="default_track">ברירת מחדל</string>
|
||||
<string name="delete">מחק</string>
|
||||
<string name="died">מת</string>
|
||||
<string name="directed_by">בבימויו של %1$s</string>
|
||||
<string name="director">במאי</string>
|
||||
<string name="disabled">מושבת</string>
|
||||
<string name="born">נולד</string>
|
||||
<string name="choose_stream">בחר %1$s</string>
|
||||
</resources>
|
||||
|
|
|
|||
46
app/src/main/res/values-kab/strings.xml
Normal file
46
app/src/main/res/values-kab/strings.xml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about">Ɣef</string>
|
||||
<string name="audio">Imesli</string>
|
||||
<string name="birthplace">Adig n tlalit</string>
|
||||
<string name="bitrate">Aktum</string>
|
||||
<string name="cancel">Semmet</string>
|
||||
<string name="chapters">Ixfawen</string>
|
||||
<string name="collection">Tagrumma</string>
|
||||
<string name="collections">Tigrummiwin</string>
|
||||
<string name="confirm">Serggeg</string>
|
||||
<string name="default_track">Amezwer</string>
|
||||
<string name="delete">Kkes</string>
|
||||
<string name="died">Yemmut</string>
|
||||
<string name="hide">Ffer-it</string>
|
||||
<string name="home">Tazwara</string>
|
||||
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
|
||||
<string name="library">Tamkarḍit</string>
|
||||
<string name="restart">Ales asekker</string>
|
||||
<string name="resume">Kemmel</string>
|
||||
<string name="save">Sekles</string>
|
||||
<string name="search">Nadi</string>
|
||||
<string name="searching">Yettnadi…</string>
|
||||
<string name="show">Sken-d</string>
|
||||
<string name="sort_by_name">Isem</string>
|
||||
<string name="sort_by_random">Agacuṛan</string>
|
||||
<string name="version">Lqem</string>
|
||||
<string name="video">Tavidyut</string>
|
||||
<string name="videos">Tividyutin</string>
|
||||
<string name="font">Tasefsit</string>
|
||||
<string name="background">Agilal</string>
|
||||
<string name="success">Yedda</string>
|
||||
<string name="year">Aseggas</string>
|
||||
<string name="automatic">Awurman</string>
|
||||
<string name="login">Tuqqna</string>
|
||||
<string name="general">Amatu</string>
|
||||
<string name="container">Amagbar</string>
|
||||
<string name="title">Azwel</string>
|
||||
<string name="codec">Akudak</string>
|
||||
<string name="profile">Amaɣnu</string>
|
||||
<string name="level">Aswir</string>
|
||||
<string name="hdr10">HDR10</string>
|
||||
<string name="hdr10_plus">HDR10+</string>
|
||||
<string name="hlg">HLG</string>
|
||||
<string name="choose_stream">Fren %1$s</string>
|
||||
</resources>
|
||||
|
|
@ -3,12 +3,12 @@
|
|||
<string name="about">Om</string>
|
||||
<string name="active_recordings">Aktive opptak</string>
|
||||
<string name="add_favorite">Favoritt</string>
|
||||
<string name="add_server">Legg til Server</string>
|
||||
<string name="add_user">Legg til Brukar</string>
|
||||
<string name="add_server">Legg til server</string>
|
||||
<string name="add_user">Legg til brukar</string>
|
||||
<string name="audio">Lyd</string>
|
||||
<string name="birthplace">Fødestad</string>
|
||||
<string name="bitrate">Bitrate</string>
|
||||
<string name="born">Født</string>
|
||||
<string name="born">Fødd</string>
|
||||
<string name="cancel_recording">Avbryt opptak</string>
|
||||
<string name="cancel_series_recording">Avbryt opptak av serie</string>
|
||||
<string name="cancel">Avbryt</string>
|
||||
|
|
@ -21,4 +21,342 @@
|
|||
<string name="delete">Slett</string>
|
||||
<string name="died">Dødd</string>
|
||||
<string name="directed_by">Regissert av %1$s</string>
|
||||
<string name="ac3_supported">Eininga støttar AC3/Dolby Digital</string>
|
||||
<string name="clear_image_cache">Tøm biletmellomlager</string>
|
||||
<string name="commercial">Reklame</string>
|
||||
<string name="community_rating">Brukarvurdering</string>
|
||||
<string name="compose_error_message_title">Ein feil har oppstått! Trykk på knappen for å sende loggar til servaren din.</string>
|
||||
<string name="continue_watching">Hald fram med å sjå</string>
|
||||
<string name="critic_rating">Meldevurdering</string>
|
||||
<string name="decimal_seconds">%.1f sekund</string>
|
||||
<string name="director">Regissør</string>
|
||||
<string name="disabled">Deaktivert</string>
|
||||
<string name="discovered_servers">Funne servarar</string>
|
||||
<string name="download_and_update"><![CDATA[Last ned og oppdater]]></string>
|
||||
<string name="downloading">Lastar ned…</string>
|
||||
<string name="enabled">Aktivert</string>
|
||||
<string name="enter_server_url">Oppgi servar-IP eller URL</string>
|
||||
<string name="enter_server_address">Oppgi servaradresse</string>
|
||||
<string name="episodes">Episodar</string>
|
||||
<string name="error_loading_collection">Feil ved lasting av samling %1$s</string>
|
||||
<string name="external_track">Ekstern</string>
|
||||
<string name="favorites">Favorittar</string>
|
||||
<string name="file_size">Storleik</string>
|
||||
<string name="forced_track">Tvungen</string>
|
||||
<string name="genres">Sjangrar</string>
|
||||
<string name="go_to_series">Gå til serie</string>
|
||||
<string name="go_to">Gå til</string>
|
||||
<string name="hide_controller_timeout">Gøym avspelingskontrollar</string>
|
||||
<string name="hide_debug_info">Gøym feilsøkingsinfo</string>
|
||||
<string name="hide">Gøym</string>
|
||||
<string name="home">Heim</string>
|
||||
<string name="immediate">Omgåande</string>
|
||||
<string name="intro">Intro</string>
|
||||
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ</string>
|
||||
<string name="library">Bibliotek</string>
|
||||
<string name="license_info">Lisensinformasjon</string>
|
||||
<string name="live_tv">Direkte-TV</string>
|
||||
<string name="loading">Lastar…</string>
|
||||
<string name="mark_entire_series_as_played">Marker heile serien som sett?</string>
|
||||
<string name="mark_entire_series_as_unplayed">Marker heile serien som usett?</string>
|
||||
<string name="mark_unwatched">Marker som usett</string>
|
||||
<string name="mark_watched">Marker som sett</string>
|
||||
<string name="max_bitrate">Maks bitrate</string>
|
||||
<string name="more_like_this">Meir som dette</string>
|
||||
<string name="more">Meir</string>
|
||||
<string name="movies">Filmar</string>
|
||||
<string name="name">Namn</string>
|
||||
<string name="next_up">Neste</string>
|
||||
<string name="no_data">Ingen data</string>
|
||||
<string name="no_results">Ingen resultat</string>
|
||||
<string name="no_servers_found">Ingen servarar funne</string>
|
||||
<string name="no_scheduled_recordings">Ingen planlagde opptak</string>
|
||||
<string name="no_update_available">Ingen oppdatering tilgjengeleg</string>
|
||||
<string name="outro">Outro</string>
|
||||
<string name="path">Filveg</string>
|
||||
<string name="people">Folk</string>
|
||||
<string name="play_count">Antall avspelingar</string>
|
||||
<string name="play_from_here">Spel av herfrå</string>
|
||||
<string name="play">Spel av</string>
|
||||
<string name="playback_debug_info">Vis feilsøkingsinfo for avspeling</string>
|
||||
<string name="playback_speed">Avspelingsfart</string>
|
||||
<string name="playback">Avspeling</string>
|
||||
<string name="playlist">Speleliste</string>
|
||||
<string name="playlists">Spelelister</string>
|
||||
<string name="preview">Førehandsvising</string>
|
||||
<string name="profile_specific_settings">Innstillingar for brukarprofil</string>
|
||||
<string name="queue">Kø</string>
|
||||
<string name="recap">Samandrag</string>
|
||||
<string name="recently_added_in">Sist lagt til i %1$s</string>
|
||||
<string name="recently_added">Sist lagt til</string>
|
||||
<string name="recently_recorded">Sist tatt opp</string>
|
||||
<string name="recently_released">Sist utgitt</string>
|
||||
<string name="recommended">Tilrådd</string>
|
||||
<string name="record_program">Ta opp program</string>
|
||||
<string name="record_series">Ta opp serie</string>
|
||||
<string name="remove_favorite">Fjern favoritt</string>
|
||||
<string name="restart">Start på nytt</string>
|
||||
<string name="resume">Hald fram</string>
|
||||
<string name="save">Lagre</string>
|
||||
<string name="search_and_download"><![CDATA[Søk og last ned]]></string>
|
||||
<string name="search">Søk</string>
|
||||
<string name="searching">Søker…</string>
|
||||
<string name="select_server">Vel servar</string>
|
||||
<string name="select_user">Vel brukar</string>
|
||||
<string name="show_debug_info">Vis feilsøkingsinfo</string>
|
||||
<string name="show_next_up_when">Vis \'Neste\'</string>
|
||||
<string name="show">Serie</string>
|
||||
<string name="shuffle">Tilfeldig rekkjefølgje</string>
|
||||
<string name="skip">Hopp over</string>
|
||||
<string name="sort_by_date_added">Dato lagt til</string>
|
||||
<string name="sort_by_date_episode_added">Dato episode lagt til</string>
|
||||
<string name="sort_by_date_played">Dato spela av</string>
|
||||
<string name="sort_by_date_released">Utginningsdato</string>
|
||||
<string name="sort_by_name">Namn</string>
|
||||
<string name="sort_by_random">Tilfeldig</string>
|
||||
<string name="studios">Studio</string>
|
||||
<string name="submit">Send inn</string>
|
||||
<string name="subtitle">Undertekst</string>
|
||||
<string name="subtitles">Undertekstar</string>
|
||||
<string name="suggestions">Forslag</string>
|
||||
<string name="switch_servers">Byt servar</string>
|
||||
<string name="switch_user">Byt brukar</string>
|
||||
<string name="top_unwatched">Best vurderte usette</string>
|
||||
<string name="trailer">Trailer</string>
|
||||
<plurals name="trailers">
|
||||
<item quantity="one">Trailerar</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="tv_dvr_schedule">DVR-plan</string>
|
||||
<string name="tv_guide">Programoversikt</string>
|
||||
<string name="tv_season">Sesong</string>
|
||||
<string name="tv_seasons">Sesongar</string>
|
||||
<string name="tv_shows">TV-seriar</string>
|
||||
<string name="ui_interface">Grensesnitt</string>
|
||||
<string name="unknown">Ukjend</string>
|
||||
<string name="updates">Oppdateringar</string>
|
||||
<string name="version">Versjon</string>
|
||||
<string name="video_scale">Videoskalering</string>
|
||||
<string name="video">Video</string>
|
||||
<string name="videos">Videoar</string>
|
||||
<string name="watch_live">Sjå direkte</string>
|
||||
<string name="years_old">%1$d år gammal</string>
|
||||
<string name="play_with_transcoding">Spel av med transkoding</string>
|
||||
<string name="media_information">Mediainformasjon</string>
|
||||
<string name="show_clock">Vis klokke</string>
|
||||
<string name="aired_episode_order">Rekkjefølgje etter sendedato</string>
|
||||
<string name="create_playlist">Lag ny speleliste</string>
|
||||
<string name="add_to_playlist">Legg til i speleliste</string>
|
||||
<string name="one_click_pause">Pause med eitt klikk</string>
|
||||
<string name="one_click_pause_summary_on">Trykk i midten på styreputa for å pause/spele av</string>
|
||||
<string name="italic_font">Kursiv skrift</string>
|
||||
<string name="font">Skrifttype</string>
|
||||
<string name="background">Bakgrunn</string>
|
||||
<string name="success">Fullført</string>
|
||||
<string name="official_rating">Aldersgrense</string>
|
||||
<string name="runtime_sort">Speltid</string>
|
||||
<string name="extras">Ekstra</string>
|
||||
<plurals name="other_extras">
|
||||
<item quantity="one">Anna</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="behind_the_scenes">
|
||||
<item quantity="one">Bak kulissane</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="theme_songs">
|
||||
<item quantity="one">Temasongar</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="theme_videos">
|
||||
<item quantity="one">Temavideoar</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="clips">
|
||||
<item quantity="one">Klipp</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="deleted_scenes">
|
||||
<item quantity="one">Sletta sener</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="interviews">
|
||||
<item quantity="one">Intervju</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="scenes">
|
||||
<item quantity="one">Scener</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="samples">
|
||||
<item quantity="one">Smakebitar</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="featurettes">
|
||||
<item quantity="one">Bakomfilmar</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<plurals name="shorts">
|
||||
<item quantity="one">Kortfilmar</item>
|
||||
<item quantity="other"/>
|
||||
</plurals>
|
||||
<string name="advanced_settings">Avanserte innstillingar</string>
|
||||
<string name="advanced_ui">Avansert grensesnitt</string>
|
||||
<string name="app_theme">App-tema</string>
|
||||
<string name="auto_check_for_updates">Sjekk automatisk etter oppdateringar</string>
|
||||
<string name="auto_play_next_delay">Forseinking før neste vert spela av</string>
|
||||
<string name="auto_play_next">Spel neste automatisk</string>
|
||||
<string name="check_for_updates">Sjekk etter oppdateringar</string>
|
||||
<string name="combine_continue_next_summary">Gjeld berre TV-seriar</string>
|
||||
<string name="combine_continue_next">Slå saman \'Hald fram med å sjå\' og \'Neste\'</string>
|
||||
<string name="direct_play_ass">Direkteavspeling av ASS-undertekstar</string>
|
||||
<string name="direct_play_pgs">Direkteavspeling av PGS-undertekstar</string>
|
||||
<string name="downmix_stereo">Alltid nedmiks til stereo</string>
|
||||
<string name="ffmpeg_extension_pref">Bruk FFmpeg-dekodermodul</string>
|
||||
<string name="global_content_scale">Standard innhaldsskalering</string>
|
||||
<string name="install_update">Installer oppdatering</string>
|
||||
<string name="installed_version">Installert versjon</string>
|
||||
<string name="max_homepage_items">Maks element på rader på heimskjermen</string>
|
||||
<string name="nav_drawer_pins">Tilpass element i navigasjonsskuffa</string>
|
||||
<string name="nav_drawer_switch_on_focus_summary_off">Klikk for å byte side</string>
|
||||
<string name="nav_drawer_switch_on_focus">Byt side i navigasjonsskuffa ved fokus</string>
|
||||
<string name="pass_out_protection">Svevn-beskyttelse</string>
|
||||
<string name="play_theme_music">Spel temamusikk</string>
|
||||
<string name="playback_overrides">Overstyring av avspeling</string>
|
||||
<string name="remember_selected_tab">Hugs valde faner</string>
|
||||
<string name="rewatch_next_up">Tillat gjensjåing i \'Neste\'</string>
|
||||
<string name="seek_bar_steps">Steglengde for søkelinje</string>
|
||||
<string name="send_app_logs_summary">Nyttig for feilsøking</string>
|
||||
<string name="send_app_logs">Send app-loggar til gjeldande servar</string>
|
||||
<string name="send_crash_reports_summary">Vil prøve å sende til sist tilkopla servar</string>
|
||||
<string name="send_crash_reports">Send krasjrapportar</string>
|
||||
<string name="settings">Innstillingar</string>
|
||||
<string name="skip_back_on_resume_preference">Hopp tilbake ved framhald av avspeling</string>
|
||||
<string name="skip_back_preference">Hopp tilbake</string>
|
||||
<string name="skip_commercials_behavior">Handling for overhopping av reklame</string>
|
||||
<string name="skip_forward_preference">Hopp framover</string>
|
||||
<string name="skip_intro_behavior">Handling for overhopping av intro</string>
|
||||
<string name="skip_outro_behavior">Handling for overhopping av outro</string>
|
||||
<string name="skip_previews_behavior">Handling for overhopping av førehandsvising</string>
|
||||
<string name="skip_recap_behavior">Handling for overhopping av samandrag</string>
|
||||
<string name="update_available">Oppdatering tilgjengeleg</string>
|
||||
<string name="update_url_summary">URL for sjekk av app-oppdateringar</string>
|
||||
<string name="update_url">URL for oppdatering</string>
|
||||
<string name="font_size">Skriftstorleik</string>
|
||||
<string name="font_color">Skriftfarge</string>
|
||||
<string name="font_opacity">Gjennomsiktigheit for skrift</string>
|
||||
<string name="edge_style">Kantstil</string>
|
||||
<string name="edge_color">Kantfarge</string>
|
||||
<string name="background_opacity">Gjennomsiktigheit for bakgrunn</string>
|
||||
<string name="background_style">Bakgrunnsstil</string>
|
||||
<string name="subtitle_style">Stil for undertekst</string>
|
||||
<string name="background_color">Bakgrunnsfarge</string>
|
||||
<string name="reset">Nullstill</string>
|
||||
<string name="bold_font">Feit skrift</string>
|
||||
<string name="player_backend">Avspelingsmotor</string>
|
||||
<string name="mpv_hardware_decoding">MPV: Bruk maskinvaredekoding</string>
|
||||
<string name="disable_if_crash">Deaktiver dersom appen krasjar</string>
|
||||
<string name="mpv_options">MPV-val</string>
|
||||
<string name="exoplayer_options">ExoPlayer-val</string>
|
||||
<string name="skip_segment_unknown">Hopp over segment</string>
|
||||
<string name="skip_segment_commercial">Hopp over reklame</string>
|
||||
<string name="skip_segment_preview">Hopp over førehandsvising</string>
|
||||
<string name="skip_segment_recap">Hopp over samandrag</string>
|
||||
<string name="skip_segment_outro">Hopp over outro</string>
|
||||
<string name="skip_segment_intro">Hopp over intro</string>
|
||||
<string name="played">Sett</string>
|
||||
<string name="filter">Filter</string>
|
||||
<string name="year">År</string>
|
||||
<string name="decade">Tiår</string>
|
||||
<string name="remove">Fjern</string>
|
||||
<string name="dolby_vision">Dolby Vision</string>
|
||||
<string name="dolby_atmos">Dolby Atmos</string>
|
||||
<string name="mpv_use_gpu_next">MPV: Bruk gpu-next</string>
|
||||
<string name="mpv_conf">Rediger mpv.conf</string>
|
||||
<string name="discard_change">Forkast endringar?</string>
|
||||
<string name="subtitle_margin">Marg</string>
|
||||
<string name="verbose_logging">Detaljert logging</string>
|
||||
<string name="enter_pin">Tast inn PIN</string>
|
||||
<string name="sign_in_auto">Logg inn automatisk</string>
|
||||
<string name="use_server_credentials">Logg inn via servar</string>
|
||||
<string name="press_enter_to_confirm">Trykk i midten for å bekrefte</string>
|
||||
<string name="require_pin_code">Krev PIN for profil</string>
|
||||
<string name="confirm_pin">Bekreft PIN</string>
|
||||
<string name="incorrect">Feil</string>
|
||||
<string name="pin_too_short">PIN må vere 4 tastar eller lenger</string>
|
||||
<string name="will_remove_pin">Vil fjerne PIN</string>
|
||||
<string name="image_cache_size">Storleik på biletmellomlager (MB)</string>
|
||||
<string name="view_options">Visingsval</string>
|
||||
<string name="columns">Kolonner</string>
|
||||
<string name="spacing">Mellomrom</string>
|
||||
<string name="aspect_ratio">Bileteforhold</string>
|
||||
<string name="show_details">Vis detaljar</string>
|
||||
<string name="image_type">Bilettype</string>
|
||||
<string name="cast_and_crew"><![CDATA[Skodespelarar og medarbeidarar]]></string>
|
||||
<string name="guest_stars">Gjesteroller</string>
|
||||
<string name="edge_size">Kantstorleik</string>
|
||||
<string name="refresh_rate_switching">Byting av bildeoppdateringsfrekvens</string>
|
||||
<string name="automatic">Automatisk</string>
|
||||
<string name="username_or_password">Bruk brukarnamn/passord</string>
|
||||
<string name="login">Logg inn</string>
|
||||
<string name="general">Generelt</string>
|
||||
<string name="container">Containar</string>
|
||||
<string name="title">Tittel</string>
|
||||
<string name="codec">Kodek</string>
|
||||
<string name="profile">Profil</string>
|
||||
<string name="level">Nivå</string>
|
||||
<string name="resolution">Oppløysing</string>
|
||||
<string name="anamorphic">Anamorfisk</string>
|
||||
<string name="interlaced">Linjefletta</string>
|
||||
<string name="framerate">Bildefrekvens</string>
|
||||
<string name="bit_depth">Bit-dybde</string>
|
||||
<string name="video_range">Videoområde</string>
|
||||
<string name="video_range_type">Type videoområde</string>
|
||||
<string name="color_space">Fargerom</string>
|
||||
<string name="color_transfer">Fargeoverføring</string>
|
||||
<string name="color_primaries">Fargeprimærar</string>
|
||||
<string name="pixel_format">Pikselformat</string>
|
||||
<string name="ref_frames">Referanserammer</string>
|
||||
<string name="nal">NAL</string>
|
||||
<string name="language">Språk</string>
|
||||
<string name="layout">Layout</string>
|
||||
<string name="channels">Kanalar</string>
|
||||
<string name="sample_rate">Samplingsfrekvens</string>
|
||||
<string name="avc">AVC</string>
|
||||
<string name="yes">Ja</string>
|
||||
<string name="no">Nei</string>
|
||||
<string name="sdr">SDR</string>
|
||||
<string name="hdr">HDR</string>
|
||||
<string name="hdr10">HDR10</string>
|
||||
<string name="hdr10_plus">HDR10+</string>
|
||||
<string name="hlg">HLG</string>
|
||||
<string name="bit_unit">bit</string>
|
||||
<string name="sample_rate_unit">Hz</string>
|
||||
<string name="show_titles">Vis titlar</string>
|
||||
<string name="live_tv_repeat">Repeter</string>
|
||||
<string name="favorite_channels_at_beginning">Vis favorittkanalar først</string>
|
||||
<string name="sort_channels_recently_watched">Sorter kanalar etter sist sett</string>
|
||||
<string name="color_code_programs">Fargekod program</string>
|
||||
<string name="subtitle_delay">Undertekstforseinking</string>
|
||||
<string name="backdrop_display">Bakgrunnsstil</string>
|
||||
<string name="none">Ingen</string>
|
||||
<string name="subtitle_download_too_long">Nedlastinga tek lang tid, du må kanskje starte avspelinga på nytt</string>
|
||||
<plurals name="downloads">
|
||||
<item quantity="one">%s nedlasting</item>
|
||||
<item quantity="other">%s nedlastingar</item>
|
||||
</plurals>
|
||||
<plurals name="hours">
|
||||
<item quantity="one">%d time</item>
|
||||
<item quantity="other">%d timar</item>
|
||||
</plurals>
|
||||
<plurals name="items">
|
||||
<item quantity="one">%d element</item>
|
||||
<item quantity="other">%d elementer</item>
|
||||
</plurals>
|
||||
<plurals name="seconds">
|
||||
<item quantity="one">%d sekund</item>
|
||||
<item quantity="other">%d sekund</item>
|
||||
</plurals>
|
||||
<string name="nav_drawer_pins_summary">Vel standardelementa som skal visast, andre vert skjulde</string>
|
||||
<string name="ends_at">Sluttar %1$s</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -371,4 +371,8 @@
|
|||
<string name="sort_channels_recently_watched">Ordenar canais por visualizações recentes</string>
|
||||
<string name="color_code_programs">Codificação de cores para os programas</string>
|
||||
<string name="subtitle_delay">Atraso da legenda</string>
|
||||
<string name="enter_server_address">Insira o endereço do servidor</string>
|
||||
<string name="no_servers_found">Nenhum servidor encontrado</string>
|
||||
<string name="backdrop_display">Estilo de fundo</string>
|
||||
<string name="ends_at">Termina às %1$s</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -339,4 +339,8 @@
|
|||
<string name="sort_channels_recently_watched">按最近观看的频道排序</string>
|
||||
<string name="color_code_programs">节目颜色标记</string>
|
||||
<string name="subtitle_delay">字幕延迟</string>
|
||||
<string name="enter_server_address">输入服务器地址</string>
|
||||
<string name="no_servers_found">未找到服务器</string>
|
||||
<string name="backdrop_display">背景幕样式</string>
|
||||
<string name="ends_at">结束于 %1$s</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -183,8 +183,8 @@
|
|||
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
|
||||
<string name="license_info">授權資訊</string>
|
||||
<string name="live_tv">電視直播</string>
|
||||
<string name="mark_entire_series_as_played">標記整部電視劇為已觀看?</string>
|
||||
<string name="mark_entire_series_as_unplayed">標記整部電視劇為未觀看?</string>
|
||||
<string name="mark_entire_series_as_played">標記整部劇為已觀看?</string>
|
||||
<string name="mark_entire_series_as_unplayed">標記整部劇為未觀看?</string>
|
||||
<string name="mark_unwatched">標記為未觀看</string>
|
||||
<string name="mark_watched">標記為已觀看</string>
|
||||
<string name="max_bitrate">最大位元率</string>
|
||||
|
|
@ -299,4 +299,48 @@
|
|||
<string name="username_or_password">使用帳號/密碼</string>
|
||||
<string name="login">登入</string>
|
||||
<string name="subtitle_delay">字幕同步</string>
|
||||
<string name="show_titles">顯示標題</string>
|
||||
<string name="enter_server_address">輸入伺服器位址</string>
|
||||
<string name="no_servers_found">未找到伺服器</string>
|
||||
<string name="backdrop_display">背景圖樣式</string>
|
||||
<string name="color_code_programs">節目顏色標記</string>
|
||||
<string name="favorite_channels_at_beginning">優先顯示最愛頻道</string>
|
||||
<string name="sort_channels_recently_watched">按最近觀看的頻道排序</string>
|
||||
<string name="ends_at">結束於 %1$s</string>
|
||||
<string name="general">一般</string>
|
||||
<string name="container">封裝格式</string>
|
||||
<string name="title">標題</string>
|
||||
<string name="codec">編碼</string>
|
||||
<string name="resolution">解析度</string>
|
||||
<string name="anamorphic">變形寬銀幕</string>
|
||||
<string name="level">等級</string>
|
||||
<string name="profile">編碼設定檔</string>
|
||||
<string name="language">語言</string>
|
||||
<string name="yes">是</string>
|
||||
<string name="no">否</string>
|
||||
<string name="sdr">SDR</string>
|
||||
<string name="hdr">HDR</string>
|
||||
<string name="hdr10">HDR10</string>
|
||||
<string name="hdr10_plus">HDR10+</string>
|
||||
<string name="hlg">HLG</string>
|
||||
<string name="bit_unit">bit</string>
|
||||
<string name="sample_rate_unit">Hz</string>
|
||||
<string name="live_tv_repeat">重複</string>
|
||||
<string name="interlaced">隔行掃描</string>
|
||||
<string name="ref_frames">參考影格數</string>
|
||||
<string name="framerate">影格率</string>
|
||||
<string name="nal">NAL</string>
|
||||
<string name="bit_depth">位元深度</string>
|
||||
<string name="avc">AVC</string>
|
||||
<string name="layout">聲道配置</string>
|
||||
<string name="channels">聲道數</string>
|
||||
<string name="video_range">動態範圍</string>
|
||||
<string name="video_range_type">動態範圍類型</string>
|
||||
<string name="color_space">色彩空間</string>
|
||||
<string name="color_transfer">色彩轉換</string>
|
||||
<string name="color_primaries">色彩原色</string>
|
||||
<string name="pixel_format">像素格式</string>
|
||||
<string name="sample_rate">取樣率</string>
|
||||
<string name="seek_bar_steps">進度條跳轉值</string>
|
||||
<string name="playback_overrides">播放覆蓋設定</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -399,6 +399,9 @@
|
|||
<string name="subtitle_delay">Subtitle delay</string>
|
||||
<string name="backdrop_display">Backdrop style</string>
|
||||
<string name="resolution_switching">Resolution switching</string>
|
||||
<string name="local">Local</string>
|
||||
<string name="play_trailer">Play trailer</string>
|
||||
<string name="no_trailers">No trailers</string>
|
||||
|
||||
<string name="discover">Discover</string>
|
||||
<string name="request">Request</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue