Fixes for error handling, UI padding, & more (#1759)
## Description Another collection of small individual fixes that don't warrant a full PR: - Better error handling for series and collection detail pages - Better error handling on Discover search tab - Fix issues when changing view options on card grid without reloading the page - Better error handling when changing the refresh rate or resolution - Fix some nav drawer items disappearing briefly when restarting the app - Fix that the discover search row would not clear when the query is cleared And some UI tweaks: - Use consistent padding for the different customize home page sections - Convert the "Continue watching click behavior" setting from a toggle to choice dialog (the options & behaviors have not changed) ### Related issues I think the error handling when changing the refresh rate might help with #1737 ### Testing Emulator mostly ## Screenshots N/A, UI changes are minor ## AI or LLM usage None
This commit is contained in:
parent
2463841663
commit
8bae9c7f23
18 changed files with 149 additions and 96 deletions
|
|
@ -6,6 +6,7 @@ import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
@ -391,10 +392,17 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
fun changeDisplayMode(modeId: Int) {
|
fun changeDisplayMode(modeId: Int) {
|
||||||
lifecycleScope.launch(WholphinDispatchers.Main + ExceptionHandler(autoToast = true)) {
|
lifecycleScope.launch(WholphinDispatchers.Main + ExceptionHandler(autoToast = true)) {
|
||||||
val attrs = window.attributes
|
try {
|
||||||
if (attrs.preferredDisplayModeId != modeId) {
|
val attrs = window.attributes
|
||||||
Timber.d("Switch preferredDisplayModeId to %s", modeId)
|
if (attrs.preferredDisplayModeId != modeId) {
|
||||||
window.attributes = attrs.apply { preferredDisplayModeId = modeId }
|
Timber.d("Switch preferredDisplayModeId to %s", modeId)
|
||||||
|
window.attributes = attrs.apply { preferredDisplayModeId = modeId }
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Error switching preferredDisplayModeId to %s", modeId)
|
||||||
|
Toast
|
||||||
|
.makeText(this@MainActivity, "Error changing display mode", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,15 +218,16 @@ sealed interface AppPreference<Pref, T> {
|
||||||
)
|
)
|
||||||
|
|
||||||
val HomeClickToPlay =
|
val HomeClickToPlay =
|
||||||
AppSwitchPreference<AppPreferences>(
|
AppChoicePreference<AppPreferences, Boolean>(
|
||||||
title = R.string.continue_watching_click_behavior,
|
title = R.string.continue_watching_click_behavior,
|
||||||
defaultValue = false,
|
defaultValue = false,
|
||||||
getter = { it.homePagePreferences.clickToPlay },
|
getter = { it.homePagePreferences.clickToPlay },
|
||||||
setter = { prefs, value ->
|
setter = { prefs, value ->
|
||||||
prefs.updateHomePagePreferences { clickToPlay = value }
|
prefs.updateHomePagePreferences { clickToPlay = value }
|
||||||
},
|
},
|
||||||
summaryOn = R.string.continue_watching_click_summary_on,
|
displayValues = R.array.home_click_to_play_options,
|
||||||
summaryOff = R.string.continue_watching_click_summary_off,
|
indexToValue = { it != 0 },
|
||||||
|
valueToIndex = { if (it) 1 else 0 },
|
||||||
)
|
)
|
||||||
|
|
||||||
val PlayThemeMusic =
|
val PlayThemeMusic =
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,11 @@ class NavDrawerService
|
||||||
userDto?.id,
|
userDto?.id,
|
||||||
discoverActive,
|
discoverActive,
|
||||||
)
|
)
|
||||||
_state.update { NavDrawerItemState() }
|
|
||||||
try {
|
try {
|
||||||
if (user != null && userDto != null && user.id == userDto.id) {
|
if (user != null && userDto != null && user.id == userDto.id) {
|
||||||
updateNavDrawer(user, userDto, discoverActive)
|
updateNavDrawer(user, userDto, discoverActive)
|
||||||
|
} else {
|
||||||
|
_state.update { NavDrawerItemState() }
|
||||||
}
|
}
|
||||||
} catch (ex: CancellationException) {
|
} catch (ex: CancellationException) {
|
||||||
throw ex
|
throw ex
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,7 @@ class CollectionFolderViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveViewOptions(viewOptions: ViewOptions) {
|
fun saveViewOptions(viewOptions: ViewOptions) {
|
||||||
|
position = 0
|
||||||
_state.update { it.copy(viewOptions = viewOptions) }
|
_state.update { it.copy(viewOptions = viewOptions) }
|
||||||
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
|
viewModelScope.launch(ExceptionHandler() + WholphinDispatchers.IO) {
|
||||||
saveLibraryDisplayInfo(viewOptions = viewOptions)
|
saveLibraryDisplayInfo(viewOptions = viewOptions)
|
||||||
|
|
|
||||||
|
|
@ -345,7 +345,7 @@ fun <T : CardGridItem> CardGrid(
|
||||||
items(pager.size) { index ->
|
items(pager.size) { index ->
|
||||||
val item = pager[index]
|
val item = pager[index]
|
||||||
val details =
|
val details =
|
||||||
remember(index, item, cardWidthPx) {
|
remember(index, item, cardWidthPx, columns) {
|
||||||
val mod =
|
val mod =
|
||||||
if ((index == currentFocusedIndex) or (currentFocusedIndex < 0 && index == 0)) {
|
if ((index == currentFocusedIndex) or (currentFocusedIndex < 0 && index == 0)) {
|
||||||
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
|
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -136,26 +137,33 @@ class CollectionViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModelScope.launchDefault {
|
viewModelScope.launchDefault {
|
||||||
val collection =
|
try {
|
||||||
api.userLibraryApi
|
val collection =
|
||||||
.getItem(itemId)
|
api.userLibraryApi
|
||||||
.content
|
.getItem(itemId)
|
||||||
.let { BaseItem(it, false) }
|
.content
|
||||||
backdropService.submit(collection)
|
.let { BaseItem(it, false) }
|
||||||
val logoImageUrl =
|
backdropService.submit(collection)
|
||||||
if (ImageType.LOGO in collection.data.imageTags.orEmpty()) {
|
val logoImageUrl =
|
||||||
imageUrlService.getItemImageUrl(collection, ImageType.LOGO)
|
if (ImageType.LOGO in collection.data.imageTags.orEmpty()) {
|
||||||
} else {
|
imageUrlService.getItemImageUrl(collection, ImageType.LOGO)
|
||||||
null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
_state.update {
|
||||||
|
it.copy(
|
||||||
|
collection = collection,
|
||||||
|
logoImageUrl = logoImageUrl,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_state.update {
|
listenForStateUpdates()
|
||||||
it.copy(
|
themeSongPlayer.playThemeFor(itemId)
|
||||||
collection = collection,
|
} catch (ex: CancellationException) {
|
||||||
logoImageUrl = logoImageUrl,
|
throw ex
|
||||||
)
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Error getting collection %s", itemId)
|
||||||
|
_state.update { it.copy(loadingState = LoadingState.Error(ex)) }
|
||||||
}
|
}
|
||||||
listenForStateUpdates()
|
|
||||||
themeSongPlayer.playThemeFor(itemId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,6 +187,8 @@ class CollectionViewModel
|
||||||
.collectLatest { (sort, filter, separateTypes) ->
|
.collectLatest { (sort, filter, separateTypes) ->
|
||||||
try {
|
try {
|
||||||
updateData(sort, filter, separateTypes)
|
updateData(sort, filter, separateTypes)
|
||||||
|
} catch (ex: CancellationException) {
|
||||||
|
throw ex
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(
|
Timber.e(
|
||||||
ex,
|
ex,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -158,8 +159,18 @@ class SeriesViewModel
|
||||||
} else {
|
} else {
|
||||||
CompletableDeferred(value = EpisodeList.Loading)
|
CompletableDeferred(value = EpisodeList.Loading)
|
||||||
}
|
}
|
||||||
val seasons = seasonsDeferred.await()
|
val (seasons, episodes) =
|
||||||
val episodes = episodeListDeferred.await()
|
try {
|
||||||
|
val seasons = seasonsDeferred.await()
|
||||||
|
val episodes = episodeListDeferred.await()
|
||||||
|
seasons to episodes
|
||||||
|
} catch (ex: CancellationException) {
|
||||||
|
throw ex
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Exception fetching seasons/episodes for series %s", seriesId)
|
||||||
|
_state.update { it.copy(series = DataLoadingState.Error(ex)) }
|
||||||
|
return@launchIO
|
||||||
|
}
|
||||||
Timber.v("Done")
|
Timber.v("Done")
|
||||||
|
|
||||||
if (seriesPageType == SeriesPageType.OVERVIEW && seasonEpisodeIds != null) {
|
if (seriesPageType == SeriesPageType.OVERVIEW && seasonEpisodeIds != null) {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
import com.github.damontecres.wholphin.ui.rememberInt
|
import com.github.damontecres.wholphin.ui.rememberInt
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -88,13 +89,20 @@ class DiscoverSearchViewModel
|
||||||
}
|
}
|
||||||
Timber.v("Starting seerr search")
|
Timber.v("Starting seerr search")
|
||||||
seerrResults.value = SearchResult.Searching
|
seerrResults.value = SearchResult.Searching
|
||||||
val results =
|
try {
|
||||||
seerrService
|
val results =
|
||||||
.search(query)
|
seerrService
|
||||||
.map { seerrService.createDiscoverItem(it) }
|
.search(query)
|
||||||
.filter { it.type == SeerrItemType.MOVIE || it.type == SeerrItemType.TV }
|
.map { seerrService.createDiscoverItem(it) }
|
||||||
Timber.v("Seerr search complete: %s results", results.size)
|
.filter { it.type == SeerrItemType.MOVIE || it.type == SeerrItemType.TV }
|
||||||
seerrResults.value = SearchResult.SuccessSeerr(results)
|
Timber.v("Seerr search complete: %s results", results.size)
|
||||||
|
seerrResults.value = SearchResult.SuccessSeerr(results)
|
||||||
|
} catch (ex: CancellationException) {
|
||||||
|
throw ex
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Error during seerr search")
|
||||||
|
seerrResults.value = SearchResult.Error(ex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -169,21 +169,10 @@ class SearchViewModel
|
||||||
currentQuery = query
|
currentQuery = query
|
||||||
combinedMode = combined
|
combinedMode = combined
|
||||||
if (query.isNotNullOrBlank()) {
|
if (query.isNotNullOrBlank()) {
|
||||||
|
_state.update { SearchState.searchingState }
|
||||||
if (combined) {
|
if (combined) {
|
||||||
_state.update { it.copy(combinedResults = SearchResult.Searching) }
|
|
||||||
searchCombined(query)
|
searchCombined(query)
|
||||||
} else {
|
} else {
|
||||||
_state.update {
|
|
||||||
it.copy(
|
|
||||||
movies = SearchResult.Searching,
|
|
||||||
series = SearchResult.Searching,
|
|
||||||
episodes = SearchResult.Searching,
|
|
||||||
collections = SearchResult.Searching,
|
|
||||||
albums = SearchResult.Searching,
|
|
||||||
artists = SearchResult.Searching,
|
|
||||||
songs = SearchResult.Searching,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
searchInternal(
|
searchInternal(
|
||||||
query,
|
query,
|
||||||
BaseItemKind.MOVIE,
|
BaseItemKind.MOVIE,
|
||||||
|
|
@ -219,18 +208,7 @@ class SearchViewModel
|
||||||
}
|
}
|
||||||
searchSeerr(query)
|
searchSeerr(query)
|
||||||
} else {
|
} else {
|
||||||
_state.update {
|
_state.update { SearchState() }
|
||||||
it.copy(
|
|
||||||
combinedResults = SearchResult.NoQuery,
|
|
||||||
movies = SearchResult.NoQuery,
|
|
||||||
series = SearchResult.NoQuery,
|
|
||||||
episodes = SearchResult.NoQuery,
|
|
||||||
collections = SearchResult.NoQuery,
|
|
||||||
albums = SearchResult.NoQuery,
|
|
||||||
artists = SearchResult.NoQuery,
|
|
||||||
songs = SearchResult.NoQuery,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -479,7 +457,22 @@ data class SearchState(
|
||||||
val songs: SearchResult = SearchResult.NoQuery,
|
val songs: SearchResult = SearchResult.NoQuery,
|
||||||
val seerrResults: SearchResult = SearchResult.NoQuery,
|
val seerrResults: SearchResult = SearchResult.NoQuery,
|
||||||
val combinedResults: SearchResult = SearchResult.NoQuery,
|
val combinedResults: SearchResult = SearchResult.NoQuery,
|
||||||
)
|
) {
|
||||||
|
companion object {
|
||||||
|
val searchingState =
|
||||||
|
SearchState(
|
||||||
|
movies = SearchResult.Searching,
|
||||||
|
series = SearchResult.Searching,
|
||||||
|
episodes = SearchResult.Searching,
|
||||||
|
collections = SearchResult.Searching,
|
||||||
|
albums = SearchResult.Searching,
|
||||||
|
artists = SearchResult.Searching,
|
||||||
|
songs = SearchResult.Searching,
|
||||||
|
seerrResults = SearchResult.Searching,
|
||||||
|
combinedResults = SearchResult.Searching,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private const val SEARCH_ROW = 0
|
private const val SEARCH_ROW = 0
|
||||||
private const val TAB_ROW = SEARCH_ROW + 1
|
private const val TAB_ROW = SEARCH_ROW + 1
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
package com.github.damontecres.wholphin.ui.main.settings
|
package com.github.damontecres.wholphin.ui.main.settings
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -16,7 +13,6 @@ import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.focusRestorer
|
import androidx.compose.ui.focus.focusRestorer
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.tv.material3.ListItem
|
import androidx.tv.material3.ListItem
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
|
|
@ -36,9 +32,7 @@ fun HomeLibraryRowTypeList(
|
||||||
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
TitleText(stringResource(R.string.add_row_for, library.name))
|
TitleText(stringResource(R.string.add_row_for, library.name))
|
||||||
LazyColumn(
|
HomeSettingsLazyColumn(
|
||||||
contentPadding = PaddingValues(8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package com.github.damontecres.wholphin.ui.main.settings
|
package com.github.damontecres.wholphin.ui.main.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -249,9 +247,8 @@ fun HomeRowPresetsContent(
|
||||||
LaunchedEffect(Unit) { focusRequesters[0].tryRequestFocus() }
|
LaunchedEffect(Unit) { focusRequesters[0].tryRequestFocus() }
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
TitleText(stringResource(R.string.display_presets))
|
TitleText(stringResource(R.string.display_presets))
|
||||||
LazyColumn(
|
HomeSettingsLazyColumn(
|
||||||
contentPadding = PaddingValues(8.dp),
|
contentPadding = PaddingValues(8.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,11 @@ fun HomeRowSettings(
|
||||||
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
TitleText(title)
|
TitleText(title)
|
||||||
LazyColumn {
|
HomeSettingsLazyColumn {
|
||||||
preferenceOptions.forEachIndexed { groupIndex, prefGroup ->
|
preferenceOptions.forEachIndexed { groupIndex, prefGroup ->
|
||||||
if (preferenceOptions.size > 1) {
|
if (preferenceOptions.size > 1) {
|
||||||
item {
|
item {
|
||||||
TitleText(stringResource(prefGroup.title))
|
SubTitleText(stringResource(prefGroup.title))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
itemsIndexed(prefGroup.preferences) { index, pref ->
|
itemsIndexed(prefGroup.preferences) { index, pref ->
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
package com.github.damontecres.wholphin.ui.main.settings
|
package com.github.damontecres.wholphin.ui.main.settings
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -15,7 +12,6 @@ import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.focusRestorer
|
import androidx.compose.ui.focus.focusRestorer
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.ui.ifElse
|
import com.github.damontecres.wholphin.ui.ifElse
|
||||||
|
|
||||||
|
|
@ -31,9 +27,7 @@ fun HomeSettingsAddRow(
|
||||||
// LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
// LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
TitleText(stringResource(R.string.add_row))
|
TitleText(stringResource(R.string.add_row))
|
||||||
LazyColumn(
|
HomeSettingsLazyColumn(
|
||||||
contentPadding = PaddingValues(8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
package com.github.damontecres.wholphin.ui.main.settings
|
package com.github.damontecres.wholphin.ui.main.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -14,7 +11,6 @@ import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.focusRestorer
|
import androidx.compose.ui.focus.focusRestorer
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.ui.ifElse
|
import com.github.damontecres.wholphin.ui.ifElse
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
|
|
@ -31,9 +27,7 @@ fun HomeSettingsFavoriteList(
|
||||||
TitleText(
|
TitleText(
|
||||||
stringResource(R.string.add_row_for, stringResource(R.string.favorites)),
|
stringResource(R.string.add_row_for, stringResource(R.string.favorites)),
|
||||||
)
|
)
|
||||||
LazyColumn(
|
HomeSettingsLazyColumn(
|
||||||
contentPadding = PaddingValues(8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package com.github.damontecres.wholphin.ui.main.settings
|
package com.github.damontecres.wholphin.ui.main.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||||
|
|
@ -18,7 +16,6 @@ import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.focusRestorer
|
import androidx.compose.ui.focus.focusRestorer
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.tv.material3.Icon
|
import androidx.tv.material3.Icon
|
||||||
import androidx.tv.material3.MaterialTheme
|
import androidx.tv.material3.MaterialTheme
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
|
|
@ -51,8 +48,7 @@ fun HomeSettingsGlobal(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
LazyColumn(
|
HomeSettingsLazyColumn(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
package com.github.damontecres.wholphin.ui.main.settings
|
package com.github.damontecres.wholphin.ui.main.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.BoxScope
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.NonRestartableComposable
|
import androidx.compose.runtime.NonRestartableComposable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -57,3 +63,21 @@ fun HomeSettingsListItem(
|
||||||
glow = glow,
|
glow = glow,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@NonRestartableComposable
|
||||||
|
fun HomeSettingsLazyColumn(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
state: LazyListState = rememberLazyListState(),
|
||||||
|
contentPadding: PaddingValues = PaddingValues(8.dp),
|
||||||
|
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(0.dp),
|
||||||
|
content: LazyListScope.() -> Unit,
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = modifier,
|
||||||
|
state = state,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
verticalArrangement = verticalArrangement,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
|
@ -76,9 +75,8 @@ fun HomeSettingsRowList(
|
||||||
}
|
}
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
TitleText(stringResource(R.string.customize_home))
|
TitleText(stringResource(R.string.customize_home))
|
||||||
LazyColumn(
|
HomeSettingsLazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
|
@ -255,6 +253,24 @@ fun HomeRowConfigContent(
|
||||||
fun TitleText(
|
fun TitleText(
|
||||||
title: String,
|
title: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
textAlign = TextAlign.Start,
|
||||||
|
modifier =
|
||||||
|
modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 8.dp, bottom = 4.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@NonRestartableComposable
|
||||||
|
fun SubTitleText(
|
||||||
|
title: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
|
|
|
||||||
|
|
@ -888,6 +888,11 @@
|
||||||
<item>@string/subtitle_mode_none</item>
|
<item>@string/subtitle_mode_none</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="home_click_to_play_options">
|
||||||
|
<item>@string/continue_watching_click_summary_off</item>
|
||||||
|
<item>@string/continue_watching_click_summary_on</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string name="preferred_subtitle_language">Preferred subtitle language</string>
|
<string name="preferred_subtitle_language">Preferred subtitle language</string>
|
||||||
<string name="preferred_audio_language">Preferred audio language</string>
|
<string name="preferred_audio_language">Preferred audio language</string>
|
||||||
<string name="override_user_profile_settings">More user profile settings</string>
|
<string name="override_user_profile_settings">More user profile settings</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue