feat(auth): KTO-01 Passwort zurücksetzen (01c) (4/4) #36

Merged
cschlaefke merged 5 commits from feature/1-01c-passwort-reset into main 2026-11-03 09:21:44 +00:00
2 changed files with 42 additions and 1 deletions
Showing only changes of commit 553a2b67cd - Show all commits

View file

@ -17,6 +17,7 @@ class AppBanner extends StatelessWidget {
super.key,
this.actionLabel,
this.onAction,
this.actionEnabled = true,
}) : assert(
(actionLabel == null) == (onAction == null),
'actionLabel and onAction belong together',
@ -28,6 +29,11 @@ class AppBanner extends StatelessWidget {
final String? actionLabel;
final VoidCallback? onAction;
/// `false` keeps the action visible and in the focus order but disabled
/// (e.g. while a request runs). Screen readers still find it and hear that
/// it is unavailable, instead of the control vanishing under their focus.
final bool actionEnabled;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@ -81,7 +87,7 @@ class AppBanner extends StatelessWidget {
Align(
alignment: AlignmentDirectional.centerEnd,
child: TextButton(
onPressed: onAction,
onPressed: actionEnabled ? onAction : null,
style: TextButton.styleFrom(foregroundColor: foreground),
child: Text(actionLabel!),
),

View file

@ -1,3 +1,5 @@
import 'dart:ui' show Tristate;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shuffle/core/widgets/app_banner.dart';
@ -46,6 +48,39 @@ void main() {
handle.dispose();
});
testWidgets('a disabled action stays visible and announced as disabled', (
tester,
) async {
final handle = tester.ensureSemantics();
var calls = 0;
await pumpWidgetUnderTest(
tester,
AppBanner(
type: AppBannerType.info,
typeLabel: 'Note',
message: 'Confirm first',
actionLabel: 'Resend',
onAction: () => calls++,
actionEnabled: false,
),
);
final action = find.widgetWithText(TextButton, 'Resend');
expect(action, findsOneWidget);
expect(tester.widget<TextButton>(action).onPressed, isNull);
expect(
tester
.getSemantics(action)
.getSemanticsData()
.flagsCollection
.isEnabled,
Tristate.isFalse,
);
await tester.tap(action, warnIfMissed: false);
expect(calls, 0);
handle.dispose();
});
testWidgets('action calls back and is at least 48 dp', (tester) async {
var calls = 0;
await pumpWidgetUnderTest(