955f9b13c1
Task 9 (P3 plan): queue tab replaces the stub, continuous capture page enqueues per shot, album detail gains an upload FAB, and the upload engine lifecycle is now bound to the login session. - Engine scope: session account drives UploadEngine start/stop; wired from app boot, login success, logout, and 401 eviction. Tasks stay in the store across logout (accountId hard isolation). - Queue tab: album x state x time filter bar, task rows with thumbnail, state chip, localized error copy, attempt count, per-row progress via a broadcast progress hub, state-dependent actions (re-pick retry, retryNow, cancel, delete), batch retry bar, 200ms-debounced live refresh from drift table updates. - Capture page: camera preview via injected CaptureSource, one enqueue per shutter press, persistent album/category/badges overlay with a switch-only-affects-new-shots hint, gallery multi-pick, exit confirm while uploads are pending, permission-denied and init-failure views. - POST_NOTIFICATIONS runtime permission via a small MethodChannel (photolive/permissions) + PermissionPlugin.kt: single runtime permission need, avoids permission_handler dependency; requested once on first enqueue, silent degradation when denied or unavailable. - Album detail FAB: capture-and-upload / pick-from-gallery sheet. - l10n: ~50 new keys in zh/en arbs; tests: +45 (filter matrix, engine scope lifecycle, permission gate, queue tab, capture page, FAB entry); existing page tests updated to inject session/task-store fakes. Co-Authored-By: Claude Code <noreply@anthropic.com>
541 lines
12 KiB
Dart
541 lines
12 KiB
Dart
// ignore: unused_import
|
|
import 'package:intl/intl.dart' as intl;
|
|
import 'app_localizations.dart';
|
|
|
|
// ignore_for_file: type=lint
|
|
|
|
/// The translations for English (`en`).
|
|
class AppLocalizationsEn extends AppLocalizations {
|
|
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
|
|
|
@override
|
|
String get appName => 'Photo Live';
|
|
|
|
@override
|
|
String get login => 'Sign in';
|
|
|
|
@override
|
|
String get logout => 'Sign out';
|
|
|
|
@override
|
|
String get username => 'Account';
|
|
|
|
@override
|
|
String get password => 'Password';
|
|
|
|
@override
|
|
String get albums => 'Albums';
|
|
|
|
@override
|
|
String get albumDetail => 'Album details';
|
|
|
|
@override
|
|
String get queue => 'Upload queue';
|
|
|
|
@override
|
|
String get settings => 'Settings';
|
|
|
|
@override
|
|
String get language => 'Language';
|
|
|
|
@override
|
|
String get localeFollowSystem => 'Follow system';
|
|
|
|
@override
|
|
String get localeChinese => '中文';
|
|
|
|
@override
|
|
String get localeEnglish => 'English';
|
|
|
|
@override
|
|
String get retry => 'Retry';
|
|
|
|
@override
|
|
String get cancel => 'Cancel';
|
|
|
|
@override
|
|
String get errorGeneric => 'Something went wrong, please retry';
|
|
|
|
@override
|
|
String get ok => 'OK';
|
|
|
|
@override
|
|
String get homeTabAlbums => 'Albums';
|
|
|
|
@override
|
|
String get homeTabQueue => 'Queue';
|
|
|
|
@override
|
|
String get homeTabSettings => 'Settings';
|
|
|
|
@override
|
|
String get loginHint => 'Sign in with your staff account';
|
|
|
|
@override
|
|
String get fieldRequired => 'This field is required';
|
|
|
|
@override
|
|
String get passwordChangeTitle => 'Change password';
|
|
|
|
@override
|
|
String get currentPassword => 'Current password';
|
|
|
|
@override
|
|
String get newPassword => 'New password';
|
|
|
|
@override
|
|
String get confirmNewPassword => 'Confirm new password';
|
|
|
|
@override
|
|
String get passwordMinLength => 'New password must be at least 8 characters';
|
|
|
|
@override
|
|
String get passwordMismatch => 'New passwords do not match';
|
|
|
|
@override
|
|
String get passwordChangeSuccess => 'Password changed';
|
|
|
|
@override
|
|
String get errorAuthInvalidCredentials => 'Incorrect account or password';
|
|
|
|
@override
|
|
String get errorOldPasswordIncorrect => 'Current password is incorrect';
|
|
|
|
@override
|
|
String get errorAuthRateLimited =>
|
|
'Too many attempts. Please try again later';
|
|
|
|
@override
|
|
String get errorAuthTokenExpired => 'Session expired. Please sign in again';
|
|
|
|
@override
|
|
String get errorValidation => 'Invalid input. Please check and retry';
|
|
|
|
@override
|
|
String get errorNetwork => 'Network error. Check your connection and retry';
|
|
|
|
@override
|
|
String get errorNetworkTimeout => 'Network timed out. Please retry';
|
|
|
|
@override
|
|
String get errorInternal =>
|
|
'Service temporarily unavailable. Please retry later';
|
|
|
|
@override
|
|
String get albumsEmpty =>
|
|
'No albums yet. Tap \"Create album\" to get started';
|
|
|
|
@override
|
|
String get loadMoreFailed => 'Failed to load more. Tap to retry';
|
|
|
|
@override
|
|
String get albumCreate => 'Create album';
|
|
|
|
@override
|
|
String get albumEdit => 'Edit album';
|
|
|
|
@override
|
|
String get albumTitle => 'Title';
|
|
|
|
@override
|
|
String get albumDescription => 'Description';
|
|
|
|
@override
|
|
String get albumVenue => 'Venue';
|
|
|
|
@override
|
|
String get albumAddress => 'Address';
|
|
|
|
@override
|
|
String get albumDefaultLocale => 'Default locale';
|
|
|
|
@override
|
|
String get albumStartAt => 'Start time';
|
|
|
|
@override
|
|
String get albumEndAtOptional => 'End time (optional)';
|
|
|
|
@override
|
|
String get clearEndAt => 'Clear end time';
|
|
|
|
@override
|
|
String get albumTimezone => 'Timezone';
|
|
|
|
@override
|
|
String get albumTimezoneInvalid => 'Invalid IANA timezone name';
|
|
|
|
@override
|
|
String get switchUpload => 'Allow uploads';
|
|
|
|
@override
|
|
String get switchPublic => 'Publicly visible';
|
|
|
|
@override
|
|
String get switchDownload => 'Allow downloads';
|
|
|
|
@override
|
|
String get switchOriginalDownload => 'Allow original downloads';
|
|
|
|
@override
|
|
String get formStartAtRequired => 'Pick a start time';
|
|
|
|
@override
|
|
String get formDefaultLocaleMissing => 'Default locale must have a title';
|
|
|
|
@override
|
|
String get formTitleRequiredWithFields =>
|
|
'Title is required when description, venue or address is filled';
|
|
|
|
@override
|
|
String get formEndAtNotAfterStartAt => 'End time must be after start time';
|
|
|
|
@override
|
|
String get create => 'Create';
|
|
|
|
@override
|
|
String get save => 'Save';
|
|
|
|
@override
|
|
String get albumStatusActive => 'Active';
|
|
|
|
@override
|
|
String get albumStatusOffline => 'Offline';
|
|
|
|
@override
|
|
String get tagUpload => 'Upload';
|
|
|
|
@override
|
|
String get tagPublic => 'Public';
|
|
|
|
@override
|
|
String get tagDownload => 'Download';
|
|
|
|
@override
|
|
String get tagOriginal => 'Original';
|
|
|
|
@override
|
|
String get notSet => 'Not set';
|
|
|
|
@override
|
|
String get actionEdit => 'Edit';
|
|
|
|
@override
|
|
String get albumMembers => 'Members';
|
|
|
|
@override
|
|
String get albumCategories => 'Categories';
|
|
|
|
@override
|
|
String get shareQrTitle => 'Share QR code';
|
|
|
|
@override
|
|
String get albumPhotos => 'Photos';
|
|
|
|
@override
|
|
String get delete => 'Delete';
|
|
|
|
@override
|
|
String get deleteConfirmCategory =>
|
|
'Delete this category? Its photos will become uncategorized.';
|
|
|
|
@override
|
|
String get categoryEmpty => 'No categories yet. Tap + to add one';
|
|
|
|
@override
|
|
String get categoryAdd => 'Add category';
|
|
|
|
@override
|
|
String get categoryEdit => 'Edit category';
|
|
|
|
@override
|
|
String get categoryNameZh => 'Chinese name';
|
|
|
|
@override
|
|
String get categoryNameEn => 'English name';
|
|
|
|
@override
|
|
String get categorySortOrder => 'Sort order';
|
|
|
|
@override
|
|
String get categoryNameRequired => 'At least one language name is required';
|
|
|
|
@override
|
|
String get categorySortOrderInvalid => 'Sort order must be an integer';
|
|
|
|
@override
|
|
String get albumMembersEmpty => 'No members yet';
|
|
|
|
@override
|
|
String get inviteSearchHint =>
|
|
'Search by account prefix to invite (at least 2 characters)';
|
|
|
|
@override
|
|
String get inviteNoResults => 'No matching users';
|
|
|
|
@override
|
|
String get invite => 'Invite';
|
|
|
|
@override
|
|
String get memberInvited => 'Invited';
|
|
|
|
@override
|
|
String get removeMember => 'Remove member';
|
|
|
|
@override
|
|
String get removeMemberConfirm => 'Remove this member?';
|
|
|
|
@override
|
|
String get roleOwner => 'Owner';
|
|
|
|
@override
|
|
String get roleCollaborator => 'Collaborator';
|
|
|
|
@override
|
|
String get selfMarker => ' (you)';
|
|
|
|
@override
|
|
String get errorMemberConflict => 'User is already a member';
|
|
|
|
@override
|
|
String get qrHint => 'Scan the code or open the link to view';
|
|
|
|
@override
|
|
String get copyLink => 'Copy link';
|
|
|
|
@override
|
|
String get copiedToClipboard => 'Copied';
|
|
|
|
@override
|
|
String get photosTask9Placeholder =>
|
|
'Photo management is a placeholder; the full experience ships in Task 9';
|
|
|
|
@override
|
|
String get albumPhotosEmpty => 'No photos yet';
|
|
|
|
@override
|
|
String get visibilityPublished => 'Published';
|
|
|
|
@override
|
|
String get visibilityUnpublished => 'Unpublished';
|
|
|
|
@override
|
|
String get visibilityHidden => 'Hidden';
|
|
|
|
@override
|
|
String get visibilityDeleted => 'Deleted';
|
|
|
|
@override
|
|
String get procPendingUpload => 'Pending upload';
|
|
|
|
@override
|
|
String get procUploaded => 'Uploaded';
|
|
|
|
@override
|
|
String get procProcessing => 'Processing';
|
|
|
|
@override
|
|
String get procReady => 'Ready';
|
|
|
|
@override
|
|
String get procProcessingFailed => 'Processing failed';
|
|
|
|
@override
|
|
String get queueStubHint =>
|
|
'Local upload queue and continuous capture arrive in Task 9';
|
|
|
|
@override
|
|
String get serverHistoryEntry => 'View server upload history';
|
|
|
|
@override
|
|
String get serverHistoryTitle => 'Server upload history';
|
|
|
|
@override
|
|
String get serverHistoryBanner =>
|
|
'Server-side history (cross-device) — for this device\'s pending uploads see the Queue tab';
|
|
|
|
@override
|
|
String get serverHistoryEmpty => 'No upload sessions yet';
|
|
|
|
@override
|
|
String get uploadStatePending => 'Pending';
|
|
|
|
@override
|
|
String get uploadStateConfirmed => 'Confirmed';
|
|
|
|
@override
|
|
String get uploadStateCancelled => 'Cancelled';
|
|
|
|
@override
|
|
String get uploadStateExpired => 'Expired';
|
|
|
|
@override
|
|
String get thisDevice => 'This device';
|
|
|
|
@override
|
|
String get queueAlbumFilterAll => 'All albums';
|
|
|
|
@override
|
|
String get queueStateAll => 'All';
|
|
|
|
@override
|
|
String get queueStatePreparing => 'Preparing';
|
|
|
|
@override
|
|
String get queueStateQueued => 'Queued';
|
|
|
|
@override
|
|
String get queueStateUploading => 'Uploading';
|
|
|
|
@override
|
|
String get queueStateWaitingNetwork => 'Waiting for network';
|
|
|
|
@override
|
|
String get queueStateFailed => 'Failed';
|
|
|
|
@override
|
|
String get queueStateCompleted => 'Done';
|
|
|
|
@override
|
|
String get queueTimeAll => 'Any time';
|
|
|
|
@override
|
|
String get queueTimeToday => 'Today';
|
|
|
|
@override
|
|
String get queueTimeLast7Days => 'Last 7 days';
|
|
|
|
@override
|
|
String get queueTimeLast30Days => 'Last 30 days';
|
|
|
|
@override
|
|
String get queueEmpty => 'No upload tasks';
|
|
|
|
@override
|
|
String get queueRetryAllFailed => 'Retry all failed';
|
|
|
|
@override
|
|
String queueAttemptCount(int count) {
|
|
return '$count attempt(s)';
|
|
}
|
|
|
|
@override
|
|
String get taskStatePreparing => 'Preparing';
|
|
|
|
@override
|
|
String get taskStatePreparationFailed => 'Preparation failed';
|
|
|
|
@override
|
|
String get taskStateQueued => 'Queued';
|
|
|
|
@override
|
|
String get taskStateUploading => 'Uploading';
|
|
|
|
@override
|
|
String get taskStateUploadedConfirming => 'Confirming';
|
|
|
|
@override
|
|
String get taskStateCompleted => 'Completed';
|
|
|
|
@override
|
|
String get taskStateWaitingNetwork => 'Waiting for network';
|
|
|
|
@override
|
|
String get taskStateRetryableFailed => 'Upload failed';
|
|
|
|
@override
|
|
String get taskStateCancelled => 'Cancelled';
|
|
|
|
@override
|
|
String get errorPrepSourceUnreadable =>
|
|
'Could not read the selected photo. Please reselect';
|
|
|
|
@override
|
|
String get errorPrepUnsupportedType =>
|
|
'Only JPG, PNG and HEIC images are supported';
|
|
|
|
@override
|
|
String get errorPrepTooLarge => 'Photo exceeds the 50MB limit';
|
|
|
|
@override
|
|
String get errorPrepCopyFailed => 'Failed to copy the photo. Please retry';
|
|
|
|
@override
|
|
String get errorUploadSourceMissing =>
|
|
'Source file is missing. Please reselect';
|
|
|
|
@override
|
|
String get errorAlbumUploadDisabled => 'Album uploads are disabled';
|
|
|
|
@override
|
|
String get errorUploadSessionConflict =>
|
|
'Upload session conflict. Please retry';
|
|
|
|
@override
|
|
String get errorUploadVerifyFailed =>
|
|
'Upload verification failed. Will retry';
|
|
|
|
@override
|
|
String get captureTitle => 'Continuous capture';
|
|
|
|
@override
|
|
String get captureCategoryDefault => 'Default category';
|
|
|
|
@override
|
|
String get captureSwitchHint =>
|
|
'Switching only affects photos captured afterwards';
|
|
|
|
@override
|
|
String capturePendingBadge(int count) {
|
|
return 'Pending $count';
|
|
}
|
|
|
|
@override
|
|
String captureFailedBadge(int count) {
|
|
return 'Failed $count';
|
|
}
|
|
|
|
@override
|
|
String get capturePickFromGallery => 'Pick from gallery';
|
|
|
|
@override
|
|
String get captureShutter => 'Capture';
|
|
|
|
@override
|
|
String get captureExitTitle => 'Leave shooting?';
|
|
|
|
@override
|
|
String captureExitBody(int count) {
|
|
return '$count photo(s) are still uploading. Tasks will continue in the background after you leave.';
|
|
}
|
|
|
|
@override
|
|
String get captureKeepShooting => 'Keep shooting';
|
|
|
|
@override
|
|
String get captureExitConfirm => 'Leave';
|
|
|
|
@override
|
|
String get cameraPermissionDenied =>
|
|
'Camera unavailable. Allow camera access in system settings';
|
|
|
|
@override
|
|
String get cameraInitFailed => 'Camera failed to initialize';
|
|
|
|
@override
|
|
String get uploadActionCapture => 'Capture and upload';
|
|
|
|
@override
|
|
String get uploadActionPick => 'Pick from gallery';
|
|
|
|
@override
|
|
String get uploadAction => 'Upload';
|
|
|
|
@override
|
|
String uploadEnqueuedCount(int count) {
|
|
return 'Added $count photo(s) to the upload queue';
|
|
}
|
|
|
|
@override
|
|
String get uploadPickNone => 'No photos selected';
|
|
}
|