Skip to content

Commit d08d7cf

Browse files
authored
Merge pull request TeamNewPipe#9310 from mahendranv/fr_larger_thumbs
FR: Full width thumbnails aka card view mode
2 parents c47d1af + 7924bb5 commit d08d7cf

24 files changed

Lines changed: 601 additions & 69 deletions

app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.schabi.newpipe.fragments.BaseStateFragment;
2727
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
2828
import org.schabi.newpipe.info_list.InfoListAdapter;
29+
import org.schabi.newpipe.info_list.ItemViewMode;
2930
import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
3031
import org.schabi.newpipe.util.NavigationHelper;
3132
import org.schabi.newpipe.util.OnClickGesture;
@@ -91,11 +92,7 @@ public void onResume() {
9192

9293
if (updateFlags != 0) {
9394
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
94-
final boolean useGrid = isGridLayout();
95-
itemsList.setLayoutManager(useGrid
96-
? getGridLayoutManager() : getListLayoutManager());
97-
infoListAdapter.setUseGridVariant(useGrid);
98-
infoListAdapter.notifyDataSetChanged();
95+
refreshItemViewMode();
9996
}
10097
updateFlags = 0;
10198
}
@@ -221,15 +218,23 @@ protected RecyclerView.LayoutManager getGridLayoutManager() {
221218
return lm;
222219
}
223220

221+
/**
222+
* Updates the item view mode based on user preference.
223+
*/
224+
private void refreshItemViewMode() {
225+
final ItemViewMode itemViewMode = getItemViewMode();
226+
itemsList.setLayoutManager((itemViewMode == ItemViewMode.GRID)
227+
? getGridLayoutManager() : getListLayoutManager());
228+
infoListAdapter.setItemViewMode(itemViewMode);
229+
infoListAdapter.notifyDataSetChanged();
230+
}
231+
224232
@Override
225233
protected void initViews(final View rootView, final Bundle savedInstanceState) {
226234
super.initViews(rootView, savedInstanceState);
227235

228-
final boolean useGrid = isGridLayout();
229236
itemsList = rootView.findViewById(R.id.items_list);
230-
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
231-
232-
infoListAdapter.setUseGridVariant(useGrid);
237+
refreshItemViewMode();
233238

234239
final Supplier<View> listHeaderSupplier = getListHeaderSupplier();
235240
if (listHeaderSupplier != null) {
@@ -474,7 +479,11 @@ public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
474479
}
475480
}
476481

477-
protected boolean isGridLayout() {
478-
return ThemeHelper.shouldUseGridLayout(activity);
482+
/**
483+
* Returns preferred item view mode.
484+
* @return ItemViewMode
485+
*/
486+
protected ItemViewMode getItemViewMode() {
487+
return ThemeHelper.getItemViewMode(requireContext());
479488
}
480489
}

app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.schabi.newpipe.extractor.comments.CommentsInfo;
1818
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
1919
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
20+
import org.schabi.newpipe.info_list.ItemViewMode;
2021
import org.schabi.newpipe.ktx.ViewUtils;
2122
import org.schabi.newpipe.util.ExtractorHelper;
2223

@@ -106,7 +107,7 @@ public void onCreateOptionsMenu(@NonNull final Menu menu,
106107
@NonNull final MenuInflater inflater) { }
107108

108109
@Override
109-
protected boolean isGridLayout() {
110-
return false;
110+
protected ItemViewMode getItemViewMode() {
111+
return ItemViewMode.LIST;
111112
}
112113
}

app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ protected Supplier<View> getListHeaderSupplier() {
132132
protected void initViews(final View rootView, final Bundle savedInstanceState) {
133133
super.initViews(rootView, savedInstanceState);
134134

135+
// Is mini variant still relevant?
136+
// Only the remote playlist screen uses it now
135137
infoListAdapter.setUseMiniVariant(true);
136138
}
137139

app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedItemsFragment.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.schabi.newpipe.extractor.ListExtractor;
2020
import org.schabi.newpipe.extractor.stream.StreamInfo;
2121
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
22+
import org.schabi.newpipe.info_list.ItemViewMode;
2223
import org.schabi.newpipe.ktx.ViewUtils;
2324
import org.schabi.newpipe.util.RelatedItemInfo;
2425

@@ -167,7 +168,12 @@ public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
167168
}
168169

169170
@Override
170-
protected boolean isGridLayout() {
171-
return false;
171+
protected ItemViewMode getItemViewMode() {
172+
ItemViewMode mode = super.getItemViewMode();
173+
// Only list mode is supported. Either List or card will be used.
174+
if (mode != ItemViewMode.LIST && mode != ItemViewMode.CARD) {
175+
mode = ItemViewMode.LIST;
176+
}
177+
return mode;
172178
}
173179
}

app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
2424
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
2525
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
26+
import org.schabi.newpipe.info_list.holder.PlaylistCardInfoItemHolder;
2627
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
2728
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
2829
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
30+
import org.schabi.newpipe.info_list.holder.StreamCardInfoItemHolder;
2931
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
3032
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
3133
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
@@ -67,12 +69,14 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
6769
private static final int MINI_STREAM_HOLDER_TYPE = 0x100;
6870
private static final int STREAM_HOLDER_TYPE = 0x101;
6971
private static final int GRID_STREAM_HOLDER_TYPE = 0x102;
72+
private static final int CARD_STREAM_HOLDER_TYPE = 0x103;
7073
private static final int MINI_CHANNEL_HOLDER_TYPE = 0x200;
7174
private static final int CHANNEL_HOLDER_TYPE = 0x201;
7275
private static final int GRID_CHANNEL_HOLDER_TYPE = 0x202;
7376
private static final int MINI_PLAYLIST_HOLDER_TYPE = 0x300;
7477
private static final int PLAYLIST_HOLDER_TYPE = 0x301;
7578
private static final int GRID_PLAYLIST_HOLDER_TYPE = 0x302;
79+
private static final int CARD_PLAYLIST_HOLDER_TYPE = 0x303;
7680
private static final int MINI_COMMENT_HOLDER_TYPE = 0x400;
7781
private static final int COMMENT_HOLDER_TYPE = 0x401;
7882

@@ -82,9 +86,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
8286
private final HistoryRecordManager recordManager;
8387

8488
private boolean useMiniVariant = false;
85-
private boolean useGridVariant = false;
8689
private boolean showFooter = false;
8790

91+
private ItemViewMode itemMode = ItemViewMode.LIST;
92+
8893
private Supplier<View> headerSupplier = null;
8994

9095
public InfoListAdapter(final Context context) {
@@ -114,8 +119,8 @@ public void setUseMiniVariant(final boolean useMiniVariant) {
114119
this.useMiniVariant = useMiniVariant;
115120
}
116121

117-
public void setUseGridVariant(final boolean useGridVariant) {
118-
this.useGridVariant = useGridVariant;
122+
public void setItemViewMode(final ItemViewMode itemViewMode) {
123+
this.itemMode = itemViewMode;
119124
}
120125

121126
public void addInfoItemList(@Nullable final List<? extends InfoItem> data) {
@@ -234,14 +239,33 @@ public int getItemViewType(int position) {
234239
final InfoItem item = infoItemList.get(position);
235240
switch (item.getInfoType()) {
236241
case STREAM:
237-
return useGridVariant ? GRID_STREAM_HOLDER_TYPE : useMiniVariant
238-
? MINI_STREAM_HOLDER_TYPE : STREAM_HOLDER_TYPE;
242+
if (itemMode == ItemViewMode.CARD) {
243+
return CARD_STREAM_HOLDER_TYPE;
244+
} else if (itemMode == ItemViewMode.GRID) {
245+
return GRID_STREAM_HOLDER_TYPE;
246+
} else if (useMiniVariant) {
247+
return MINI_STREAM_HOLDER_TYPE;
248+
} else {
249+
return STREAM_HOLDER_TYPE;
250+
}
239251
case CHANNEL:
240-
return useGridVariant ? GRID_CHANNEL_HOLDER_TYPE : useMiniVariant
241-
? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
252+
if (itemMode == ItemViewMode.GRID) {
253+
return GRID_CHANNEL_HOLDER_TYPE;
254+
} else if (useMiniVariant) {
255+
return MINI_CHANNEL_HOLDER_TYPE;
256+
} else {
257+
return CHANNEL_HOLDER_TYPE;
258+
}
242259
case PLAYLIST:
243-
return useGridVariant ? GRID_PLAYLIST_HOLDER_TYPE : useMiniVariant
244-
? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
260+
if (itemMode == ItemViewMode.CARD) {
261+
return CARD_PLAYLIST_HOLDER_TYPE;
262+
} else if (itemMode == ItemViewMode.GRID) {
263+
return GRID_PLAYLIST_HOLDER_TYPE;
264+
} else if (useMiniVariant) {
265+
return MINI_PLAYLIST_HOLDER_TYPE;
266+
} else {
267+
return PLAYLIST_HOLDER_TYPE;
268+
}
245269
case COMMENT:
246270
return useMiniVariant ? MINI_COMMENT_HOLDER_TYPE : COMMENT_HOLDER_TYPE;
247271
default:
@@ -274,6 +298,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup paren
274298
return new StreamInfoItemHolder(infoItemBuilder, parent);
275299
case GRID_STREAM_HOLDER_TYPE:
276300
return new StreamGridInfoItemHolder(infoItemBuilder, parent);
301+
case CARD_STREAM_HOLDER_TYPE:
302+
return new StreamCardInfoItemHolder(infoItemBuilder, parent);
277303
case MINI_CHANNEL_HOLDER_TYPE:
278304
return new ChannelMiniInfoItemHolder(infoItemBuilder, parent);
279305
case CHANNEL_HOLDER_TYPE:
@@ -286,6 +312,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup paren
286312
return new PlaylistInfoItemHolder(infoItemBuilder, parent);
287313
case GRID_PLAYLIST_HOLDER_TYPE:
288314
return new PlaylistGridInfoItemHolder(infoItemBuilder, parent);
315+
case CARD_PLAYLIST_HOLDER_TYPE:
316+
return new PlaylistCardInfoItemHolder(infoItemBuilder, parent);
289317
case MINI_COMMENT_HOLDER_TYPE:
290318
return new CommentsMiniInfoItemHolder(infoItemBuilder, parent);
291319
case COMMENT_HOLDER_TYPE:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.schabi.newpipe.info_list;
2+
3+
/**
4+
* Item view mode for streams & playlist listing screens.
5+
*/
6+
public enum ItemViewMode {
7+
/**
8+
* Default mode.
9+
*/
10+
AUTO,
11+
/**
12+
* Full width list item with thumb on the left and two line title & uploader in right.
13+
*/
14+
LIST,
15+
/**
16+
* Grid mode places two cards per row.
17+
*/
18+
GRID,
19+
/**
20+
* A full width card in phone - portrait.
21+
*/
22+
CARD
23+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.schabi.newpipe.info_list.holder;
2+
3+
import android.view.ViewGroup;
4+
5+
import org.schabi.newpipe.R;
6+
import org.schabi.newpipe.info_list.InfoItemBuilder;
7+
8+
/**
9+
* Playlist card layout.
10+
*/
11+
public class PlaylistCardInfoItemHolder extends PlaylistMiniInfoItemHolder {
12+
13+
public PlaylistCardInfoItemHolder(final InfoItemBuilder infoItemBuilder,
14+
final ViewGroup parent) {
15+
super(infoItemBuilder, R.layout.list_playlist_card_item, parent);
16+
}
17+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.schabi.newpipe.info_list.holder;
2+
3+
import android.view.ViewGroup;
4+
5+
import org.schabi.newpipe.R;
6+
import org.schabi.newpipe.info_list.InfoItemBuilder;
7+
8+
/**
9+
* Card layout for stream.
10+
*/
11+
public class StreamCardInfoItemHolder extends StreamInfoItemHolder {
12+
13+
public StreamCardInfoItemHolder(final InfoItemBuilder infoItemBuilder, final ViewGroup parent) {
14+
super(infoItemBuilder, R.layout.list_stream_card_item, parent);
15+
}
16+
}

app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
import org.schabi.newpipe.databinding.PignateFooterBinding;
2323
import org.schabi.newpipe.fragments.BaseStateFragment;
2424
import org.schabi.newpipe.fragments.list.ListViewContract;
25+
import org.schabi.newpipe.info_list.ItemViewMode;
2526

2627
import static org.schabi.newpipe.ktx.ViewUtils.animate;
2728
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
28-
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
29+
import static org.schabi.newpipe.util.ThemeHelper.getItemViewMode;
2930

3031
/**
3132
* This fragment is design to be used with persistent data such as
@@ -77,16 +78,23 @@ public void onResume() {
7778
super.onResume();
7879
if (updateFlags != 0) {
7980
if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
80-
final boolean useGrid = shouldUseGridLayout(requireContext());
81-
itemsList.setLayoutManager(
82-
useGrid ? getGridLayoutManager() : getListLayoutManager());
83-
itemListAdapter.setUseGridVariant(useGrid);
84-
itemListAdapter.notifyDataSetChanged();
81+
refreshItemViewMode();
8582
}
8683
updateFlags = 0;
8784
}
8885
}
8986

87+
/**
88+
* Updates the item view mode based on user preference.
89+
*/
90+
private void refreshItemViewMode() {
91+
final ItemViewMode itemViewMode = getItemViewMode(requireContext());
92+
itemsList.setLayoutManager((itemViewMode == ItemViewMode.GRID)
93+
? getGridLayoutManager() : getListLayoutManager());
94+
itemListAdapter.setItemViewMode(itemViewMode);
95+
itemListAdapter.notifyDataSetChanged();
96+
}
97+
9098
/*//////////////////////////////////////////////////////////////////////////
9199
// Lifecycle - View
92100
//////////////////////////////////////////////////////////////////////////*/
@@ -120,11 +128,9 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {
120128

121129
itemListAdapter = new LocalItemListAdapter(activity);
122130

123-
final boolean useGrid = shouldUseGridLayout(requireContext());
124131
itemsList = rootView.findViewById(R.id.items_list);
125-
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
132+
refreshItemViewMode();
126133

127-
itemListAdapter.setUseGridVariant(useGrid);
128134
headerRootBinding = getListHeader();
129135
if (headerRootBinding != null) {
130136
itemListAdapter.setHeader(headerRootBinding.getRoot());

0 commit comments

Comments
 (0)