mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Improve accessibility code for countries list.
This commit is contained in:
@@ -7,56 +7,55 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/language_box.h"
|
||||
|
||||
#include "data/data_peer_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/screen_reader_state.h"
|
||||
#include "ui/accessible/ui_accessible_item.h"
|
||||
#include "ui/boxes/choose_language_box.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
#include "boxes/translate_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/application.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "platform/platform_translate_provider.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "spellcheck/spellcheck_types.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "ui/accessible/ui_accessible_item.h"
|
||||
#include "ui/boxes/choose_language_box.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/widgets/box_content_divider.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/screen_reader_mode.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_passport.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_passport.h"
|
||||
#include "styles/style_settings.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -89,80 +88,17 @@ public:
|
||||
|
||||
static int DefaultRowHeight();
|
||||
|
||||
QAccessible::Role accessibilityRole() override {
|
||||
return QAccessible::List;
|
||||
}
|
||||
|
||||
QAccessible::Role accessibilityChildRole() const override {
|
||||
return QAccessible::RadioButton;
|
||||
}
|
||||
|
||||
QAccessible::State accessibilityChildState(int index) const override {
|
||||
QAccessible::State state;
|
||||
if (base::ScreenReaderState::Instance()->active()) {
|
||||
state.focusable = true;
|
||||
}
|
||||
state.checkable = true;
|
||||
state.checked = (index == chosenIndex());
|
||||
if (index == selected()) {
|
||||
state.active = true;
|
||||
if (hasFocus()) {
|
||||
state.focused = true;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
int accessibilityChildCount() const override {
|
||||
return count();
|
||||
}
|
||||
|
||||
QString accessibilityChildName(int index) const override {
|
||||
if (index < 0 || index >= count()) {
|
||||
return {};
|
||||
}
|
||||
const auto &row = rowByIndex(index);
|
||||
// Announce native name followed by English name.
|
||||
return row.data.nativeName + u", "_q + row.data.name;
|
||||
}
|
||||
|
||||
QRect accessibilityChildRect(int index) const override {
|
||||
if (index < 0 || index >= count()) {
|
||||
return QRect();
|
||||
}
|
||||
const auto &row = rowByIndex(index);
|
||||
return QRect(0, row.top, width(), row.height);
|
||||
}
|
||||
|
||||
int accessibilityChildColumnCount(int row) const override {
|
||||
return 2;
|
||||
}
|
||||
|
||||
QAccessible::Role accessibilityChildSubItemRole() const override {
|
||||
return QAccessible::Cell;
|
||||
}
|
||||
|
||||
QString accessibilityChildSubItemName(int row, int column) const override {
|
||||
if (column == 0) {
|
||||
return tr::lng_sr_languages_column_native(tr::now);
|
||||
} else if (column == 1) {
|
||||
return tr::lng_sr_languages_column_name(tr::now);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString accessibilityChildSubItemValue(int row, int column) const override {
|
||||
if (row < 0 || row >= count()) {
|
||||
return {};
|
||||
}
|
||||
const auto &data = rowByIndex(row).data;
|
||||
if (column == 0) {
|
||||
return data.nativeName;
|
||||
} else if (column == 1) {
|
||||
return data.name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
QAccessible::Role accessibilityRole() override;
|
||||
Qt::FocusPolicy accessibilityFocusPolicy() override;
|
||||
QAccessible::Role accessibilityChildRole() const override;
|
||||
QAccessible::State accessibilityChildState(int index) const override;
|
||||
int accessibilityChildCount() const override;
|
||||
QString accessibilityChildName(int index) const override;
|
||||
QRect accessibilityChildRect(int index) const override;
|
||||
int accessibilityChildColumnCount(int row) const override;
|
||||
QAccessible::Role accessibilityChildSubItemRole() const override;
|
||||
QString accessibilityChildSubItemName(int row, int column) const override;
|
||||
QString accessibilityChildSubItemValue(int row, int column) const override;
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
@@ -237,6 +173,13 @@ private:
|
||||
void repaintChecked(not_null<const Row*> row);
|
||||
void activateByIndex(int index);
|
||||
|
||||
enum class Announce {
|
||||
No,
|
||||
OnChange,
|
||||
Always,
|
||||
};
|
||||
void setSelected(int index, Announce announce);
|
||||
|
||||
void showMenu(int index);
|
||||
void setForceRippled(not_null<Row*> row, bool rippled);
|
||||
bool canShare(not_null<const Row*> row) const;
|
||||
@@ -266,6 +209,26 @@ private:
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] bool ForwardListNavigation(
|
||||
not_null<QKeyEvent*> e,
|
||||
not_null<Rows*> rows,
|
||||
int pageHeight) {
|
||||
const auto key = e->key();
|
||||
if (key == Qt::Key_Down) {
|
||||
rows->selectSkip(1);
|
||||
} else if (key == Qt::Key_Up) {
|
||||
rows->selectSkip(-1);
|
||||
} else if (key == Qt::Key_PageDown || key == Qt::Key_PageUp) {
|
||||
const auto perPage = std::max(
|
||||
pageHeight / Rows::DefaultRowHeight(),
|
||||
1);
|
||||
rows->selectSkip((key == Qt::Key_PageDown) ? perPage : -perPage);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class Content : public Ui::RpWidget {
|
||||
public:
|
||||
Content(
|
||||
@@ -373,53 +336,34 @@ Rows::Rows(
|
||||
update();
|
||||
|
||||
setAccessibleName(tr::lng_languages(tr::now));
|
||||
|
||||
base::ScreenReaderState::Instance()->activeValue(
|
||||
) | rpl::on_next([=](bool active) {
|
||||
setFocusPolicy(active ? Qt::TabFocus : Qt::NoFocus);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void Rows::focusInEvent(QFocusEvent *e) {
|
||||
// Select first item or chosen item when focus enters.
|
||||
if (selected() < 0 && count() > 0) {
|
||||
const auto chosen = chosenIndex();
|
||||
setSelected(chosen >= 0 ? chosen : 0);
|
||||
setSelected(chosen >= 0 ? chosen : 0, Announce::No);
|
||||
}
|
||||
|
||||
RpWidget::focusInEvent(e);
|
||||
|
||||
if (base::ScreenReaderState::Instance()->active()) {
|
||||
const auto index = selected();
|
||||
if (index >= 0) {
|
||||
InvokeQueued(this, [=] {
|
||||
if (selected() != index || !hasFocus()) {
|
||||
return;
|
||||
}
|
||||
const auto index = selected();
|
||||
if (index >= 0) {
|
||||
InvokeQueued(this, [=] {
|
||||
if (selected() == index && hasFocus()) {
|
||||
accessibilityChildFocused(index);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Rows::keyPressEvent(QKeyEvent *e) {
|
||||
const auto pageHeight = window() ? window()->height() : height();
|
||||
if (ForwardListNavigation(e, this, pageHeight)) {
|
||||
return;
|
||||
}
|
||||
const auto key = e->key();
|
||||
if (key == Qt::Key_Down) {
|
||||
selectSkip(1);
|
||||
} else if (key == Qt::Key_Up) {
|
||||
selectSkip(-1);
|
||||
} else if (key == Qt::Key_PageDown || key == Qt::Key_PageUp) {
|
||||
const auto visibleHeight = visibleRegion().boundingRect().height();
|
||||
const auto rowsPerPage = std::max(visibleHeight / DefaultRowHeight(), 1);
|
||||
selectSkip(key == Qt::Key_PageDown ? rowsPerPage : -rowsPerPage);
|
||||
} else if (key == Qt::Key_Home) {
|
||||
if (count() > 0) {
|
||||
setSelected(0);
|
||||
}
|
||||
} else if (key == Qt::Key_End) {
|
||||
if (count() > 0) {
|
||||
setSelected(count() - 1);
|
||||
}
|
||||
if (key == Qt::Key_Home && count() > 0) {
|
||||
setSelected(0, Announce::Always);
|
||||
} else if (key == Qt::Key_End && count() > 0) {
|
||||
setSelected(count() - 1, Announce::Always);
|
||||
} else if (!e->isAutoRepeat()
|
||||
&& (key == Qt::Key_Space
|
||||
|| key == Qt::Key_Return
|
||||
@@ -697,10 +641,8 @@ void Rows::setForceRippled(not_null<Row*> row, bool rippled) {
|
||||
void Rows::activateByIndex(int index) {
|
||||
_chosen = rowByIndex(index).data.id;
|
||||
_activations.fire_copy(rowByIndex(index).data);
|
||||
if (base::ScreenReaderState::Instance()->active()) {
|
||||
accessibilityChildStateChanged(index, { .checked = true });
|
||||
accessibilityChildNameChanged(index);
|
||||
}
|
||||
accessibilityChildStateChanged(index, { .checked = true });
|
||||
accessibilityChildNameChanged(index);
|
||||
}
|
||||
|
||||
void Rows::leaveEventHook(QEvent *e) {
|
||||
@@ -795,21 +737,20 @@ void Rows::activateSelected() {
|
||||
void Rows::selectSkip(int dir) {
|
||||
const auto limit = count();
|
||||
auto now = selected();
|
||||
// If no keyboard selection, start from the checked item.
|
||||
if (now < 0) {
|
||||
now = chosenIndex();
|
||||
}
|
||||
if (now >= 0) {
|
||||
const auto changed = now + dir;
|
||||
if (changed < 0) {
|
||||
setSelected(0);
|
||||
setSelected(0, Announce::Always);
|
||||
} else if (changed >= limit) {
|
||||
setSelected(limit - 1);
|
||||
setSelected(limit - 1, Announce::Always);
|
||||
} else {
|
||||
setSelected(changed);
|
||||
setSelected(changed, Announce::Always);
|
||||
}
|
||||
} else if (dir > 0) {
|
||||
setSelected(0);
|
||||
setSelected(0, Announce::Always);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,27 +764,35 @@ void Rows::changeChosen(const QString &chosen) {
|
||||
for (const auto &row : _rows) {
|
||||
row.check->setChecked(row.data.id == chosen, anim::type::normal);
|
||||
}
|
||||
if (base::ScreenReaderState::Instance()->active()) {
|
||||
const auto newIndex = chosenIndex();
|
||||
if (newIndex != oldIndex && newIndex >= 0) {
|
||||
accessibilityChildStateChanged(newIndex, { .checked = true });
|
||||
accessibilityChildNameChanged(newIndex);
|
||||
}
|
||||
const auto newIndex = chosenIndex();
|
||||
if (newIndex != oldIndex && newIndex >= 0) {
|
||||
accessibilityChildStateChanged(newIndex, { .checked = true });
|
||||
accessibilityChildNameChanged(newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Rows::setSelected(int selected) {
|
||||
setSelected(selected, Announce::OnChange);
|
||||
}
|
||||
|
||||
void Rows::setSelected(int selected, Announce announce) {
|
||||
_mouseSelection = false;
|
||||
const auto limit = count();
|
||||
if (selected >= 0 && selected < limit) {
|
||||
updateSelected(RowSelection{ selected });
|
||||
const auto clamped = (selected >= 0 && selected < limit)
|
||||
? selected
|
||||
: -1;
|
||||
const auto changed = (indexFromSelection(_selected) != clamped)
|
||||
|| (clamped < 0 && !v::is_null(_selected));
|
||||
if (clamped >= 0) {
|
||||
updateSelected(RowSelection{ clamped });
|
||||
} else {
|
||||
updateSelected({});
|
||||
}
|
||||
if (selected >= 0 && selected < limit
|
||||
&& base::ScreenReaderState::Instance()->active()) {
|
||||
accessibilityChildNameChanged(selected);
|
||||
accessibilityChildFocused(selected);
|
||||
const auto shouldAnnounce = (announce == Announce::Always)
|
||||
|| (announce == Announce::OnChange && changed);
|
||||
if (shouldAnnounce && clamped >= 0) {
|
||||
accessibilityChildNameChanged(clamped);
|
||||
accessibilityChildFocused(clamped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1064,6 +1013,84 @@ void Rows::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
QAccessible::Role Rows::accessibilityRole() {
|
||||
return QAccessible::List;
|
||||
}
|
||||
|
||||
Qt::FocusPolicy Rows::accessibilityFocusPolicy() {
|
||||
return Qt::TabFocus;
|
||||
}
|
||||
|
||||
QAccessible::Role Rows::accessibilityChildRole() const {
|
||||
return QAccessible::RadioButton;
|
||||
}
|
||||
|
||||
QAccessible::State Rows::accessibilityChildState(int index) const {
|
||||
QAccessible::State state;
|
||||
if (Ui::ScreenReaderModeActive()) {
|
||||
state.focusable = true;
|
||||
}
|
||||
state.checkable = true;
|
||||
state.checked = (index == chosenIndex());
|
||||
if (index == selected()) {
|
||||
state.active = true;
|
||||
if (hasFocus()) {
|
||||
state.focused = true;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
int Rows::accessibilityChildCount() const {
|
||||
return count();
|
||||
}
|
||||
|
||||
QString Rows::accessibilityChildName(int index) const {
|
||||
if (index < 0 || index >= count()) {
|
||||
return {};
|
||||
}
|
||||
const auto &row = rowByIndex(index);
|
||||
return row.data.nativeName + u", "_q + row.data.name;
|
||||
}
|
||||
|
||||
QRect Rows::accessibilityChildRect(int index) const {
|
||||
if (index < 0 || index >= count()) {
|
||||
return {};
|
||||
}
|
||||
const auto &row = rowByIndex(index);
|
||||
return QRect(0, row.top, width(), row.height);
|
||||
}
|
||||
|
||||
int Rows::accessibilityChildColumnCount(int row) const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
QAccessible::Role Rows::accessibilityChildSubItemRole() const {
|
||||
return QAccessible::Cell;
|
||||
}
|
||||
|
||||
QString Rows::accessibilityChildSubItemName(int row, int column) const {
|
||||
if (column == 0) {
|
||||
return tr::lng_sr_languages_column_native(tr::now);
|
||||
} else if (column == 1) {
|
||||
return tr::lng_sr_languages_column_name(tr::now);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString Rows::accessibilityChildSubItemValue(int row, int column) const {
|
||||
if (row < 0 || row >= count()) {
|
||||
return {};
|
||||
}
|
||||
const auto &data = rowByIndex(row).data;
|
||||
if (column == 0) {
|
||||
return data.nativeName;
|
||||
} else if (column == 1) {
|
||||
return data.name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Content::Content(
|
||||
QWidget *parent,
|
||||
const Languages &recent,
|
||||
|
||||
Reference in New Issue
Block a user