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:
Damontecres 2026-07-29 10:21:49 -04:00 • committed by GitHub
parent 2463841663
commit 8bae9c7f23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 149 additions and 96 deletions

View file

@ -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()
} }
} }
} }

View file

@ -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 =

View file

@ -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

View file

@ -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)

View file

@ -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")

View file

@ -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,

View file

@ -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) {

View file

@ -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)
}
} }
} }
} }

View file

@ -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

View file

@ -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()

View file

@ -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()

View file

@ -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 ->

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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,
)
}

View file

@ -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,

View file

@ -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>