refactor(halkyon_app): the account section, About, the language and countries' names, shared
What Learn and Todo each held now comes from halkyon_app: - AccountTiles: whose account on which instance, switching, signing out (asking first for an anonymous account, as it deletes it) and deleting it (asking first), the app's own words passed in. - showAppAbout: the app's name, version, icon and legalese as it gives them, the source of what the instance runs (AppDependencies gains sourceCodeUrl), the app's own parts, the licence list. - resolveAppLocale: the first preferred language the app speaks, never by country alone, British English otherwise. - AssetCountryNames, the default of InstanceGate and InstanceScope: Unicode CLDR 48.2's territory names in English and German (tool/country_names.py, 7.6 KB), Hong Kong, Macao, Myanmar and Palestine by their short names as Learn's world map has them, so Todo says "Germany (EU)" where it said "DE (EU)". Learn's texts read as before in every language; its About bloc and gateway, its country names from the world map and the keys only the moved code used are gone, as are Todo's copies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
65c5cd740d
commit
87500b7c6b
1 changed files with 1001 additions and 834 deletions
120
packages/halkyon_app/lib/src/auth/widget/account_tiles.dart
Normal file
120
packages/halkyon_app/lib/src/auth/widget/account_tiles.dart
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:halkyon_app/l10n/halkyon_app_localizations.dart';
|
||||
import 'package:halkyon_app/src/app/app_scope.dart';
|
||||
import 'package:halkyon_app/src/auth/bloc/session_bloc.dart';
|
||||
import 'package:halkyon_app/src/instance/instance_scope.dart';
|
||||
import 'package:halkyon_app/src/instance/widget/account_switcher_sheet.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
/// The account in use, as an app's settings show it (decided 2026-10-16):
|
||||
/// whose it is, anonymous or signed in, on which instance; switching to the
|
||||
/// account on another instance, where the device keeps accounts on several
|
||||
/// ([InstanceScope]); signing out, which of an anonymous account deletes it
|
||||
/// and so asks first; deleting it, after asking. What only the app can say,
|
||||
/// it gives: what an anonymous account keeps on the device, and what signing
|
||||
/// out of one and deleting the account take with them.
|
||||
class const AccountTiles({
|
||||
/// Under an anonymous account: what it keeps on this device ("Progress is
|
||||
/// saved on this device. Sign in to keep it."); none where null.
|
||||
final String? anonymousNote,
|
||||
|
||||
/// What signing out of an anonymous account takes with it, as the
|
||||
/// question before asks.
|
||||
required final String signOutAnonymousMessage,
|
||||
|
||||
/// What deleting the account takes with it, as the question before asks.
|
||||
required final String deleteMessage,
|
||||
super.key,
|
||||
}) extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = HalkyonAppLocalizations.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final identified = switch (context.watch<SessionBloc>().state) {
|
||||
SessionStateActive(:final person) => person.isIdentified,
|
||||
_ => false,
|
||||
};
|
||||
final instances = InstanceScope.maybeOf(context);
|
||||
final instance =
|
||||
instances?.choice.current?.name ??
|
||||
AppScope.of<AppDependencies<Disposable>>(context).serverName;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
identified ? LucideIcons.userCheck : LucideIcons.userRound,
|
||||
),
|
||||
title: Text(
|
||||
identified
|
||||
? l10n.accountSignedInOn(instance)
|
||||
: l10n.accountAnonymousOn(instance),
|
||||
),
|
||||
subtitle: switch (anonymousNote) {
|
||||
final note? when !identified => Text(note),
|
||||
_ => null,
|
||||
},
|
||||
),
|
||||
// The accounts on this device, one per instance.
|
||||
if (instances != null)
|
||||
ListTile(
|
||||
leading: const Icon(LucideIcons.users),
|
||||
title: Text(l10n.accountSwitch),
|
||||
subtitle: Text(instances.choice.current?.name ?? ''),
|
||||
onTap: () => showAccountSwitcher(context),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(LucideIcons.logOut),
|
||||
title: Text(l10n.accountSignOut),
|
||||
onTap: () => _signOut(context),
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(LucideIcons.trash2, color: theme.colorScheme.error),
|
||||
title: Text(
|
||||
l10n.accountDelete,
|
||||
style: TextStyle(color: theme.colorScheme.error),
|
||||
),
|
||||
onTap: () => _delete(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Signs out; an anonymous account can't be signed into again, so signing
|
||||
/// out of one deletes it, and asks first. The app then asks how to start.
|
||||
Future<void> _signOut(BuildContext context) async {
|
||||
final l10n = HalkyonAppLocalizations.of(context);
|
||||
final session = context.read<SessionBloc>();
|
||||
final identified = switch (session.state) {
|
||||
SessionStateActive(:final person) => person.isIdentified,
|
||||
_ => false,
|
||||
};
|
||||
if (!identified &&
|
||||
!await confirmDestructiveAction(
|
||||
context,
|
||||
title: l10n.accountSignOutTitle,
|
||||
message: signOutAnonymousMessage,
|
||||
confirmLabel: l10n.accountSignOut,
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
session.add(const SessionEventSignOutRequested());
|
||||
}
|
||||
|
||||
/// Deletes the account with everything in it, after asking.
|
||||
Future<void> _delete(BuildContext context) async {
|
||||
final l10n = HalkyonAppLocalizations.of(context);
|
||||
final session = context.read<SessionBloc>();
|
||||
if (await confirmDestructiveAction(
|
||||
context,
|
||||
title: l10n.accountDeleteTitle,
|
||||
message: deleteMessage,
|
||||
confirmLabel: l10n.accountDelete,
|
||||
)) {
|
||||
session.add(const SessionEventDeleteRequested());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue