feat(mobile): upload queue ui and continuous capture page
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>
This commit is contained in:
@@ -117,5 +117,60 @@
|
||||
"uploadStateConfirmed": "Confirmed",
|
||||
"uploadStateCancelled": "Cancelled",
|
||||
"uploadStateExpired": "Expired",
|
||||
"thisDevice": "This device"
|
||||
"thisDevice": "This device",
|
||||
"queueAlbumFilterAll": "All albums",
|
||||
"queueStateAll": "All",
|
||||
"queueStatePreparing": "Preparing",
|
||||
"queueStateQueued": "Queued",
|
||||
"queueStateUploading": "Uploading",
|
||||
"queueStateWaitingNetwork": "Waiting for network",
|
||||
"queueStateFailed": "Failed",
|
||||
"queueStateCompleted": "Done",
|
||||
"queueTimeAll": "Any time",
|
||||
"queueTimeToday": "Today",
|
||||
"queueTimeLast7Days": "Last 7 days",
|
||||
"queueTimeLast30Days": "Last 30 days",
|
||||
"queueEmpty": "No upload tasks",
|
||||
"queueRetryAllFailed": "Retry all failed",
|
||||
"queueAttemptCount": "{count} attempt(s)",
|
||||
"@queueAttemptCount": { "placeholders": { "count": { "type": "int" } } },
|
||||
"taskStatePreparing": "Preparing",
|
||||
"taskStatePreparationFailed": "Preparation failed",
|
||||
"taskStateQueued": "Queued",
|
||||
"taskStateUploading": "Uploading",
|
||||
"taskStateUploadedConfirming": "Confirming",
|
||||
"taskStateCompleted": "Completed",
|
||||
"taskStateWaitingNetwork": "Waiting for network",
|
||||
"taskStateRetryableFailed": "Upload failed",
|
||||
"taskStateCancelled": "Cancelled",
|
||||
"errorPrepSourceUnreadable": "Could not read the selected photo. Please reselect",
|
||||
"errorPrepUnsupportedType": "Only JPG, PNG and HEIC images are supported",
|
||||
"errorPrepTooLarge": "Photo exceeds the 50MB limit",
|
||||
"errorPrepCopyFailed": "Failed to copy the photo. Please retry",
|
||||
"errorUploadSourceMissing": "Source file is missing. Please reselect",
|
||||
"errorAlbumUploadDisabled": "Album uploads are disabled",
|
||||
"errorUploadSessionConflict": "Upload session conflict. Please retry",
|
||||
"errorUploadVerifyFailed": "Upload verification failed. Will retry",
|
||||
"captureTitle": "Continuous capture",
|
||||
"captureCategoryDefault": "Default category",
|
||||
"captureSwitchHint": "Switching only affects photos captured afterwards",
|
||||
"capturePendingBadge": "Pending {count}",
|
||||
"@capturePendingBadge": { "placeholders": { "count": { "type": "int" } } },
|
||||
"captureFailedBadge": "Failed {count}",
|
||||
"@captureFailedBadge": { "placeholders": { "count": { "type": "int" } } },
|
||||
"capturePickFromGallery": "Pick from gallery",
|
||||
"captureShutter": "Capture",
|
||||
"captureExitTitle": "Leave shooting?",
|
||||
"captureExitBody": "{count} photo(s) are still uploading. Tasks will continue in the background after you leave.",
|
||||
"@captureExitBody": { "placeholders": { "count": { "type": "int" } } },
|
||||
"captureKeepShooting": "Keep shooting",
|
||||
"captureExitConfirm": "Leave",
|
||||
"cameraPermissionDenied": "Camera unavailable. Allow camera access in system settings",
|
||||
"cameraInitFailed": "Camera failed to initialize",
|
||||
"uploadActionCapture": "Capture and upload",
|
||||
"uploadActionPick": "Pick from gallery",
|
||||
"uploadAction": "Upload",
|
||||
"uploadEnqueuedCount": "Added {count} photo(s) to the upload queue",
|
||||
"@uploadEnqueuedCount": { "placeholders": { "count": { "type": "int" } } },
|
||||
"uploadPickNone": "No photos selected"
|
||||
}
|
||||
|
||||
@@ -805,6 +805,306 @@ abstract class AppLocalizations {
|
||||
/// In zh, this message translates to:
|
||||
/// **'本设备'**
|
||||
String get thisDevice;
|
||||
|
||||
/// No description provided for @queueAlbumFilterAll.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'全部相册'**
|
||||
String get queueAlbumFilterAll;
|
||||
|
||||
/// No description provided for @queueStateAll.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'全部'**
|
||||
String get queueStateAll;
|
||||
|
||||
/// No description provided for @queueStatePreparing.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'准备中'**
|
||||
String get queueStatePreparing;
|
||||
|
||||
/// No description provided for @queueStateQueued.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'待传'**
|
||||
String get queueStateQueued;
|
||||
|
||||
/// No description provided for @queueStateUploading.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'上传中'**
|
||||
String get queueStateUploading;
|
||||
|
||||
/// No description provided for @queueStateWaitingNetwork.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'等待网络'**
|
||||
String get queueStateWaitingNetwork;
|
||||
|
||||
/// No description provided for @queueStateFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'失败'**
|
||||
String get queueStateFailed;
|
||||
|
||||
/// No description provided for @queueStateCompleted.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'已完成'**
|
||||
String get queueStateCompleted;
|
||||
|
||||
/// No description provided for @queueTimeAll.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'全部时间'**
|
||||
String get queueTimeAll;
|
||||
|
||||
/// No description provided for @queueTimeToday.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'今天'**
|
||||
String get queueTimeToday;
|
||||
|
||||
/// No description provided for @queueTimeLast7Days.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'近7天'**
|
||||
String get queueTimeLast7Days;
|
||||
|
||||
/// No description provided for @queueTimeLast30Days.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'近30天'**
|
||||
String get queueTimeLast30Days;
|
||||
|
||||
/// No description provided for @queueEmpty.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'暂无上传任务'**
|
||||
String get queueEmpty;
|
||||
|
||||
/// No description provided for @queueRetryAllFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'一键重试全部失败'**
|
||||
String get queueRetryAllFailed;
|
||||
|
||||
/// No description provided for @queueAttemptCount.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'已尝试 {count} 次'**
|
||||
String queueAttemptCount(int count);
|
||||
|
||||
/// No description provided for @taskStatePreparing.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'准备中'**
|
||||
String get taskStatePreparing;
|
||||
|
||||
/// No description provided for @taskStatePreparationFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'准备失败'**
|
||||
String get taskStatePreparationFailed;
|
||||
|
||||
/// No description provided for @taskStateQueued.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'待上传'**
|
||||
String get taskStateQueued;
|
||||
|
||||
/// No description provided for @taskStateUploading.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'上传中'**
|
||||
String get taskStateUploading;
|
||||
|
||||
/// No description provided for @taskStateUploadedConfirming.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'确认中'**
|
||||
String get taskStateUploadedConfirming;
|
||||
|
||||
/// No description provided for @taskStateCompleted.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'已完成'**
|
||||
String get taskStateCompleted;
|
||||
|
||||
/// No description provided for @taskStateWaitingNetwork.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'等待网络'**
|
||||
String get taskStateWaitingNetwork;
|
||||
|
||||
/// No description provided for @taskStateRetryableFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'上传失败'**
|
||||
String get taskStateRetryableFailed;
|
||||
|
||||
/// No description provided for @taskStateCancelled.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'已取消'**
|
||||
String get taskStateCancelled;
|
||||
|
||||
/// No description provided for @errorPrepSourceUnreadable.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'无法读取所选图片,请重新选择'**
|
||||
String get errorPrepSourceUnreadable;
|
||||
|
||||
/// No description provided for @errorPrepUnsupportedType.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'仅支持 JPG/PNG/HEIC 图片'**
|
||||
String get errorPrepUnsupportedType;
|
||||
|
||||
/// No description provided for @errorPrepTooLarge.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'图片超过 50MB 上限'**
|
||||
String get errorPrepTooLarge;
|
||||
|
||||
/// No description provided for @errorPrepCopyFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'保存图片副本失败,请重试'**
|
||||
String get errorPrepCopyFailed;
|
||||
|
||||
/// No description provided for @errorUploadSourceMissing.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'源文件已缺失,请重新选择'**
|
||||
String get errorUploadSourceMissing;
|
||||
|
||||
/// No description provided for @errorAlbumUploadDisabled.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'相册已关闭上传'**
|
||||
String get errorAlbumUploadDisabled;
|
||||
|
||||
/// No description provided for @errorUploadSessionConflict.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'上传会话冲突,请重试'**
|
||||
String get errorUploadSessionConflict;
|
||||
|
||||
/// No description provided for @errorUploadVerifyFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'上传核验失败,将自动重试'**
|
||||
String get errorUploadVerifyFailed;
|
||||
|
||||
/// No description provided for @captureTitle.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'连拍上传'**
|
||||
String get captureTitle;
|
||||
|
||||
/// No description provided for @captureCategoryDefault.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'默认分类'**
|
||||
String get captureCategoryDefault;
|
||||
|
||||
/// No description provided for @captureSwitchHint.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'切换分类仅影响之后拍摄的照片'**
|
||||
String get captureSwitchHint;
|
||||
|
||||
/// No description provided for @capturePendingBadge.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'待传 {count}'**
|
||||
String capturePendingBadge(int count);
|
||||
|
||||
/// No description provided for @captureFailedBadge.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'失败 {count}'**
|
||||
String captureFailedBadge(int count);
|
||||
|
||||
/// No description provided for @capturePickFromGallery.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'从相册选择'**
|
||||
String get capturePickFromGallery;
|
||||
|
||||
/// No description provided for @captureShutter.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'拍摄'**
|
||||
String get captureShutter;
|
||||
|
||||
/// No description provided for @captureExitTitle.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'退出拍摄?'**
|
||||
String get captureExitTitle;
|
||||
|
||||
/// No description provided for @captureExitBody.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'还有 {count} 张照片未上传,退出后任务将在后台继续。'**
|
||||
String captureExitBody(int count);
|
||||
|
||||
/// No description provided for @captureKeepShooting.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'继续拍摄'**
|
||||
String get captureKeepShooting;
|
||||
|
||||
/// No description provided for @captureExitConfirm.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'退出'**
|
||||
String get captureExitConfirm;
|
||||
|
||||
/// No description provided for @cameraPermissionDenied.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'无法访问相机,请在系统设置中允许相机权限'**
|
||||
String get cameraPermissionDenied;
|
||||
|
||||
/// No description provided for @cameraInitFailed.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'相机初始化失败'**
|
||||
String get cameraInitFailed;
|
||||
|
||||
/// No description provided for @uploadActionCapture.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'拍照上传'**
|
||||
String get uploadActionCapture;
|
||||
|
||||
/// No description provided for @uploadActionPick.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'从相册选择'**
|
||||
String get uploadActionPick;
|
||||
|
||||
/// No description provided for @uploadAction.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'上传'**
|
||||
String get uploadAction;
|
||||
|
||||
/// No description provided for @uploadEnqueuedCount.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'已加入 {count} 张上传队列'**
|
||||
String uploadEnqueuedCount(int count);
|
||||
|
||||
/// No description provided for @uploadPickNone.
|
||||
///
|
||||
/// In zh, this message translates to:
|
||||
/// **'未选择照片'**
|
||||
String get uploadPickNone;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -370,4 +370,171 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@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';
|
||||
}
|
||||
|
||||
@@ -361,4 +361,164 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get thisDevice => '本设备';
|
||||
|
||||
@override
|
||||
String get queueAlbumFilterAll => '全部相册';
|
||||
|
||||
@override
|
||||
String get queueStateAll => '全部';
|
||||
|
||||
@override
|
||||
String get queueStatePreparing => '准备中';
|
||||
|
||||
@override
|
||||
String get queueStateQueued => '待传';
|
||||
|
||||
@override
|
||||
String get queueStateUploading => '上传中';
|
||||
|
||||
@override
|
||||
String get queueStateWaitingNetwork => '等待网络';
|
||||
|
||||
@override
|
||||
String get queueStateFailed => '失败';
|
||||
|
||||
@override
|
||||
String get queueStateCompleted => '已完成';
|
||||
|
||||
@override
|
||||
String get queueTimeAll => '全部时间';
|
||||
|
||||
@override
|
||||
String get queueTimeToday => '今天';
|
||||
|
||||
@override
|
||||
String get queueTimeLast7Days => '近7天';
|
||||
|
||||
@override
|
||||
String get queueTimeLast30Days => '近30天';
|
||||
|
||||
@override
|
||||
String get queueEmpty => '暂无上传任务';
|
||||
|
||||
@override
|
||||
String get queueRetryAllFailed => '一键重试全部失败';
|
||||
|
||||
@override
|
||||
String queueAttemptCount(int count) {
|
||||
return '已尝试 $count 次';
|
||||
}
|
||||
|
||||
@override
|
||||
String get taskStatePreparing => '准备中';
|
||||
|
||||
@override
|
||||
String get taskStatePreparationFailed => '准备失败';
|
||||
|
||||
@override
|
||||
String get taskStateQueued => '待上传';
|
||||
|
||||
@override
|
||||
String get taskStateUploading => '上传中';
|
||||
|
||||
@override
|
||||
String get taskStateUploadedConfirming => '确认中';
|
||||
|
||||
@override
|
||||
String get taskStateCompleted => '已完成';
|
||||
|
||||
@override
|
||||
String get taskStateWaitingNetwork => '等待网络';
|
||||
|
||||
@override
|
||||
String get taskStateRetryableFailed => '上传失败';
|
||||
|
||||
@override
|
||||
String get taskStateCancelled => '已取消';
|
||||
|
||||
@override
|
||||
String get errorPrepSourceUnreadable => '无法读取所选图片,请重新选择';
|
||||
|
||||
@override
|
||||
String get errorPrepUnsupportedType => '仅支持 JPG/PNG/HEIC 图片';
|
||||
|
||||
@override
|
||||
String get errorPrepTooLarge => '图片超过 50MB 上限';
|
||||
|
||||
@override
|
||||
String get errorPrepCopyFailed => '保存图片副本失败,请重试';
|
||||
|
||||
@override
|
||||
String get errorUploadSourceMissing => '源文件已缺失,请重新选择';
|
||||
|
||||
@override
|
||||
String get errorAlbumUploadDisabled => '相册已关闭上传';
|
||||
|
||||
@override
|
||||
String get errorUploadSessionConflict => '上传会话冲突,请重试';
|
||||
|
||||
@override
|
||||
String get errorUploadVerifyFailed => '上传核验失败,将自动重试';
|
||||
|
||||
@override
|
||||
String get captureTitle => '连拍上传';
|
||||
|
||||
@override
|
||||
String get captureCategoryDefault => '默认分类';
|
||||
|
||||
@override
|
||||
String get captureSwitchHint => '切换分类仅影响之后拍摄的照片';
|
||||
|
||||
@override
|
||||
String capturePendingBadge(int count) {
|
||||
return '待传 $count';
|
||||
}
|
||||
|
||||
@override
|
||||
String captureFailedBadge(int count) {
|
||||
return '失败 $count';
|
||||
}
|
||||
|
||||
@override
|
||||
String get capturePickFromGallery => '从相册选择';
|
||||
|
||||
@override
|
||||
String get captureShutter => '拍摄';
|
||||
|
||||
@override
|
||||
String get captureExitTitle => '退出拍摄?';
|
||||
|
||||
@override
|
||||
String captureExitBody(int count) {
|
||||
return '还有 $count 张照片未上传,退出后任务将在后台继续。';
|
||||
}
|
||||
|
||||
@override
|
||||
String get captureKeepShooting => '继续拍摄';
|
||||
|
||||
@override
|
||||
String get captureExitConfirm => '退出';
|
||||
|
||||
@override
|
||||
String get cameraPermissionDenied => '无法访问相机,请在系统设置中允许相机权限';
|
||||
|
||||
@override
|
||||
String get cameraInitFailed => '相机初始化失败';
|
||||
|
||||
@override
|
||||
String get uploadActionCapture => '拍照上传';
|
||||
|
||||
@override
|
||||
String get uploadActionPick => '从相册选择';
|
||||
|
||||
@override
|
||||
String get uploadAction => '上传';
|
||||
|
||||
@override
|
||||
String uploadEnqueuedCount(int count) {
|
||||
return '已加入 $count 张上传队列';
|
||||
}
|
||||
|
||||
@override
|
||||
String get uploadPickNone => '未选择照片';
|
||||
}
|
||||
|
||||
@@ -117,5 +117,60 @@
|
||||
"uploadStateConfirmed": "已确认",
|
||||
"uploadStateCancelled": "已取消",
|
||||
"uploadStateExpired": "已过期",
|
||||
"thisDevice": "本设备"
|
||||
"thisDevice": "本设备",
|
||||
"queueAlbumFilterAll": "全部相册",
|
||||
"queueStateAll": "全部",
|
||||
"queueStatePreparing": "准备中",
|
||||
"queueStateQueued": "待传",
|
||||
"queueStateUploading": "上传中",
|
||||
"queueStateWaitingNetwork": "等待网络",
|
||||
"queueStateFailed": "失败",
|
||||
"queueStateCompleted": "已完成",
|
||||
"queueTimeAll": "全部时间",
|
||||
"queueTimeToday": "今天",
|
||||
"queueTimeLast7Days": "近7天",
|
||||
"queueTimeLast30Days": "近30天",
|
||||
"queueEmpty": "暂无上传任务",
|
||||
"queueRetryAllFailed": "一键重试全部失败",
|
||||
"queueAttemptCount": "已尝试 {count} 次",
|
||||
"@queueAttemptCount": { "placeholders": { "count": { "type": "int" } } },
|
||||
"taskStatePreparing": "准备中",
|
||||
"taskStatePreparationFailed": "准备失败",
|
||||
"taskStateQueued": "待上传",
|
||||
"taskStateUploading": "上传中",
|
||||
"taskStateUploadedConfirming": "确认中",
|
||||
"taskStateCompleted": "已完成",
|
||||
"taskStateWaitingNetwork": "等待网络",
|
||||
"taskStateRetryableFailed": "上传失败",
|
||||
"taskStateCancelled": "已取消",
|
||||
"errorPrepSourceUnreadable": "无法读取所选图片,请重新选择",
|
||||
"errorPrepUnsupportedType": "仅支持 JPG/PNG/HEIC 图片",
|
||||
"errorPrepTooLarge": "图片超过 50MB 上限",
|
||||
"errorPrepCopyFailed": "保存图片副本失败,请重试",
|
||||
"errorUploadSourceMissing": "源文件已缺失,请重新选择",
|
||||
"errorAlbumUploadDisabled": "相册已关闭上传",
|
||||
"errorUploadSessionConflict": "上传会话冲突,请重试",
|
||||
"errorUploadVerifyFailed": "上传核验失败,将自动重试",
|
||||
"captureTitle": "连拍上传",
|
||||
"captureCategoryDefault": "默认分类",
|
||||
"captureSwitchHint": "切换分类仅影响之后拍摄的照片",
|
||||
"capturePendingBadge": "待传 {count}",
|
||||
"@capturePendingBadge": { "placeholders": { "count": { "type": "int" } } },
|
||||
"captureFailedBadge": "失败 {count}",
|
||||
"@captureFailedBadge": { "placeholders": { "count": { "type": "int" } } },
|
||||
"capturePickFromGallery": "从相册选择",
|
||||
"captureShutter": "拍摄",
|
||||
"captureExitTitle": "退出拍摄?",
|
||||
"captureExitBody": "还有 {count} 张照片未上传,退出后任务将在后台继续。",
|
||||
"@captureExitBody": { "placeholders": { "count": { "type": "int" } } },
|
||||
"captureKeepShooting": "继续拍摄",
|
||||
"captureExitConfirm": "退出",
|
||||
"cameraPermissionDenied": "无法访问相机,请在系统设置中允许相机权限",
|
||||
"cameraInitFailed": "相机初始化失败",
|
||||
"uploadActionCapture": "拍照上传",
|
||||
"uploadActionPick": "从相册选择",
|
||||
"uploadAction": "上传",
|
||||
"uploadEnqueuedCount": "已加入 {count} 张上传队列",
|
||||
"@uploadEnqueuedCount": { "placeholders": { "count": { "type": "int" } } },
|
||||
"uploadPickNone": "未选择照片"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user