From b7a61425ca3991a71d8c374461ee6cc0fe47975d Mon Sep 17 00:00:00 2001 From: Koen J Date: Sat, 15 Nov 2025 15:22:52 +0100 Subject: [PATCH] Implemented history position playlist id tracking. --- .../java/com/futo/platformplayer/Utility.kt | 2 +- .../mainactivity/main/HistoryFragment.kt | 18 +++++++++++++--- .../mainactivity/main/VideoDetailView.kt | 5 +++-- .../platformplayer/models/HistoryVideo.kt | 6 ++++-- .../futo/platformplayer/states/StateBackup.kt | 2 +- .../platformplayer/states/StateHistory.kt | 5 +++-- .../futo/platformplayer/states/StatePlayer.kt | 21 ++++--------------- .../platformplayer/states/StatePlaylists.kt | 4 ++-- .../futo/platformplayer/states/StateSync.kt | 2 +- 9 files changed, 34 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/Utility.kt b/app/src/main/java/com/futo/platformplayer/Utility.kt index 0875aadb..5b00bbb9 100644 --- a/app/src/main/java/com/futo/platformplayer/Utility.kt +++ b/app/src/main/java/com/futo/platformplayer/Utility.kt @@ -101,7 +101,7 @@ fun String.isHexColor(): Boolean { fun IPlatformClient.fromPool(pool: PlatformMultiClientPool) = pool.getClientPooled(this); -fun IPlatformVideo.withTimestamp(sec: Long) = PlatformVideoWithTime(this, sec); +fun IPlatformVideo.withTimestamp(sec: Long) = PlatformVideoWithTime(this, sec); fun DocumentFile.getInputStream(context: Context) = context.contentResolver.openInputStream(this.uri); fun DocumentFile.getOutputStream(context: Context) = context.contentResolver.openOutputStream(this.uri); diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt index 80bd08cf..8bb2d0e1 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt @@ -26,6 +26,7 @@ import com.futo.platformplayer.models.HistoryVideo import com.futo.platformplayer.states.StateHistory import com.futo.platformplayer.states.StatePlatform import com.futo.platformplayer.states.StatePlayer +import com.futo.platformplayer.states.StatePlaylists import com.futo.platformplayer.states.StatePlugins import com.futo.platformplayer.views.ToggleBar import com.futo.platformplayer.views.adapters.HistoryListViewHolder @@ -243,12 +244,23 @@ class HistoryFragment : MainFragment() { return; } - val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager; val diff = v.video.duration - v.position; val vid: Any = if (diff > 5) { v.video.withTimestamp(v.position) } else { v.video }; - StatePlayer.instance.clearQueue(); - _fragment.navigate(vid).maximizeVideoDetail(); + + val playlistId = v.playlistId + val playlist = playlistId?.let { StatePlaylists.instance.getPlaylist(it) } + val playlistIndex = playlist?.videos?.indexOfFirst { it.url == v.video.url } + if (playlist != null && playlistIndex != null && playlistIndex >= 0) { + _fragment.navigate(vid).maximizeVideoDetail(); + StatePlayer.instance.setPlaylist(playlist, playlistIndex) + + } else { + StatePlayer.instance.clearQueue(); + _fragment.navigate(vid).maximizeVideoDetail(); + } + _editSearch.clearFocus(); + val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager; inputMethodManager.hideSoftInputFromWindow(_editSearch.windowToken, 0); _fragment.lifecycleScope.launch(Dispatchers.Main) { diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index d01586af..c7d012bf 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -1777,7 +1777,8 @@ class VideoDetailView : ConstraintLayout { false, (toResume.toFloat() / 1000.0f).toLong(), null, - true + true, + StatePlayer.instance.playlistId ); Logger.i( TAG, @@ -3095,7 +3096,7 @@ class VideoDetailView : ConstraintLayout { if (v !is TutorialFragment.TutorialVideo) { fragment.lifecycleScope.launch(Dispatchers.IO) { val history = getHistoryIndex(v) ?: return@launch; - StateHistory.instance.updateHistoryPosition(v, history, true, (positionMilliseconds.toFloat() / 1000.0f).toLong(), null, true); + StateHistory.instance.updateHistoryPosition(v, history, true, (positionMilliseconds.toFloat() / 1000.0f).toLong(), null, true, StatePlayer.instance.playlistId); } } _lastPositionSaveTime = currentTime; diff --git a/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt b/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt index 80574968..fee3f7e0 100644 --- a/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt +++ b/app/src/main/java/com/futo/platformplayer/models/HistoryVideo.kt @@ -14,15 +14,17 @@ import java.time.ZoneOffset class HistoryVideo { var video: SerializedPlatformVideo; var position: Long; + var playlistId: String? = null @kotlinx.serialization.Serializable(with = OffsetDateTimeSerializer::class) var date: OffsetDateTime; - constructor(video: SerializedPlatformVideo, position: Long, date: OffsetDateTime) { + constructor(video: SerializedPlatformVideo, position: Long, date: OffsetDateTime, playlistId: String?) { this.video = video; this.position = position; this.date = date; + this.playlistId = playlistId } @@ -59,7 +61,7 @@ class HistoryVideo { viewCount = -1 ); - return HistoryVideo(video, position, OffsetDateTime.of(LocalDateTime.ofEpochSecond(dateSec, 0, ZoneOffset.UTC), ZoneOffset.UTC)); + return HistoryVideo(video, position, OffsetDateTime.of(LocalDateTime.ofEpochSecond(dateSec, 0, ZoneOffset.UTC), ZoneOffset.UTC), null); } } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt index 11aae89e..9a368152 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt @@ -365,7 +365,7 @@ class StateBackup { } val hist = StateHistory.instance.getHistoryByVideo(histObj.video, true, histObj.date); if(hist != null) - StateHistory.instance.updateHistoryPosition(histObj.video, hist, true, histObj.position, histObj.date, false); + StateHistory.instance.updateHistoryPosition(histObj.video, hist, true, histObj.position, histObj.date, false, histObj.playlistId); } catch(ex: Throwable) { Logger.e(TAG, "Failed to import subscription group", ex); diff --git a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt index 26fc3170..57b8d39c 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt @@ -65,7 +65,7 @@ class StateHistory { } private var _lastHistoryBroadcast = ""; - fun updateHistoryPosition(liveObj: IPlatformVideo, index: DBHistory.Index, updateExisting: Boolean, position: Long = -1L, date: OffsetDateTime? = null, isUserAction: Boolean = false): Long { + fun updateHistoryPosition(liveObj: IPlatformVideo, index: DBHistory.Index, updateExisting: Boolean, position: Long = -1L, date: OffsetDateTime? = null, isUserAction: Boolean = false, playlistId: String? = null): Long { val pos = if(position < 0) 0 else position; val historyVideo = index.obj; @@ -86,6 +86,7 @@ class StateHistory { historyVideo.position = pos; historyVideo.date = date ?: OffsetDateTime.now(); + historyVideo.playlistId = playlistId _historyDBStore.update(index.id!!, historyVideo); onHistoricVideoChanged.emit(liveObj, pos); @@ -157,7 +158,7 @@ class StateHistory { UIDialogs.toast("History item null?\nNo history tracking.."); } else if(create) { - val newHistItem = HistoryVideo(SerializedPlatformVideo.fromVideo(video), 0, watchDate ?: OffsetDateTime.now()); + val newHistItem = HistoryVideo(SerializedPlatformVideo.fromVideo(video), 0, watchDate ?: OffsetDateTime.now(), StatePlayer.instance.playlistId); val id = _historyDBStore.insert(newHistItem); result = _historyDBStore.getOrNull(id); if(result == null) diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt index 24b4eed0..1e6b0321 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt @@ -114,6 +114,9 @@ class StatePlayer { var currentVideo: IPlatformVideo? = null private set; + private var _currentPlaylistId: String? = null + val playlistId: String? get() = if (_queueType == TYPE_PLAYLIST) _currentPlaylistId else null + init { onQueueChanged.subscribe { updateLastQueue() @@ -275,23 +278,6 @@ class StatePlayer { } onQueueChanged.emit(true); } - fun setPlaylist(playlist: IPlatformPlaylistDetails, toPlayIndex: Int = 0, focus: Boolean = false, shuffle: Boolean = false) { - synchronized(_queue) { - _queue.clear(); - setQueueType(TYPE_PLAYLIST); - _queueName = playlist.name; - _queue.addAll(playlist.contents.getResults()); - queueFocused = focus; - queueShuffle = shuffle; - if (shuffle) { - createShuffledQueue(); - } - _queuePosition = toPlayIndex; - } - playlist.id.value?.let { StatePlaylists.instance.didPlay(it); }; - - onQueueChanged.emit(true); - } fun setPlaylist(playlist: Playlist, toPlayIndex: Int = 0, focus: Boolean = false, shuffle: Boolean = false) { synchronized(_queue) { _queue.clear(); @@ -305,6 +291,7 @@ class StatePlayer { } _queuePosition = toPlayIndex; } + _currentPlaylistId = playlist.id StatePlaylists.instance.didPlay(playlist.id); onQueueChanged.emit(true); diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt index ab7159d9..8eeb2342 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt @@ -200,10 +200,10 @@ class StatePlaylists { } fun getLastPlayedPlaylist() : Playlist? { - return playlistStore.queryItem { it.maxByOrNull { x -> x.datePlayed } }; + return playlistStore.queryItem { it.filter { x -> x.id != StatePlaylists.LAST_QUEUE_PLAYLIST_ID }.maxByOrNull { x -> x.datePlayed } }; } fun getLastUpdatedPlaylist() : Playlist? { - return playlistStore.queryItem { it.maxByOrNull { x -> x.dateUpdate } }; + return playlistStore.queryItem { it.filter { x -> x.id != StatePlaylists.LAST_QUEUE_PLAYLIST_ID }.maxByOrNull { x -> x.dateUpdate } }; } fun getPlaylists() : List { diff --git a/app/src/main/java/com/futo/platformplayer/states/StateSync.kt b/app/src/main/java/com/futo/platformplayer/states/StateSync.kt index 8b620239..2aee32c2 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateSync.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateSync.kt @@ -463,7 +463,7 @@ class StateSync { for(video in history){ val hist = StateHistory.instance.getHistoryByVideo(video.video, true, video.date); if(hist != null) - StateHistory.instance.updateHistoryPosition(video.video, hist, true, video.position, video.date) + StateHistory.instance.updateHistoryPosition(video.video, hist, true, video.position, video.date, false, video.playlistId) if(lastHistory < video.date) lastHistory = video.date; }