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>
This commit is contained in:
parent
ccdf22b936
commit
05db5e2f45
17 changed files with 425 additions and 217 deletions
|
|
@ -61,7 +61,7 @@ class const _TaskList({
|
|||
12,
|
||||
8,
|
||||
12,
|
||||
96 + FloatingNavigationBar.coverOf(context),
|
||||
96 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
if (description case final description? when !description.isBlank)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class const FiltersScreen({super.key}) extends StatelessWidget {
|
|||
12,
|
||||
8,
|
||||
12,
|
||||
16 + FloatingNavigationBar.coverOf(context),
|
||||
16 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
SectionCard(
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ class _MonthGridState() extends State<MonthGrid> {
|
|||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 88 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 88 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class _ProjectBoardState() extends State<ProjectBoard> {
|
|||
key: ProjectBoard.dotsKey,
|
||||
padding: EdgeInsets.only(
|
||||
top: 8,
|
||||
bottom: 8 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 8 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ class const ProjectTable({
|
|||
),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 88 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 88 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ class const ProjectTasks({required final String projectId, super.key})
|
|||
),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 88 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 88 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -374,7 +374,7 @@ class const ProjectTasks({required final String projectId, super.key})
|
|||
),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 88 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 88 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ class _ReportingScreenState() extends State<ReportingScreen> {
|
|||
12,
|
||||
8,
|
||||
12,
|
||||
24 + FloatingNavigationBar.coverOf(context),
|
||||
24 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
SegmentedButton<_Page>(
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class _SearchScreenState() extends State<SearchScreen> {
|
|||
),
|
||||
body: ListView(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 16 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 16 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
if (words.isEmpty)
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class _BrowseTabState() extends State<BrowseTab> {
|
|||
12,
|
||||
8,
|
||||
12,
|
||||
24 + FloatingNavigationBar.coverOf(context),
|
||||
24 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
SectionCard(
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ class _DayAgendaState() extends State<DayAgenda> {
|
|||
controller: _scroll,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 88 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 88 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ class _HourGridState() extends State<HourGrid> {
|
|||
key: HourGrid.hoursKey,
|
||||
controller: _scroll,
|
||||
padding: EdgeInsets.only(
|
||||
bottom: widget.foot + FloatingNavigationBar.coverOf(context),
|
||||
bottom: widget.foot + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 24 * _hourHeight,
|
||||
|
|
|
|||
|
|
@ -146,9 +146,9 @@ mixin PlanHost<T extends StatefulWidget> on State<T> {
|
|||
)
|
||||
: grid(_grid, 0);
|
||||
}
|
||||
// A phone's Plan over the hours' foot, above the floating bar; held
|
||||
// A phone's Plan over the hours' foot, above the navigation bar; held
|
||||
// rows lower it to its heading, the hours free behind it.
|
||||
final cover = FloatingNavigationBar.coverOf(context);
|
||||
final cover = FlushNavigationBar.coverOf(context);
|
||||
final height = constraints.maxHeight * 0.5;
|
||||
const heading = 56.0;
|
||||
// Back closes the Plan first, the navigation bar away meanwhile.
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class _PlanPanelState() extends State<PlanPanel> {
|
|||
)
|
||||
: ListView(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 16 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 16 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
for (final (group, title, tasks) in groups)
|
||||
|
|
|
|||
|
|
@ -58,10 +58,10 @@ class const TabScreen({
|
|||
// 2026).
|
||||
child: ScrollHidingFab(
|
||||
fab: switch (floatingActionButton) {
|
||||
// Clear of the navigation bar floating over the foot on a phone.
|
||||
// Clear of the navigation bar and its fade at the foot on a phone.
|
||||
final button? when !choosing => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: FloatingNavigationBar.coverOf(context),
|
||||
bottom: FlushNavigationBar.buttonLiftOf(context),
|
||||
),
|
||||
child: button,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class _TodayTabState() extends State<TodayTab> with PlanHost<TodayTab> {
|
|||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 88 + FloatingNavigationBar.coverOf(context),
|
||||
bottom: 88 + FlushNavigationBar.coverOf(context),
|
||||
),
|
||||
children: [
|
||||
if (overdue.isNotEmpty) ...[
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import 'package:material_ui/material_ui.dart';
|
|||
|
||||
/// The frame around Todo's tabs (ADR 0033, D1, D2): halkyon_ui's
|
||||
/// [NavigationFrame], as every Halkyon app's, with Inbox, Today, Upcoming
|
||||
/// and Browse (Today opening), a bar floating above the foot below medium windows and a rail
|
||||
/// and Browse (Today opening), a bar flush with the foot below medium windows and a rail
|
||||
/// with Todo's icon on top from medium on. Every tab keeps its own stack of
|
||||
/// screens. After an update, what's new shows once (halkyon_app's
|
||||
/// [WhatsNewOnUpdate]), where the app is given it.
|
||||
|
|
|
|||
|
|
@ -1835,8 +1835,8 @@ void main() {
|
|||
}
|
||||
|
||||
testWidgets("the hours run on down to the navigation bar, the day's "
|
||||
"end just above it, as Todoist's (the developer's review, 7 Nov "
|
||||
'2026)', (tester) async {
|
||||
"end just above it and its fade, as Todoist's (the developer's "
|
||||
'review, 7 Nov 2026)', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await threeDay(tester);
|
||||
final hours = find.descendant(
|
||||
|
|
@ -1848,7 +1848,9 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
|
||||
final today = Day.of(DateTime.now());
|
||||
final bar = tester.getTopLeft(find.byType(FloatingNavigationBar)).dy;
|
||||
final bar = tester
|
||||
.getTopLeft(find.byKey(FlushNavigationBar.fadeKey))
|
||||
.dy;
|
||||
expect(
|
||||
tester.getBottomLeft(find.byKey(HourGrid.columnKey(today))).dy,
|
||||
moreOrLessEquals(bar, epsilon: 1),
|
||||
|
|
|
|||
Loading…
Reference in a new issue