Browse Source

Add a new DisplaySettingsCallBackDelegate to handle viewmodel refresh

merge-requests/2332/head
Nicolas Pomepuy 9 months ago
parent
commit
24991b1c86
  1. 1
      application/television/src/main/java/org/videolan/television/ui/compose/composable/components/MediaListSidePanel.kt
  2. 2
      application/television/src/main/java/org/videolan/television/ui/compose/composable/lists/AudioList.kt
  3. 2
      application/television/src/main/java/org/videolan/television/ui/compose/composable/lists/PlaylistsList.kt
  4. 2
      application/television/src/main/java/org/videolan/television/ui/compose/composable/lists/VideoList.kt
  5. 1
      application/television/src/main/java/org/videolan/television/viewmodel/MainActivityViewModel.kt
  6. 2
      application/vlc-android/src/org/videolan/vlc/util/UiUtils.kt
  7. 135
      application/vlc-android/src/org/videolan/vlc/viewmodels/DisplaySettingsCallBackDelegate.kt
  8. 4
      application/vlc-android/src/org/videolan/vlc/viewmodels/MedialibraryViewModel.kt
  9. 4
      application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/VideosViewModel.kt

1
application/television/src/main/java/org/videolan/television/ui/compose/composable/components/MediaListSidePanel.kt

@ -52,6 +52,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.launch
import org.videolan.television.R
import org.videolan.vlc.util.MediaListEntry
import org.videolan.television.viewmodel.MainActivityViewModel
@Composable

2
application/television/src/main/java/org/videolan/television/ui/compose/composable/lists/AudioList.kt

@ -82,7 +82,7 @@ import org.videolan.television.ui.compose.composable.items.AudioItemList
import org.videolan.television.ui.compose.theme.Transparent
import org.videolan.television.ui.compose.theme.White
import org.videolan.television.ui.compose.theme.WhiteTransparent50
import org.videolan.television.ui.utils.MediaListEntry
import org.videolan.vlc.util.MediaListEntry
import org.videolan.television.viewmodel.MainActivityViewModel
import org.videolan.tools.KEY_AUDIO_TAB
import org.videolan.tools.Settings

2
application/television/src/main/java/org/videolan/television/ui/compose/composable/lists/PlaylistsList.kt

@ -30,7 +30,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.focusProperties
import org.videolan.television.ui.utils.MediaListEntry
import org.videolan.vlc.util.MediaListEntry
@Composable
fun PlaylistsList(onFocusExit: () -> Unit, onFocusEnter: () -> Unit) {

2
application/television/src/main/java/org/videolan/television/ui/compose/composable/lists/VideoList.kt

@ -76,7 +76,6 @@ import org.videolan.television.ui.compose.composable.items.VideoItem
import org.videolan.television.ui.compose.composable.items.VideoItemList
import org.videolan.television.ui.compose.theme.White
import org.videolan.television.ui.compose.theme.WhiteTransparent50
import org.videolan.television.ui.utils.MediaListEntry
import org.videolan.television.viewmodel.MainActivityViewModel
import org.videolan.tools.KEY_GROUP_VIDEOS
import org.videolan.tools.KEY_VIDEOS_CARDS
@ -85,6 +84,7 @@ import org.videolan.tools.Settings
import org.videolan.tools.putSingle
import org.videolan.vlc.BuildConfig
import org.videolan.vlc.media.MediaUtils
import org.videolan.vlc.util.MediaListEntry
import org.videolan.vlc.viewmodels.mobile.VideoGroupingType
import org.videolan.vlc.viewmodels.mobile.VideosViewModel

1
application/television/src/main/java/org/videolan/television/viewmodel/MainActivityViewModel.kt

@ -33,6 +33,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.videolan.medialibrary.interfaces.Medialibrary
import org.videolan.television.R
import org.videolan.vlc.util.MediaListEntry
import org.videolan.vlc.MediaParsingService
import org.videolan.vlc.ScanProgress

2
application/television/src/main/java/org/videolan/television/ui/utils/UiUtils.kt → application/vlc-android/src/org/videolan/vlc/util/UiUtils.kt

@ -22,7 +22,7 @@
*
*/
package org.videolan.television.ui.utils
package org.videolan.vlc.util
import android.content.Context
import org.videolan.tools.KEY_VIDEOS_CARDS

135
application/vlc-android/src/org/videolan/vlc/viewmodels/DisplaySettingsCallBackDelegate.kt

@ -0,0 +1,135 @@
/*
*****************************************************************************
* DisplaySettingsCallBackDelegate.kt
*****************************************************************************
* Copyright © 2025 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.viewmodels
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.launch
import org.videolan.medialibrary.interfaces.Medialibrary
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.resources.AppContextProvider
import org.videolan.tools.conflatedActor
import org.videolan.vlc.media.PlaylistManager
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.util.FileUtils
import org.videolan.vlc.util.MediaListEntry
import java.io.File
interface IDisplaySettingsCallBackHandler {
fun CoroutineScope.registerDisplaySettingsCallBacks(refresh: () -> Unit, getAllProviders: () -> Array<MedialibraryProvider<out MediaLibraryItem>>)
fun releaseDisplaySettingsCallbacks()
fun watchFor(entry:MediaListEntry)
fun onPause()
fun onResume()
}
open class DisplaySettingsCallBackDelegate : IDisplaySettingsCallBackHandler
{
private lateinit var collectionJob: Job
private lateinit var refreshActor: SendChannel<Unit>
private var watchedEntries = mutableListOf<MediaListEntry>()
var paused = false
set(value) {
field = value
if (!value && isInvalid) {
refreshActor.trySend(Unit)
isInvalid = false
}
}
var isInvalid = false
/**
* Pause the callbacks while the caller is paused to avoid unwanted refreshes
* During this time, instead of refreshing, it's marked as invalid.
* If invalid, a refresh is launched upon resuming
*/
override fun onPause() {
paused = true
}
/**
* Resumes the callback and refresh if it has been marked invalid in the meantime
*/
override fun onResume() {
paused = false
}
@OptIn(ObsoleteCoroutinesApi::class)
override fun CoroutineScope.registerDisplaySettingsCallBacks(refresh: () -> Unit, getAllProviders: () -> Array<MedialibraryProvider<out MediaLibraryItem>>) {
refreshActor = conflatedActor {
if (paused) isInvalid = true else refresh()
}
collectionJob = launch {
DisplaySettingsEventManager.currentDisplaySettingsChange.collect { displaySettingsEvent ->
if (displaySettingsEvent?.currentEntry in watchedEntries) {
if (displaySettingsEvent is DisplaySettingsEvent.OnlyFavsChanged) {
getAllProviders().forEach {
it.onlyFavorites = displaySettingsEvent.onlyFavorites
}
}
refreshActor.trySend(Unit)
}
}
}
}
override fun watchFor(entry: MediaListEntry) {
watchedEntries.add(entry)
}
override fun releaseDisplaySettingsCallbacks() {
refreshActor.close()
collectionJob.cancel()
}
}
sealed class DisplaySettingsEvent(val currentEntry: MediaListEntry, time: Long) {
data class OnlyFavsChanged(val entry: MediaListEntry, val onlyFavorites: Boolean): DisplaySettingsEvent(entry, System.currentTimeMillis())
}
object DisplaySettingsEventManager {
private val _currentDisplaySettingsChange: MutableStateFlow<DisplaySettingsEvent?> = MutableStateFlow(null)
val currentDisplaySettingsChange: StateFlow<DisplaySettingsEvent?> = _currentDisplaySettingsChange.asStateFlow()
suspend fun onOnlyFavsChanged(entry: MediaListEntry, onlyFavorites: Boolean) {
_currentDisplaySettingsChange.emit(DisplaySettingsEvent.OnlyFavsChanged(entry, onlyFavorites))
}
}

4
application/vlc-android/src/org/videolan/vlc/viewmodels/MedialibraryViewModel.kt

@ -14,11 +14,12 @@ import java.util.ArrayList
abstract class MedialibraryViewModel(context: Context) : SortableModel(context),
ICallBackHandler by CallBackDelegate() {
ICallBackHandler by CallBackDelegate(), IDisplaySettingsCallBackHandler by DisplaySettingsCallBackDelegate() {
init {
@Suppress("LeakingThis")
viewModelScope.registerCallBacks { refresh() }
viewModelScope.registerDisplaySettingsCallBacks({ refresh() }) { providers }
}
abstract val providers : Array<MedialibraryProvider<out MediaLibraryItem>>
@ -44,6 +45,7 @@ abstract class MedialibraryViewModel(context: Context) : SortableModel(context),
override fun onCleared() {
releaseCallbacks()
releaseDisplaySettingsCallbacks()
super.onCleared()
}

4
application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/VideosViewModel.kt

@ -54,6 +54,7 @@ import org.videolan.vlc.providers.medialibrary.FoldersProvider
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.providers.medialibrary.VideoGroupsProvider
import org.videolan.vlc.providers.medialibrary.VideosProvider
import org.videolan.vlc.util.MediaListEntry
import org.videolan.vlc.viewmodels.MedialibraryViewModel
class VideosViewModel(context: Context, type: VideoGroupingType, val folder: Folder?, val group: VideoGroup?) : MedialibraryViewModel(context) {
@ -84,6 +85,9 @@ class VideosViewModel(context: Context, type: VideoGroupingType, val folder: Fol
watchMedia()
watchMediaGroups()
watchFolders()
watchFor(MediaListEntry.VIDEO)
watchFor(MediaListEntry.VIDEO_FOLDER)
watchFor(MediaListEntry.VIDEO_GROUPS)
}
class Factory(val context: Context, private val groupingType: VideoGroupingType, val folder: Folder? = null, val group: VideoGroup? = null) : ViewModelProvider.NewInstanceFactory() {

Loading…
Cancel
Save