feat(ui): tabs folding into the title, in Learn's and Train's Profile (ADR 0030, D60)

halkyon_ui's FoldingTabs: the tab row under the app bar's title at the
top, scrolling away with the content, the chosen tab's name then small
under the title, which, tapped, scrolls back up to the row, as Strava's.
Learn's Profile (Profile, Statistics) is built on it, and Train's
Profile in tabs: Progress (your body, the last 12 weeks, this year),
Days, and Plans where the device doesn't record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-31 19:12:11 +01:00
commit 581cf1f1cd
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -15,7 +15,8 @@ import 'package:material_ui/material_ui.dart';
/// The profile tab, in two tabs as Vaia has it (decided 2026-10-12): the
/// profile (the ways the person signs in, SimpleLogin, ADR 0020, and their
/// password and authenticators, ADR 0017) and the person's statistics.
/// Settings are behind the gear.
/// Settings are behind the gear. The tab row folds into the title as the
/// content scrolls ([FoldingTabs], as Strava's).
class const ProfileScreen({super.key}) extends StatelessWidget {
@override
Widget build(BuildContext context) {
@ -26,38 +27,24 @@ class const ProfileScreen({super.key}) extends StatelessWidget {
child: TopGradient(
color: Brand.primary,
background: Theme.of(context).colorScheme.surfaceContainerLow,
child: DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.transparent,
systemOverlayStyle: TopGradient.overlayStyle(context),
title: Text(l10n.profileTitle),
actions: [
IconButton(
icon: const WaitingAccountsBadge(
child: SyncTroubleBadge(
child: Icon(LucideIcons.settings),
),
),
tooltip: l10n.profileSettingsTooltip,
onPressed: () => context.push(RoutePaths.settings),
),
const SizedBox(width: 4),
],
bottom: TabBar(
isScrollable: true,
tabAlignment: TabAlignment.start,
dividerColor: Colors.transparent,
tabs: [
Tab(text: l10n.profileTabProfile),
Tab(text: l10n.profileTabStatistics),
],
child: FoldingTabs(
title: l10n.profileTitle,
actions: [
IconButton(
icon: const WaitingAccountsBadge(
child: SyncTroubleBadge(child: Icon(LucideIcons.settings)),
),
tooltip: l10n.profileSettingsTooltip,
onPressed: () => context.push(RoutePaths.settings),
),
body: const TabBarView(children: [_Account(), StatisticsView()]),
),
],
tabs: [
FoldingTab(label: l10n.profileTabProfile, body: const _Account()),
FoldingTab(
label: l10n.profileTabStatistics,
body: const StatisticsView(),
),
],
),
),
);