2026-10-30 23:52:39 +01:00
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
|
|
import 'package:halkyon_ui/halkyon_ui.dart';
|
|
|
|
|
|
import 'package:material_ui/material_ui.dart';
|
|
|
|
|
|
|
|
|
|
|
|
import '../support/test_app.dart';
|
|
|
|
|
|
|
|
|
|
|
|
/// Every Halkyon app's frame around its tabs: a rail with the app's icon
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
/// from medium windows on, a flush bar below with a fade above it, a tick on every choice.
|
2026-10-30 23:52:39 +01:00
|
|
|
|
void main() {
|
|
|
|
|
|
/// A 1 × 1 PNG, the app's icon in these tests.
|
|
|
|
|
|
final icon = MemoryImage(
|
|
|
|
|
|
Uint8List.fromList(const [
|
|
|
|
|
|
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, //
|
|
|
|
|
|
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
|
|
|
|
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00,
|
|
|
|
|
|
0x0B, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9C, 0x63, 0x60, 0x00, 0x02, 0x00,
|
|
|
|
|
|
0x00, 0x05, 0x00, 0x01, 0x7A, 0x5E, 0xAB, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
|
0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82,
|
|
|
|
|
|
]),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/// The frame in a window [width] wide, on tab [selected]; the tabs chosen
|
|
|
|
|
|
/// go into [chosen].
|
|
|
|
|
|
Future<void> show(
|
|
|
|
|
|
WidgetTester tester, {
|
|
|
|
|
|
required double width,
|
|
|
|
|
|
required List<int> chosen,
|
|
|
|
|
|
int selected = 1,
|
|
|
|
|
|
}) async {
|
|
|
|
|
|
tester.view.physicalSize = Size(width, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
2026-10-30 23:52:39 +01:00
|
|
|
|
selectedIndex: selected,
|
|
|
|
|
|
onSelected: chosen.add,
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
(label: 'Profile', icon: Icon(Icons.person), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: const Scaffold(body: Text('The tab')),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// The ticks the platform was asked for while [act] ran.
|
|
|
|
|
|
Future<List<Object?>> ticks(
|
|
|
|
|
|
WidgetTester tester,
|
|
|
|
|
|
Future<void> Function() act,
|
|
|
|
|
|
) async {
|
|
|
|
|
|
final haptics = <Object?>[];
|
|
|
|
|
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
|
|
|
|
SystemChannels.platform,
|
|
|
|
|
|
(call) async {
|
|
|
|
|
|
if (call.method == 'HapticFeedback.vibrate') {
|
|
|
|
|
|
haptics.add(call.arguments);
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
addTearDown(
|
|
|
|
|
|
() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
|
|
|
|
|
|
SystemChannels.platform,
|
|
|
|
|
|
null,
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await act();
|
|
|
|
|
|
return haptics;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
testWidgets('below medium windows, a bar stands at the foot', (
|
2026-10-30 23:52:39 +01:00
|
|
|
|
tester,
|
|
|
|
|
|
) async {
|
|
|
|
|
|
await show(tester, width: 400, chosen: []);
|
|
|
|
|
|
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
expect(find.byType(FlushNavigationBar), findsOneWidget);
|
2026-10-30 23:52:39 +01:00
|
|
|
|
expect(find.byType(NavigationRail), findsNothing);
|
|
|
|
|
|
expect(find.text('The tab'), findsOneWidget);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
testWidgets('below medium windows, the bar is flush with the foot: as wide '
|
|
|
|
|
|
"as the window, 64 high above the system's bar, in the theme's colour", (
|
|
|
|
|
|
tester,
|
|
|
|
|
|
) async {
|
|
|
|
|
|
tester.view.padding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.viewPadding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
await show(tester, width: 400, chosen: []);
|
|
|
|
|
|
|
|
|
|
|
|
final bar = find.byType(NavigationBar);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.getRect(bar),
|
|
|
|
|
|
const Rect.fromLTRB(0, 800 - 64 - 24, 400, 800),
|
|
|
|
|
|
);
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
final colour = find.descendant(
|
|
|
|
|
|
of: find.byKey(FlushNavigationBar.barKey),
|
|
|
|
|
|
matching: find.byType(ColoredBox),
|
|
|
|
|
|
);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.widget<ColoredBox>(colour.first).color,
|
|
|
|
|
|
Theme.of(tester.element(bar)).colorScheme.surfaceContainer,
|
|
|
|
|
|
);
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('right above the bar, a fade into the background of the screen '
|
|
|
|
|
|
'in view, which taps pass through to the screen', (tester) async {
|
|
|
|
|
|
tester.view.padding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.viewPadding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
var tapped = 0;
|
|
|
|
|
|
const background = Color(0xFFFFE4C4);
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: TopGradient(
|
|
|
|
|
|
background: background,
|
|
|
|
|
|
child: GestureDetector(
|
|
|
|
|
|
behavior: HitTestBehavior.opaque,
|
|
|
|
|
|
onTap: () => tapped++,
|
|
|
|
|
|
child: const SizedBox.expand(),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
final fade = find.byKey(FlushNavigationBar.fadeKey);
|
|
|
|
|
|
final bar = tester.getRect(find.byType(NavigationBar));
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.getRect(fade),
|
|
|
|
|
|
Rect.fromLTRB(0, bar.top - FlushNavigationBar.fadeHeight, 400, bar.top),
|
|
|
|
|
|
);
|
|
|
|
|
|
final gradient =
|
|
|
|
|
|
(tester.widget<DecoratedBox>(fade).decoration as BoxDecoration)
|
|
|
|
|
|
.gradient!
|
|
|
|
|
|
as LinearGradient;
|
|
|
|
|
|
expect(gradient.colors, [background.withValues(alpha: 0), background]);
|
|
|
|
|
|
|
|
|
|
|
|
await tester.tapAt(tester.getCenter(fade));
|
|
|
|
|
|
expect(tapped, 1);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('before a screen claims its background, the fade ends in the '
|
|
|
|
|
|
"theme's surface, light and dark", (tester) async {
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
for (final brightness in Brightness.values) {
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
brightness: brightness,
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: const Scaffold(body: Text('The tab')),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
final fade = find.byKey(FlushNavigationBar.fadeKey);
|
|
|
|
|
|
final surface = Theme.of(tester.element(fade)).colorScheme.surface;
|
|
|
|
|
|
final gradient =
|
|
|
|
|
|
(tester.widget<DecoratedBox>(fade).decoration as BoxDecoration)
|
|
|
|
|
|
.gradient!
|
|
|
|
|
|
as LinearGradient;
|
|
|
|
|
|
expect(gradient.colors.last, surface, reason: '$brightness');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-11-10 00:18:44 +01:00
|
|
|
|
/// A tab's screen with a floating button, which paints the fade above
|
|
|
|
|
|
/// the bar itself ([FrameFade]); its content's room in [cover].
|
|
|
|
|
|
Widget fadingScreen({
|
|
|
|
|
|
void Function(double cover)? cover,
|
|
|
|
|
|
Key? key,
|
|
|
|
|
|
bool resizes = true,
|
|
|
|
|
|
}) => Builder(
|
|
|
|
|
|
builder: (context) => Scaffold(
|
|
|
|
|
|
key: key,
|
|
|
|
|
|
extendBody: true,
|
|
|
|
|
|
resizeToAvoidBottomInset: resizes,
|
|
|
|
|
|
floatingActionButtonLocation: FrameFade.buttonLocation(context),
|
|
|
|
|
|
body: Builder(
|
|
|
|
|
|
builder: (context) {
|
|
|
|
|
|
cover?.call(FlushNavigationBar.coverOf(context));
|
|
|
|
|
|
return ListView(
|
|
|
|
|
|
key: const Key('tab'),
|
|
|
|
|
|
children: [
|
|
|
|
|
|
for (var i = 0; i < 30; i++)
|
|
|
|
|
|
SizedBox(height: 60, child: Text('Row $i')),
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
floatingActionButton: FloatingActionButton(
|
|
|
|
|
|
onPressed: () {},
|
|
|
|
|
|
child: const Icon(Icons.add),
|
|
|
|
|
|
),
|
|
|
|
|
|
bottomNavigationBar: const FrameFade(),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/// The frame on a phone 400 × 800 with a system bar 24 high, around
|
|
|
|
|
|
/// [child].
|
|
|
|
|
|
Future<void> showPhone(WidgetTester tester, Widget child, {Widget? status}) {
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
tester.view.padding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.viewPadding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
2026-11-10 00:18:44 +01:00
|
|
|
|
return tester.pumpWidget(
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
2026-11-10 00:18:44 +01:00
|
|
|
|
status: status,
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
2026-11-10 00:18:44 +01:00
|
|
|
|
child: child,
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
2026-11-10 00:18:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// The fades painting: the frame's, or the screens'.
|
|
|
|
|
|
Finder fades() => find.byKey(FlushNavigationBar.fadeKey);
|
|
|
|
|
|
|
|
|
|
|
|
/// Whether the fade painting is the screen's own, beneath its button.
|
|
|
|
|
|
bool screenFades(WidgetTester tester) => find
|
|
|
|
|
|
.descendant(of: find.byType(FrameFade), matching: fades())
|
|
|
|
|
|
.evaluate()
|
|
|
|
|
|
.isNotEmpty;
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets("a tab's content leaves room for the bar, its fade and the "
|
|
|
|
|
|
"system's bar, running on beneath them; its floating button stands 16 "
|
|
|
|
|
|
'above the bar, over the fade, which the screen paints beneath it (the '
|
|
|
|
|
|
"developer's review, 9 Nov 2026)", (tester) async {
|
|
|
|
|
|
late double cover;
|
|
|
|
|
|
await showPhone(tester, fadingScreen(cover: (room) => cover = room));
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(cover, FlushNavigationBar.fadeHeight + 64 + 24);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.getBottomLeft(find.byKey(const Key('tab'))).dy,
|
|
|
|
|
|
800,
|
|
|
|
|
|
reason: 'the content runs on beneath the fade and the bar',
|
|
|
|
|
|
);
|
2026-11-10 00:18:44 +01:00
|
|
|
|
final bar = tester.getRect(find.byKey(FlushNavigationBar.barKey));
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.getRect(find.byType(FloatingActionButton)).bottom,
|
|
|
|
|
|
bar.top - 16,
|
|
|
|
|
|
);
|
|
|
|
|
|
expect(fades(), findsOneWidget, reason: 'one fade, not two');
|
|
|
|
|
|
expect(screenFades(tester), isTrue);
|
|
|
|
|
|
expect(tester.getRect(fades()).bottom, bar.top);
|
|
|
|
|
|
expect(tester.getRect(fades()).height, FlushNavigationBar.fadeHeight);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('the keyboard leaves the button where it stands on a screen '
|
|
|
|
|
|
"that doesn't make way for it (Todo's)", (tester) async {
|
|
|
|
|
|
await showPhone(tester, fadingScreen(resizes: false));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
final before = tester.getRect(find.byType(FloatingActionButton));
|
|
|
|
|
|
|
|
|
|
|
|
tester.view.viewInsets = const FakeViewPadding(bottom: 300);
|
|
|
|
|
|
addTearDown(tester.view.resetViewInsets);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(tester.getRect(find.byType(FloatingActionButton)), before);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets("a screen without its own fade keeps the frame's", (
|
|
|
|
|
|
tester,
|
|
|
|
|
|
) async {
|
|
|
|
|
|
await showPhone(tester, const Scaffold(body: Text('The tab')));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(fades(), findsOneWidget);
|
|
|
|
|
|
expect(screenFades(tester), isFalse);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('a menu or a dialog over the screen leaves its fade the '
|
|
|
|
|
|
"screen's, beneath its button", (tester) async {
|
|
|
|
|
|
await showPhone(
|
|
|
|
|
|
tester,
|
|
|
|
|
|
Builder(
|
|
|
|
|
|
builder: (context) => Scaffold(
|
|
|
|
|
|
extendBody: true,
|
|
|
|
|
|
body: Center(
|
|
|
|
|
|
child: TextButton(
|
|
|
|
|
|
onPressed: () => showDialog<void>(
|
|
|
|
|
|
context: context,
|
|
|
|
|
|
builder: (context) => const AlertDialog(content: Text('Hi')),
|
|
|
|
|
|
),
|
|
|
|
|
|
child: const Text('Ask'),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
floatingActionButton: FloatingActionButton(
|
|
|
|
|
|
onPressed: () {},
|
|
|
|
|
|
child: const Icon(Icons.add),
|
|
|
|
|
|
),
|
|
|
|
|
|
floatingActionButtonLocation: FrameFade.buttonLocation(context),
|
|
|
|
|
|
bottomNavigationBar: const FrameFade(),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
await tester.tap(find.text('Ask'));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(find.text('Hi'), findsOneWidget);
|
|
|
|
|
|
expect(fades(), findsOneWidget);
|
|
|
|
|
|
expect(screenFades(tester), isTrue);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('a page over the screen in its tab without a fade of its own '
|
|
|
|
|
|
"has the frame's, and back the screen's returns", (tester) async {
|
|
|
|
|
|
final tab = GlobalKey<NavigatorState>();
|
|
|
|
|
|
await showPhone(
|
|
|
|
|
|
tester,
|
|
|
|
|
|
Navigator(
|
|
|
|
|
|
key: tab,
|
|
|
|
|
|
onGenerateRoute: (_) =>
|
|
|
|
|
|
MaterialPageRoute<void>(builder: (context) => fadingScreen()),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
expect(screenFades(tester), isTrue);
|
|
|
|
|
|
|
|
|
|
|
|
tab.currentState!.push(
|
|
|
|
|
|
MaterialPageRoute<void>(
|
|
|
|
|
|
builder: (context) => const Scaffold(body: Text('Inside')),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
expect(find.text('Inside'), findsOneWidget);
|
|
|
|
|
|
expect(fades(), findsOneWidget);
|
|
|
|
|
|
expect(screenFades(tester), isFalse);
|
|
|
|
|
|
|
|
|
|
|
|
tab.currentState!.pop();
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
expect(fades(), findsOneWidget);
|
|
|
|
|
|
expect(screenFades(tester), isTrue);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('with a status above the bar, the fade and the button stand '
|
|
|
|
|
|
'above it', (tester) async {
|
|
|
|
|
|
await showPhone(
|
|
|
|
|
|
tester,
|
|
|
|
|
|
fadingScreen(),
|
|
|
|
|
|
status: const SizedBox(height: 40, child: Text('Recording')),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
final status = tester.getRect(find.text('Recording'));
|
|
|
|
|
|
expect(tester.getRect(fades()).bottom, lessThanOrEqualTo(status.top));
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
expect(
|
|
|
|
|
|
tester.getRect(find.byType(FloatingActionButton)).bottom,
|
2026-11-10 00:18:44 +01:00
|
|
|
|
lessThanOrEqualTo(tester.getRect(fades()).bottom - 16),
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('from medium windows on, a screen with its own fade paints '
|
|
|
|
|
|
'none, as there is no bar', (tester) async {
|
|
|
|
|
|
tester.view.physicalSize = const Size(1000, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
|
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
|
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: fadingScreen(),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
);
|
2026-11-10 00:18:44 +01:00
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(fades(), findsNothing);
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
});
|
|
|
|
|
|
|
fix(ui): on a phone, a snack bar stands above the screen's floating button
Below medium windows the frame's scaffold showed the screens' snack bars,
under the floating button of the screen's own scaffold, so a tap on a
snack bar's Undo hit the button instead (found 9 Nov 2026, Todo's Undo
after deleting the completed tasks). The screens get a messenger of their
own there, and their scaffolds lift the snack bars above their buttons, as
Material places them. From medium windows on the frame's scaffold still
shows them, once: a messenger shows a snack bar on each of its scaffolds
not inside another, as two panes side by side are. As the window grows
past a phone's, the phone's snack bars go, since a scaffold whose
messenger changes keeps the one it showed for good.
Whats-New: On a phone, a message's Undo is no longer hidden under the + button.
Whats-New-De: Auf dem Handy liegt das Rückgängig einer Meldung nicht mehr unter der +-Schaltfläche.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-09 23:12:29 +01:00
|
|
|
|
testWidgets("a screen's snack bar stands above its floating button, so "
|
|
|
|
|
|
'the button never takes its Undo (found 9 Nov 2026)', (tester) async {
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
var undone = 0;
|
|
|
|
|
|
var added = 0;
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
|
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
|
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: Builder(
|
|
|
|
|
|
builder: (context) => Scaffold(
|
|
|
|
|
|
body: Center(
|
|
|
|
|
|
child: TextButton(
|
|
|
|
|
|
onPressed: () => showUndoSnackBar(
|
|
|
|
|
|
context,
|
|
|
|
|
|
message: 'Task completed',
|
|
|
|
|
|
onUndo: () => undone++,
|
|
|
|
|
|
),
|
|
|
|
|
|
child: const Text('Complete'),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
2026-11-10 00:18:44 +01:00
|
|
|
|
extendBody: true,
|
|
|
|
|
|
floatingActionButtonLocation: FrameFade.buttonLocation(context),
|
|
|
|
|
|
floatingActionButton: FloatingActionButton(
|
|
|
|
|
|
onPressed: () => added++,
|
|
|
|
|
|
child: const Icon(Icons.add),
|
fix(ui): on a phone, a snack bar stands above the screen's floating button
Below medium windows the frame's scaffold showed the screens' snack bars,
under the floating button of the screen's own scaffold, so a tap on a
snack bar's Undo hit the button instead (found 9 Nov 2026, Todo's Undo
after deleting the completed tasks). The screens get a messenger of their
own there, and their scaffolds lift the snack bars above their buttons, as
Material places them. From medium windows on the frame's scaffold still
shows them, once: a messenger shows a snack bar on each of its scaffolds
not inside another, as two panes side by side are. As the window grows
past a phone's, the phone's snack bars go, since a scaffold whose
messenger changes keeps the one it showed for good.
Whats-New: On a phone, a message's Undo is no longer hidden under the + button.
Whats-New-De: Auf dem Handy liegt das Rückgängig einer Meldung nicht mehr unter der +-Schaltfläche.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-09 23:12:29 +01:00
|
|
|
|
),
|
2026-11-10 00:18:44 +01:00
|
|
|
|
bottomNavigationBar: const FrameFade(),
|
fix(ui): on a phone, a snack bar stands above the screen's floating button
Below medium windows the frame's scaffold showed the screens' snack bars,
under the floating button of the screen's own scaffold, so a tap on a
snack bar's Undo hit the button instead (found 9 Nov 2026, Todo's Undo
after deleting the completed tasks). The screens get a messenger of their
own there, and their scaffolds lift the snack bars above their buttons, as
Material places them. From medium windows on the frame's scaffold still
shows them, once: a messenger shows a snack bar on each of its scaffolds
not inside another, as two panes side by side are. As the window grows
past a phone's, the phone's snack bars go, since a scaffold whose
messenger changes keeps the one it showed for good.
Whats-New: On a phone, a message's Undo is no longer hidden under the + button.
Whats-New-De: Auf dem Handy liegt das Rückgängig einer Meldung nicht mehr unter der +-Schaltfläche.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-09 23:12:29 +01:00
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.text('Complete'));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.getRect(find.text('Undo')).bottom,
|
|
|
|
|
|
lessThanOrEqualTo(
|
|
|
|
|
|
tester.getRect(find.byType(FloatingActionButton)).top,
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.tap(find.text('Undo'));
|
|
|
|
|
|
expect((undone, added), (1, 0));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets("a screen's snack bar shown on a phone doesn't stay once the "
|
|
|
|
|
|
'window grows past it', (tester) async {
|
|
|
|
|
|
final screens = GlobalKey();
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
|
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
|
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
// The screens keep their state as the frame's layout changes, as an
|
|
|
|
|
|
// app's router keeps its navigator by its key.
|
|
|
|
|
|
child: KeyedSubtree(
|
|
|
|
|
|
key: screens,
|
|
|
|
|
|
child: Builder(
|
|
|
|
|
|
builder: (context) => Scaffold(
|
|
|
|
|
|
body: Center(
|
|
|
|
|
|
child: TextButton(
|
|
|
|
|
|
onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
|
|
const SnackBar(content: Text('Archived')),
|
|
|
|
|
|
),
|
|
|
|
|
|
child: const Text('Archive'),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.tap(find.text('Archive'));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
expect(find.text('Archived'), findsOneWidget);
|
|
|
|
|
|
|
|
|
|
|
|
tester.view.physicalSize = const Size(1200, 800);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
await tester.pump(const Duration(seconds: 5));
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
expect(find.text('Archived'), findsNothing);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
testWidgets("outside the frame, content leaves room for the system's bar "
|
|
|
|
|
|
'alone', (tester) async {
|
|
|
|
|
|
tester.view.padding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.viewPadding = const FakeViewPadding(bottom: 24);
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
late double cover;
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
Scaffold(
|
|
|
|
|
|
body: Builder(
|
|
|
|
|
|
builder: (context) {
|
|
|
|
|
|
cover = FlushNavigationBar.coverOf(context);
|
|
|
|
|
|
return const SizedBox.expand();
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
expect(cover, 24);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-10-30 23:52:39 +01:00
|
|
|
|
testWidgets("from medium windows on, a rail with the app's icon on top, "
|
|
|
|
|
|
'which leads to the first tab', (tester) async {
|
|
|
|
|
|
final chosen = <int>[];
|
|
|
|
|
|
await show(tester, width: 800, chosen: chosen);
|
|
|
|
|
|
|
|
|
|
|
|
expect(find.byType(NavigationRail), findsOneWidget);
|
|
|
|
|
|
expect(find.byType(NavigationBar), findsNothing);
|
|
|
|
|
|
expect(find.bySemanticsLabel('Halkyon Test'), findsOneWidget);
|
|
|
|
|
|
|
|
|
|
|
|
await tester.tap(find.byTooltip('Home'));
|
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
expect(chosen, [0]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('every choice on the bar ticks, lightly', (tester) async {
|
|
|
|
|
|
final chosen = <int>[];
|
|
|
|
|
|
await show(tester, width: 400, chosen: chosen);
|
|
|
|
|
|
final haptics = await ticks(tester, () async {
|
|
|
|
|
|
await tester.tap(find.text('Profile'));
|
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
expect(haptics, ['HapticFeedbackType.selectionClick']);
|
|
|
|
|
|
expect(chosen, [2]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('every choice on the rail ticks, lightly', (tester) async {
|
|
|
|
|
|
final chosen = <int>[];
|
|
|
|
|
|
await show(tester, width: 800, chosen: chosen);
|
|
|
|
|
|
final haptics = await ticks(tester, () async {
|
|
|
|
|
|
await tester.tap(find.text('Maps'));
|
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
expect(haptics, ['HapticFeedbackType.selectionClick']);
|
|
|
|
|
|
expect(chosen, [1]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('the window crossing from compact to medium and back swaps '
|
|
|
|
|
|
'the bar for the rail', (tester) async {
|
|
|
|
|
|
await show(tester, width: 400, chosen: []);
|
|
|
|
|
|
for (final width in const [800.0, 400.0]) {
|
|
|
|
|
|
tester.view.physicalSize = Size(width, 800);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
expect(find.byType(FlushNavigationBar), findsOneWidget);
|
2026-10-30 23:52:39 +01:00
|
|
|
|
expect(find.text('The tab'), findsOneWidget);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
testWidgets('the bar steps aside where a screen has a bar of its own, '
|
|
|
|
|
|
"leaving the system's bar its room", (tester) async {
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
tester.view.padding = const FakeViewPadding(bottom: 24);
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
tester.view.viewPadding = const FakeViewPadding(bottom: 24);
|
2026-10-30 23:52:39 +01:00
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
2026-10-30 23:52:39 +01:00
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
hidesNavigationBar: true,
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: const Scaffold(body: Text('The tab')),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
|
expect(find.byType(FlushNavigationBar), findsNothing);
|
2026-10-30 23:52:39 +01:00
|
|
|
|
expect(tester.getBottomLeft(find.byType(Scaffold).last).dy, 800 - 24);
|
|
|
|
|
|
});
|
2026-10-31 12:12:55 +01:00
|
|
|
|
|
|
|
|
|
|
testWidgets('a status stands above the bar below medium windows, and at '
|
|
|
|
|
|
"the foot of the screen's panel from there on", (tester) async {
|
|
|
|
|
|
for (final width in const [400.0, 800.0]) {
|
|
|
|
|
|
tester.view.physicalSize = Size(width, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
await tester.pumpWidget(
|
|
|
|
|
|
testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
2026-10-31 12:12:55 +01:00
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
status: const Text('Recording'),
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: const Scaffold(body: Text('The tab')),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
|
|
|
|
|
|
|
|
final status = tester.getBottomLeft(find.text('Recording')).dy;
|
|
|
|
|
|
final tab = tester.getTopLeft(find.text('The tab')).dy;
|
|
|
|
|
|
expect(status, greaterThan(tab), reason: '$width');
|
|
|
|
|
|
if (width < 600) {
|
|
|
|
|
|
expect(
|
|
|
|
|
|
status,
|
|
|
|
|
|
lessThan(tester.getTopLeft(find.byType(NavigationBar)).dy),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
fix(learn,ui): the open assistant field holds still: no flicker, no sliding away, no resizing under the keyboard (ADR 0021, D69)
Inside a studyset the field flickered as it opened and closed: the
floating location switched between a raised centre and the centre,
which Scaffold animates by scaling the button out and in. It keeps one
location now, raised above the licence line by padding. While open it
no longer slides away as the studyset or the Library scrolls
(ScrollHidingFab.pinned, new), and the keyboard covers Home, the
Library, a studyset and a session rather than shrinking them; the field
lifts itself by as much of the keyboard as reaches above it.
NavigationFrame no longer resizes for the keyboard itself, leaving it
to each tab's own scaffold, which still does by default (Todo's,
Train's and Meditate's tests pass unchanged).
Whats-New: Inside a studyset, the question field opens without flickering, stays while you scroll, and the screen no longer jumps when the keyboard comes.
Whats-New-De: In einem Lernset öffnet sich das Fragefeld ohne Flackern, bleibt beim Scrollen stehen, und der Bildschirm springt nicht mehr, wenn die Tastatur kommt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 21:15:48 +01:00
|
|
|
|
|
|
|
|
|
|
testWidgets("the keyboard leaves the frame's tab its size: the tab's own "
|
|
|
|
|
|
'screen decides whether it makes way, as one with a field floating '
|
|
|
|
|
|
"over it doesn't", (tester) async {
|
|
|
|
|
|
tester.view.physicalSize = const Size(400, 800);
|
|
|
|
|
|
tester.view.devicePixelRatio = 1;
|
|
|
|
|
|
addTearDown(tester.view.reset);
|
|
|
|
|
|
Widget frame({required bool screenResizes}) => testApp(
|
|
|
|
|
|
NavigationFrame(
|
|
|
|
|
|
appName: 'Halkyon Test',
|
|
|
|
|
|
icon: icon,
|
feat(ui,learn,todo,train,meditate): a wave in the app's colour over the navigation bar
The developer's choice of 7 Nov 2026 (the mockup's variant E): a tap on
another destination sends a radial glow in the app's colour over the bar
from that destination's centre, solid to 35 % of its radius and gone at
70 %, growing to cover the bar (cubic(.2, .7, .2, 1)) while it fades from
half its strength in dark mode and a third in light, over 1.2 s, behind
the destinations and clipped to the bar. None for the destination already
chosen, none with animations off, and none for a tab changed without a
tap (a link, back): the wave answers the finger. The destination chosen
takes the app's colour, its indicator tinted 22 % with it, without
Material's ripple or the indicator growing; the bar's top corners are
rounded, 20 dp, the screen showing through them.
Each app gives the frame its colour (NavigationFrame's accent, from
PaletteColor): Learn's purple, its icon's last colour, Todo's strawberry,
Train's carrot and Meditate's fern, their screens' wash.
For trying it on a phone, a debug build's Settings has a section
Navigation bar (debug), halkyon_ui's NavigationBarDebugSection, switching
live, in memory alone: the variant (A Material only, C the wave with
Material's fill, E without it, F without the indicator too), the wave's
time (0.7 to 2 s) and the corners (0 to 28 dp). Release builds never read
it and show shippingNavigationBarStyle, the debug section's start: to
remove it, delete the section from the four Settings screens and
debugNavigationBarStyle, and let effectiveNavigationBarStyle return the
shipping style.
Whats-New: Tapping a tab sends a soft wave in the app's colour across the navigation bar, now with rounded corners.
Whats-New-De: Ein Tipp auf einen Tab schickt eine sanfte Welle in der Farbe der App über die Navigationsleiste, jetzt mit abgerundeten Ecken.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:29:14 +01:00
|
|
|
|
accent: const Color(0xFFEC3E7C),
|
fix(learn,ui): the open assistant field holds still: no flicker, no sliding away, no resizing under the keyboard (ADR 0021, D69)
Inside a studyset the field flickered as it opened and closed: the
floating location switched between a raised centre and the centre,
which Scaffold animates by scaling the button out and in. It keeps one
location now, raised above the licence line by padding. While open it
no longer slides away as the studyset or the Library scrolls
(ScrollHidingFab.pinned, new), and the keyboard covers Home, the
Library, a studyset and a session rather than shrinking them; the field
lifts itself by as much of the keyboard as reaches above it.
NavigationFrame no longer resizes for the keyboard itself, leaving it
to each tab's own scaffold, which still does by default (Todo's,
Train's and Meditate's tests pass unchanged).
Whats-New: Inside a studyset, the question field opens without flickering, stays while you scroll, and the screen no longer jumps when the keyboard comes.
Whats-New-De: In einem Lernset öffnet sich das Fragefeld ohne Flackern, bleibt beim Scrollen stehen, und der Bildschirm springt nicht mehr, wenn die Tastatur kommt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-04 21:15:48 +01:00
|
|
|
|
selectedIndex: 0,
|
|
|
|
|
|
onSelected: (_) {},
|
|
|
|
|
|
destinations: const [
|
|
|
|
|
|
(label: 'Home', icon: Icon(Icons.home), selectedIcon: null),
|
|
|
|
|
|
(label: 'Maps', icon: Icon(Icons.map), selectedIcon: null),
|
|
|
|
|
|
],
|
|
|
|
|
|
child: Scaffold(
|
|
|
|
|
|
resizeToAvoidBottomInset: screenResizes,
|
|
|
|
|
|
body: const SizedBox.expand(key: Key('tab')),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
await tester.pumpWidget(frame(screenResizes: false));
|
|
|
|
|
|
final before = tester.getSize(find.byKey(const Key('tab')));
|
|
|
|
|
|
|
|
|
|
|
|
tester.view.viewInsets = const FakeViewPadding(bottom: 300);
|
|
|
|
|
|
addTearDown(tester.view.resetViewInsets);
|
|
|
|
|
|
await tester.pump();
|
|
|
|
|
|
expect(tester.getSize(find.byKey(const Key('tab'))), before);
|
|
|
|
|
|
|
|
|
|
|
|
await tester.pumpWidget(frame(screenResizes: true));
|
|
|
|
|
|
expect(
|
|
|
|
|
|
tester.getSize(find.byKey(const Key('tab'))).height,
|
|
|
|
|
|
lessThan(before.height),
|
|
|
|
|
|
reason: 'a screen that resizes still makes way',
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
2026-10-30 23:52:39 +01:00
|
|
|
|
}
|