diff --git a/src/main/assets/changelog-alpha.txt b/src/main/assets/changelog-alpha.txt index 2195bcda5..820d7f6f1 100644 --- a/src/main/assets/changelog-alpha.txt +++ b/src/main/assets/changelog-alpha.txt @@ -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 diff --git a/src/main/assets/changelog.txt b/src/main/assets/changelog.txt index 7067746f0..bf220c0e6 100644 --- a/src/main/assets/changelog.txt +++ b/src/main/assets/changelog.txt @@ -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 diff --git a/src/main/java/org/quantumbadger/redreader/fragments/CommentListingFragment.java b/src/main/java/org/quantumbadger/redreader/fragments/CommentListingFragment.java index f54b1d741..970097481 100644 --- a/src/main/java/org/quantumbadger/redreader/fragments/CommentListingFragment.java +++ b/src/main/java/org/quantumbadger/redreader/fragments/CommentListingFragment.java @@ -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; @@ -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; @@ -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; @@ -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, @@ -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); + }); } }