More bug fixes (#45)

Fixes:
* Issue from #39 where pressing back from playback went back two screens
instead of one
* Sometimes having to click on a server twice to switch to it
* Update UI when marking a single season as watched
* Fix needing to press back twice to hide skip segment buttons
* Fix skip intro/outro behaviors being swapped
* Always attempt to save playback progress when stopping playback
This commit is contained in:
damontecres 2025-10-19 22:35:47 -04:00 committed by GitHub
parent 95a74b73ff
commit 77aaa87126
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 51 additions and 35 deletions

View file

@ -135,6 +135,8 @@ class MainActivity : AppCompatActivity() {
val initialDestination = val initialDestination =
if (server != null && user != null) { if (server != null && user != null) {
Destination.Home() Destination.Home()
} else if (server != null) {
Destination.UserList
} else { } else {
Destination.ServerList Destination.ServerList
} }
@ -164,4 +166,11 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
override fun onPause() {
if (navigationManager.backStack.lastOrNull() is Destination.Playback) {
navigationManager.goBack()
}
super.onPause()
}
} }

View file

@ -127,11 +127,7 @@ fun SeriesDetails(
season, season,
onClickItem = { viewModel.navigateTo(it.destination()) }, onClickItem = { viewModel.navigateTo(it.destination()) },
markPlayed = { played -> markPlayed = { played ->
viewModel.setWatched( viewModel.setSeasonWatched(season.id, played)
season.id,
played,
null,
)
}, },
) )
}, },

View file

@ -220,7 +220,7 @@ class SeriesViewModel
itemId: UUID, itemId: UUID,
played: Boolean, played: Boolean,
listIndex: Int?, listIndex: Int?,
) = viewModelScope.launch(ExceptionHandler()) { ) = viewModelScope.launch(Dispatchers.IO + ExceptionHandler()) {
if (played) { if (played) {
api.playStateApi.markPlayedItem(itemId) api.playStateApi.markPlayedItem(itemId)
} else { } else {
@ -231,6 +231,16 @@ class SeriesViewModel
} }
} }
fun setSeasonWatched(
seasonId: UUID,
played: Boolean,
) = viewModelScope.launch(Dispatchers.IO + ExceptionHandler()) {
setWatched(seasonId, played, null)
val series = fetchItem(seriesId, null)
val seasons = getSeasons(series)
this@SeriesViewModel.seasons.setValueOnMain(seasons)
}
fun setWatchedSeries(played: Boolean) = fun setWatchedSeries(played: Boolean) =
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) { viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
if (played) { if (played) {

View file

@ -373,32 +373,32 @@ fun PlaybackPage(
currentSegment = currentSegment, currentSegment = currentSegment,
) )
} }
}
// Ask to skip intros, etc button // Ask to skip intros, etc button
AnimatedVisibility( AnimatedVisibility(
showSegment, showSegment,
modifier = modifier =
Modifier Modifier
.padding(40.dp) .padding(40.dp)
.align(Alignment.BottomEnd), .align(Alignment.BottomEnd),
) { ) {
currentSegment?.let { segment -> currentSegment?.let { segment ->
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
focusRequester.tryRequestFocus() focusRequester.tryRequestFocus()
delay(10.seconds) delay(10.seconds)
segmentCancelled = false segmentCancelled = false
} }
Button( Button(
onClick = { onClick = {
player.seekTo(segment.endTicks.ticks.inWholeMilliseconds) player.seekTo(segment.endTicks.ticks.inWholeMilliseconds)
}, },
modifier = Modifier.focusRequester(focusRequester), modifier = Modifier.focusRequester(focusRequester),
) { ) {
Text( Text(
text = "Skip ${segment.type.serialName}", text = "Skip ${segment.type.serialName}",
) )
}
} }
} }
} }

View file

@ -619,8 +619,8 @@ class PlaybackViewModel
MediaSegmentType.COMMERCIAL -> prefs.skipCommercials MediaSegmentType.COMMERCIAL -> prefs.skipCommercials
MediaSegmentType.PREVIEW -> prefs.skipPreviews MediaSegmentType.PREVIEW -> prefs.skipPreviews
MediaSegmentType.RECAP -> prefs.skipRecaps MediaSegmentType.RECAP -> prefs.skipRecaps
MediaSegmentType.OUTRO -> prefs.skipIntros MediaSegmentType.OUTRO -> prefs.skipOutros
MediaSegmentType.INTRO -> prefs.skipOutros MediaSegmentType.INTRO -> prefs.skipIntros
MediaSegmentType.UNKNOWN -> SkipSegmentBehavior.IGNORE MediaSegmentType.UNKNOWN -> SkipSegmentBehavior.IGNORE
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -731,8 +731,8 @@ class PlaybackViewModel
} }
fun release() { fun release() {
activityListener?.release()
player.release() player.release()
navigationManager.goBack()
} }
} }

View file

@ -92,11 +92,12 @@ class TrackActivityPlaybackListener(
fun release() { fun release() {
task.cancel() task.cancel()
TIMER.purge() TIMER.purge()
val position = player.currentPosition.milliseconds.inWholeTicks
coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) { coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) {
api.playStateApi.reportPlaybackStopped( api.playStateApi.reportPlaybackStopped(
PlaybackStopInfo( PlaybackStopInfo(
itemId = itemPlayback.itemId, itemId = itemPlayback.itemId,
positionTicks = withContext(Dispatchers.Main) { player.currentPosition.milliseconds.inWholeTicks }, positionTicks = position,
failed = false, failed = false,
playSessionId = playback.playSessionId, playSessionId = playback.playSessionId,
), ),