Switch to Inter, round the corners softly and make the nav switch tabs

Inter replaces General Sans (Inter Display for titles and big numbers).
Corners come back from before the squaring commit, scaled to a soft set
(16 cards, 14 buttons, 12 rows, 8 chips) and applied to the screens built
since. The nav is now a cluster of round frosted buttons that switches
Today, Routines, Goals, Groups and Progress in place inside Home: no
pushed pages, no back arrows, and Android back returns to Today.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
This commit is contained in:
alvocool
2026-11-09 07:08:46 +03:00
parent add94f621c
commit d3431ca5de
54 changed files with 736 additions and 518 deletions

View File

@@ -1,125 +1,100 @@
import 'package:flutter/material.dart';
import '../about/internal/application/TextType.dart';
import '../utils/Colors.dart';
import 'GlassSurface.dart';
import 'text/Text.dart';
typedef NavEntry = ({IconData icon, String label, VoidCallback onTap});
/// The floating tab bar: the selected tab is a filled night block, the rest
/// sit quietly on white. An optional dark action button can sit beside it.
/// The floating tab bar: a cluster of round frosted buttons, icons only.
/// The open tab rises out of the row as a solid white disc. It switches tabs
/// in place; nothing here pushes a page.
class FloatingNav extends StatelessWidget {
final List<NavEntry> entries;
final int selected;
final IconData? actionIcon;
final VoidCallback? onAction;
const FloatingNav({
super.key,
required this.entries,
required this.selected,
this.actionIcon,
this.onAction,
});
static const double _size = 58;
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 14),
child: Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.zero,
boxShadow: const [
BoxShadow(
color: Color(0x1A1A1F1C),
blurRadius: 30,
offset: Offset(0, 10),
),
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Center(
child: Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(_size)),
boxShadow: [
BoxShadow(
color: Color(0x1F1A1F1C),
blurRadius: 30,
offset: Offset(0, 12),
),
],
),
child: GlassSurface(
radius: const BorderRadius.all(Radius.circular(_size)),
tint: colorGlass,
padding: const EdgeInsets.all(5),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
for (int index = 0; index < entries.length; index++) ...[
if (index > 0) const SizedBox(width: 4),
_button(entries[index], index == selected),
],
),
child: GlassSurface(
radius: BorderRadius.zero,
tint: colorGlassStrong,
padding: const EdgeInsets.all(6),
child: Row(
children: [
for (int index = 0; index < entries.length; index++)
Expanded(child: _tab(entries[index], index == selected)),
],
),
),
],
),
),
if (onAction != null) ...[
const SizedBox(width: 10),
GestureDetector(
onTap: onAction,
child: Container(
width: 72,
height: 72,
decoration: BoxDecoration(
gradient: const RadialGradient(
center: Alignment(-0.3, -0.4),
colors: <Color>[colorNightGlow, colorNight],
),
border: Border.all(color: colorWhite, width: 3),
boxShadow: const [
BoxShadow(
color: Color(0x331A1F1C),
blurRadius: 24,
offset: Offset(0, 10),
),
],
),
child: Icon(actionIcon, size: 24, color: colorLime),
),
),
],
],
),
),
),
);
}
Widget _tab(NavEntry entry, bool active) {
return GestureDetector(
onTap: entry.onTap,
behavior: HitTestBehavior.opaque,
child: AnimatedContainer(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: active ? colorHeaderBottom : colorWhite.withValues(alpha: 0.0),
borderRadius: BorderRadius.zero,
boxShadow: active
? const [
BoxShadow(
color: Color(0x141A1F1C),
blurRadius: 12,
offset: Offset(0, 4),
),
]
: const [],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(entry.icon,
size: 23, color: active ? colorWhite : colorInkSoft),
const SizedBox(height: 4),
text(entry.label, 10, active ? TextType.Medium : TextType.Regular,
color: active ? colorWhite : colorInkSoft, maxLines: 1),
],
Widget _button(NavEntry entry, bool active) {
return Semantics(
button: true,
selected: active,
label: entry.label,
child: Tooltip(
message: entry.label,
child: GestureDetector(
onTap: entry.onTap,
behavior: HitTestBehavior.opaque,
child: AnimatedContainer(
duration: const Duration(milliseconds: 220),
curve: Curves.easeOutCubic,
width: _size,
height: _size,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: active ? colorWhite : colorWhite.withValues(alpha: 0.35),
border: Border.all(
color: colorWhite.withValues(alpha: active ? 1 : 0.6),
width: 1,
),
boxShadow: active
? const [
BoxShadow(
color: Color(0x261A1F1C),
blurRadius: 16,
offset: Offset(0, 6),
),
]
: const [],
),
child: Icon(entry.icon,
size: 22, color: active ? colorInk : colorInkSoft),
),
),
),
);