Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependencies {
implementation(libs.commons.text)

implementation(libs.okhttp)
implementation(libs.picasso)
implementation(libs.netcipher.webkit)
implementation(libs.media3.exoplayer)
implementation(libs.media3.ui)
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ kotlinx-serialization = "1.9.0"
media3 = "1.8.0"
netcipher = "2.1.0"
okhttp = "5.3.0"
picasso = "2.8"
pmd = "6.55.0"
zstd = "1.5.7-6"

Expand Down Expand Up @@ -70,6 +71,7 @@ media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref =
media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3" }
netcipher-webkit = { module = "info.guardianproject.netcipher:netcipher-webkit", version.ref = "netcipher" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
picasso = { module = "com.squareup.picasso:picasso", version.ref = "picasso" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
zstd = { module = "com.github.luben:zstd-jni", version.ref = "zstd" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.quantumbadger.redreader.listingcontrollers.CommentListingController;
import org.quantumbadger.redreader.listingcontrollers.PostListingController;
import org.quantumbadger.redreader.reddit.PostCommentSort;
import org.quantumbadger.redreader.reddit.PostFilter;
import org.quantumbadger.redreader.reddit.PostSort;
import org.quantumbadger.redreader.reddit.RedditSubredditHistory;
import org.quantumbadger.redreader.reddit.UserCommentSort;
Expand Down Expand Up @@ -912,6 +913,12 @@ public void onSortSelected(final PostSort order) {
requestRefresh(RefreshableFragment.POSTS, false);
}

@Override
public void onPostFilterSelected(final PostFilter filter) {
postListingController.setFilter(filter);
requestRefresh(RefreshableFragment.POSTS, false);
}

@Override
public void onSearchPosts() {
PostListingActivity.onSearchPosts(postListingController, this);
Expand Down Expand Up @@ -1124,6 +1131,15 @@ public PostSort getPostSort() {
return postListingController.getSort();
}

@Override
public PostFilter getPostFilter() {
if(postListingController == null) {
return PostFilter.ALL;
}

return postListingController.getFilter();
}

@Override
public OptionsMenuUtility.Sort getCommentSort() {
if(commentListingController == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.quantumbadger.redreader.common.UnexpectedInternalStateException;
import org.quantumbadger.redreader.fragments.AccountListDialog;
import org.quantumbadger.redreader.reddit.PostCommentSort;
import org.quantumbadger.redreader.reddit.PostFilter;
import org.quantumbadger.redreader.reddit.PostSort;
import org.quantumbadger.redreader.reddit.UserCommentSort;
import org.quantumbadger.redreader.reddit.api.SubredditSubscriptionState;
Expand Down Expand Up @@ -68,7 +69,8 @@ public enum AppbarItemsPref {
SETTINGS,
CLOSE_ALL,
REPLY,
SEARCH
SEARCH,
FILTER
}

public static final int DO_NOT_SHOW = -1;
Expand Down Expand Up @@ -128,6 +130,10 @@ public static <E extends ViewsBaseActivity & OptionsMenuListener> void prepare(
false);

} else if(!subredditsVisible && postsVisible && !commentsVisible) {
addAllPostFilters(
activity,
menu,
getOrThrow(appbarItemsPrefs, AppbarItemsPref.FILTER));
if(postsSortable) {

if(areSearchResults) {
Expand Down Expand Up @@ -258,6 +264,10 @@ public static <E extends ViewsBaseActivity & OptionsMenuListener> void prepare(
} else {

if(postsVisible && commentsVisible) {
addAllPostFilters(
activity,
menu,
getOrThrow(appbarItemsPrefs, AppbarItemsPref.FILTER));
if(getOrThrow(appbarItemsPrefs, AppbarItemsPref.SORT) != DO_NOT_SHOW) {
final SubMenu sortMenu = menu.addSubMenu(
Menu.NONE,
Expand Down Expand Up @@ -293,6 +303,10 @@ public static <E extends ViewsBaseActivity & OptionsMenuListener> void prepare(
}
}
} else if(postsVisible) {
addAllPostFilters(
activity,
menu,
getOrThrow(appbarItemsPrefs, AppbarItemsPref.FILTER));
if(postsSortable) {
if(areSearchResults) {
addAllSearchSorts(
Expand Down Expand Up @@ -1142,6 +1156,44 @@ private static void addAllPostSorts(
sortPosts.setGroupCheckable(Menu.NONE, true, true);
}

private static void addAllPostFilters(
final AppCompatActivity activity,
final Menu menu,
final int showAsAction) {

if(showAsAction == DO_NOT_SHOW) {
return;
}

final SubMenu filterPosts = menu.addSubMenu(
Menu.NONE,
AppbarItemsPref.FILTER.ordinal(),
Menu.NONE,
R.string.options_filter_posts);

if(showAsAction != MenuItem.SHOW_AS_ACTION_NEVER) {
filterPosts.getItem().setIcon(R.drawable.ic_filter_dark);
filterPosts.getItem().setShowAsAction(handleShowAsActionIfRoom(showAsAction));
}

final PostFilter activeFilter = ((OptionsMenuPostsListener)activity).getPostFilter();

for(final PostFilter filter : PostFilter.values()) {
final MenuItem menuItem = filterPosts.add(activity.getString(filter.getMenuTitle()))
.setCheckable(true)
.setOnMenuItemClickListener(item -> {
((OptionsMenuPostsListener)activity).onPostFilterSelected(filter);
return true;
});

if(filter.equals(activeFilter)) {
menuItem.setChecked(true);
}
}

filterPosts.setGroupCheckable(Menu.NONE, true, true);
}

private static void addAllSearchSorts(
final AppCompatActivity activity,
final Menu menu,
Expand Down Expand Up @@ -1422,6 +1474,8 @@ public interface OptionsMenuPostsListener extends OptionsMenuListener {

void onSortSelected(PostSort order);

void onPostFilterSelected(PostFilter filter);

void onSearchPosts();

void onSubscribe();
Expand All @@ -1439,6 +1493,8 @@ public interface OptionsMenuPostsListener extends OptionsMenuListener {
void onUnblock();

PostSort getPostSort();

PostFilter getPostFilter();
}

public interface OptionsMenuCommentsListener extends OptionsMenuListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.quantumbadger.redreader.fragments.PostListingFragment;
import org.quantumbadger.redreader.fragments.SessionListDialog;
import org.quantumbadger.redreader.listingcontrollers.PostListingController;
import org.quantumbadger.redreader.reddit.PostFilter;
import org.quantumbadger.redreader.reddit.PostSort;
import org.quantumbadger.redreader.reddit.api.RedditSubredditSubscriptionManager;
import org.quantumbadger.redreader.reddit.api.SubredditSubscriptionState;
Expand All @@ -65,6 +66,7 @@ public class PostListingActivity extends RefreshableActivity

private static final String SAVEDSTATE_SESSION = "pla_session";
private static final String SAVEDSTATE_SORT = "pla_sort";
private static final String SAVEDSTATE_FILTER = "pla_filter";
private static final String SAVEDSTATE_FRAGMENT = "pla_fragment";

private PostListingFragment fragment;
Expand Down Expand Up @@ -125,6 +127,11 @@ public void onCreate(final Bundle savedInstanceState) {
savedInstanceState.getString(SAVEDSTATE_SORT)));
}

if(savedInstanceState.containsKey(SAVEDSTATE_FILTER)) {
controller.setFilter(PostFilter.valueOf(
savedInstanceState.getString(SAVEDSTATE_FILTER)));
}

if(savedInstanceState.containsKey(SAVEDSTATE_FRAGMENT)) {
fragmentSavedInstanceState = savedInstanceState.getBundle(
SAVEDSTATE_FRAGMENT);
Expand Down Expand Up @@ -157,6 +164,8 @@ protected void onSaveInstanceState(@NonNull final Bundle outState) {
outState.putString(SAVEDSTATE_SORT, sort.name());
}

outState.putString(SAVEDSTATE_FILTER, controller.getFilter().name());

if(fragment != null) {
outState.putBundle(SAVEDSTATE_FRAGMENT, fragment.onSaveInstanceState());
}
Expand Down Expand Up @@ -327,6 +336,13 @@ public void onSortSelected(final PostSort order) {
invalidateOptionsMenu();
}

@Override
public void onPostFilterSelected(final PostFilter filter) {
controller.setFilter(filter);
requestRefresh(RefreshableFragment.POSTS, false);
invalidateOptionsMenu();
}

@Override
public void onSearchPosts() {
onSearchPosts(controller, this);
Expand Down Expand Up @@ -577,4 +593,9 @@ protected boolean baseActivityAllowToolbarHideOnScroll() {
public PostSort getPostSort() {
return controller.getSort();
}

@Override
public PostFilter getPostFilter() {
return controller.getFilter();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@

package org.quantumbadger.redreader.adapters;

import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -31,6 +33,12 @@ public class GroupedRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVie

private static final AtomicLong ITEM_UNIQUE_ID_GENERATOR = new AtomicLong(100_000);

// Used by staggered (masonry) grid layouts to decide which items should span
// the full width instead of occupying a single column.
public interface FullSpanChecker {
boolean isFullSpan(final int position);
}

public static abstract class Item<VH extends RecyclerView.ViewHolder> {

private final long mUniqueId = ITEM_UNIQUE_ID_GENERATOR.incrementAndGet();
Expand All @@ -54,6 +62,7 @@ private void onBindViewHolderInner(
private final ArrayList<Item<?>>[] mItems;
private final HashMap<Class<?>, Integer> mItemViewTypeMap = new HashMap<>();
private final HashMap<Integer, Item<?>> mViewTypeItemMap = new HashMap<>();
private FullSpanChecker mFullSpanChecker;

public GroupedRecyclerViewAdapter(final int groups) {
//noinspection unchecked
Expand All @@ -66,6 +75,10 @@ public GroupedRecyclerViewAdapter(final int groups) {
setHasStableIds(true);
}

public void setFullSpanChecker(final FullSpanChecker fullSpanChecker) {
mFullSpanChecker = fullSpanChecker;
}

private int getItemPositionInternal(final int groupId, final Item<?> item) {

final ArrayList<Item<?>> group = mItems[groupId];
Expand Down Expand Up @@ -168,6 +181,43 @@ public void onBindViewHolder(
@NonNull final RecyclerView.ViewHolder viewHolder,
final int position) {
getItemInternal(position).onBindViewHolderInner(viewHolder);

if(mFullSpanChecker != null) {
applyFullSpan(viewHolder.itemView, position);
}
}

@Override
public void onViewAttachedToWindow(
@NonNull final RecyclerView.ViewHolder viewHolder) {
super.onViewAttachedToWindow(viewHolder);

if(mFullSpanChecker == null) {
return;
}

final int position = viewHolder.getLayoutPosition();

if(position != RecyclerView.NO_POSITION) {
applyFullSpan(viewHolder.itemView, position);
}
}

// In staggered (masonry) grid layouts items are confined to a single column;
// chrome items (headers, loading spinners, load-more buttons, errors) must
// span the full width so the masonry flow isn't broken. In list mode (or any
// other layout manager) this is a no-op, because the layout params never are
// StaggeredGridLayoutManager.LayoutParams.
private void applyFullSpan(
@NonNull final View itemView,
final int position) {

final ViewGroup.LayoutParams layoutParams = itemView.getLayoutParams();

if(layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
((StaggeredGridLayoutManager.LayoutParams)layoutParams)
.setFullSpan(mFullSpanChecker.isFullSpan(position));
}
}

@Override
Expand Down Expand Up @@ -223,6 +273,34 @@ public Item<?> getItemAtPosition(final int position) {
return getItemInternal(position);
}

public int getGroupIdAtPosition(final int position) {

int currentPosition = 0;

for(int groupId = 0; groupId < mItems.length; groupId++) {

for(int positionInGroup = 0;
positionInGroup < mItems[groupId].size();
positionInGroup++) {

final Item<?> item = mItems[groupId].get(positionInGroup);

if(!item.mCurrentlyHidden) {

if(currentPosition == position) {
return groupId;
}

currentPosition++;
}
}
}

throw new RuntimeException("Item position "
+ position
+ " is too high");
}

public void appendToGroup(final int group, final Item<?> item) {

final int position = getItemPositionInternal(group + 1, 0);
Expand Down
Loading
Loading