mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	refactor(mobile): backup info box (#14171)
split up backup info box into separate widgets
This commit is contained in:
		
							parent
							
								
									6729782c3f
								
							
						
					
					
						commit
						caf6c0996d
					
				@ -21,6 +21,7 @@ const Color immichBrandColorLight = Color(0xFF4150AF);
 | 
			
		||||
const Color immichBrandColorDark = Color(0xFFACCBFA);
 | 
			
		||||
const Color whiteOpacity75 = Color.fromARGB((0.75 * 255) ~/ 1, 255, 255, 255);
 | 
			
		||||
const Color blackOpacity90 = Color.fromARGB((0.90 * 255) ~/ 1, 0, 0, 0);
 | 
			
		||||
const Color red400 = Color(0xFFEF5350);
 | 
			
		||||
 | 
			
		||||
final Map<ImmichColorPreset, ImmichTheme> _themePresetsMap = {
 | 
			
		||||
  ImmichColorPreset.indigo: ImmichTheme(
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,9 @@ class CurrentUploadAsset {
 | 
			
		||||
    this.iCloudAsset,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @pragma('vm:prefer-inline')
 | 
			
		||||
  bool get isIcloudAsset => iCloudAsset != null && iCloudAsset!;
 | 
			
		||||
 | 
			
		||||
  CurrentUploadAsset copyWith({
 | 
			
		||||
    String? id,
 | 
			
		||||
    DateTime? fileCreatedAt,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										102
									
								
								mobile/lib/widgets/backup/asset_info_table.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								mobile/lib/widgets/backup/asset_info_table.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
			
		||||
import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
 | 
			
		||||
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
 | 
			
		||||
 | 
			
		||||
class BackupAssetInfoTable extends ConsumerWidget {
 | 
			
		||||
  const BackupAssetInfoTable({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final isManualUpload = ref.watch(
 | 
			
		||||
      backupProvider.select(
 | 
			
		||||
        (value) => value.backupProgress == BackUpProgressEnum.manualInProgress,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final asset = isManualUpload
 | 
			
		||||
        ? ref.watch(
 | 
			
		||||
            manualUploadProvider.select((value) => value.currentUploadAsset),
 | 
			
		||||
          )
 | 
			
		||||
        : ref.watch(backupProvider.select((value) => value.currentUploadAsset));
 | 
			
		||||
 | 
			
		||||
    return Padding(
 | 
			
		||||
      padding: const EdgeInsets.only(top: 8.0),
 | 
			
		||||
      child: Table(
 | 
			
		||||
        border: TableBorder.all(
 | 
			
		||||
          color: context.colorScheme.outlineVariant,
 | 
			
		||||
          width: 1,
 | 
			
		||||
        ),
 | 
			
		||||
        children: [
 | 
			
		||||
          TableRow(
 | 
			
		||||
            children: [
 | 
			
		||||
              TableCell(
 | 
			
		||||
                verticalAlignment: TableCellVerticalAlignment.middle,
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(6.0),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    'backup_controller_page_filename',
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      color: context.colorScheme.onSurfaceSecondary,
 | 
			
		||||
                      fontWeight: FontWeight.bold,
 | 
			
		||||
                      fontSize: 10.0,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ).tr(
 | 
			
		||||
                    args: [asset.fileName, asset.fileType.toLowerCase()],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
          TableRow(
 | 
			
		||||
            children: [
 | 
			
		||||
              TableCell(
 | 
			
		||||
                verticalAlignment: TableCellVerticalAlignment.middle,
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(6.0),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    "backup_controller_page_created",
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      color: context.colorScheme.onSurfaceSecondary,
 | 
			
		||||
                      fontWeight: FontWeight.bold,
 | 
			
		||||
                      fontSize: 10.0,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ).tr(
 | 
			
		||||
                    args: [_getAssetCreationDate(asset)],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
          TableRow(
 | 
			
		||||
            children: [
 | 
			
		||||
              TableCell(
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(6.0),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    "backup_controller_page_id",
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      color: context.colorScheme.onSurfaceSecondary,
 | 
			
		||||
                      fontWeight: FontWeight.bold,
 | 
			
		||||
                      fontSize: 10.0,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ).tr(args: [asset.id]),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @pragma('vm:prefer-inline')
 | 
			
		||||
  String _getAssetCreationDate(CurrentUploadAsset asset) {
 | 
			
		||||
    return DateFormat.yMMMMd().format(asset.fileCreatedAt.toLocal());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,275 +1,26 @@
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
 | 
			
		||||
import 'package:auto_route/auto_route.dart';
 | 
			
		||||
import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/entities/asset.entity.dart';
 | 
			
		||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/repositories/asset_media.repository.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/backup/asset_info_table.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/backup/error_chip.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/backup/icloud_download_progress_bar.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/backup/upload_progress_bar.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/backup/upload_stats.dart';
 | 
			
		||||
 | 
			
		||||
class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
 | 
			
		||||
class CurrentUploadingAssetInfoBox extends StatelessWidget {
 | 
			
		||||
  const CurrentUploadingAssetInfoBox({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    var isManualUpload = ref.watch(backupProvider).backupProgress ==
 | 
			
		||||
        BackUpProgressEnum.manualInProgress;
 | 
			
		||||
    var asset = !isManualUpload
 | 
			
		||||
        ? ref.watch(backupProvider).currentUploadAsset
 | 
			
		||||
        : ref.watch(manualUploadProvider).currentUploadAsset;
 | 
			
		||||
    var uploadProgress = !isManualUpload
 | 
			
		||||
        ? ref.watch(backupProvider).progressInPercentage
 | 
			
		||||
        : ref.watch(manualUploadProvider).progressInPercentage;
 | 
			
		||||
    var uploadFileProgress = !isManualUpload
 | 
			
		||||
        ? ref.watch(backupProvider).progressInFileSize
 | 
			
		||||
        : ref.watch(manualUploadProvider).progressInFileSize;
 | 
			
		||||
    var uploadFileSpeed = !isManualUpload
 | 
			
		||||
        ? ref.watch(backupProvider).progressInFileSpeed
 | 
			
		||||
        : ref.watch(manualUploadProvider).progressInFileSpeed;
 | 
			
		||||
    var iCloudDownloadProgress =
 | 
			
		||||
        ref.watch(backupProvider).iCloudDownloadProgress;
 | 
			
		||||
    final isShowThumbnail = useState(false);
 | 
			
		||||
 | 
			
		||||
    String formatUploadFileSpeed(double uploadFileSpeed) {
 | 
			
		||||
      if (uploadFileSpeed < 1024) {
 | 
			
		||||
        return '${uploadFileSpeed.toStringAsFixed(2)} B/s';
 | 
			
		||||
      } else if (uploadFileSpeed < 1024 * 1024) {
 | 
			
		||||
        return '${(uploadFileSpeed / 1024).toStringAsFixed(2)} KB/s';
 | 
			
		||||
      } else if (uploadFileSpeed < 1024 * 1024 * 1024) {
 | 
			
		||||
        return '${(uploadFileSpeed / (1024 * 1024)).toStringAsFixed(2)} MB/s';
 | 
			
		||||
      } else {
 | 
			
		||||
        return '${(uploadFileSpeed / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB/s';
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String getAssetCreationDate() {
 | 
			
		||||
      return DateFormat.yMMMMd().format(
 | 
			
		||||
        DateTime.parse(
 | 
			
		||||
          asset.fileCreatedAt.toString(),
 | 
			
		||||
        ).toLocal(),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Widget buildErrorChip() {
 | 
			
		||||
      return ActionChip(
 | 
			
		||||
        avatar: Icon(
 | 
			
		||||
          Icons.info,
 | 
			
		||||
          color: Colors.red[400],
 | 
			
		||||
        ),
 | 
			
		||||
        elevation: 1,
 | 
			
		||||
        visualDensity: VisualDensity.compact,
 | 
			
		||||
        label: Text(
 | 
			
		||||
          "backup_controller_page_failed",
 | 
			
		||||
          style: TextStyle(
 | 
			
		||||
            color: Colors.red[400],
 | 
			
		||||
            fontWeight: FontWeight.bold,
 | 
			
		||||
            fontSize: 11,
 | 
			
		||||
          ),
 | 
			
		||||
        ).tr(
 | 
			
		||||
          args: [ref.watch(errorBackupListProvider).length.toString()],
 | 
			
		||||
        ),
 | 
			
		||||
        backgroundColor: Colors.white,
 | 
			
		||||
        onPressed: () => context.pushRoute(const FailedBackupStatusRoute()),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Widget buildAssetInfoTable() {
 | 
			
		||||
      return Table(
 | 
			
		||||
        border: TableBorder.all(
 | 
			
		||||
          color: context.colorScheme.outlineVariant,
 | 
			
		||||
          width: 1,
 | 
			
		||||
        ),
 | 
			
		||||
        children: [
 | 
			
		||||
          TableRow(
 | 
			
		||||
            children: [
 | 
			
		||||
              TableCell(
 | 
			
		||||
                verticalAlignment: TableCellVerticalAlignment.middle,
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(6.0),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    'backup_controller_page_filename',
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      color: context.colorScheme.onSurfaceSecondary,
 | 
			
		||||
                      fontWeight: FontWeight.bold,
 | 
			
		||||
                      fontSize: 10.0,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ).tr(
 | 
			
		||||
                    args: [asset.fileName, asset.fileType.toLowerCase()],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
          TableRow(
 | 
			
		||||
            children: [
 | 
			
		||||
              TableCell(
 | 
			
		||||
                verticalAlignment: TableCellVerticalAlignment.middle,
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(6.0),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    "backup_controller_page_created",
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      color: context.colorScheme.onSurfaceSecondary,
 | 
			
		||||
                      fontWeight: FontWeight.bold,
 | 
			
		||||
                      fontSize: 10.0,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ).tr(
 | 
			
		||||
                    args: [getAssetCreationDate()],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
          TableRow(
 | 
			
		||||
            children: [
 | 
			
		||||
              TableCell(
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.all(6.0),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    "backup_controller_page_id",
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      color: context.colorScheme.onSurfaceSecondary,
 | 
			
		||||
                      fontWeight: FontWeight.bold,
 | 
			
		||||
                      fontSize: 10.0,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ).tr(args: [asset.id]),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildiCloudDownloadProgerssBar() {
 | 
			
		||||
      if (asset.iCloudAsset != null && asset.iCloudAsset!) {
 | 
			
		||||
        return Padding(
 | 
			
		||||
          padding: const EdgeInsets.only(top: 8.0),
 | 
			
		||||
          child: Row(
 | 
			
		||||
            children: [
 | 
			
		||||
              SizedBox(
 | 
			
		||||
                width: 110,
 | 
			
		||||
                child: Text(
 | 
			
		||||
                  "iCloud Download",
 | 
			
		||||
                  style: context.textTheme.labelSmall,
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
              Expanded(
 | 
			
		||||
                child: LinearProgressIndicator(
 | 
			
		||||
                  minHeight: 10.0,
 | 
			
		||||
                  value: uploadProgress / 100.0,
 | 
			
		||||
                  borderRadius: const BorderRadius.all(Radius.circular(10.0)),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
              Text(
 | 
			
		||||
                " ${iCloudDownloadProgress.toStringAsFixed(0)}%",
 | 
			
		||||
                style: const TextStyle(fontSize: 12),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return const SizedBox();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildUploadProgressBar() {
 | 
			
		||||
      return Padding(
 | 
			
		||||
        padding: const EdgeInsets.only(top: 8.0),
 | 
			
		||||
        child: Row(
 | 
			
		||||
          children: [
 | 
			
		||||
            if (asset.iCloudAsset != null && asset.iCloudAsset!)
 | 
			
		||||
              SizedBox(
 | 
			
		||||
                width: 110,
 | 
			
		||||
                child: Text(
 | 
			
		||||
                  "Immich Upload",
 | 
			
		||||
                  style: context.textTheme.labelSmall,
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            Expanded(
 | 
			
		||||
              child: LinearProgressIndicator(
 | 
			
		||||
                minHeight: 10.0,
 | 
			
		||||
                value: uploadProgress / 100.0,
 | 
			
		||||
                borderRadius: const BorderRadius.all(Radius.circular(10.0)),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            Text(
 | 
			
		||||
              " ${uploadProgress.toStringAsFixed(0)}%",
 | 
			
		||||
              style: const TextStyle(fontSize: 12, fontFamily: "OverpassMono"),
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildUploadStats() {
 | 
			
		||||
      return Padding(
 | 
			
		||||
        padding: const EdgeInsets.only(top: 2.0, bottom: 2.0),
 | 
			
		||||
        child: Row(
 | 
			
		||||
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
          children: [
 | 
			
		||||
            Text(
 | 
			
		||||
              uploadFileProgress,
 | 
			
		||||
              style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono"),
 | 
			
		||||
            ),
 | 
			
		||||
            Text(
 | 
			
		||||
              formatUploadFileSpeed(uploadFileSpeed),
 | 
			
		||||
              style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono"),
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return FutureBuilder<Asset?>(
 | 
			
		||||
      future: ref.read(assetMediaRepositoryProvider).get(asset.id),
 | 
			
		||||
      builder: (context, thumbnail) => ListTile(
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return ListTile(
 | 
			
		||||
      isThreeLine: true,
 | 
			
		||||
        leading: AnimatedCrossFade(
 | 
			
		||||
          alignment: Alignment.centerLeft,
 | 
			
		||||
          firstChild: GestureDetector(
 | 
			
		||||
            onTap: () => isShowThumbnail.value = false,
 | 
			
		||||
            child: thumbnail.hasData
 | 
			
		||||
                ? ClipRRect(
 | 
			
		||||
                    borderRadius: BorderRadius.circular(5),
 | 
			
		||||
                    child: ImmichThumbnail(
 | 
			
		||||
                      asset: thumbnail.data,
 | 
			
		||||
                      width: 50,
 | 
			
		||||
                      height: 50,
 | 
			
		||||
                    ),
 | 
			
		||||
                  )
 | 
			
		||||
                : const SizedBox(
 | 
			
		||||
                    width: 50,
 | 
			
		||||
                    height: 50,
 | 
			
		||||
                    child: Padding(
 | 
			
		||||
                      padding: EdgeInsets.all(8.0),
 | 
			
		||||
                      child: CircularProgressIndicator.adaptive(
 | 
			
		||||
                        strokeWidth: 1,
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
          ),
 | 
			
		||||
          secondChild: GestureDetector(
 | 
			
		||||
            onTap: () => isShowThumbnail.value = true,
 | 
			
		||||
            child: Icon(
 | 
			
		||||
      leading: Icon(
 | 
			
		||||
        Icons.image_outlined,
 | 
			
		||||
        color: context.primaryColor,
 | 
			
		||||
        size: 30,
 | 
			
		||||
      ),
 | 
			
		||||
          ),
 | 
			
		||||
          crossFadeState: isShowThumbnail.value
 | 
			
		||||
              ? CrossFadeState.showFirst
 | 
			
		||||
              : CrossFadeState.showSecond,
 | 
			
		||||
          duration: const Duration(milliseconds: 200),
 | 
			
		||||
        ),
 | 
			
		||||
      title: Row(
 | 
			
		||||
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
        children: [
 | 
			
		||||
@ -277,21 +28,17 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
 | 
			
		||||
            "backup_controller_page_uploading_file_info",
 | 
			
		||||
            style: context.textTheme.titleSmall,
 | 
			
		||||
          ).tr(),
 | 
			
		||||
            if (ref.watch(errorBackupListProvider).isNotEmpty) buildErrorChip(),
 | 
			
		||||
          const BackupErrorChip(),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      subtitle: Column(
 | 
			
		||||
        children: [
 | 
			
		||||
            if (Platform.isIOS) buildiCloudDownloadProgerssBar(),
 | 
			
		||||
            buildUploadProgressBar(),
 | 
			
		||||
            buildUploadStats(),
 | 
			
		||||
            Padding(
 | 
			
		||||
              padding: const EdgeInsets.only(top: 8.0),
 | 
			
		||||
              child: buildAssetInfoTable(),
 | 
			
		||||
            ),
 | 
			
		||||
          if (Platform.isIOS) const IcloudDownloadProgressBar(),
 | 
			
		||||
          const BackupUploadProgressBar(),
 | 
			
		||||
          const BackupUploadStats(),
 | 
			
		||||
          const BackupAssetInfoTable(),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								mobile/lib/widgets/backup/error_chip.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mobile/lib/widgets/backup/error_chip.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
import 'package:auto_route/auto_route.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/constants/immich_colors.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/routing/router.dart';
 | 
			
		||||
import 'package:immich_mobile/widgets/backup/error_chip_text.dart';
 | 
			
		||||
 | 
			
		||||
class BackupErrorChip extends ConsumerWidget {
 | 
			
		||||
  const BackupErrorChip({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final hasErrors =
 | 
			
		||||
        ref.watch(errorBackupListProvider.select((value) => value.isNotEmpty));
 | 
			
		||||
    if (!hasErrors) {
 | 
			
		||||
      return const SizedBox();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ActionChip(
 | 
			
		||||
      avatar: const Icon(
 | 
			
		||||
        Icons.info,
 | 
			
		||||
        color: red400,
 | 
			
		||||
      ),
 | 
			
		||||
      elevation: 1,
 | 
			
		||||
      visualDensity: VisualDensity.compact,
 | 
			
		||||
      label: const BackupErrorChipText(),
 | 
			
		||||
      backgroundColor: Colors.white,
 | 
			
		||||
      onPressed: () => context.pushRoute(const FailedBackupStatusRoute()),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								mobile/lib/widgets/backup/error_chip_text.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								mobile/lib/widgets/backup/error_chip_text.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/constants/immich_colors.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
 | 
			
		||||
 | 
			
		||||
class BackupErrorChipText extends ConsumerWidget {
 | 
			
		||||
  const BackupErrorChipText({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final count = ref.watch(errorBackupListProvider).length;
 | 
			
		||||
    if (count == 0) {
 | 
			
		||||
      return const SizedBox();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return const Text(
 | 
			
		||||
      "backup_controller_page_failed",
 | 
			
		||||
      style: TextStyle(
 | 
			
		||||
        color: red400,
 | 
			
		||||
        fontWeight: FontWeight.bold,
 | 
			
		||||
        fontSize: 11,
 | 
			
		||||
      ),
 | 
			
		||||
    ).tr(
 | 
			
		||||
      args: [count.toString()],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								mobile/lib/widgets/backup/icloud_download_progress_bar.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								mobile/lib/widgets/backup/icloud_download_progress_bar.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
 | 
			
		||||
 | 
			
		||||
class IcloudDownloadProgressBar extends ConsumerWidget {
 | 
			
		||||
  const IcloudDownloadProgressBar({super.key});
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final isManualUpload = ref.watch(
 | 
			
		||||
      backupProvider.select(
 | 
			
		||||
        (value) => value.backupProgress == BackUpProgressEnum.manualInProgress,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final isIcloudAsset = isManualUpload
 | 
			
		||||
        ? ref.watch(
 | 
			
		||||
            manualUploadProvider
 | 
			
		||||
                .select((value) => value.currentUploadAsset.isIcloudAsset),
 | 
			
		||||
          )
 | 
			
		||||
        : ref.watch(
 | 
			
		||||
            backupProvider
 | 
			
		||||
                .select((value) => value.currentUploadAsset.isIcloudAsset),
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
    if (!isIcloudAsset) {
 | 
			
		||||
      return const SizedBox();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final iCloudDownloadProgress = ref
 | 
			
		||||
        .watch(backupProvider.select((value) => value.iCloudDownloadProgress));
 | 
			
		||||
 | 
			
		||||
    return Padding(
 | 
			
		||||
      padding: const EdgeInsets.only(top: 8.0),
 | 
			
		||||
      child: Row(
 | 
			
		||||
        children: [
 | 
			
		||||
          SizedBox(
 | 
			
		||||
            width: 110,
 | 
			
		||||
            child: Text(
 | 
			
		||||
              "iCloud Download",
 | 
			
		||||
              style: context.textTheme.labelSmall,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          Expanded(
 | 
			
		||||
            child: LinearProgressIndicator(
 | 
			
		||||
              minHeight: 10.0,
 | 
			
		||||
              value: iCloudDownloadProgress / 100.0,
 | 
			
		||||
              borderRadius: const BorderRadius.all(Radius.circular(10.0)),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          Text(
 | 
			
		||||
            " ${iCloudDownloadProgress ~/ 1}%",
 | 
			
		||||
            style: const TextStyle(fontSize: 12),
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								mobile/lib/widgets/backup/upload_progress_bar.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								mobile/lib/widgets/backup/upload_progress_bar.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
 | 
			
		||||
 | 
			
		||||
class BackupUploadProgressBar extends ConsumerWidget {
 | 
			
		||||
  const BackupUploadProgressBar({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final isManualUpload = ref.watch(
 | 
			
		||||
      backupProvider.select(
 | 
			
		||||
        (value) => value.backupProgress == BackUpProgressEnum.manualInProgress,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final isIcloudAsset = isManualUpload
 | 
			
		||||
        ? ref.watch(
 | 
			
		||||
            manualUploadProvider
 | 
			
		||||
                .select((value) => value.currentUploadAsset.isIcloudAsset),
 | 
			
		||||
          )
 | 
			
		||||
        : ref.watch(
 | 
			
		||||
            backupProvider
 | 
			
		||||
                .select((value) => value.currentUploadAsset.isIcloudAsset),
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
    final uploadProgress = isManualUpload
 | 
			
		||||
        ? ref.watch(
 | 
			
		||||
            manualUploadProvider.select((value) => value.progressInPercentage),
 | 
			
		||||
          )
 | 
			
		||||
        : ref.watch(
 | 
			
		||||
            backupProvider.select((value) => value.progressInPercentage),
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
    return Padding(
 | 
			
		||||
      padding: const EdgeInsets.only(top: 8.0),
 | 
			
		||||
      child: Row(
 | 
			
		||||
        children: [
 | 
			
		||||
          if (isIcloudAsset)
 | 
			
		||||
            SizedBox(
 | 
			
		||||
              width: 110,
 | 
			
		||||
              child: Text(
 | 
			
		||||
                "Immich Upload",
 | 
			
		||||
                style: context.textTheme.labelSmall,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          Expanded(
 | 
			
		||||
            child: LinearProgressIndicator(
 | 
			
		||||
              minHeight: 10.0,
 | 
			
		||||
              value: uploadProgress / 100.0,
 | 
			
		||||
              borderRadius: const BorderRadius.all(Radius.circular(10.0)),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          Text(
 | 
			
		||||
            " ${uploadProgress.toStringAsFixed(0)}%",
 | 
			
		||||
            style: const TextStyle(fontSize: 12, fontFamily: "OverpassMono"),
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								mobile/lib/widgets/backup/upload_stats.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								mobile/lib/widgets/backup/upload_stats.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
 | 
			
		||||
 | 
			
		||||
class BackupUploadStats extends ConsumerWidget {
 | 
			
		||||
  const BackupUploadStats({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context, WidgetRef ref) {
 | 
			
		||||
    final isManualUpload = ref.watch(
 | 
			
		||||
      backupProvider.select(
 | 
			
		||||
        (value) => value.backupProgress == BackUpProgressEnum.manualInProgress,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    final uploadFileProgress = isManualUpload
 | 
			
		||||
        ? ref.watch(
 | 
			
		||||
            manualUploadProvider.select((value) => value.progressInFileSize),
 | 
			
		||||
          )
 | 
			
		||||
        : ref.watch(backupProvider.select((value) => value.progressInFileSize));
 | 
			
		||||
 | 
			
		||||
    final uploadFileSpeed = isManualUpload
 | 
			
		||||
        ? ref.watch(
 | 
			
		||||
            manualUploadProvider.select((value) => value.progressInFileSpeed),
 | 
			
		||||
          )
 | 
			
		||||
        : ref.watch(
 | 
			
		||||
            backupProvider.select((value) => value.progressInFileSpeed),
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
    return Padding(
 | 
			
		||||
      padding: const EdgeInsets.only(top: 2.0, bottom: 2.0),
 | 
			
		||||
      child: Row(
 | 
			
		||||
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
        children: [
 | 
			
		||||
          Text(
 | 
			
		||||
            uploadFileProgress,
 | 
			
		||||
            style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono"),
 | 
			
		||||
          ),
 | 
			
		||||
          Text(
 | 
			
		||||
            _formatUploadFileSpeed(uploadFileSpeed),
 | 
			
		||||
            style: const TextStyle(fontSize: 10, fontFamily: "OverpassMono"),
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @pragma('vm:prefer-inline')
 | 
			
		||||
  String _formatUploadFileSpeed(double uploadFileSpeed) {
 | 
			
		||||
    if (uploadFileSpeed < 1024) {
 | 
			
		||||
      return '${uploadFileSpeed.toStringAsFixed(2)} B/s';
 | 
			
		||||
    } else if (uploadFileSpeed < 1024 * 1024) {
 | 
			
		||||
      return '${(uploadFileSpeed / 1024).toStringAsFixed(2)} KB/s';
 | 
			
		||||
    } else if (uploadFileSpeed < 1024 * 1024 * 1024) {
 | 
			
		||||
      return '${(uploadFileSpeed / (1024 * 1024)).toStringAsFixed(2)} MB/s';
 | 
			
		||||
    } else {
 | 
			
		||||
      return '${(uploadFileSpeed / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB/s';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user