halkyon_app: instances, sign-in and sync plumbing for Halkyon's apps
What every Halkyon app's shell needs, taken from Halkyon Learn's and set on halkyon_base's client: the instances a device keeps an account on, the first start's tiles and where an instance keeps people's data, the account switcher; signing in anonymously, with GitHub or an email code, switching person and the start screen; the gates that build an app's dependencies per instance and per person; and the sync service with its status, Settings card and banner. Texts of its own in English and German take the app's name; what only the app can say, it passes in. Fakes for apps' tests are in testing.dart. An instance's basics now name the app it serves (`app`, set by the host's configuration), and an app accepts only an instance of its own. SerialQueue and CoalescingRunner move into halkyon_core. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
af1de799f4
commit
e23cc77f7c
1 changed files with 10761 additions and 10 deletions
201
packages/halkyon_app/lib/l10n/halkyon_app_en.arb
Normal file
201
packages/halkyon_app/lib/l10n/halkyon_app_en.arb
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
{
|
||||
"@@locale": "en",
|
||||
"tryAgain": "Try again",
|
||||
"instanceWelcome": "Welcome to {app}",
|
||||
"@instanceWelcome": {
|
||||
"description": "Screen readers hear it for the wordmark on the first start.",
|
||||
"placeholders": {
|
||||
"app": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceBuiltInTagline": "Comes with the app",
|
||||
"instanceAnother": "Another instance",
|
||||
"instanceAnotherTagline": "Enter its address",
|
||||
"instanceAddress": "Instance address",
|
||||
"instanceAddressInvalid": "This isn't an address.",
|
||||
"instanceAddressRequired": "Enter the address of an instance.",
|
||||
"instanceContinue": "Continue",
|
||||
"instanceUnreachable": "No instance of {app} answers at {name}.",
|
||||
"@instanceUnreachable": {
|
||||
"placeholders": {
|
||||
"app": {
|
||||
"type": "String"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceUseBuiltIn": "Use {name}",
|
||||
"@instanceUseBuiltIn": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceOpenFailed": "Couldn't open the app on {name}.",
|
||||
"@instanceOpenFailed": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceDataAndBackupsIn": "Data and backups: {place}",
|
||||
"@instanceDataAndBackupsIn": {
|
||||
"placeholders": {
|
||||
"place": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceDataIn": "Data: {place}",
|
||||
"@instanceDataIn": {
|
||||
"placeholders": {
|
||||
"place": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceBackupsIn": "Backups: {place}",
|
||||
"@instanceBackupsIn": {
|
||||
"placeholders": {
|
||||
"place": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"instanceNoBackups": "No backups",
|
||||
"instanceEuropeanUnion": "European Union",
|
||||
"accountsTitle": "Accounts",
|
||||
"accountAdd": "Add account",
|
||||
"accountAddSubtitle": "Choose the instance for the account to add.",
|
||||
"accountSignedIn": "Signed in",
|
||||
"accountAnonymous": "Anonymous",
|
||||
"accountRemoveTooltip": "Remove account",
|
||||
"accountRemoveTitle": "Remove account?",
|
||||
"accountRemoveMessage": "Removes the account on {name} from this device, with all the device holds of it. What it synced stays on {name}: sign in there again to have it. An anonymous account can't be signed into again.",
|
||||
"@accountRemoveMessage": {
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"accountRemoveConfirm": "Remove",
|
||||
"sessionUnreachable": "Couldn't reach the server.",
|
||||
"personDataFailed": "Couldn't open this device's data.",
|
||||
"startSignedOut": "Signed out",
|
||||
"startOn": "Start on {instance}:",
|
||||
"@startOn": {
|
||||
"placeholders": {
|
||||
"instance": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"startWithGitHub": "Sign in with GitHub",
|
||||
"startWithEmail": "Continue with email",
|
||||
"startWithoutAccount": "Start without an account",
|
||||
"startAnonymous": "Progress is saved on this device. Sign in to keep it.",
|
||||
"startGitHubFailed": "Couldn't sign in with GitHub.",
|
||||
"startNoGitHubAccount": "No account here signs in with this GitHub account yet. Start without an account, then add GitHub in Profile.",
|
||||
"startOtherInstance": "Use another instance",
|
||||
"emailSignInTitle": "Continue with email",
|
||||
"emailSignInIntro": "We mail you a code to sign in. This instance keeps only a fingerprint of your address, never the address itself, and writes to it only when you ask for a code.",
|
||||
"emailSignInAddress": "Email address",
|
||||
"emailSignInSend": "Send code",
|
||||
"emailSignInCodeSent": "We mailed a code to {address}. It's valid for 15 minutes.",
|
||||
"@emailSignInCodeSent": {
|
||||
"placeholders": {
|
||||
"address": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"emailSignInResent": "A new code is on its way.",
|
||||
"emailSignInCode": "Code",
|
||||
"emailSignInContinue": "Continue",
|
||||
"emailSignInResend": "Send a new code",
|
||||
"emailSignInOtherAddress": "Use another address",
|
||||
"emailSignInSwitchTitle": "Switch to the account of {address}?",
|
||||
"@emailSignInSwitchTitle": {
|
||||
"placeholders": {
|
||||
"address": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"emailSignInSwitchConfirm": "Switch",
|
||||
"emailSignInSwitchStay": "Stay anonymous",
|
||||
"emailSignInTaken": "{address} already signs in to another account. To switch to it, sign out first.",
|
||||
"@emailSignInTaken": {
|
||||
"placeholders": {
|
||||
"address": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"emailSignInUnavailable": "This instance doesn't offer signing in with email.",
|
||||
"emailSignInNotAnAddress": "This isn't an email address.",
|
||||
"emailSignInTooManyCodes": "Too many codes in the last hour. Try again later.",
|
||||
"emailSignInWrongCode": "That code isn't right.",
|
||||
"emailSignInTooManyTries": "Too many wrong codes. Ask for a new one.",
|
||||
"emailSignInCodeExpired": "This code is no longer valid. Ask for a new one.",
|
||||
"emailSignInOtherAddressLinked": "You already sign in with another address.",
|
||||
"emailSignInMailFailed": "The instance couldn't send the mail. Try again later.",
|
||||
"emailSignInFailed": "Couldn't reach the instance. Try again.",
|
||||
"syncTitle": "Sync",
|
||||
"syncNow": "Sync now",
|
||||
"syncStateSyncing": "Syncing…",
|
||||
"syncStateSynced": "Everything synced",
|
||||
"syncStateFailing": "Sync is failing",
|
||||
"syncStateNotYet": "Not synced yet",
|
||||
"syncStateMismatch": "This app can't sync with {server}",
|
||||
"@syncStateMismatch": {
|
||||
"placeholders": {
|
||||
"server": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"syncMismatchDetail": "Update the app. If it is up to date, the server needs an update. What you do meanwhile stays on this device and syncs afterwards.",
|
||||
"syncLastCompleted": "Last completed at {time}",
|
||||
"@syncLastCompleted": {
|
||||
"placeholders": {
|
||||
"time": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"syncLastFailed": "Last attempt failed at {time}",
|
||||
"@syncLastFailed": {
|
||||
"placeholders": {
|
||||
"time": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"syncNoRunYet": "No sync has completed since the app started",
|
||||
"syncPending": "{count, plural, =1{1 change waits to sync} other{{count} changes wait to sync}}",
|
||||
"@syncPending": {
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"syncTroubleLabel": "Sync needs attention",
|
||||
"syncMismatchBanner": "This app can't sync with {server} any more. Update it to keep syncing.",
|
||||
"@syncMismatchBanner": {
|
||||
"placeholders": {
|
||||
"server": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"syncMismatchMore": "More"
|
||||
}
|
||||
Reference in a new issue