Commit 60b7d253 authored by Geoffrey Métais's avatar Geoffrey Métais

Videos: Implement paging libary

parent 5da2faa2
......@@ -269,6 +269,13 @@ AndroidMediaLibrary::searchFromPLaylist( int64_t playlistId, const std::string&
return playlist == nullptr ? nullptr : playlist->searchMedia(query, params);
}
medialibrary::Query<medialibrary::IMedia>
AndroidMediaLibrary::searchFromFolder( int64_t folderId, const std::string& query, medialibrary::IMedia::Type type, const medialibrary::QueryParameters* params )
{
auto folder = p_ml->folder(folderId);
return folder == nullptr ? nullptr : folder->searchMedia(query, type, params);
}
medialibrary::Query<medialibrary::IPlaylist>
AndroidMediaLibrary::searchPlaylists(const std::string& query, const medialibrary::QueryParameters* params)
{
......
......@@ -69,6 +69,7 @@ public:
medialibrary::Query<medialibrary::IMedia> searchFromGenre( int64_t genreId, const std::string& query, const medialibrary::QueryParameters* params = nullptr );
medialibrary::Query<medialibrary::IAlbum> searchAlbumsFromGenre( int64_t genreId, const std::string& query, const medialibrary::QueryParameters* params = nullptr );
medialibrary::Query<medialibrary::IMedia> searchFromPLaylist( int64_t playlistId, const std::string& query, const medialibrary::QueryParameters* params = nullptr );
medialibrary::Query<medialibrary::IMedia> searchFromFolder( int64_t folderId, const std::string& query, medialibrary::IMedia::Type type, const medialibrary::QueryParameters* params = nullptr );
medialibrary::MediaPtr media(long id);
medialibrary::MediaPtr media(const std::string& mrl);
medialibrary::MediaPtr addMedia(const std::string& mrl);
......
......@@ -261,10 +261,11 @@ bool clearHistory(JNIEnv* env, jobject thiz)
}
static jobjectArray
getInternalVideos(JNIEnv* env, jobject thiz, const medialibrary::QueryParameters* params = nullptr )
getInternalVideos(JNIEnv* env, jobject thiz, const medialibrary::QueryParameters* params = nullptr, jint nbItems = 0, jint offset = 0 )
{
AndroidMediaLibrary *aml = MediaLibrary_getInstance(env, thiz);
std::vector<medialibrary::MediaPtr> videoFiles = aml->videoFiles(params)->all();
const auto query = aml->videoFiles(params);
std::vector<medialibrary::MediaPtr> videoFiles = nbItems != 0 ? query->items(nbItems, offset) : query->all();
jobjectArray videoRefs = (jobjectArray) env->NewObjectArray(videoFiles.size(), ml_fields.MediaWrapper.clazz, NULL);
int index = -1, drops = 0;
for(medialibrary::MediaPtr const& media : videoFiles) {
......@@ -293,6 +294,16 @@ getSortedVideos(JNIEnv* env, jobject thiz, jint sortingCriteria, jboolean desc)
return getInternalVideos(env, thiz, &params );
}
jobjectArray
getPagedVideos(JNIEnv* env, jobject thiz, jint sortingCriteria, jboolean desc, jint nbItems, jint offset)
{
medialibrary::QueryParameters params {
static_cast<medialibrary::SortingCriteria>(sortingCriteria),
static_cast<bool>( desc )
};
return getInternalVideos(env, thiz, &params, nbItems, offset );
}
jobjectArray
getRecentVideos(JNIEnv* env, jobject thiz)
{
......@@ -1621,6 +1632,37 @@ mediaFromFolderCount(JNIEnv* env, jobject thiz, jobject medialibrary, jlong id,
return (jint) (query != nullptr ? query->count() : 0);
}
jobjectArray
searchMediaFromFolder(JNIEnv* env, jobject thiz, jobject medialibrary, jlong id, jstring filterQuery, jint mediaType, jint sortingCriteria, jboolean desc, jint nbItems, jint offset)
{
AndroidMediaLibrary *aml = MediaLibrary_getInstance(env, medialibrary);
medialibrary::QueryParameters params {
static_cast<medialibrary::SortingCriteria>(sortingCriteria),
static_cast<bool>( desc )
};
const char *queryChar = env->GetStringUTFChars(filterQuery, JNI_FALSE);
const auto query = aml->searchFromFolder(id, queryChar, (medialibrary::IMedia::Type)mediaType, &params);
if (query == nullptr) return (jobjectArray) env->NewObjectArray(0, ml_fields.MediaWrapper.clazz, NULL);
std::vector<medialibrary::MediaPtr> mediaList = nbItems != 0 ? query->items(nbItems, offset) : query->all();
jobjectArray mediaRefs = (jobjectArray) env->NewObjectArray(mediaList.size(), ml_fields.MediaWrapper.clazz, NULL);
int index = -1;
for(medialibrary::MediaPtr const& media : mediaList) {
jobject item = mediaToMediaWrapper(env, &ml_fields, media);
env->SetObjectArrayElement(mediaRefs, ++index, item);
env->DeleteLocalRef(item);
}
env->ReleaseStringUTFChars(filterQuery, queryChar);
return mediaRefs;
}
jint
getSearchMediaFromFolderCount(JNIEnv* env, jobject thiz, jobject medialibrary, jlong id, jstring filterQuery, jint mediaType) {
const char *queryChar = env->GetStringUTFChars(filterQuery, JNI_FALSE);
const auto query = MediaLibrary_getInstance(env, medialibrary)->searchFromFolder(id, queryChar, (medialibrary::IMedia::Type)mediaType);
env->ReleaseStringUTFChars(filterQuery, queryChar);
return (jint) (query != nullptr ? query->count() : 0);
}
jobjectArray
subFolders(JNIEnv* env, jobject thiz, jobject medialibrary, jlong id, jint sortingCriteria, jboolean desc, jint nbItems, jint offset ) {
AndroidMediaLibrary *aml = MediaLibrary_getInstance(env, medialibrary);
......@@ -1694,6 +1736,7 @@ static JNINativeMethod methods[] = {
{"nativeClearHistory", "()Z", (void*)clearHistory },
{"nativeGetVideos", "()[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)getVideos },
{"nativeGetSortedVideos", "(IZ)[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)getSortedVideos },
{"nativeGetSortedPagedVideos", "(IZII)[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)getPagedVideos },
{"nativeGetRecentVideos", "()[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)getRecentVideos },
{"nativeGetAudio", "()[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)getAudio },
{"nativeGetSortedAudio", "(IZ)[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)getSortedAudio },
......@@ -1808,6 +1851,8 @@ static JNINativeMethod folder_methods[] = {
{"nativeSubfolders", "(Lorg/videolan/medialibrary/Medialibrary;JIZII)[Lorg/videolan/medialibrary/media/Folder;", (void*)subFolders },
{"nativeMediaCount", "(Lorg/videolan/medialibrary/Medialibrary;JI)I", (void*)mediaFromFolderCount },
{"nativeSubfoldersCount", "(Lorg/videolan/medialibrary/Medialibrary;JI)I", (void*)subFoldersCount },
{"nativeSearch", "(Lorg/videolan/medialibrary/Medialibrary;JLjava/lang/String;IIZII)[Lorg/videolan/medialibrary/media/MediaWrapper;", (void*)searchMediaFromFolder },
{"nativeGetSearchCount", "(Lorg/videolan/medialibrary/Medialibrary;JLjava/lang/String;I)I", (void*)getSearchMediaFromFolderCount },
};
static JNINativeMethod playlist_methods[] = {
......
......@@ -222,6 +222,11 @@ public class Medialibrary {
return mIsInitiated ? nativeGetVideos() : new MediaWrapper[0];
}
@WorkerThread
public MediaWrapper[] getPagedVideos(int sort, boolean desc, int nbItems, int offset) {
return mIsInitiated ? nativeGetSortedPagedVideos(sort, desc, nbItems, offset) : new MediaWrapper[0];
}
@WorkerThread
public MediaWrapper[] getVideos(int sort, boolean desc) {
return mIsInitiated ? nativeGetSortedVideos(sort, desc) : new MediaWrapper[0];
......@@ -981,6 +986,7 @@ public class Medialibrary {
private native MediaWrapper[] nativeGetAudio();
private native MediaWrapper[] nativeGetSortedAudio(int sort, boolean desc);
private native MediaWrapper[] nativeGetSortedPagedAudio(int sort, boolean desc, int nbItems, int offset);
private native MediaWrapper[] nativeGetSortedPagedVideos(int sort, boolean desc, int nbItems, int offset);
private native MediaWrapper[] nativeGetRecentAudio();
private native int nativeGetVideoCount();
private native int nativeGetAudioCount();
......
......@@ -56,12 +56,24 @@ public class Folder extends MediaLibraryItem {
return ml.isInitiated() ? nativeSubfoldersCount(ml, mId, type) : 0;
}
// private native MediaWrapper[] nativeGetTracks();
public MediaWrapper[] searchTracks(String query, int mediaType, int sort, boolean desc, int nbItems, int offset) {
final Medialibrary ml = Medialibrary.getInstance();
return ml.isInitiated() ? nativeSearch(ml, mId, query, mediaType, sort, desc, nbItems, offset) : Medialibrary.EMPTY_COLLECTION;
}
public int searchTracksCount(String query, int mediaType) {
final Medialibrary ml = Medialibrary.getInstance();
return ml.isInitiated() ? nativeGetSearchCount(ml, mId, query, mediaType) : 0;
}
// private native MediaWrapper[] nativeGetTracks();
// private native int nativeGetTracksCount();
private native MediaWrapper[] nativeMedia(Medialibrary ml, long mId, int type, int sort, boolean desc, int nbItems, int offset);
private native int nativeMediaCount(Medialibrary ml, long mId, int type);
private native Folder[] nativeSubfolders(Medialibrary ml, long mId, int sort, boolean desc, int nbItems, int offset);
private native int nativeSubfoldersCount(Medialibrary ml, long mId, int type);
private native MediaWrapper[] nativeSearch(Medialibrary ml, long mId, String query, int mediaType, int sort, boolean desc, int nbItems, int offset);
private native int nativeGetSearchCount(Medialibrary ml, long mId, String query, int mediaType);
@Override
public void writeToParcel(Parcel parcel, int i) {
......
......@@ -161,7 +161,6 @@ public class AudioBrowserAdapter extends PagedListAdapter<MediaLibraryItem, Audi
@Override
public MediaLibraryItem getItem(int position) {
return super.getItem(position);
// return null;
}
@Override
......@@ -174,12 +173,12 @@ public class AudioBrowserAdapter extends PagedListAdapter<MediaLibraryItem, Audi
// getDataset().clear();
}
@Override
public void onCurrentListChanged(@Nullable PagedList<MediaLibraryItem> currentList) {
public void onCurrentListChanged(@Nullable PagedList<MediaLibraryItem> previousList, @Nullable PagedList<MediaLibraryItem> currentList) {
mIEventsHandler.onUpdateFinished(AudioBrowserAdapter.this);
}
@Override
public boolean hasSections() {
return true;
......
This diff is collapsed.
......@@ -22,7 +22,6 @@ package org.videolan.vlc.viewmodels
import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
......@@ -38,7 +37,6 @@ import org.videolan.medialibrary.Medialibrary
import org.videolan.medialibrary.media.Folder
import org.videolan.medialibrary.media.MediaWrapper
import org.videolan.vlc.R
import org.videolan.vlc.RecommendationsService
import org.videolan.vlc.media.MediaGroup
import org.videolan.vlc.media.getAll
import org.videolan.vlc.util.AndroidDevices
......@@ -120,21 +118,6 @@ open class VideosModel(context: Context, private val group: String?, val folder
super.onCleared()
}
fun getListWithPosition(list: MutableList<MediaWrapper>, position: Int): Int {
if (group != null || minGroupLen <= 0) {
list.addAll(dataset.value)
return position
}
var offset = 0
for ((i, mw) in dataset.value.withIndex()) {
if (mw is MediaGroup) {
for (item in mw.all) list.add(item)
if (i < position) offset += mw.size() - 1
} else list.add(mw)
}
return position + offset
}
class Factory(
private val context: Context,
val group: String?,
......
......@@ -99,6 +99,8 @@ abstract class MLPagedModel<T : MediaLibraryItem>(context: Context) : SortableMo
}
}
fun isEmpty() = pagedList.value.isNullOrEmpty()
override fun refresh(): Boolean {
headers.clear()
if (this::restoreJob.isInitialized && restoreJob.isActive) restoreJob.cancel()
......
......@@ -3,11 +3,13 @@ package org.videolan.vlc.viewmodels.paged
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.Medialibrary
import org.videolan.medialibrary.media.*
import org.videolan.vlc.util.EmptyMLCallbacks
import org.videolan.vlc.util.Settings
@ExperimentalCoroutinesApi
class PagedTracksModel(context: Context, val parent: MediaLibraryItem? = null): MLPagedModel<MediaWrapper>(context),
Medialibrary.MediaCb,
Medialibrary.ArtistsCb by EmptyMLCallbacks,
......
package org.videolan.vlc.viewmodels.paged
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.libvlc.util.AndroidUtil
import org.videolan.medialibrary.Medialibrary
import org.videolan.medialibrary.media.Folder
import org.videolan.medialibrary.media.MediaWrapper
import org.videolan.vlc.media.getAll
import org.videolan.vlc.util.AndroidDevices
import org.videolan.vlc.util.Settings
import org.videolan.vlc.util.launchChannelUpdate
@ExperimentalCoroutinesApi
class PagedVideosModel(
context: Context,
val folder : Folder?,
customSort : Int,
customDesc: Boolean?
) : MLPagedModel<MediaWrapper>(context), Medialibrary.MediaCb {
override fun onMediaAdded() {
refresh()
}
override fun onMediaModified() {
refresh()
}
override fun onMediaDeleted() {
refresh()
}
override fun canSortByFileNameName() = true
override fun canSortByDuration() = true
override fun canSortByLastModified() = folder == null
init {
sort = if (customSort != Medialibrary.SORT_DEFAULT) customSort
else Settings.getInstance(context).getInt(sortKey, Medialibrary.SORT_ALPHA)
desc = customDesc ?: Settings.getInstance(context).getBoolean(sortKey + "_desc", false)
if (medialibrary.isStarted) {
medialibrary.addMediaCb(this)
}
}
//TODO Search in folder
override fun getTotalCount() = if (filterQuery == null) when {
folder !== null -> folder.mediaCount(Folder.TYPE_FOLDER_VIDEO)
else -> medialibrary.videoCount
} else when {
folder !== null -> folder.searchTracksCount(filterQuery, Folder.TYPE_FOLDER_VIDEO)
else -> medialibrary.getVideoCount(filterQuery)
}
override fun getPage(loadSize: Int, startposition: Int): Array<MediaWrapper> = if (filterQuery == null) when {
folder !== null -> folder.media(Folder.TYPE_FOLDER_VIDEO, sort, desc, loadSize, startposition)
else -> medialibrary.getPagedVideos(sort, desc, loadSize, startposition)
} else when {
folder !== null -> folder.searchTracks(filterQuery, Folder.TYPE_FOLDER_VIDEO, sort, desc, loadSize, startposition)
else -> medialibrary.searchVideo(filterQuery, sort, desc, loadSize, startposition)
}
override fun getAll(): Array<MediaWrapper> = when {
folder !== null -> folder.getAll(Folder.TYPE_FOLDER_VIDEO, sort, desc).toTypedArray()
else -> medialibrary.videos
}
@TargetApi(Build.VERSION_CODES.O)
override fun onMedialibraryIdle() {
super.onMedialibraryIdle()
if (AndroidDevices.isAndroidTv && AndroidUtil.isOOrLater) context.launchChannelUpdate()
}
class Factory(
private val context: Context,
private val folder : Folder?,
private val sort : Int,
private val desc : Boolean?
): ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return PagedVideosModel(context.applicationContext, folder, sort, desc) as T
}
}
companion object {
@JvmOverloads
fun get(
context: Context,
fragment: Fragment,
folder: Folder? = null,
sort : Int = Medialibrary.SORT_DEFAULT,
desc : Boolean? = null
) : PagedVideosModel {
return ViewModelProviders.of(fragment, Factory(context, folder, sort, desc)).get(PagedVideosModel::class.java)
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment