Add accessability semantics

This commit is contained in:
problematicconsumer
2023-09-12 00:05:44 +03:30
parent d54917868b
commit 18bffd8646
10 changed files with 156 additions and 105 deletions

View File

@@ -48,6 +48,7 @@ class ProfileTile extends HookConsumerWidget {
profile.active ? theme.colorScheme.outlineVariant : Colors.transparent;
return Card(
semanticContainer: false,
margin: effectiveMargin,
elevation: effectiveElevation,
shape: RoundedRectangleBorder(
@@ -55,86 +56,87 @@ class ProfileTile extends HookConsumerWidget {
borderRadius: BorderRadius.circular(16),
),
shadowColor: Colors.transparent,
child: InkWell(
onTap: isMain
? null
: () {
if (selectActiveMutation.state.isInProgress) return;
if (profile.active) return;
selectActiveMutation.setFuture(
ref
.read(profilesNotifierProvider.notifier)
.selectActiveProfile(profile.id),
);
},
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: 48,
child: ProfileActionButton(profile, !isMain),
),
VerticalDivider(
width: 1,
color: effectiveOutlineColor,
),
Flexible(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isMain)
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Material(
borderRadius: BorderRadius.circular(8),
color: Colors.transparent,
clipBehavior: Clip.antiAlias,
child: Semantics(
button: true,
label: t.profile.overviewPageTitle,
child: InkWell(
onTap: () => const ProfilesRoute().go(context),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
profile.name,
style: theme.textTheme.titleMedium,
),
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: 48,
child: ProfileActionButton(profile, !isMain),
),
VerticalDivider(
width: 1,
color: effectiveOutlineColor,
),
Flexible(
child: Semantics(
button: true,
label: isMain
? t.profile.overviewPageTitle
: t.profile.edit.selectActiveTxt,
child: InkWell(
onTap: () {
if (isMain) {
const ProfilesRoute().go(context);
} else {
if (selectActiveMutation.state.isInProgress) return;
if (profile.active) return;
selectActiveMutation.setFuture(
ref
.read(profilesNotifierProvider.notifier)
.selectActiveProfile(profile.id),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isMain)
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Material(
borderRadius: BorderRadius.circular(8),
color: Colors.transparent,
clipBehavior: Clip.antiAlias,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
profile.name,
style: theme.textTheme.titleMedium,
),
const Icon(Icons.arrow_drop_down),
],
),
),
const Icon(Icons.arrow_drop_down),
],
),
),
)
else
Text(
profile.name,
style: theme.textTheme.titleMedium,
),
)
else
Text(
profile.name,
style: theme.textTheme.titleMedium,
),
if (subInfo != null) ...[
const Gap(4),
RemainingTrafficIndicator(subInfo.ratio),
const Gap(4),
ProfileSubscriptionInfo(subInfo),
const Gap(4),
if (subInfo != null) ...[
const Gap(4),
RemainingTrafficIndicator(subInfo.ratio),
const Gap(4),
ProfileSubscriptionInfo(subInfo),
const Gap(4),
],
],
],
),
),
),
),
],
),
),
],
),
),
);

View File

@@ -26,10 +26,12 @@ class StatsOverview extends HookConsumerWidget {
firstStat: (
label: "",
data: stats.uplink.speed(),
semanticLabel: t.home.stats.uplink,
),
secondStat: (
label: "",
data: stats.downlink.speed(),
semanticLabel: t.home.stats.downlink,
),
),
const Gap(8),
@@ -38,10 +40,12 @@ class StatsOverview extends HookConsumerWidget {
firstStat: (
label: "",
data: stats.uplinkTotal.size(),
semanticLabel: t.home.stats.uplink,
),
secondStat: (
label: "",
data: stats.downlinkTotal.size(),
semanticLabel: t.home.stats.downlink,
),
),
],
@@ -58,8 +62,8 @@ class _StatCard extends HookConsumerWidget {
});
final String title;
final ({String label, String data}) firstStat;
final ({String label, String data}) secondStat;
final ({String label, String data, String semanticLabel}) firstStat;
final ({String label, String data, String semanticLabel}) secondStat;
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -80,6 +84,7 @@ class _StatCard extends HookConsumerWidget {
children: [
Text(
firstStat.label,
semanticsLabel: firstStat.semanticLabel,
style: const TextStyle(color: Colors.green),
),
Text(
@@ -93,6 +98,7 @@ class _StatCard extends HookConsumerWidget {
children: [
Text(
secondStat.label,
semanticsLabel: secondStat.semanticLabel,
style: TextStyle(color: theme.colorScheme.error),
),
Text(

View File

@@ -83,6 +83,7 @@ class AppVersionLabel extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final t = ref.watch(translationsProvider);
final theme = Theme.of(context);
final version = ref.watch(
@@ -96,19 +97,23 @@ class AppVersionLabel extends HookConsumerWidget {
if (version.isEmpty) return const SizedBox();
return Container(
decoration: BoxDecoration(
color: theme.colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 1,
),
child: Text(
version,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSecondaryContainer,
return Semantics(
label: t.about.version,
button: false,
child: Container(
decoration: BoxDecoration(
color: theme.colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 1,
),
child: Text(
version,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSecondaryContainer,
),
),
),
);

View File

@@ -125,7 +125,10 @@ class ProfilesSortModal extends HookConsumerWidget {
icon: AnimatedRotation(
turns: arrowTurn,
duration: const Duration(milliseconds: 100),
child: const Icon(Icons.arrow_upward),
child: Icon(
Icons.arrow_upward,
semanticLabel: sort.mode.name,
),
),
)
: null,

View File

@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:hiddify/core/core_providers.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class ThemeModeSwitch extends StatelessWidget {
class ThemeModeSwitch extends HookConsumerWidget {
const ThemeModeSwitch({
super.key,
required this.themeMode,
@@ -10,7 +12,9 @@ class ThemeModeSwitch extends StatelessWidget {
final ValueChanged<ThemeMode> onChanged;
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final t = ref.watch(translationsProvider);
final List<bool> isSelected = <bool>[
themeMode == ThemeMode.light,
themeMode == ThemeMode.system,
@@ -28,10 +32,19 @@ class ThemeModeSwitch extends StatelessWidget {
onChanged(ThemeMode.dark);
}
},
children: const <Widget>[
Icon(Icons.wb_sunny),
Icon(Icons.phone_iphone),
Icon(Icons.bedtime),
children: <Widget>[
Icon(
Icons.wb_sunny,
semanticLabel: t.settings.general.themeModes.light,
),
Icon(
Icons.phone_iphone,
semanticLabel: t.settings.general.themeModes.system,
),
Icon(
Icons.bedtime,
semanticLabel: t.settings.general.themeModes.dark,
),
],
);
}