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;
......
/*****************************************************************************
* VideoListActivity.java
* VideoGridFragment.java
*****************************************************************************
* Copyright © 2011-2018 VLC authors and VideoLAN
* Copyright © 2011-2019 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
......@@ -62,7 +62,7 @@ import org.videolan.vlc.media.MediaUtils;
import org.videolan.vlc.media.PlaylistManager;
import org.videolan.vlc.util.Constants;
import org.videolan.vlc.util.Settings;
import org.videolan.vlc.viewmodels.VideosModel;
import org.videolan.vlc.viewmodels.paged.PagedVideosModel;
import java.util.ArrayList;
import java.util.List;
......@@ -73,10 +73,10 @@ import androidx.annotation.Nullable;
import androidx.appcompat.view.ActionMode;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.paging.PagedList;
import androidx.recyclerview.widget.RecyclerView;
public class VideoGridFragment extends MediaBrowserFragment<VideosModel> implements SwipeRefreshLayout.OnRefreshListener, IEventsHandler, Observer<List<MediaWrapper>>, CtxActionReceiver {
public class VideoGridFragment extends MediaBrowserFragment<PagedVideosModel> implements SwipeRefreshLayout.OnRefreshListener, IEventsHandler, Observer<PagedList<MediaWrapper>>, CtxActionReceiver {
private final static String TAG = "VLC/VideoListFragment";
......@@ -95,8 +95,8 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
final boolean seenMarkVisible = preferences.getBoolean("media_seen", true);
mAdapter = new VideoListAdapter(this, seenMarkVisible);
multiSelectHelper = mAdapter.getMultiSelectHelper();
viewModel = ViewModelProviders.of(requireActivity(), new VideosModel.Factory(requireContext(), mGroup, mFolder, 0, Medialibrary.SORT_DEFAULT, null)).get(VideosModel.class);
viewModel.getDataset().observe(this, this);
viewModel = PagedVideosModel.Companion.get(requireContext(), this, mFolder);
viewModel.getPagedList().observe(this, this);
}
if (savedInstanceState != null) setGroup(savedInstanceState.getString(Constants.KEY_GROUP));
}
......@@ -120,7 +120,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mBinding = VideoGridBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}
......@@ -128,7 +128,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final boolean empty = viewModel.getDataset().getValue().isEmpty();
final boolean empty = viewModel.isEmpty();
mBinding.loadingFlipper.setVisibility(empty ? View.VISIBLE : View.GONE);
mBinding.loadingTitle.setVisibility(empty ? View.VISIBLE : View.GONE);
mBinding.setEmpty(empty);
......@@ -181,12 +181,13 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
public void onDestroy() {
super.onDestroy();
mGridItemDecoration = null;
mAdapter.release();
}
@Override
public void onChanged(@Nullable List<MediaWrapper> mediaWrappers) {
public void onChanged(@Nullable PagedList<MediaWrapper> list) {
mAdapter.showFilename(viewModel.getSort() == Medialibrary.SORT_FILENAME);
if (mediaWrappers != null) mAdapter.update(mediaWrappers);
if (list != null) mAdapter.submitList(list);
}
@Override
......@@ -221,21 +222,20 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
}
protected void playVideo(MediaWrapper media, boolean fromStart) {
private void playVideo(MediaWrapper media, boolean fromStart) {
media.removeFlags(MediaWrapper.MEDIA_FORCE_AUDIO);
if (fromStart) media.addFlags(MediaWrapper.MEDIA_FROM_START);
MediaUtils.INSTANCE.openMedia(requireContext(), media);
}
protected void playAudio(MediaWrapper media) {
private void playAudio(MediaWrapper media) {
media.addFlags(MediaWrapper.MEDIA_FORCE_AUDIO);
MediaUtils.INSTANCE.openMedia(getActivity(), media);
}
@Override
public void onFabPlayClick(View view) {
List<MediaWrapper> playList = new ArrayList<>();
MediaUtils.INSTANCE.openList(getActivity(), playList, viewModel.getListWithPosition(playList, 0));
MediaUtils.INSTANCE.playAll(requireContext(), viewModel, 0, false);
}
@MainThread
......@@ -244,7 +244,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
mHandler.sendEmptyMessageDelayed(SET_REFRESHING, 300);
}
void updateEmptyView() {
private void updateEmptyView() {
final boolean empty = viewModel.isEmpty();
final boolean working = mMediaLibrary.isWorking();
mBinding.loadingFlipper.setVisibility(empty && working ? View.VISIBLE : View.GONE);
......@@ -273,7 +273,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
@Override
public void setFabPlayVisibility(boolean enable) {
super.setFabPlayVisibility(!mAdapter.isEmpty() && enable);
super.setFabPlayVisibility(!viewModel.isEmpty() && enable);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
......@@ -297,7 +297,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
final List<MediaWrapper> list = new ArrayList();
final List<MediaWrapper> list = new ArrayList<>();
for (MediaWrapper mw : multiSelectHelper.getSelection()) {
if (mw.getType() == MediaWrapper.TYPE_GROUP) list.addAll(((MediaGroup) mw).getAll());
else list.add(mw);
......@@ -368,7 +368,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
};
@Override
public void onClick(View v, int position, MediaLibraryItem item) {
public void onClick(@NotNull View v, int position, @NotNull MediaLibraryItem item) {
final MediaWrapper media = (MediaWrapper) item;
if (mActionMode != null) {
multiSelectHelper.toggleSelection(position);
......@@ -384,8 +384,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
media.removeFlags(MediaWrapper.MEDIA_FORCE_AUDIO);
final SharedPreferences settings = Settings.INSTANCE.getInstance(v.getContext());
if (settings.getBoolean("force_play_all", false)) {
final List<MediaWrapper> playList = new ArrayList<>();
MediaUtils.INSTANCE.openList(activity, playList, viewModel.getListWithPosition(playList, position));
MediaUtils.INSTANCE.playAll(requireContext(), viewModel, position, false);
} else {
playVideo(media, false);
}
......@@ -393,7 +392,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
}
@Override
public boolean onLongClick(View v, int position, MediaLibraryItem item) {
public boolean onLongClick(@NotNull View v, int position, @NotNull MediaLibraryItem item) {
if (mActionMode != null) return false;
multiSelectHelper.toggleSelection(position);
startActionMode();
......@@ -404,22 +403,28 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
public void onImageClick(@NotNull View v, int position, @NotNull MediaLibraryItem item) {}
@Override
public void onCtxClick(View v, int position, MediaLibraryItem item) {
public void onCtxClick(@NotNull View v, int position, @NotNull MediaLibraryItem item) {
final MediaWrapper mw = (MediaWrapper) item;
final boolean group = mw.getType() == MediaWrapper.TYPE_GROUP;
int flags = group ? Constants.CTX_VIDEO_GOUP_FLAGS : Constants.CTX_VIDEO_FLAGS;
if (mw.getTime() != 0l && !group) flags |= Constants.CTX_PLAY_FROM_START;
if (mw.getTime() != 0L && !group) flags |= Constants.CTX_PLAY_FROM_START;
if (mActionMode == null)
ContextSheetKt.showContext(requireActivity(), this, position, item.getTitle(), flags);
}
@Override
public void onUpdateFinished(RecyclerView.Adapter adapter) {
if (!mMediaLibrary.isWorking()) mHandler.sendEmptyMessage(UNSET_REFRESHING);
updateEmptyView();
setFabPlayVisibility(true);
UiTools.updateSortTitles(this);
public void onUpdateFinished(@NotNull RecyclerView.Adapter adapter) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (!isResumed()) return;
if (!mMediaLibrary.isWorking()) mHandler.sendEmptyMessage(UNSET_REFRESHING);
updateEmptyView();
setFabPlayVisibility(true);
UiTools.updateSortTitles(VideoGridFragment.this);
}
});
}
public void updateSeenMediaMarker() {
......@@ -442,8 +447,7 @@ public class VideoGridFragment extends MediaBrowserFragment<VideosModel> impleme
playAudio(media);
break;
case Constants.CTX_PLAY_ALL:
final List<MediaWrapper> playList = new ArrayList<>();
MediaUtils.INSTANCE.openList(activity, playList, viewModel.getListWithPosition(playList, position));
MediaUtils.INSTANCE.playAll(requireContext(), viewModel, position, false);
break;
case Constants.CTX_INFORMATION:
showInfoDialog(media);
......
/*****************************************************************************
* VideoListAdapter.java
*****************************************************************************
* Copyright © 2011-2012 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.gui.video;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import org.jetbrains.annotations.NotNull;
import org.videolan.libvlc.util.AndroidUtil;
import org.videolan.medialibrary.Tools;
import org.videolan.medialibrary.media.MediaWrapper;
import org.videolan.tools.MultiSelectAdapter;
import org.videolan.tools.MultiSelectHelper;
import org.videolan.vlc.BR;
import org.videolan.vlc.R;
import org.videolan.vlc.gui.DiffUtilAdapter;
import org.videolan.vlc.gui.helpers.ImageLoaderKt;
import org.videolan.vlc.gui.helpers.SelectorViewHolder;
import org.videolan.vlc.gui.helpers.UiTools;
import org.videolan.vlc.interfaces.IEventsHandler;
import org.videolan.vlc.util.Constants;
import org.videolan.vlc.util.MediaItemDiffCallback;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.databinding.BindingAdapter;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableBoolean;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.GridLayoutManager;
public class VideoListAdapter extends DiffUtilAdapter<MediaWrapper, VideoListAdapter.ViewHolder> implements MultiSelectAdapter<MediaWrapper> {
public final static String TAG = "VLC/VideoListAdapter";
private boolean mListMode = false;
private IEventsHandler mEventsHandler;
private int mGridCardWidth = 0;
private boolean mIsSeenMediaMarkerVisible;
private ObservableBoolean mShowFilename = new ObservableBoolean();
private MultiSelectHelper<MediaWrapper> multiSelectHelper;
VideoListAdapter(IEventsHandler eventsHandler, boolean seenMarkVisible) {
super();
multiSelectHelper = new MultiSelectHelper<>(this, Constants.UPDATE_SELECTION);
mEventsHandler = eventsHandler;
mIsSeenMediaMarkerVisible = seenMarkVisible;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ViewDataBinding binding = DataBindingUtil.inflate(inflater, mListMode ? R.layout.video_list_card : R.layout.video_grid_card, parent, false);
binding.setVariable(BR.showFilename, mShowFilename);
if (!mListMode) {
final GridLayoutManager.LayoutParams params = (GridLayoutManager.LayoutParams) binding.getRoot().getLayoutParams();
params.width = mGridCardWidth;
params.height = params.width*10/16;
binding.getRoot().setLayoutParams(params);
}
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final MediaWrapper media = getDataset().get(position);
if (media == null)
return;
holder.binding.setVariable(BR.scaleType, ImageView.ScaleType.CENTER_CROP);
fillView(holder, media);
holder.binding.setVariable(BR.media, media);
holder.selectView(multiSelectHelper.isSelected(position));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) onBindViewHolder(holder, position);
else {
final MediaWrapper media = getDataset().get(position);
for (Object data : payloads) {
switch ((int) data) {
case Constants.UPDATE_THUMB:
ImageLoaderKt.loadImage(holder.overlay, media);
break;
case Constants.UPDATE_TIME:
case Constants.UPDATE_SEEN:
fillView(holder, media);
break;
case Constants.UPDATE_SELECTION:
holder.selectView(multiSelectHelper.isSelected(position));
break;
}
}
}
}
@Override
public void onViewRecycled(@NotNull ViewHolder holder) {
holder.binding.setVariable(BR.cover, UiTools.getDefaultVideoDrawable(holder.itemView.getContext()));
}
@Override
@Nullable
public MediaWrapper getItem(int position) {
return isPositionValid(position) ? getDataset().get(position) : null;
}
private boolean isPositionValid(int position) {
return position >= 0 && position < getDataset().size();
}
public boolean contains(MediaWrapper mw) {
return getDataset().indexOf(mw) != -1;
}
public List<MediaWrapper> getAll() {
return getDataset();
}
public MultiSelectHelper<MediaWrapper> getMultiSelectHelper() {
return multiSelectHelper;
}
@MainThread
public void clear() {
update(new ArrayList<MediaWrapper>());
}
private void fillView(ViewHolder holder, MediaWrapper media) {
String text;
String resolution;
int max = 0;
int progress = 0;
long seen = 0L;
if (media.getType() == MediaWrapper.TYPE_GROUP) {
text = media.getDescription();
} else {
/* Time / Duration */
resolution = Tools.getResolution(media);
if (media.getLength() > 0) {
final long lastTime = media.getDisplayTime();
if (lastTime > 0) {
max = (int) (media.getLength() / 1000);
progress = (int) (lastTime / 1000);
}
if (TextUtils.isEmpty(resolution)) text = Tools.millisToText(media.getLength());
else text = Tools.millisToText(media.getLength())+" | "+resolution;
} else text = resolution;
seen = mIsSeenMediaMarkerVisible ? media.getSeen() : 0L;
}
holder.binding.setVariable(BR.time, text);
holder.binding.setVariable(BR.max, max);
holder.binding.setVariable(BR.progress, progress);
holder.binding.setVariable(BR.seen, seen);
}
public void setListMode(boolean value) {
mListMode = value;
}
void setGridCardWidth(int gridCardWidth) {
mGridCardWidth = gridCardWidth;
}
public boolean isListMode() {
return mListMode;
}
@Override
public long getItemId(int position) {
return 0L;
}
@Override
public int getItemCount() {
return getDataset().size();
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
public class ViewHolder extends SelectorViewHolder<ViewDataBinding> implements View.OnFocusChangeListener {
private ImageView overlay;
@TargetApi(Build.VERSION_CODES.M)
public ViewHolder(ViewDataBinding binding) {
super(binding);
overlay = itemView.findViewById(R.id.ml_item_overlay);
binding.setVariable(BR.holder, this);
binding.setVariable(BR.cover, UiTools.getDefaultVideoDrawable(itemView.getContext()));
if (AndroidUtil.isMarshMallowOrLater) itemView.setOnContextClickListener(new View.OnContextClickListener() {
@Override
public boolean onContextClick(View v) {
onMoreClick(v);
return true;
}
});
}
public void onClick(View v) {
final int position = getLayoutPosition();
if (isPositionValid(position))
mEventsHandler.onClick(v, position, getDataset().get(position));
}
public void onMoreClick(View v){
final int position = getLayoutPosition();
if (isPositionValid(position))
mEventsHandler.onCtxClick(v, position, getItem(position));
}
public boolean onLongClick(View v) {
final int position = getLayoutPosition();
return isPositionValid(position) && mEventsHandler.onLongClick(v, position, getDataset().get(position));
}
@Override
public void selectView(boolean selected) {
overlay.setImageResource(selected ? R.drawable.ic_action_mode_select_1610 : mListMode ? 0 : R.drawable.black_gradient);
if (mListMode) overlay.setVisibility(selected ? View.VISIBLE : View.GONE);
super.selectView(selected);
}
@Override
protected boolean isSelected() {
return multiSelectHelper.isSelected(getLayoutPosition());
}
}
@BindingAdapter({"time", "resolution"})
public static void setLayoutHeight(View view, String time, String resolution) {
final ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = TextUtils.isEmpty(time) && TextUtils.isEmpty(resolution) ?
ViewGroup.LayoutParams.MATCH_PARENT :
ViewGroup.LayoutParams.WRAP_CONTENT;
view.setLayoutParams(layoutParams);
}
@Override
protected MediaItemDiffCallback<MediaWrapper> createCB() {
return new VideoItemDiffCallback();
}
@Override
protected void onUpdateFinished() {
mEventsHandler.onUpdateFinished(null);
}
private class VideoItemDiffCallback extends MediaItemDiffCallback<MediaWrapper> {
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
final MediaWrapper oldItem = oldList.get(oldItemPosition);
final MediaWrapper newItem = newList.get(newItemPosition);
return oldItem == newItem || (oldItem.getType() == newItem.getType() && oldItem.equals(newItem));
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
final MediaWrapper oldItem = oldList.get(oldItemPosition);
final MediaWrapper newItem = newList.get(newItemPosition);
return oldItem == newItem || (oldItem.getDisplayTime() == newItem.getDisplayTime()