chore: dart http foreground upload (#24883)

* feat: bring back manual backup

* expose iCloud retrieval progress

* wip

* unify http upload method, check for connectivity on iOS

* handle LivePhotos progress

* feat: speed calculation

* wip

* better upload detail page

* handle error

* handle error

* pr feedback

* feat: share intent upload

* feat: manual upload

* feat: manual upload progress

* chore: styling

* refactor

* refactor

* remove unused logs

* fix: background android backup

* feat: add error section

* remove complete section

* remove empty state and prevent slot jumps

* more refactor

* fix: background test

* chore: add metadata to foreground upload

* fix: email and name get reset in auth provider

* pr feedback

* remove version check for metadata field in upload payload

* chore: fix unit test

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
Alex
2026-01-15 20:10:08 -06:00
committed by GitHub
parent 843d563178
commit e4443fa43e
31 changed files with 1855 additions and 848 deletions

View File

@@ -8,6 +8,7 @@ import 'package:immich_mobile/extensions/duration_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
import 'package:immich_mobile/providers/backup/asset_upload_progress.provider.dart';
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
@@ -62,6 +63,10 @@ class _ThumbnailTileState extends ConsumerState<ThumbnailTile> {
_showSelectionContainer = true;
}
final uploadProgress = asset is LocalAsset
? ref.watch(assetUploadProgressProvider.select((map) => map[asset.id]))
: null;
return Stack(
children: [
Container(
@@ -168,6 +173,7 @@ class _ThumbnailTileState extends ConsumerState<ThumbnailTile> {
),
),
),
if (uploadProgress != null) _UploadProgressOverlay(progress: uploadProgress),
],
),
),
@@ -293,3 +299,46 @@ class _AssetTypeIcons extends StatelessWidget {
);
}
}
class _UploadProgressOverlay extends StatelessWidget {
final double progress;
const _UploadProgressOverlay({required this.progress});
@override
Widget build(BuildContext context) {
final isError = progress < 0;
final percentage = isError ? 0 : (progress * 100).toInt();
return Positioned.fill(
child: Container(
color: isError ? Colors.red.withValues(alpha: 0.6) : Colors.black54,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (isError)
const Icon(Icons.error_outline, color: Colors.white, size: 36)
else
SizedBox(
width: 36,
height: 36,
child: CircularProgressIndicator(
value: progress,
strokeWidth: 3,
backgroundColor: Colors.white24,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
),
const SizedBox(height: 4),
Text(
isError ? 'Error' : '$percentage%',
style: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
),
],
),
),
),
);
}
}