@@ -4083,25 +4083,22 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
40834083 const auto elements = accessibleElements ();
40844084 const auto barIndex
40854085 = accessibilityUnreadBarIndex ();
4086- const auto elementIndex = (barIndex >= 0
4087- && _accessibilityFocusedIndex > barIndex)
4088- ? (_accessibilityFocusedIndex - 1 )
4089- : _accessibilityFocusedIndex;
4090- if (elementIndex < 0
4091- || elementIndex >= int (elements.size ())
4092- || elements[elementIndex]->data ().get ()
4093- != _accessibilityFocusedItem) {
4086+ if (accessibilityItemAtIndex (
4087+ _accessibilityFocusedIndex,
4088+ elements,
4089+ barIndex) != _accessibilityFocusedItem) {
40944090 // The focused item is still the same message, but
40954091 // its index in accessibleElements() shifted (the list
4096- // was mutated since the last navigation). Repair the
4097- // cached index in-place without emitting a focus
4098- // change — the framework still thinks the focused
4099- // child is _accessibilityFocusedItem and we are only
4100- // catching up our bookkeeping. If the item is not in
4101- // the loaded slice anymore the index is invalidated
4102- // instead: selection and media actions dispatch by
4103- // index, and a stale one would silently operate on
4104- // whatever unrelated row occupies it now.
4092+ // was mutated since the last navigation, possibly by
4093+ // an unread bar appearing right at the cached index).
4094+ // Repair the cached index in-place without emitting a
4095+ // focus change — the framework still thinks the
4096+ // focused child is _accessibilityFocusedItem and we
4097+ // are only catching up our bookkeeping. If the item
4098+ // is not in the loaded slice anymore the index is
4099+ // invalidated instead: selection and media actions
4100+ // dispatch by index, and a stale one would silently
4101+ // operate on whatever unrelated row occupies it now.
41054102 _accessibilityFocusedIndex = -1 ;
41064103 for (auto i = 0 , n = int (elements.size ());
41074104 i < n; ++i) {
@@ -4115,6 +4112,13 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
41154112 }
41164113 }
41174114 }
4115+ } else if (_accessibilityFocusedIndex >= 0 ) {
4116+ // A nonnegative index with no cached item means the unread
4117+ // bar was focused. Follow the bar to wherever it sits now
4118+ // (rows inserted or removed above shift its index), or
4119+ // invalidate the focus when the bar is gone: the row that
4120+ // occupies the old index was never announced to the user.
4121+ _accessibilityFocusedIndex = accessibilityUnreadBarIndex ();
41184122 }
41194123 const auto modifiers = e->modifiers ()
41204124 & ~(Qt::KeypadModifier | Qt::GroupSwitchModifier);
@@ -4184,14 +4188,10 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
41844188 const auto elements = accessibleElements ();
41854189 const auto barIndex
41864190 = accessibilityUnreadBarIndex ();
4187- const auto elementIndex = (barIndex >= 0
4188- && newIndex > barIndex)
4189- ? (newIndex - 1 )
4190- : newIndex;
4191- const auto item = (elementIndex >= 0
4192- && elementIndex < int (elements.size ()))
4193- ? elements[elementIndex]->data ().get ()
4194- : nullptr ;
4191+ const auto item = accessibilityItemAtIndex (
4192+ newIndex,
4193+ elements,
4194+ barIndex);
41954195 if (shiftRange) {
41964196 extendAccessibilitySelection (
41974197 _accessibilityFocusedIndex,
@@ -4213,12 +4213,8 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
42134213 }
42144214 }
42154215
4216- if (_widget->markingMessagesRead ()
4217- && (barIndex < 0 || newIndex != barIndex)
4218- && elementIndex >= 0
4219- && elementIndex < int (elements.size ())) {
4220- session ().data ().histories ().readInboxTill (
4221- elements[elementIndex]->data ());
4216+ if (_widget->markingMessagesRead () && item) {
4217+ session ().data ().histories ().readInboxTill (item);
42224218 }
42234219
42244220 e->accept ();
@@ -5968,17 +5964,8 @@ void HistoryInner::extendAccessibilitySelection(
59685964 // towards it deselects the row being left.
59695965 const auto elements = accessibleElements ();
59705966 const auto barIndex = accessibilityUnreadBarIndex ();
5971- const auto itemAt = [&](int index) -> HistoryItem* {
5972- if (barIndex >= 0 && index == barIndex) {
5973- return nullptr ;
5974- }
5975- const auto elementIndex = (barIndex >= 0 && index > barIndex)
5976- ? (index - 1 )
5977- : index;
5978- return (elementIndex >= 0
5979- && elementIndex < int (elements.size ()))
5980- ? elements[elementIndex]->data ().get ()
5981- : nullptr ;
5967+ const auto itemAt = [&](int index) {
5968+ return accessibilityItemAtIndex (index, elements, barIndex);
59825969 };
59835970 if (oldIndex < 0 ) {
59845971 _accessibilitySelectionAnchor = itemAt (newIndex);
@@ -6024,22 +6011,14 @@ void HistoryInner::extendAccessibilitySelection(
60246011}
60256012
60266013void HistoryInner::playPauseFocusedMedia () {
6027- if (_accessibilityFocusedIndex < 0 ) {
6028- return ;
6029- }
6030- const auto barIndex = accessibilityUnreadBarIndex ();
6031- if (barIndex >= 0 && _accessibilityFocusedIndex == barIndex) {
6032- return ;
6033- }
60346014 const auto elements = accessibleElements ();
6035- const auto elementIndex = (barIndex >= 0
6036- && _accessibilityFocusedIndex > barIndex)
6037- ? (_accessibilityFocusedIndex - 1 )
6038- : _accessibilityFocusedIndex ;
6039- if (elementIndex < 0 || elementIndex >= int (elements. size ()) ) {
6015+ const auto item = accessibilityItemAtIndex (
6016+ _accessibilityFocusedIndex,
6017+ elements,
6018+ accessibilityUnreadBarIndex ()) ;
6019+ if (!item ) {
60406020 return ;
60416021 }
6042- const auto item = elements[elementIndex]->data ();
60436022 if (const auto media = item->media ()) {
60446023 if (const auto document = media->document ()) {
60456024 if (document->isVoiceMessage ()
@@ -6401,6 +6380,24 @@ int HistoryInner::accessibilityUnreadBarIndex() const {
64016380 return -1 ;
64026381}
64036382
6383+ HistoryItem *HistoryInner::accessibilityItemAtIndex (
6384+ int index,
6385+ const std::vector<Element*> &elements,
6386+ int barIndex) const {
6387+ // The unread bar row maps to no item: a focused bar is cached as
6388+ // a null item with a nonnegative index, so it can never be
6389+ // mistaken for the message it is anchored to when rows shift.
6390+ if (index < 0 || (barIndex >= 0 && index == barIndex)) {
6391+ return nullptr ;
6392+ }
6393+ const auto elementIndex = (barIndex >= 0 && index > barIndex)
6394+ ? (index - 1 )
6395+ : index;
6396+ return (elementIndex < int (elements.size ()))
6397+ ? elements[elementIndex]->data ().get ()
6398+ : nullptr ;
6399+ }
6400+
64046401int HistoryInner::accessibilityChildCount () const {
64056402 const auto barIndex = accessibilityUnreadBarIndex ();
64066403 return int (accessibleElements ().size ()) + (barIndex >= 0 ? 1 : 0 );
@@ -6612,6 +6609,13 @@ void HistoryInner::focusInEvent(QFocusEvent *e) {
66126609 // branch below establishes a fresh focus instead.
66136610 _accessibilityFocusedItem = nullptr ;
66146611 _accessibilityFocusedIndex = -1 ;
6612+ } else if (_accessibilityFocusedIndex >= 0 ) {
6613+ // A nonnegative index with no cached item means the unread
6614+ // bar was focused. Follow the bar to wherever it sits now,
6615+ // or fall through to pick a fresh focus target when it is
6616+ // gone: the row that occupies the old index was never
6617+ // announced to the user.
6618+ _accessibilityFocusedIndex = accessibilityUnreadBarIndex ();
66156619 }
66166620 if (_accessibilityFocusedIndex >= 0
66176621 && _accessibilityFocusedIndex < count) {
@@ -6623,14 +6627,10 @@ void HistoryInner::focusInEvent(QFocusEvent *e) {
66236627 ? (barIndex + 1 )
66246628 : (count - 1 );
66256629 const auto elements = accessibleElements ();
6626- const auto elementIndex = (barIndex >= 0
6627- && index > barIndex)
6628- ? (index - 1 )
6629- : index;
6630- const auto item = (elementIndex >= 0
6631- && elementIndex < int (elements.size ()))
6632- ? elements[elementIndex]->data ().get ()
6633- : nullptr ;
6630+ const auto item = accessibilityItemAtIndex (
6631+ index,
6632+ elements,
6633+ barIndex);
66346634 setAccessibilityFocusedItem (index, item);
66356635 });
66366636}
@@ -6702,13 +6702,7 @@ void HistoryInner::applyAccessibilityFocus(
67026702 bool announceAlways) {
67036703 const auto elements = accessibleElements ();
67046704 const auto barIndex = accessibilityUnreadBarIndex ();
6705- const auto elementIndex = (barIndex >= 0 && index > barIndex)
6706- ? (index - 1 )
6707- : index;
6708- const auto item = (elementIndex >= 0
6709- && elementIndex < int (elements.size ()))
6710- ? elements[elementIndex]->data ().get ()
6711- : nullptr ;
6705+ const auto item = accessibilityItemAtIndex (index, elements, barIndex);
67126706 const auto changed = (_accessibilityFocusedIndex != index)
67136707 || (_accessibilityFocusedItem != item);
67146708 _accessibilitySelectionAnchor = nullptr ;
@@ -6732,12 +6726,8 @@ void HistoryInner::applyAccessibilityFocus(
67326726 - (_visibleAreaBottom - _visibleAreaTop));
67336727 }
67346728 }
6735- if (_widget->markingMessagesRead ()
6736- && (barIndex < 0 || index != barIndex)
6737- && elementIndex >= 0
6738- && elementIndex < int (elements.size ())) {
6739- session ().data ().histories ().readInboxTill (
6740- elements[elementIndex]->data ());
6729+ if (_widget->markingMessagesRead () && item) {
6730+ session ().data ().histories ().readInboxTill (item);
67416731 }
67426732}
67436733
0 commit comments