From 06448f32c11a027699126c56ef671be76071a53f Mon Sep 17 00:00:00 2001 From: Nicolas Pomepuy Date: Thu, 15 Feb 2024 10:12:55 +0100 Subject: [PATCH] Allow renaming a playlist --- .../org/videolan/vlc/gui/PlaylistFragment.kt | 20 +++++++++++++++++-- .../org/videolan/vlc/util/ContextOption.kt | 1 + .../viewmodels/mobile/PlaylistsViewModel.kt | 7 +++++++ medialibrary/jni/medialibrary.cpp | 11 ++++++++++ .../interfaces/media/Playlist.java | 2 ++ .../medialibrary/media/PlaylistImpl.java | 8 ++++++++ .../medialibrary/stubs/StubPlaylist.java | 6 ++++++ 7 files changed, 53 insertions(+), 2 deletions(-) diff --git a/application/vlc-android/src/org/videolan/vlc/gui/PlaylistFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/PlaylistFragment.kt index 7df57a43d..c5a91cc26 100644 --- a/application/vlc-android/src/org/videolan/vlc/gui/PlaylistFragment.kt +++ b/application/vlc-android/src/org/videolan/vlc/gui/PlaylistFragment.kt @@ -27,12 +27,14 @@ import android.view.* import androidx.appcompat.view.ActionMode import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.google.android.material.appbar.AppBarLayout import com.google.android.material.floatingactionbutton.FloatingActionButton +import kotlinx.coroutines.launch import org.videolan.medialibrary.interfaces.Medialibrary import org.videolan.medialibrary.interfaces.media.MediaWrapper import org.videolan.medialibrary.interfaces.media.Playlist @@ -242,8 +244,22 @@ class PlaylistFragment : BaseAudioBrowser(), SwipeRefreshLay override fun onCtxAction(position: Int, option: ContextOption) { @Suppress("UNCHECKED_CAST") - if (option == CTX_PLAY_ALL) MediaUtils.playAll(activity, viewModel.provider as MedialibraryProvider, position, false) - else super.onCtxAction(position, option) + when (option) { + CTX_PLAY_ALL -> MediaUtils.playAll(activity, viewModel.provider as MedialibraryProvider, position, false) + CTX_RENAME -> { + val media = getCurrentAdapter()?.getItem(position) ?: return + val dialog = RenameDialog.newInstance(media) + dialog.show(requireActivity().supportFragmentManager, RenameDialog::class.simpleName) + dialog.setListener { item, name -> + lifecycleScope.launch { + viewModel.rename(media, name) + } + } + } + else -> super.onCtxAction(position, option) + } + + } override fun onRefresh() { diff --git a/application/vlc-android/src/org/videolan/vlc/util/ContextOption.kt b/application/vlc-android/src/org/videolan/vlc/util/ContextOption.kt index 9150cb113..c3dd157cb 100644 --- a/application/vlc-android/src/org/videolan/vlc/util/ContextOption.kt +++ b/application/vlc-android/src/org/videolan/vlc/util/ContextOption.kt @@ -85,6 +85,7 @@ enum class ContextOption : Flag { fun createCtxPlaylistAlbumFlags() = createCtxAudioFlags().apply { add(CTX_DELETE) + add(CTX_RENAME) } fun createCtxPlaylistItemFlags() = createBaseFlags().apply { diff --git a/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistsViewModel.kt b/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistsViewModel.kt index c64a1cda4..7837020bb 100644 --- a/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistsViewModel.kt +++ b/application/vlc-android/src/org/videolan/vlc/viewmodels/mobile/PlaylistsViewModel.kt @@ -23,6 +23,8 @@ package org.videolan.vlc.viewmodels.mobile import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.videolan.medialibrary.interfaces.media.Playlist import org.videolan.medialibrary.media.MediaLibraryItem import org.videolan.vlc.gui.PlaylistFragment @@ -41,6 +43,11 @@ class PlaylistsViewModel(context: Context, type: Playlist.Type) : MedialibraryVi providerInCard = settings.getBoolean(displayModeKey, providerInCard) } + suspend fun rename(media: MediaLibraryItem, name: String) { + withContext(Dispatchers.IO) { (media as? Playlist)?.setName(name) } + refresh() + } + class Factory(val context: Context, val type: Playlist.Type): ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { @Suppress("UNCHECKED_CAST") diff --git a/medialibrary/jni/medialibrary.cpp b/medialibrary/jni/medialibrary.cpp index c828ec083..665e44b01 100644 --- a/medialibrary/jni/medialibrary.cpp +++ b/medialibrary/jni/medialibrary.cpp @@ -1736,6 +1736,16 @@ playlistDelete(JNIEnv* env, jobject thiz, jobject medialibrary, jlong playlistId return aml->PlaylistDelete(playlistId); } +jboolean +setPlaylistName(JNIEnv* env, jobject thiz, jobject medialibrary, jlong id, jstring name) { + AndroidMediaLibrary *aml = MediaLibrary_getInstance(env, medialibrary); + const char *char_name = env->GetStringUTFChars(name, JNI_FALSE); + const medialibrary::PlaylistPtr playlist = aml->playlist(id); + const bool result = playlist->setName(char_name); + env->ReleaseStringUTFChars(name, char_name); + return result; +} + /* * Folder methods */ @@ -2671,6 +2681,7 @@ static JNINativeMethod playlist_methods[] = { {"nativePlaylistMove", "(Lorg/videolan/medialibrary/interfaces/Medialibrary;JII)Z", (void*)playlistMove }, {"nativePlaylistRemove", "(Lorg/videolan/medialibrary/interfaces/Medialibrary;JI)Z", (void*)playlistRemove }, {"nativePlaylistDelete", "(Lorg/videolan/medialibrary/interfaces/Medialibrary;J)Z", (void*)playlistDelete }, + {"nativePlaylistSetName", "(Lorg/videolan/medialibrary/interfaces/Medialibrary;JLjava/lang/String;)Z", (void*)setPlaylistName }, {"nativeSetFavorite", "(Lorg/videolan/medialibrary/interfaces/Medialibrary;JZ)Z", (void*)setPlaylistFavorite }, }; diff --git a/medialibrary/src/org/videolan/medialibrary/interfaces/media/Playlist.java b/medialibrary/src/org/videolan/medialibrary/interfaces/media/Playlist.java index 793865620..35ec826bc 100644 --- a/medialibrary/src/org/videolan/medialibrary/interfaces/media/Playlist.java +++ b/medialibrary/src/org/videolan/medialibrary/interfaces/media/Playlist.java @@ -51,6 +51,8 @@ public abstract class Playlist extends MediaLibraryItem { abstract public boolean move(int oldPosition, int newPosition); abstract public boolean remove(int position); abstract public boolean delete(); + abstract public boolean setName(String name); + abstract public MediaWrapper[] searchTracks(String query, int sort, boolean desc, boolean includeMissing, boolean onlyFavorites, int nbItems, int offset); abstract public int searchTracksCount(String query); diff --git a/medialibrary/src/org/videolan/medialibrary/media/PlaylistImpl.java b/medialibrary/src/org/videolan/medialibrary/media/PlaylistImpl.java index b7ea6affb..2ff770eae 100644 --- a/medialibrary/src/org/videolan/medialibrary/media/PlaylistImpl.java +++ b/medialibrary/src/org/videolan/medialibrary/media/PlaylistImpl.java @@ -80,6 +80,12 @@ public class PlaylistImpl extends Playlist { return ml.isInitiated() && nativePlaylistDelete(ml, mId); } + @Override + public boolean setName(String name) { + final Medialibrary ml = Medialibrary.getInstance(); + return ml.isInitiated() && nativePlaylistSetName(ml, mId, name); + } + public MediaWrapper[] searchTracks(String query, int sort, boolean desc, boolean includeMissing, boolean onlyFavorites, int nbItems, int offset) { final Medialibrary ml = Medialibrary.getInstance(); return ml.isInitiated() ? nativeSearch(ml, mId, query, sort, desc, includeMissing, onlyFavorites, nbItems, offset) : Medialibrary.EMPTY_COLLECTION; @@ -113,5 +119,7 @@ public class PlaylistImpl extends Playlist { private native boolean nativePlaylistRemove(Medialibrary ml, long id, int position); private native boolean nativePlaylistDelete(Medialibrary ml, long id); + private native boolean nativePlaylistSetName(Medialibrary ml, long mId, String name); + private native boolean nativeSetFavorite(Medialibrary ml, long id, boolean favorite); } diff --git a/medialibrary/src/org/videolan/medialibrary/stubs/StubPlaylist.java b/medialibrary/src/org/videolan/medialibrary/stubs/StubPlaylist.java index d0f9bbc16..1eea87161 100644 --- a/medialibrary/src/org/videolan/medialibrary/stubs/StubPlaylist.java +++ b/medialibrary/src/org/videolan/medialibrary/stubs/StubPlaylist.java @@ -97,6 +97,12 @@ public class StubPlaylist extends Playlist { return false; } + @Override + public boolean setName(String name) { + mTitle = name; + return true; + } + public MediaWrapper[] searchTracks(String query, int sort, boolean desc, boolean includeMissing, boolean onlyFavorites, int nbItems, int offset) { ArrayList results = new ArrayList<>(); for (MediaWrapper media : dt.mAudioMediaWrappers) {