add infinite loading to the main library fragments

This commit is contained in:
dkanada 2020-08-10 22:46:10 +09:00
commit 8ca5a7a6aa
7 changed files with 249 additions and 58 deletions

View file

@ -9,7 +9,7 @@ import android.view.View;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.util.Util;
public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extends RecyclerView.Adapter, L extends RecyclerView.LayoutManager> extends AbsLibraryPagerRecyclerViewFragment<A, L> {
public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extends RecyclerView.Adapter, L extends RecyclerView.LayoutManager, Q> extends AbsLibraryPagerRecyclerViewFragment<A, L, Q> {
private int gridSize;
private String sortMethod;

View file

@ -4,8 +4,14 @@ import android.os.Bundle;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
@ -21,7 +27,7 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView.Adapter, L extends RecyclerView.LayoutManager> extends AbsLibraryPagerFragment implements OnOffsetChangedListener {
public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView.Adapter, L extends RecyclerView.LayoutManager, Q> extends AbsLibraryPagerFragment implements OnOffsetChangedListener {
private Unbinder unbinder;
@ -34,6 +40,10 @@ public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView
private A adapter;
private L layoutManager;
private Q query;
public int size;
public boolean loading;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -48,13 +58,16 @@ public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView
getLibraryFragment().addOnAppBarOffsetChangedListener(this);
initLayoutManager();
initAdapter();
initLayoutManager();
initRecyclerView();
}
private void initAdapter() {
adapter = createAdapter();
query = createQuery();
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
@ -62,6 +75,8 @@ public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView
checkIsEmpty();
}
});
loadItems();
}
private void initLayoutManager() {
@ -99,11 +114,8 @@ public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView
return layoutManager;
}
private void checkIsEmpty() {
if (empty != null) {
empty.setText(getEmptyMessage());
empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
protected Q getQuery() {
return query;
}
@StringRes
@ -122,9 +134,31 @@ public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView
@NonNull
protected abstract L createLayoutManager();
@NonNull
protected abstract Q createQuery();
protected abstract void loadItems();
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
container.setPadding(container.getPaddingLeft(), container.getPaddingTop(), container.getPaddingRight(), getLibraryFragment().getTotalAppBarScrollingRange() + i);
int last = 0;
if (!loading && getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
last = layoutManager.findLastVisibleItemPosition();
} else if (!loading && getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
last = layoutManager.findLastVisibleItemPosition();
}
int page = PreferenceUtil.getInstance(App.getInstance()).getMaximumListSize();
int total = getAdapter().getItemCount();
if (last > total - page / 2 && total < size) {
query = createQuery();
loading = true;
loadItems();
}
}
@Override
@ -134,4 +168,11 @@ public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView
getLibraryFragment().removeOnAppBarOffsetChangedListener(this);
unbinder.unbind();
}
private void checkIsEmpty() {
if (empty != null) {
empty.setText(getEmptyMessage());
empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
}
}

View file

@ -5,20 +5,22 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.album.AlbumAdapter;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.dkanada.gramophone.util.QueryUtil;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.querying.ItemQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class AlbumsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager> {
public class AlbumsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager, ItemQuery> {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -35,19 +37,44 @@ public class AlbumsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFra
protected AlbumAdapter createAdapter() {
int itemLayoutRes = getItemLayoutRes();
notifyLayoutResChanged(itemLayoutRes);
List<Album> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
AlbumAdapter adapter = new AlbumAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, loadUsePalette(), getLibraryFragment());
QueryUtil.getAlbums(new ItemQuery(), new MediaCallback() {
List<Album> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
return new AlbumAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, loadUsePalette(), getLibraryFragment());
}
@NonNull
@Override
public void onLoadMedia(List<?> media) {
dataSet.clear();
dataSet.addAll((Collection<Album>) media);
adapter.notifyDataSetChanged();
protected ItemQuery createQuery() {
ItemQuery query = new ItemQuery();
query.setIncludeItemTypes(new String[]{"MusicAlbum"});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setRecursive(true);
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getMaximumListSize());
query.setStartIndex(getAdapter().getItemCount());
query.setParentId(QueryUtil.currentLibrary.getId());
return query;
}
protected void loadItems() {
App.getApiClient().GetItemsAsync(getQuery(), new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
for (BaseItemDto itemDto : result.getItems()) {
getAdapter().getDataSet().add(new Album(itemDto));
}
size = result.getTotalRecordCount();
getAdapter().notifyDataSetChanged();
loading = false;
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
return adapter;
}
@Override

View file

@ -6,21 +6,24 @@ import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.artist.ArtistAdapter;
import com.dkanada.gramophone.helper.sort.SortMethod;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.dkanada.gramophone.util.QueryUtil;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.querying.ArtistsQuery;
import org.jellyfin.apiclient.model.querying.ItemFields;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ArtistsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager> {
public class ArtistsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager, ArtistsQuery> {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -37,18 +40,45 @@ public class ArtistsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFr
protected ArtistAdapter createAdapter() {
int itemLayoutRes = getItemLayoutRes();
notifyLayoutResChanged(itemLayoutRes);
List<Artist> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
ArtistAdapter adapter = new ArtistAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, loadUsePalette(), getLibraryFragment());
QueryUtil.getArtists(new ArtistsQuery(), new MediaCallback() {
List<Artist> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
return new ArtistAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, loadUsePalette(), getLibraryFragment());
}
@NonNull
@Override
public void onLoadMedia(List<?> media) {
dataSet.addAll((Collection<Artist>) media);
adapter.notifyDataSetChanged();
protected ArtistsQuery createQuery() {
ArtistsQuery query = new ArtistsQuery();
query.setFields(new ItemFields[]{ItemFields.Genres});
query.setParentId(QueryUtil.currentLibrary.getId());
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getMaximumListSize());
query.setStartIndex(getAdapter().getItemCount());
query.setUserId(App.getApiClient().getCurrentUserId());
query.setRecursive(true);
return query;
}
@Override
protected void loadItems() {
App.getApiClient().GetAlbumArtistsAsync(getQuery(), new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
for (BaseItemDto itemDto : result.getItems()) {
getAdapter().getDataSet().add(new Artist(itemDto));
}
size = result.getTotalRecordCount();
getAdapter().notifyDataSetChanged();
loading = false;
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
return adapter;
}
@Override

View file

@ -4,16 +4,22 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.GenreAdapter;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Genre;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.dkanada.gramophone.util.QueryUtil;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.querying.ItemsByNameQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.List;
public class GenresFragment extends AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager> {
public class GenresFragment extends AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager, ItemsByNameQuery> {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -29,17 +35,42 @@ public class GenresFragment extends AbsLibraryPagerRecyclerViewFragment<GenreAda
@Override
protected GenreAdapter createAdapter() {
List<Genre> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
return new GenreAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_single_row);
}
GenreAdapter adapter = new GenreAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_single_row);
QueryUtil.getGenres(new MediaCallback() {
@NonNull
@Override
public void onLoadMedia(List<?> media) {
dataSet.addAll((List<Genre>) media);
adapter.notifyDataSetChanged();
protected ItemsByNameQuery createQuery() {
ItemsByNameQuery query = new ItemsByNameQuery();
query.setParentId(QueryUtil.currentLibrary.getId());
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getMaximumListSize());
query.setUserId(App.getApiClient().getCurrentUserId());
query.setStartIndex(getAdapter().getItemCount());
query.setRecursive(true);
return query;
}
@Override
protected void loadItems() {
App.getApiClient().GetGenresAsync(getQuery(), new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
for (BaseItemDto itemDto : result.getItems()) {
getAdapter().getDataSet().add(new Genre(itemDto));
}
size = result.getTotalRecordCount();
getAdapter().notifyDataSetChanged();
loading = false;
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
return adapter;
}
@Override

View file

@ -5,16 +5,22 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.PlaylistAdapter;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Playlist;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.dkanada.gramophone.util.QueryUtil;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.querying.ItemQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.List;
public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager> {
public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager, ItemQuery> {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -30,17 +36,43 @@ public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment<Playl
@Override
protected PlaylistAdapter createAdapter() {
List<Playlist> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
return new PlaylistAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_single_row, getLibraryFragment());
}
PlaylistAdapter adapter = new PlaylistAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_single_row, getLibraryFragment());
QueryUtil.getPlaylists(new MediaCallback() {
@NonNull
@Override
public void onLoadMedia(List<?> media) {
dataSet.addAll((List<Playlist>) media);
adapter.notifyDataSetChanged();
protected ItemQuery createQuery() {
ItemQuery query = new ItemQuery();
query.setIncludeItemTypes(new String[]{"Playlist"});
query.setParentId(QueryUtil.currentLibrary.getId());
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getMaximumListSize());
query.setStartIndex(getAdapter().getItemCount());
query.setUserId(App.getApiClient().getCurrentUserId());
query.setRecursive(true);
return query;
}
@Override
protected void loadItems() {
App.getApiClient().GetItemsAsync(getQuery(), new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
for (BaseItemDto itemDto : result.getItems()) {
getAdapter().getDataSet().add(new Playlist(itemDto));
}
size = result.getTotalRecordCount();
getAdapter().notifyDataSetChanged();
loading = false;
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
return adapter;
}
@Override

View file

@ -4,21 +4,23 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import com.dkanada.gramophone.App;
import com.dkanada.gramophone.R;
import com.dkanada.gramophone.adapter.song.ShuffleButtonSongAdapter;
import com.dkanada.gramophone.adapter.song.SongAdapter;
import com.dkanada.gramophone.interfaces.MediaCallback;
import com.dkanada.gramophone.model.Song;
import com.dkanada.gramophone.util.PreferenceUtil;
import com.dkanada.gramophone.util.QueryUtil;
import org.jellyfin.apiclient.interaction.Response;
import org.jellyfin.apiclient.model.dto.BaseItemDto;
import org.jellyfin.apiclient.model.querying.ItemQuery;
import org.jellyfin.apiclient.model.querying.ItemsResult;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SongsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager> {
public class SongsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager, ItemQuery> {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -36,9 +38,10 @@ public class SongsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFrag
int itemLayoutRes = getItemLayoutRes();
notifyLayoutResChanged(itemLayoutRes);
boolean usePalette = loadUsePalette();
List<Song> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
List<Song> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
SongAdapter adapter;
if (getGridSize() <= getMaxGridSizeForList()) {
adapter = new ShuffleButtonSongAdapter(
getLibraryFragment().getMainActivity(),
@ -55,16 +58,43 @@ public class SongsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFrag
getLibraryFragment());
}
QueryUtil.getSongs(new ItemQuery(), new MediaCallback() {
return adapter;
}
@NonNull
@Override
public void onLoadMedia(List<?> media) {
dataSet.clear();
dataSet.addAll((Collection<Song>) media);
adapter.notifyDataSetChanged();
protected ItemQuery createQuery() {
ItemQuery query = new ItemQuery();
query.setIncludeItemTypes(new String[]{"Audio"});
query.setUserId(App.getApiClient().getCurrentUserId());
query.setRecursive(true);
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getMaximumListSize());
query.setStartIndex(getAdapter().getItemCount());
query.setParentId(QueryUtil.currentLibrary.getId());
return query;
}
@Override
protected void loadItems() {
App.getApiClient().GetItemsAsync(getQuery(), new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult result) {
for (BaseItemDto itemDto : result.getItems()) {
getAdapter().getDataSet().add(new Song(itemDto));
}
size = result.getTotalRecordCount();
getAdapter().notifyDataSetChanged();
loading = false;
}
@Override
public void onError(Exception exception) {
exception.printStackTrace();
}
});
return adapter;
}
@Override