import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:halkyon_app/l10n/halkyon_app_localizations.dart'; import 'package:halkyon_app/src/agent/widget/agents_section.dart'; import 'package:halkyon_app/src/app/app_scope.dart'; import 'package:halkyon_app/src/auth/bloc/sign_in_ways_cubit.dart'; import 'package:halkyon_app/src/password/widget/account_security_section.dart'; import 'package:halkyon_app/src/profile/widget/public_profile_section.dart'; import 'package:halkyon_app/src/simplelogin/widget/simplelogin_section.dart'; import 'package:halkyon_ui/halkyon_ui.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import 'package:material_ui/material_ui.dart'; /// Every Halkyon app's Profile (decided 2026-11-02, the developer's wish /// for one profile in function and look across the apps): the person's /// own tab first, the same in every app (their account and the ways they /// sign in, SimpleLogin and the password with its authenticators, then the /// app's own [sections], then the public profile others see, one for all /// apps), and after it the app's own [tabs] (Learn's statistics, Train's /// progress). With several tabs, the tab row folds into the title as the /// content scrolls ([FoldingTabs], as Strava's); with none of the app's, /// the person's tab alone, under the title. The [actions] stand in the app /// bar (the app's Settings); the app's colour washes down from the top /// ([TopGradient], [color], into [background]). class const HalkyonProfile({ final List actions = const [], final List sections = const [], final List tabs = const [], final Color? color, final Color? background, super.key, }) extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = HalkyonAppLocalizations.of(context); final mine = _Mine(sections: sections); return BlocProvider( create: (context) => SignInWaysCubit(AppScope.of(context).auth)..load(), child: TopGradient( color: color, background: background ?? Theme.of(context).colorScheme.surface, child: tabs.isEmpty ? Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( backgroundColor: Colors.transparent, systemOverlayStyle: TopGradient.overlayStyle(context), title: Text(l10n.profileTitle), actions: actions, ), body: mine, ) : FoldingTabs( title: l10n.profileTitle, actions: actions, tabs: [ FoldingTab(label: l10n.profileTabProfile, body: mine), ...tabs, ], ), ), ); } } /// The person's own tab: a card for each part, as Settings groups its own, /// in the middle and as wide as readable text. class const _Mine({required final List sections}) extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = HalkyonAppLocalizations.of(context); return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: readableContentMaxWidth), child: ListView( // Room at the end for the navigation bar and its fade at the foot. padding: EdgeInsets.fromLTRB( 12, 12, 12, 12 + FlushNavigationBar.coverOf(context), ), children: [ SectionCard( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( l10n.profileAccount, style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 4), Text(l10n.profileIdentified), const _SignInWays(), ], ), ), for (final section in sections) ...[ const SizedBox(height: 12), SectionCard(child: section), ], const SizedBox(height: 12), const SectionCard(child: PublicProfileSection()), // The person's agents (Halkyon's ADR 0044, D45), where the // instance offers them: a card of its own, or nothing. const AgentsSection(), ], ), ), ); } } /// How the person signs in: an email address, and SimpleLogin (Halkyon /// Learn's ADR 0020, D21), with the password and authenticators beneath. class const _SignInWays() extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = HalkyonAppLocalizations.of(context); final theme = Theme.of(context); final ways = context.watch().state; Widget way(String label, String linkedAs) => ListTile( contentPadding: EdgeInsets.zero, title: Text(label), subtitle: Text(linkedAs, maxLines: 1, overflow: TextOverflow.ellipsis), trailing: Icon(LucideIcons.circleCheck, color: theme.colorScheme.primary), ); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 16), Text(l10n.profileSignInWays, style: theme.textTheme.titleSmall), if (ways.ways.email) way(l10n.profileWayEmail, ways.emailAddress ?? l10n.profileWayLinked), // SimpleLogin (ADR 0020, D21): once added, one more way in here. const SimpleLoginSection(gapAbove: 16), const SizedBox(height: 16), // The password and authenticators, and setting them up (ADR 0017), // which brings the address. const AccountSecuritySection(), ], ); } }