Refine milky Dock and refract symbols beneath the moving lens

This commit is contained in:
david1465833828
2026-10-28 17:56:40 +08:00
parent dc71e411e9
commit 23c1a58ca3
10 changed files with 351 additions and 160 deletions
+30
View File
@@ -11,6 +11,36 @@ import 'navigation_test.dart' show uiController;
void main() {
setUpAll(tzdata.initializeTimeZones);
testWidgets(
'moving lens refracts symbols above the icon row and releases cleanly',
(tester) async {
await tester.pumpWidget(_dock());
await tester.pumpAndSettle();
final optical = find.byKey(const ValueKey('dock-symbol-refraction'));
expect(optical, findsNothing);
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(54, 0));
await tester.pump(const Duration(milliseconds: 120));
expect(optical, findsOneWidget);
final filter = tester.widget<GlassRefraction>(
find.descendant(of: optical, matching: find.byType(GlassRefraction)),
);
expect(filter.strength, greaterThan(0.35));
expect(filter.blurSigma, 0); // Keep the transmitted symbols legible.
final stack = tester.widget<Stack>(
find.ancestor(of: optical, matching: find.byType(Stack)).first,
);
expect(stack.children.last.key, const ValueKey('dock-symbol-refraction'));
await gesture.up();
await tester.pumpAndSettle();
expect(optical, findsNothing);
expect(tester.takeException(), isNull);
},
);
testWidgets('edge overflow respects the actual dock parent and safe insets', (
tester,
) async {
+52
View File
@@ -9,6 +9,58 @@ import 'navigation_test.dart' show uiController;
void main() {
setUpAll(tzdata.initializeTimeZones);
testWidgets('only the selected tab is blue, including during glass travel', (
tester,
) async {
var selected = 0;
await tester.pumpWidget(
MaterialApp(
home: StatefulBuilder(
builder: (context, setState) => Scaffold(
body: Center(
child: GlassDock(
selectedIndex: selected,
onSelected: (index) => setState(() => selected = index),
),
),
),
),
),
);
Color colour(IconData icon) =>
tester.widget<Icon>(find.byIcon(icon)).color!;
void expectGrey(IconData icon) {
final value = colour(icon);
expect((value.r - value.b).abs(), lessThan(0.12));
expect(value.a, 1);
}
expect(colour(Icons.calendar_month_rounded), const Color(0xFF007AFF));
expectGrey(Icons.assignment_rounded);
expectGrey(Icons.person_rounded);
await tester.tap(find.byIcon(Icons.person_rounded));
await tester.pump();
// Colour follows the selected page, not whichever icon the lens crosses.
expect(colour(Icons.person_rounded), const Color(0xFF007AFF));
expectGrey(Icons.calendar_month_rounded);
await tester.pump(const Duration(milliseconds: 100));
expectGrey(Icons.assignment_rounded);
await tester.pumpAndSettle();
final gesture = await tester.startGesture(
tester.getCenter(find.byKey(const Key('dock-cursor'))),
);
await gesture.moveBy(const Offset(-20, 0));
await tester.pump();
await gesture.moveBy(const Offset(-90, 0));
await tester.pump(const Duration(milliseconds: 150));
expect(colour(Icons.person_rounded), const Color(0xFF007AFF));
expectGrey(Icons.assignment_rounded);
await gesture.up();
await tester.pumpAndSettle();
expect(selected, 1);
expect(colour(Icons.assignment_rounded), const Color(0xFF007AFF));
expectGrey(Icons.person_rounded);
});
testWidgets('dock drags switch tabs while body swipes only change week', (
tester,
) async {
+67 -3
View File
@@ -9,6 +9,42 @@ import 'package:hepan_everyday/widgets/glass_dock.dart';
import 'package:hepan_everyday/widgets/glass_refraction.dart';
void main() {
testWidgets(
'zero-blur glass bends an already-painted symbol without erasing it',
(tester) async {
final plain = await _render(
tester,
const GlassRefraction(
strength: 0,
blurSigma: 0,
child: SizedBox.expand(),
),
opticalSymbol: true,
);
final bent = await _render(
tester,
const GlassRefraction(
strength: 0.52,
blurSigma: 0,
child: SizedBox.expand(),
),
opticalSymbol: true,
);
var changed = 0, plainBlue = 0, bentBlue = 0;
for (var y = 16; y < 50; y++) {
for (var x = 5; x < 52; x++) {
final before = _channel(plain, x, y, 0);
final after = _channel(bent, x, y, 0);
if ((before - after).abs() > 20) changed++;
if (_channel(plain, x, y, 2) - before > 100) plainBlue++;
if (_channel(bent, x, y, 2) - after > 100) bentBlue++;
}
}
expect(changed, greaterThan(20));
expect(bentBlue, greaterThan(plainBlue * 0.7));
},
skip: !ui.ImageFilter.isShaderFilterSupported,
);
testWidgets(
'Dock has a milky white body while transmitting a dark backdrop',
(tester) async {
@@ -23,8 +59,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(50));
expect(red, lessThan(80));
expect(red, greaterThan(75));
expect(red, lessThan(112));
expect(green - red, closeTo(13, 6));
},
);
@@ -190,6 +226,7 @@ Future<ByteData> _render(
Offset offset = Offset.zero,
Color backdropColor = const Color(0xFF14B4E6),
bool held = false,
bool opticalSymbol = false,
}) async {
tester.view.physicalSize = const Size(800, 600);
tester.view.devicePixelRatio = 1;
@@ -217,6 +254,7 @@ Future<ByteData> _render(
gradient,
stripeWidth,
backdropColor,
opticalSymbol,
),
),
),
@@ -303,14 +341,40 @@ Future<ByteData> _render(
}
class _Backdrop extends CustomPainter {
const _Backdrop(this.stripes, this.gradient, this.stripeWidth, this.colour);
const _Backdrop(
this.stripes,
this.gradient,
this.stripeWidth,
this.colour,
this.opticalSymbol,
);
final bool stripes;
final bool gradient;
final double stripeWidth;
final Color colour;
final bool opticalSymbol;
@override
void paint(Canvas canvas, Size size) {
if (opticalSymbol) {
canvas.drawRect(Offset.zero & size, Paint()..color = Colors.white);
canvas.drawRRect(
RRect.fromRectAndRadius(
const Rect.fromLTWH(10, 20, 28, 25),
const Radius.circular(3),
),
Paint()..color = const Color(0xFF007AFF),
);
for (var row = 0; row < 2; row++) {
for (var col = 0; col < 3; col++) {
canvas.drawRect(
Rect.fromLTWH(15 + col * 7, 26 + row * 8, 4, 4),
Paint()..color = Colors.white,
);
}
}
return;
}
if (gradient) {
for (var x = 0; x < size.width; x++) {
canvas.drawRect(