Items in song_list.dart und artist_list.dart faden/rutschen beim ersten Erscheinen gestaffelt statt abrupt ein — angelehnt an HyperOS' fließende Motion-Sprache. Läuft einmal pro Element, respektiert Reduce-Motion und deckelt die Verzögerung ab Index 12.
77 lines
2.4 KiB
Dart
77 lines
2.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:melo/shared/einblend_item.dart';
|
|
|
|
void main() {
|
|
Widget wrap(Widget child, {bool ruhig = false}) => MaterialApp(
|
|
home: MediaQuery(
|
|
data: MediaQueryData(disableAnimations: ruhig),
|
|
child: Scaffold(body: child),
|
|
),
|
|
);
|
|
|
|
double opacityVon(WidgetTester tester, Finder einblendItem) => tester
|
|
.widget<Opacity>(
|
|
find.descendant(of: einblendItem, matching: find.byType(Opacity)))
|
|
.opacity;
|
|
|
|
double versatzYVon(WidgetTester tester, Finder einblendItem) => tester
|
|
.widget<Transform>(
|
|
find.descendant(of: einblendItem, matching: find.byType(Transform)))
|
|
.transform
|
|
.getTranslation()
|
|
.y;
|
|
|
|
testWidgets('Opacity startet bei 0 und erreicht 1,0 nach dem Einblenden',
|
|
(tester) async {
|
|
await tester.pumpWidget(wrap(
|
|
const EinblendItem(index: 0, child: Text('Titel')),
|
|
));
|
|
final item = find.byType(EinblendItem);
|
|
|
|
expect(opacityVon(tester, item), 0);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(opacityVon(tester, item), 1);
|
|
expect(versatzYVon(tester, item), 0);
|
|
});
|
|
|
|
testWidgets(
|
|
'bei abgeschalteten Systemanimationen erscheint das Element sofort',
|
|
(tester) async {
|
|
await tester.pumpWidget(wrap(
|
|
const EinblendItem(index: 3, child: Text('Titel')),
|
|
ruhig: true,
|
|
));
|
|
final item = find.byType(EinblendItem);
|
|
|
|
// Bewusst kein weiterer pump() davor: die Reduce-Motion-Einstellung
|
|
// darf nicht erst nach einer Zeitverzögerung greifen.
|
|
expect(opacityVon(tester, item), 1);
|
|
expect(versatzYVon(tester, item), 0);
|
|
});
|
|
|
|
testWidgets('der Deckel bremst die Verzögerung ab Index 12',
|
|
(tester) async {
|
|
await tester.pumpWidget(wrap(
|
|
const Column(
|
|
children: [
|
|
EinblendItem(index: 12, child: Text('Zwölf')),
|
|
EinblendItem(index: 50, child: Text('Fünfzig')),
|
|
],
|
|
),
|
|
));
|
|
|
|
// Deckel: min(index, 12) * 25ms → beide starten spätestens nach 300ms.
|
|
// Ohne Deckel bräuchte Index 50 1250ms Verzögerung und wäre hier noch
|
|
// bei Opacity 0.
|
|
await tester.pump(const Duration(milliseconds: 300));
|
|
await tester.pump(const Duration(milliseconds: 220));
|
|
|
|
for (final item in find.byType(EinblendItem).evaluate()) {
|
|
expect(opacityVon(tester, find.byWidget(item.widget)), 1);
|
|
}
|
|
});
|
|
}
|