Make GitHub mirror screen text-free

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-11-11 01:28:08 +01:00
parent 17014c6399
commit 2c52408cec
6 changed files with 76 additions and 43 deletions

View File

@ -198,9 +198,11 @@ class _GitHubMirrorScreenState extends State<GitHubMirrorScreen> {
return Scaffold(
appBar: AppBar(
backgroundColor: colorScheme.surfaceContainerHigh,
title: Text(
'Advanced sync (GitHub)',
style: TextStyle(color: colorScheme.onSurface),
// textgate: was "Advanced sync (GitHub)".
title: Icon(
Icons.code,
color: colorScheme.onSurface,
semanticLabel: 'Advanced sync (GitHub)',
),
iconTheme: IconThemeData(color: colorScheme.onSurface),
),
@ -209,15 +211,7 @@ class _GitHubMirrorScreenState extends State<GitHubMirrorScreen> {
: ListView(
padding: const EdgeInsets.all(16),
children: [
Text(
'Authorize in your browser -- no token to paste. '
'Syncs to $syncRepoOwner/$syncRepoName.',
style: TextStyle(
color: colorScheme.onSurfaceVariant,
fontSize: AppTextSize.caption,
),
),
const SizedBox(height: 12),
// textgate: the explanation sentence above is gone.
if (_syncStatus != null) ...[
_SyncStatusBadge(text: _syncStatus!, kind: _syncStatusKind),
const SizedBox(height: 12),

View File

@ -19,6 +19,12 @@ class _SyncStatusBadge extends StatelessWidget {
_SyncStatusKind.error => colorScheme.error,
_SyncStatusKind.pending => colorScheme.onSurfaceVariant,
};
// textgate: the status sentence is spoken only; the pill shows the
// state glyph in the state colour.
return Semantics(label: text, excludeSemantics: true, child: _pill(color));
}
Widget _pill(Color color) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
@ -42,17 +48,6 @@ class _SyncStatusBadge extends StatelessWidget {
color: color,
size: 16,
),
const SizedBox(width: 10),
Expanded(
child: Text(
text,
style: TextStyle(
color: color,
fontSize: AppTextSize.label,
fontWeight: FontWeight.w600,
),
),
),
],
),
);
@ -176,7 +171,12 @@ class _DeviceCodeDialogState extends State<_DeviceCodeDialog> {
),
)
else
Text(_error!, style: TextStyle(color: colorScheme.error)),
// textgate: the failure is spoken only.
Icon(
Icons.error_outline,
color: colorScheme.error,
semanticLabel: _error,
),
],
),
actions: [

View File

@ -88,7 +88,9 @@ void main() {
);
expect(
find.textContaining('Could not start device flow'),
find.bySemanticsLabel(
RegExp(RegExp.escape('Could not start device flow')),
),
findsOneWidget,
);
});
@ -141,7 +143,9 @@ void main() {
);
expect(
find.textContaining('Connected and verified via GitHub'),
find.bySemanticsLabel(
RegExp(RegExp.escape('Connected and verified via GitHub')),
),
findsOneWidget,
);
});

View File

@ -102,9 +102,15 @@ void main() {
await tester.tap(iconLabeled('Connect GitHub'));
await _pumpUntil(
tester,
() => find.textContaining('NOT syncing').evaluate().isNotEmpty,
() => find
.bySemanticsLabel(RegExp(RegExp.escape('NOT syncing')))
.evaluate()
.isNotEmpty,
);
expect(
find.bySemanticsLabel(RegExp(RegExp.escape('NOT syncing'))),
findsOneWidget,
);
expect(find.textContaining('NOT syncing'), findsOneWidget);
});
});
@ -144,17 +150,28 @@ void main() {
await tester.tap(iconLabeled('Connect GitHub'));
await _pumpUntil(
tester,
() => find.textContaining('verifying').evaluate().isNotEmpty,
() => find
.bySemanticsLabel(RegExp(RegExp.escape('verifying')))
.evaluate()
.isNotEmpty,
);
// Pending tile (spinner + white70 status colour) is now on screen.
expect(find.textContaining('verifying'), findsOneWidget);
expect(
find.bySemanticsLabel(RegExp(RegExp.escape('verifying'))),
findsOneWidget,
);
await _pumpUntil(
tester,
() =>
find.textContaining('Connected and verified').evaluate().isNotEmpty,
() => find
.bySemanticsLabel(RegExp(RegExp.escape('Connected and verified')))
.evaluate()
.isNotEmpty,
);
expect(
find.bySemanticsLabel(RegExp(RegExp.escape('Connected and verified'))),
findsOneWidget,
);
expect(find.textContaining('Connected and verified'), findsOneWidget);
});
});
@ -195,8 +212,16 @@ void main() {
});
await tester.pump();
expect(find.textContaining('recovered the saved token'), findsOneWidget);
expect(find.textContaining('NOT connected'), findsNothing);
expect(
find.bySemanticsLabel(
RegExp(RegExp.escape('recovered the saved token')),
),
findsOneWidget,
);
expect(
find.bySemanticsLabel(RegExp(RegExp.escape('NOT connected'))),
findsNothing,
);
},
);
}

View File

@ -122,9 +122,9 @@ void main() {
await _pumpUntil(
tester,
() => find.textContaining('access_denied').evaluate().isNotEmpty,
() => iconLabelContaining('access_denied').evaluate().isNotEmpty,
);
expect(find.textContaining('access_denied'), findsOneWidget);
expect(iconLabelContaining('access_denied'), findsOneWidget);
await tester.tap(iconLabeled('Open GitHub & copy code'));
await tester.pump();
@ -175,7 +175,12 @@ void main() {
.evaluate()
.isNotEmpty,
);
expect(find.textContaining('could not save the token'), findsOneWidget);
expect(
find.bySemanticsLabel(
RegExp(RegExp.escape('could not save the token')),
),
findsOneWidget,
);
});
});
}

View File

@ -84,7 +84,7 @@ void main() {
});
await tester.pump();
expect(find.text('Advanced sync (GitHub)'), findsOneWidget);
expect(iconLabeled('Advanced sync (GitHub)'), findsOneWidget);
expect(iconLabeled('Connect GitHub'), findsOneWidget);
});
@ -104,8 +104,11 @@ void main() {
});
await tester.pump();
expect(find.text('Connected.'), findsNothing);
expect(find.textContaining('NOT connected'), findsOneWidget);
expect(find.bySemanticsLabel('Connected.'), findsNothing);
expect(
find.bySemanticsLabel(RegExp(RegExp.escape('NOT connected'))),
findsOneWidget,
);
});
testWidgets('a saved token that GitHub accepts reports verified', (
@ -125,7 +128,9 @@ void main() {
await tester.pump();
expect(
find.textContaining('Connected and verified via GitHub'),
find.bySemanticsLabel(
RegExp(RegExp.escape('Connected and verified via GitHub')),
),
findsOneWidget,
);
});
@ -151,6 +156,6 @@ void main() {
await tester.enterText(_patField, 'a-pasted-token');
await tester.tap(iconLabeled('Save'));
await tester.pump();
expect(find.text('Sync token saved.'), findsOneWidget);
expect(find.bySemanticsLabel('Sync token saved.'), findsOneWidget);
});
}