feat: strengthen dock spring motion, directional follow and milky glass
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:timezone/data/latest.dart' as tzdata;
|
||||
@@ -36,16 +38,22 @@ void main() {
|
||||
await tester.tap(find.byIcon(Icons.assignment_rounded));
|
||||
await tester.pump();
|
||||
var widest = resting.width;
|
||||
var narrowest = resting.width;
|
||||
var tallest = resting.height;
|
||||
var furthest = resting.center.dx;
|
||||
for (var frame = 0; frame < 70; frame++) {
|
||||
await tester.pump(const Duration(milliseconds: 16));
|
||||
final rect = tester.getRect(lens);
|
||||
widest = widest > rect.width ? widest : rect.width;
|
||||
narrowest = narrowest < rect.width ? narrowest : rect.width;
|
||||
tallest = tallest > rect.height ? tallest : rect.height;
|
||||
furthest = furthest > rect.center.dx ? furthest : rect.center.dx;
|
||||
expect(rect.width, lessThan(resting.width * 1.4));
|
||||
expect(rect.center.dx, lessThan(target + 8));
|
||||
expect(rect.center.dx, lessThan(target + 14));
|
||||
}
|
||||
expect(widest, greaterThan(resting.width * 1.06));
|
||||
expect(widest, greaterThan(resting.width * 1.20));
|
||||
expect(narrowest, lessThan(resting.width * 0.97));
|
||||
expect(tallest, greaterThan(resting.height * 1.10));
|
||||
expect(furthest, greaterThan(target + 0.1));
|
||||
expect(tester.getCenter(lens).dx, closeTo(target, 0.1));
|
||||
expect(tester.getSize(lens).width, closeTo(resting.width, 0.1));
|
||||
@@ -166,6 +174,59 @@ void main() {
|
||||
greaterThan(0),
|
||||
);
|
||||
});
|
||||
testWidgets(
|
||||
'drag moves the whole dock in its direction and returns on release',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_dock());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byIcon(Icons.assignment_rounded));
|
||||
await tester.pumpAndSettle();
|
||||
final icon = find.byIcon(Icons.calendar_month_rounded);
|
||||
final glass = find.byType(GlassRefraction).first;
|
||||
final x = tester.getCenter(icon).dx;
|
||||
final glassX = tester.getCenter(glass).dx;
|
||||
final gesture = await tester.startGesture(
|
||||
tester.getCenter(find.byKey(const Key('dock-cursor'))),
|
||||
);
|
||||
await gesture.moveBy(const Offset(24, 0));
|
||||
await tester.pump();
|
||||
await gesture.moveBy(const Offset(45, 0));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 140));
|
||||
expect(tester.getCenter(icon).dx, greaterThan(x + 4));
|
||||
expect(tester.getCenter(glass).dx, greaterThan(glassX + 4));
|
||||
await gesture.moveBy(const Offset(-70, 0));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 220));
|
||||
expect(tester.getCenter(icon).dx, lessThan(x - 4));
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getCenter(icon).dx, closeTo(x, 0.05));
|
||||
},
|
||||
);
|
||||
testWidgets('icon bounces once when the glass arrives and then rests', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(_dock());
|
||||
await tester.pumpAndSettle();
|
||||
final icon = find.byIcon(Icons.assignment_rounded);
|
||||
final rest = tester.getRect(icon);
|
||||
await tester.tap(icon);
|
||||
await tester.pump();
|
||||
var highest = rest.top;
|
||||
var widest = rest.width;
|
||||
for (var i = 0; i < 65; i++) {
|
||||
await tester.pump(const Duration(milliseconds: 16));
|
||||
final r = tester.getRect(icon);
|
||||
highest = math.min(highest, r.top);
|
||||
widest = math.max(widest, r.width);
|
||||
}
|
||||
expect(highest, lessThan(rest.top - 1));
|
||||
expect(widest, greaterThan(rest.width * 1.1));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getRect(icon).top, closeTo(rest.top, 0.05));
|
||||
expect(tester.getSize(icon).width, closeTo(rest.width, 0.05));
|
||||
});
|
||||
testWidgets('reduced motion snaps the cursor without oscillation', (
|
||||
tester,
|
||||
) async {
|
||||
@@ -173,6 +234,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
final lens = find.byType(GlassRefraction).last;
|
||||
final resting = tester.getSize(lens);
|
||||
final iconBefore = tester.getRect(find.byIcon(Icons.person_rounded));
|
||||
await tester.tap(find.byIcon(Icons.person_rounded));
|
||||
await tester.pump();
|
||||
final target = tester.getCenter(find.byIcon(Icons.person_rounded)).dx;
|
||||
@@ -180,6 +242,51 @@ void main() {
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(tester.getCenter(lens).dx, closeTo(target, 0.05));
|
||||
expect(tester.getSize(lens), resting);
|
||||
expect(tester.getRect(find.byIcon(Icons.person_rounded)), iconBefore);
|
||||
});
|
||||
testWidgets('hovering a dragged lens animates its icon before releasing', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(_dock());
|
||||
await tester.pumpAndSettle();
|
||||
final icon = find.byIcon(Icons.assignment_rounded);
|
||||
final y = tester.getCenter(icon).dy;
|
||||
final gesture = await tester.startGesture(
|
||||
tester.getCenter(find.byKey(const Key('dock-cursor'))),
|
||||
);
|
||||
await gesture.moveBy(const Offset(24, 0));
|
||||
await tester.pump();
|
||||
await gesture.moveBy(const Offset(86, 0));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 180));
|
||||
expect(tester.getCenter(icon).dy, lessThan(y - 1));
|
||||
await tester.pump(const Duration(milliseconds: 600));
|
||||
expect(tester.getCenter(icon).dy, closeTo(y, 0.1));
|
||||
await gesture.cancel();
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
testWidgets('releasing over an animating icon preserves its bounce', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(_dock());
|
||||
await tester.pumpAndSettle();
|
||||
final icon = find.byIcon(Icons.assignment_rounded);
|
||||
final gesture = await tester.startGesture(
|
||||
tester.getCenter(find.byKey(const Key('dock-cursor'))),
|
||||
);
|
||||
await gesture.moveBy(const Offset(24, 0));
|
||||
await tester.pump();
|
||||
await gesture.moveBy(const Offset(86, 0));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 180));
|
||||
final before = tester.getRect(icon);
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
final after = tester.getRect(icon);
|
||||
expect(after.top, closeTo(before.top, 0.1));
|
||||
expect(after.width, closeTo(before.width, 0.1));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
testWidgets(
|
||||
'changing reduced motion during a tap does not leave frozen deformation',
|
||||
|
||||
@@ -23,8 +23,8 @@ void main() {
|
||||
// while its original cool colour remains visible through the material.
|
||||
final red = _channel(pixels, 160, 43, 0);
|
||||
final green = _channel(pixels, 160, 43, 1);
|
||||
expect(red, greaterThan(45));
|
||||
expect(red, lessThan(90));
|
||||
expect(red, greaterThan(75));
|
||||
expect(red, lessThan(115));
|
||||
expect(green - red, closeTo(13, 6));
|
||||
},
|
||||
);
|
||||
@@ -85,11 +85,10 @@ void main() {
|
||||
final red = _channel(pixels, 16, 40, 0);
|
||||
final green = _channel(pixels, 16, 40, 1);
|
||||
final blue = _channel(pixels, 16, 40, 2);
|
||||
expect(red, lessThan(115));
|
||||
expect(green - red, greaterThanOrEqualTo(80));
|
||||
// The milky base and resting grey lens still transmit over half of the
|
||||
// cyan source's 210-level blue/red contrast rather than becoming opaque.
|
||||
expect(blue - red, greaterThan(105));
|
||||
expect(red, lessThan(125));
|
||||
expect(green - red, greaterThanOrEqualTo(65));
|
||||
// The thicker milky base still transmits a clear cyan colour difference.
|
||||
expect(blue - red, greaterThan(90));
|
||||
},
|
||||
);
|
||||
|
||||
@@ -133,8 +132,8 @@ void main() {
|
||||
reds.reduce((a, b) => a > b ? a : b) -
|
||||
reds.reduce((a, b) => a < b ? a : b);
|
||||
// The original stripes have 180 levels of contrast. Both the base and
|
||||
// selected lens retain over half, keeping these larger shapes readable.
|
||||
expect(contrast, greaterThan(90), reason: 'background at x=$start');
|
||||
// selected lens retain at least 40%, keeping larger shapes readable.
|
||||
expect(contrast, greaterThan(72), reason: 'background at x=$start');
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user