Skip to content
Merged
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 src/main/assets/changelog-alpha.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/Alpha 370 (2026-09-13)
Accessibility announcements for collapsing/expanding comments, and voting (thanks to codeofdusk)
Fix accessibility focus when moving between parent comments (thanks to codeofdusk)
Fixes for inline image preview size in landscape mode
Improved memory usage for inline image previews
Fix for notification prompt being shown twice when logging in
Expand Down
1 change: 1 addition & 0 deletions src/main/assets/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
119/1.27
Accessibility announcements for collapsing/expanding comments, and voting (thanks to codeofdusk)
Fix accessibility focus when moving between parent comments (thanks to codeofdusk)
Fixes for inline image preview size in landscape mode
Improved memory usage for inline image previews
Fix for notification prompt being shown twice when logging in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
Expand All @@ -39,6 +38,7 @@

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.OneShotPreDrawListener;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

Expand All @@ -53,7 +53,6 @@
import org.quantumbadger.redreader.cache.downloadstrategy.DownloadStrategyAlways;
import org.quantumbadger.redreader.cache.downloadstrategy.DownloadStrategyIfNotCached;
import org.quantumbadger.redreader.cache.downloadstrategy.DownloadStrategyIfTimestampOutsideBounds;
import org.quantumbadger.redreader.common.AndroidCommon;
import org.quantumbadger.redreader.common.General;
import org.quantumbadger.redreader.common.PrefsUtility;
import org.quantumbadger.redreader.common.RRError;
Expand Down Expand Up @@ -116,6 +115,7 @@ public class CommentListingFragment extends RRFragment
private TimestampUTC mCachedTimestamp = null;

private Integer mPreviousFirstVisibleItemPosition;
private int mParentJumpCount = 0;

public CommentListingFragment(
final AppCompatActivity parent,
Expand Down Expand Up @@ -720,68 +720,93 @@ public void onPostCommentsSelected(final RedditPreparedPost post) {
}

public void onPreviousParent() {
final LinearLayoutManager layoutManager = (LinearLayoutManager)
mRecyclerView.getLayoutManager();
jumpToPreviousParent(getFirstVisiblePosition());
}

public void onNextParent() {
jumpToNextParent(getFirstVisiblePosition());
}

private int getFirstVisiblePosition() {
final LinearLayoutManager layoutManager
= (LinearLayoutManager)mRecyclerView.getLayoutManager();

return layoutManager.findFirstVisibleItemPosition();
}

private void jumpToPreviousParent(final int startingPosition) {
for(
int pos = layoutManager.findFirstVisibleItemPosition() - 1;
int pos = startingPosition - 1;
pos > 0;
pos--
) {
final GroupedRecyclerViewAdapter.Item item = mCommentListingManager.getItemAtPosition(
pos
);
if(
item instanceof RedditCommentListItem
&& ((RedditCommentListItem)item).isComment()
&& ((RedditCommentListItem)item).getIndent() == 0
) {
layoutManager.scrollToPositionWithOffset(pos, 0);
setFocusDelayed(pos);
if(isTopLevelComment(pos)) {
jumpToPosition(pos);
return;
}
}

layoutManager.scrollToPositionWithOffset(0, 0);
setFocusDelayed(0);
jumpToPosition(0);
}

public void onNextParent() {
final LinearLayoutManager layoutManager = (LinearLayoutManager)
mRecyclerView.getLayoutManager();
private void jumpToNextParent(final int startingPosition) {
final LinearLayoutManager layoutManager
= (LinearLayoutManager)mRecyclerView.getLayoutManager();

for(
int pos = layoutManager.findFirstVisibleItemPosition() + 1;
int pos = startingPosition + 1;
pos < layoutManager.getItemCount();
pos++
) {
final GroupedRecyclerViewAdapter.Item item = mCommentListingManager.getItemAtPosition(
pos
);
if(
item instanceof RedditCommentListItem
&& ((RedditCommentListItem)item).isComment()
&& ((RedditCommentListItem)item).getIndent() == 0
) {
layoutManager.scrollToPositionWithOffset(pos, 0);
setFocusDelayed(pos);
break;
if(isTopLevelComment(pos)) {
jumpToPosition(pos);
return;
}
}
}

private boolean isTopLevelComment(final int position) {
final GroupedRecyclerViewAdapter.Item item
= mCommentListingManager.getItemAtPosition(position);

return item instanceof RedditCommentListItem
&& ((RedditCommentListItem)item).isComment()
&& ((RedditCommentListItem)item).getIndent() == 0;
}

private void jumpToPosition(final int position) {
final LinearLayoutManager layoutManager
= (LinearLayoutManager)mRecyclerView.getLayoutManager();

mParentJumpCount++;
layoutManager.scrollToPositionWithOffset(position, 0);
setAccessibilityFocusAfterLayout(position, true);
}

@SuppressLint("AccessibilityFocus")
private void setFocusDelayed(final int pos) {
AndroidCommon.UI_THREAD_HANDLER.postDelayed(() -> {
final RecyclerView.ViewHolder view
= mRecyclerView.findViewHolderForAdapterPosition(pos);
if (view != null) {
final View item = view.itemView;
item.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
item.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
item.performAccessibilityAction(
private void setAccessibilityFocusAfterLayout(
final int position,
final boolean allowRetry) {

final int jumpCount = mParentJumpCount;

OneShotPreDrawListener.add(mRecyclerView, () -> {

if(jumpCount != mParentJumpCount) {
return;
}

final RecyclerView.ViewHolder holder
= mRecyclerView.findViewHolderForAdapterPosition(position);

if(holder != null) {
holder.itemView.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
null);

} else if(allowRetry && mRecyclerView.hasPendingAdapterUpdates()) {
setAccessibilityFocusAfterLayout(position, false);
}
}, 800);
});
}
}
Loading