mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Some fixes to customize homes (#893)
## Description - Update header when editing a row - Exclude non-empty rows to prevent scroll lock - Only save settings locally if they are different from the source ### Related issues Related to #803 ### Testing Emulator, tested remote & local settings changes ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
aa69646b2d
commit
1e810c1157
5 changed files with 67 additions and 25 deletions
|
|
@ -34,6 +34,7 @@ import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.main.HomePageContent
|
import com.github.damontecres.wholphin.ui.main.HomePageContent
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
|
import com.github.damontecres.wholphin.ui.rememberPosition
|
||||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||||
import com.github.damontecres.wholphin.util.HomeRowLoadingState
|
import com.github.damontecres.wholphin.util.HomeRowLoadingState
|
||||||
import com.github.damontecres.wholphin.util.LoadingState
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
|
|
@ -149,8 +150,10 @@ fun RecommendedContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadingState.Success -> {
|
LoadingState.Success -> {
|
||||||
|
var position by rememberPosition()
|
||||||
HomePageContent(
|
HomePageContent(
|
||||||
homeRows = rows,
|
homeRows = rows,
|
||||||
|
position = position,
|
||||||
onClickItem = { _, item ->
|
onClickItem = { _, item ->
|
||||||
viewModel.navigationManager.navigateTo(item.destination())
|
viewModel.navigationManager.navigateTo(item.destination())
|
||||||
},
|
},
|
||||||
|
|
@ -160,7 +163,21 @@ fun RecommendedContent(
|
||||||
onClickPlay = { _, item ->
|
onClickPlay = { _, item ->
|
||||||
viewModel.navigationManager.navigateTo(Destination.Playback(item))
|
viewModel.navigationManager.navigateTo(Destination.Playback(item))
|
||||||
},
|
},
|
||||||
onFocusPosition = onFocusPosition,
|
onFocusPosition = {
|
||||||
|
position = it
|
||||||
|
val nonEmptyRowBefore =
|
||||||
|
rows
|
||||||
|
.subList(0, it.row)
|
||||||
|
.count {
|
||||||
|
it is HomeRowLoadingState.Success && it.items.isEmpty()
|
||||||
|
}
|
||||||
|
onFocusPosition?.invoke(
|
||||||
|
RowColumn(
|
||||||
|
it.row - nonEmptyRowBefore,
|
||||||
|
it.column,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
showClock = preferences.appPreferences.interfacePreferences.showClock,
|
showClock = preferences.appPreferences.interfacePreferences.showClock,
|
||||||
onUpdateBackdrop = viewModel::updateBackdrop,
|
onUpdateBackdrop = viewModel::updateBackdrop,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
|
||||||
|
|
@ -117,12 +117,17 @@ fun HomePage(
|
||||||
var dialog by remember { mutableStateOf<DialogParams?>(null) }
|
var dialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||||
var showPlaylistDialog by remember { mutableStateOf<UUID?>(null) }
|
var showPlaylistDialog by remember { mutableStateOf<UUID?>(null) }
|
||||||
val playlistState by playlistViewModel.playlistState.observeAsState(PlaylistLoadingState.Pending)
|
val playlistState by playlistViewModel.playlistState.observeAsState(PlaylistLoadingState.Pending)
|
||||||
|
var position by rememberPosition()
|
||||||
HomePageContent(
|
HomePageContent(
|
||||||
homeRows = homeRows,
|
homeRows = homeRows,
|
||||||
onClickItem = { position, item ->
|
position = position,
|
||||||
|
onFocusPosition = { position = it },
|
||||||
|
onClickItem = { clickedPosition, item ->
|
||||||
|
position = clickedPosition
|
||||||
viewModel.navigationManager.navigateTo(item.destination())
|
viewModel.navigationManager.navigateTo(item.destination())
|
||||||
},
|
},
|
||||||
onLongClickItem = { position, item ->
|
onLongClickItem = { clickedPosition, item ->
|
||||||
|
position = clickedPosition
|
||||||
val dialogItems =
|
val dialogItems =
|
||||||
buildMoreDialogItemsForHome(
|
buildMoreDialogItemsForHome(
|
||||||
context = context,
|
context = context,
|
||||||
|
|
@ -193,19 +198,19 @@ fun HomePage(
|
||||||
@Composable
|
@Composable
|
||||||
fun HomePageContent(
|
fun HomePageContent(
|
||||||
homeRows: List<HomeRowLoadingState>,
|
homeRows: List<HomeRowLoadingState>,
|
||||||
|
position: RowColumn,
|
||||||
|
onFocusPosition: (RowColumn) -> Unit,
|
||||||
onClickItem: (RowColumn, BaseItem) -> Unit,
|
onClickItem: (RowColumn, BaseItem) -> Unit,
|
||||||
onLongClickItem: (RowColumn, BaseItem) -> Unit,
|
onLongClickItem: (RowColumn, BaseItem) -> Unit,
|
||||||
onClickPlay: (RowColumn, BaseItem) -> Unit,
|
onClickPlay: (RowColumn, BaseItem) -> Unit,
|
||||||
showClock: Boolean,
|
showClock: Boolean,
|
||||||
onUpdateBackdrop: (BaseItem) -> Unit,
|
onUpdateBackdrop: (BaseItem) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onFocusPosition: ((RowColumn) -> Unit)? = null,
|
|
||||||
loadingState: LoadingState? = null,
|
loadingState: LoadingState? = null,
|
||||||
listState: LazyListState = rememberLazyListState(),
|
listState: LazyListState = rememberLazyListState(),
|
||||||
takeFocus: Boolean = true,
|
takeFocus: Boolean = true,
|
||||||
showEmptyRows: Boolean = false,
|
showEmptyRows: Boolean = false,
|
||||||
) {
|
) {
|
||||||
var position by rememberPosition()
|
|
||||||
val focusedItem =
|
val focusedItem =
|
||||||
position.let {
|
position.let {
|
||||||
(homeRows.getOrNull(it.row) as? HomeRowLoadingState.Success)?.items?.getOrNull(it.column)
|
(homeRows.getOrNull(it.row) as? HomeRowLoadingState.Success)?.items?.getOrNull(it.column)
|
||||||
|
|
@ -329,21 +334,8 @@ fun HomePageContent(
|
||||||
cardModifier
|
cardModifier
|
||||||
.onFocusChanged {
|
.onFocusChanged {
|
||||||
if (it.isFocused) {
|
if (it.isFocused) {
|
||||||
position =
|
onFocusPosition?.invoke(
|
||||||
RowColumn(rowIndex, index)
|
RowColumn(rowIndex, index),
|
||||||
}
|
|
||||||
if (it.isFocused && onFocusPosition != null) {
|
|
||||||
val nonEmptyRowBefore =
|
|
||||||
homeRows
|
|
||||||
.subList(0, rowIndex)
|
|
||||||
.count {
|
|
||||||
it is HomeRowLoadingState.Success && it.items.isEmpty()
|
|
||||||
}
|
|
||||||
onFocusPosition.invoke(
|
|
||||||
RowColumn(
|
|
||||||
rowIndex - nonEmptyRowBefore,
|
|
||||||
index,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.onKeyEvent {
|
}.onKeyEvent {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,14 @@ class HomeViewModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val rows = deferred.awaitAll()
|
val rows =
|
||||||
|
deferred
|
||||||
|
.awaitAll()
|
||||||
|
.filter {
|
||||||
|
// Include only errors & non-empty successes
|
||||||
|
it is HomeRowLoadingState.Error ||
|
||||||
|
(it is HomeRowLoadingState.Success && it.items.isNotEmpty())
|
||||||
|
}
|
||||||
Timber.v("Got all rows")
|
Timber.v("Got all rows")
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,14 @@ import com.github.damontecres.wholphin.data.model.HomeRowConfig
|
||||||
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
import com.github.damontecres.wholphin.ui.components.ConfirmDialog
|
import com.github.damontecres.wholphin.ui.components.ConfirmDialog
|
||||||
|
import com.github.damontecres.wholphin.ui.data.RowColumn
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.main.HomePageContent
|
import com.github.damontecres.wholphin.ui.main.HomePageContent
|
||||||
import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.ChooseRowType
|
import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.ChooseRowType
|
||||||
import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.RowSettings
|
import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.RowSettings
|
||||||
|
import com.github.damontecres.wholphin.ui.rememberPosition
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
|
import com.github.damontecres.wholphin.util.HomeRowLoadingState
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -55,6 +58,7 @@ fun HomeSettingsPage(
|
||||||
var showConfirmDialog by remember { mutableStateOf<ShowConfirm?>(null) }
|
var showConfirmDialog by remember { mutableStateOf<ShowConfirm?>(null) }
|
||||||
|
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
|
var position by rememberPosition(0, 0)
|
||||||
// TODO discover rows
|
// TODO discover rows
|
||||||
val discoverEnabled = false // by viewModel.discoverEnabled.collectAsState(false)
|
val discoverEnabled = false // by viewModel.discoverEnabled.collectAsState(false)
|
||||||
|
|
||||||
|
|
@ -109,7 +113,15 @@ fun HomeSettingsPage(
|
||||||
backStack.add(RowSettings(row.id))
|
backStack.add(RowSettings(row.id))
|
||||||
scope.launch(ExceptionHandler()) {
|
scope.launch(ExceptionHandler()) {
|
||||||
Timber.v("Scroll to $index")
|
Timber.v("Scroll to $index")
|
||||||
listState.scrollToItem(index)
|
listState.animateScrollToItem(index)
|
||||||
|
// Update backdrop to first item in the row
|
||||||
|
(state.rowData.getOrNull(index) as? HomeRowLoadingState.Success)
|
||||||
|
?.items
|
||||||
|
?.firstOrNull()
|
||||||
|
?.let {
|
||||||
|
viewModel.updateBackdrop(it)
|
||||||
|
}
|
||||||
|
position = RowColumn(index, 0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = destModifier,
|
modifier = destModifier,
|
||||||
|
|
@ -259,6 +271,8 @@ fun HomeSettingsPage(
|
||||||
HomePageContent(
|
HomePageContent(
|
||||||
loadingState = state.loading,
|
loadingState = state.loading,
|
||||||
homeRows = state.rowData,
|
homeRows = state.rowData,
|
||||||
|
position = position,
|
||||||
|
onFocusPosition = { position = it },
|
||||||
onClickItem = { _, _ -> },
|
onClickItem = { _, _ -> },
|
||||||
onLongClickItem = { _, _ -> },
|
onLongClickItem = { _, _ -> },
|
||||||
onClickPlay = { _, _ -> },
|
onClickPlay = { _, _ -> },
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,9 @@ class HomeSettingsViewModel
|
||||||
|
|
||||||
val discoverEnabled = seerrServerRepository.active
|
val discoverEnabled = seerrServerRepository.active
|
||||||
|
|
||||||
|
private var originalLocalSettings: HomePageSettings? = null
|
||||||
|
private var originalRemoteSettings: HomePageSettings? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addCloseable { saveToLocal() }
|
addCloseable { saveToLocal() }
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
|
|
@ -88,6 +91,8 @@ class HomeSettingsViewModel
|
||||||
val libraries = navDrawerService.getAllUserLibraries(userDto.id, userDto.tvAccess)
|
val libraries = navDrawerService.getAllUserLibraries(userDto.id, userDto.tvAccess)
|
||||||
val currentSettings =
|
val currentSettings =
|
||||||
homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY }
|
homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY }
|
||||||
|
originalLocalSettings = homeSettingsService.loadFromLocal(userDto.id)
|
||||||
|
originalRemoteSettings = homeSettingsService.loadFromServer(userDto.id)
|
||||||
Timber.v("currentSettings=%s", currentSettings)
|
Timber.v("currentSettings=%s", currentSettings)
|
||||||
idCounter = currentSettings.rows.maxOfOrNull { it.id }?.plus(1) ?: 0
|
idCounter = currentSettings.rows.maxOfOrNull { it.id }?.plus(1) ?: 0
|
||||||
_state.update {
|
_state.update {
|
||||||
|
|
@ -493,9 +498,16 @@ class HomeSettingsViewModel
|
||||||
HomePageSettings(rows = rows, SUPPORTED_HOME_PAGE_SETTINGS_VERSION)
|
HomePageSettings(rows = rows, SUPPORTED_HOME_PAGE_SETTINGS_VERSION)
|
||||||
try {
|
try {
|
||||||
Timber.d("saveToLocal")
|
Timber.d("saveToLocal")
|
||||||
val local = homeSettingsService.loadFromLocal(user.id)
|
// Only save if there are changes based on original source
|
||||||
// Only save if there are changes
|
val shouldSave =
|
||||||
if (local != settings) {
|
if (originalLocalSettings != null) {
|
||||||
|
originalLocalSettings != settings
|
||||||
|
} else if (originalRemoteSettings != null) {
|
||||||
|
originalRemoteSettings != settings
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
if (shouldSave) {
|
||||||
homeSettingsService.saveToLocal(user.id, settings)
|
homeSettingsService.saveToLocal(user.id, settings)
|
||||||
homeSettingsService.updateCurrent(settings)
|
homeSettingsService.updateCurrent(settings)
|
||||||
showSaveToast()
|
showSaveToast()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue