[Android] Allow renaming a playlist

Nicolas Pomepuy git at videolan.org
Wed Nov 20 06:47:53 UTC 2024


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Feb 15 10:12:55 2024 +0100| [06448f32c11a027699126c56ef671be76071a53f] | committer: Duncan McNamara

Allow renaming a playlist

> https://code.videolan.org/videolan/vlc-android/commit/06448f32c11a027699126c56ef671be76071a53f
---

 .../src/org/videolan/vlc/gui/PlaylistFragment.kt     | 20 ++++++++++++++++++--
 .../src/org/videolan/vlc/util/ContextOption.kt       |  1 +
 .../vlc/viewmodels/mobile/PlaylistsViewModel.kt      |  7 +++++++
 medialibrary/jni/medialibrary.cpp                    | 11 +++++++++++
 .../medialibrary/interfaces/media/Playlist.java      |  2 ++
 .../videolan/medialibrary/media/PlaylistImpl.java    |  8 ++++++++
 .../videolan/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 7df57a43dd..c5a91cc269 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<PlaylistsViewModel>(), SwipeRefreshLay
 
     override fun onCtxAction(position: Int, option: ContextOption) {
         @Suppress("UNCHECKED_CAST")
-        if (option == CTX_PLAY_ALL) MediaUtils.playAll(activity, viewModel.provider as MedialibraryProvider<MediaWrapper>, position, false)
-        else super.onCtxAction(position, option)
+        when (option) {
+            CTX_PLAY_ALL -> MediaUtils.playAll(activity, viewModel.provider as MedialibraryProvider<MediaWrapper>, 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 9150cb113a..c3dd157cbf 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 c64a1cda49..7837020bbb 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 <T : ViewModel> create(modelClass: Class<T>): T {
             @Suppress("UNCHECKED_CAST")
diff --git a/medialibrary/jni/medialibrary.cpp b/medialibrary/jni/medialibrary.cpp
index c828ec083c..665e44b016 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 793865620a..35ec826bc4 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 b7ea6affb7..2ff770eae5 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 d0f9bbc165..1eea871611 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<MediaWrapper> results = new ArrayList<>();
         for (MediaWrapper media : dt.mAudioMediaWrappers) {



More information about the Android mailing list