feat(app,learn,todo): the operator's "This instance" card, screen and badge (ADR 0021, step 1)

Whoever operates the instance approves, refuses and suspends accounts
and names other operators in the app (D21 to D24, D34):

- halkyon_app: InstanceOperatorRepository on
  ServerpodInstanceOperatorGateway (the module's instanceOperator
  endpoint; refusals as OperatorFailed: notFound, isOperator,
  lastOperator, notAllowed for 401 and 403, failed), in AppDependencies.
  OperatingCubit counts the accounts that wait: asked as the person's
  app opens, after every change, and every 5 minutes only while they
  operate the instance, so nobody else's app keeps asking.
  InstanceOperatorCard (or its tiles) and WaitingAccountsBadge show
  nothing at all for anyone else. InstanceOperatorScreen, laid out as
  Settings: the accounts that wait, each showing its four words to read
  out before Approve (D33), Refuse for new ones after asking; who
  operates, Take back after asking, the last always kept; Name an
  operator by handle; Find an account by the start of its handle, with
  Suspend after asking and Name as operator. English and German texts
  ("Admin" as the role word in German).
- Learn: the card right after the Sync card in Settings, which the
  cogs' count leads to as their dot leads to Sync; the count on the
  Settings cogs of Home and Profile.
- Todo: the tiles in the account sheet and the count on its button.
  Todo's server is a member, whose `operating()` is always null, so
  nothing shows there until it holds the register.

Tests: the gateway's mapping, the repository, both cubits with their
denials, the card, the badge and the screen; Learn's Settings shows the
card and the count to an operator and neither to anyone else.

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-25 15:55:28 +01:00
commit 31b9c17850
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -803,7 +803,7 @@ class HalkyonAppLocalizationsEn extends HalkyonAppLocalizations {
@override
String get signUpsTooManyWaiting =>
'As many new accounts wait for approval as may. Try again later.';
'Too many new accounts already wait for approval. Try again later.';
@override
String get passwordUnsafeCosts =>
@ -1151,6 +1151,138 @@ class HalkyonAppLocalizationsEn extends HalkyonAppLocalizations {
@override
String get simpleLoginAdded => 'SimpleLogin added.';
@override
String get operatorTitle => 'This instance';
@override
String get operatorAccounts => 'Accounts and operators';
@override
String operatorWaitingCount(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count accounts wait for approval',
one: '1 account waits for approval',
zero: 'Nobody waits for approval',
);
return '$_temp0';
}
@override
String get operatorWaitingTitle => 'Waiting';
@override
String get operatorNobodyWaits => 'Nobody waits.';
@override
String get operatorNoHandle => 'No handle yet';
@override
String operatorNewSince(String date) {
return 'New, waiting since $date';
}
@override
String operatorSuspendedSince(String date) {
return 'Suspended since $date';
}
@override
String get operatorApproveNote =>
'Read them these four words, and approve only once they confirm these are on their screen.';
@override
String get operatorApprove => 'Approve';
@override
String get operatorRefuse => 'Refuse';
@override
String get operatorRefuseTitle => 'Refuse this account?';
@override
String get operatorRefuseMessage =>
'It is deleted with everything it has. They can sign up again.';
@override
String get operatorOperatorsTitle => 'Operators';
@override
String get operatorTakeBack => 'Take back';
@override
String get operatorTakeBackTitle => 'Take back the role?';
@override
String get operatorTakeBackMessage =>
'They keep their account, but no longer approve, refuse or suspend accounts here.';
@override
String get operatorAppoint => 'Name an operator';
@override
String get operatorAppointMessage =>
'They approve, refuse and suspend accounts here, and name operators, as you do.';
@override
String get operatorAppointConfirm => 'Name';
@override
String get operatorHandle => 'Handle';
@override
String get operatorFindTitle => 'Find an account';
@override
String get operatorFoundNone => 'No account\'s handle starts like this.';
@override
String operatorMadeOn(String date) {
return 'Since $date';
}
@override
String get operatorIsOperator => 'Operator';
@override
String get operatorIsWaiting => 'Waiting';
@override
String get operatorIsSuspended => 'Suspended';
@override
String get operatorSuspend => 'Suspend';
@override
String get operatorSuspendTitle => 'Suspend this account?';
@override
String get operatorSuspendMessage =>
'They are signed out everywhere and can\'t sign in until you approve them again. Nothing they have is deleted.';
@override
String get operatorMakeOperator => 'Name as operator';
@override
String get operatorNotFound =>
'That account isn\'t there any more, or doesn\'t wait.';
@override
String get operatorIsOperatorProblem =>
'An operator can\'t be suspended. Take back their role first.';
@override
String get operatorLastOperator =>
'The instance needs at least one operator.';
@override
String get operatorNotAllowed =>
'Only the instance\'s operators can do this.';
@override
String get operatorFailed => 'That didn\'t work. Try again.';
}
/// The translations for English, as used in the United Kingdom (`en_GB`).