From 6dff3a1841f513f814e21e7aa5561c0dacea6fcf Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Thu, 14 Sep 2023 15:20:48 +0330 Subject: [PATCH] Improve accessability --- assets/translations/strings.i18n.json | 5 ++++ assets/translations/strings_fa.i18n.json | 5 ++++ lib/core/app/app_view.dart | 16 +++++----- lib/domain/constants.dart | 1 + lib/features/common/profile_tile.dart | 29 ++++++++++++++++--- .../controller/system_tray_controller.dart | 2 ++ lib/utils/number_formatters.dart | 2 ++ 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/assets/translations/strings.i18n.json b/assets/translations/strings.i18n.json index 45bb39df..725984ab 100644 --- a/assets/translations/strings.i18n.json +++ b/assets/translations/strings.i18n.json @@ -29,10 +29,15 @@ "profile": { "overviewPageTitle": "Profiles", "detailsPageTitle": "Profile", + "activeProfileNameSemanticLabel": "Active profile name: ${name}", + "nonActiveProfileNameSemanticLabel": "Profile name: ${name}", + "activeProfileBtnSemanticLabel": "View all profiles", + "nonActiveProfileBtnSemanticLabel": "Select ${name} as active", "subscription": { "traffic": "Traffic", "updatedTimeAgo": "Updated ${timeago}", "remainingDuration": "${duration} Days Remaining", + "remainingTrafficSemanticLabel": "${consumed} of ${total} traffic consumed", "expired": "Expired", "noTraffic": "No more traffic" }, diff --git a/assets/translations/strings_fa.i18n.json b/assets/translations/strings_fa.i18n.json index 55f652c1..9a39a9fb 100644 --- a/assets/translations/strings_fa.i18n.json +++ b/assets/translations/strings_fa.i18n.json @@ -29,10 +29,15 @@ "profile": { "overviewPageTitle": "پروفایل‌ها", "detailsPageTitle": "پروفایل", + "activeProfileNameSemanticLabel": "نام پروفایل فعال: ${name}", + "nonActiveProfileNameSemanticLabel": "نام پروفایل: ${name}", + "activeProfileBtnSemanticLabel": "همه‌ی پروفایل‌ها", + "nonActiveProfileBtnSemanticLabel": "انتخاب ${name} به عنوان پروفایل فعال", "subscription": { "traffic": "ترافیک", "updatedTimeAgo": "بروزرسانی شده در ${timeago}", "remainingDuration": "${duration} روز باقی مانده", + "remainingTrafficSemanticLabel": "${consumed} از ${total} ترافیک مصرف شده", "expired": "منقضی شده", "noTraffic": "پایان ترافیک" }, diff --git a/lib/core/app/app_view.dart b/lib/core/app/app_view.dart index f3f6dd21..a65b6223 100644 --- a/lib/core/app/app_view.dart +++ b/lib/core/app/app_view.dart @@ -4,6 +4,7 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:hiddify/core/core_providers.dart'; import 'package:hiddify/core/prefs/prefs.dart'; import 'package:hiddify/core/router/router.dart'; +import 'package:hiddify/domain/constants.dart'; import 'package:hiddify/features/common/common_controllers.dart'; import 'package:hiddify/utils/utils.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -20,12 +21,13 @@ class AppView extends HookConsumerWidget with PresLogger { ref.watch(commonControllersProvider); return MaterialApp.router( - builder: (context, child) { - return AccessibilityTools( - checkFontOverflows: true, - child: child, - ); - }, + // builder: (context, child) { + // return AccessibilityTools( + // checkFontOverflows: true, + // child: child, + // ); + // }, + // showSemanticsDebugger: true, routerConfig: router, locale: locale, supportedLocales: AppLocaleUtils.supportedLocales, @@ -34,7 +36,7 @@ class AppView extends HookConsumerWidget with PresLogger { themeMode: theme.mode, theme: theme.light(), darkTheme: theme.dark(), - title: 'Hiddify Next', + title: Constants.appName, ); } } diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index c84ec8c5..8151c264 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -1,4 +1,5 @@ abstract class Constants { + static const appName = "Hiddify Next"; static const geoipFileName = "geoip.db"; static const geositeFileName = "geosite.db"; static const configsFolderName = "configs"; diff --git a/lib/features/common/profile_tile.dart b/lib/features/common/profile_tile.dart index 5a02154c..a42ac8c0 100644 --- a/lib/features/common/profile_tile.dart +++ b/lib/features/common/profile_tile.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hiddify/core/core_providers.dart'; @@ -48,7 +49,6 @@ class ProfileTile extends HookConsumerWidget { profile.active ? theme.colorScheme.outlineVariant : Colors.transparent; return Card( - semanticContainer: false, margin: effectiveMargin, elevation: effectiveElevation, shape: RoundedRectangleBorder( @@ -62,7 +62,10 @@ class ProfileTile extends HookConsumerWidget { children: [ SizedBox( width: 48, - child: ProfileActionButton(profile, !isMain), + child: Semantics( + sortKey: const OrdinalSortKey(1), + child: ProfileActionButton(profile, !isMain), + ), ), VerticalDivider( width: 1, @@ -71,9 +74,14 @@ class ProfileTile extends HookConsumerWidget { Flexible( child: Semantics( button: true, + sortKey: isMain ? const OrdinalSortKey(0) : null, + focused: isMain, + liveRegion: isMain, + namesRoute: isMain, label: isMain - ? t.profile.overviewPageTitle - : t.profile.edit.selectActiveTxt, + ? t.profile.activeProfileBtnSemanticLabel + : t.profile + .nonActiveProfileBtnSemanticLabel(name: profile.name), child: InkWell( onTap: () { if (isMain) { @@ -110,6 +118,10 @@ class ProfileTile extends HookConsumerWidget { Flexible( child: Text( profile.name, + semanticsLabel: t.profile + .activeProfileNameSemanticLabel( + name: profile.name, + ), style: theme.textTheme.titleMedium, ), ), @@ -121,6 +133,10 @@ class ProfileTile extends HookConsumerWidget { else Text( profile.name, + semanticsLabel: + t.profile.nonActiveProfileNameSemanticLabel( + name: profile.name, + ), style: theme.textTheme.titleMedium, ), if (subInfo != null) ...[ @@ -320,6 +336,11 @@ class ProfileSubscriptionInfo extends HookConsumerWidget { subInfo.total > 10 * 1099511627776 //10TB ? "∞ GiB" : subInfo.consumption.sizeOf(subInfo.total), + semanticsLabel: + t.profile.subscription.remainingTrafficSemanticLabel( + consumed: subInfo.consumption.sizeGB(), + total: subInfo.total.sizeGB(), + ), style: theme.textTheme.bodySmall, ), ), diff --git a/lib/features/system_tray/controller/system_tray_controller.dart b/lib/features/system_tray/controller/system_tray_controller.dart index da194952..2b3eb10e 100644 --- a/lib/features/system_tray/controller/system_tray_controller.dart +++ b/lib/features/system_tray/controller/system_tray_controller.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:hiddify/core/core_providers.dart'; import 'package:hiddify/domain/connectivity/connectivity.dart'; +import 'package:hiddify/domain/constants.dart'; import 'package:hiddify/features/common/connectivity/connectivity_controller.dart'; import 'package:hiddify/features/common/window/window_controller.dart'; import 'package:hiddify/gen/assets.gen.dart'; @@ -22,6 +23,7 @@ class SystemTrayController extends _$SystemTrayController _trayIconPath, isTemplate: Platform.isMacOS, ); + if (!Platform.isLinux) await trayManager.setToolTip(Constants.appName); trayManager.addListener(this); _initialized = true; } diff --git a/lib/utils/number_formatters.dart b/lib/utils/number_formatters.dart index df1688dd..4ddc25e4 100644 --- a/lib/utils/number_formatters.dart +++ b/lib/utils/number_formatters.dart @@ -6,6 +6,8 @@ extension ByteFormatter on int { static final _sizeOfFormat = InformationSizeFormat(permissibleValueUnits: {InformationUnit.gibibyte}); + String sizeGB() => _sizeOfFormat.format(bytes()); + String sizeOf(int total) => "${_sizeOfFormat.format(bytes())} / ${_sizeOfFormat.format(total.bytes())}";