mirror of
https://github.com/immich-app/immich.git
synced 2025-06-01 04:36:19 -04: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 immichBrandColorDark = Color(0xFFACCBFA);
|
||||||
const Color whiteOpacity75 = Color.fromARGB((0.75 * 255) ~/ 1, 255, 255, 255);
|
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 blackOpacity90 = Color.fromARGB((0.90 * 255) ~/ 1, 0, 0, 0);
|
||||||
|
const Color red400 = Color(0xFFEF5350);
|
||||||
|
|
||||||
final Map<ImmichColorPreset, ImmichTheme> _themePresetsMap = {
|
final Map<ImmichColorPreset, ImmichTheme> _themePresetsMap = {
|
||||||
ImmichColorPreset.indigo: ImmichTheme(
|
ImmichColorPreset.indigo: ImmichTheme(
|
||||||
|
@ -18,6 +18,9 @@ class CurrentUploadAsset {
|
|||||||
this.iCloudAsset,
|
this.iCloudAsset,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
bool get isIcloudAsset => iCloudAsset != null && iCloudAsset!;
|
||||||
|
|
||||||
CurrentUploadAsset copyWith({
|
CurrentUploadAsset copyWith({
|
||||||
String? id,
|
String? id,
|
||||||
DateTime? fileCreatedAt,
|
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 'dart:io';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.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/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/widgets/backup/asset_info_table.dart';
|
||||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
import 'package:immich_mobile/widgets/backup/error_chip.dart';
|
||||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
import 'package:immich_mobile/widgets/backup/icloud_download_progress_bar.dart';
|
||||||
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
|
import 'package:immich_mobile/widgets/backup/upload_progress_bar.dart';
|
||||||
import 'package:immich_mobile/providers/backup/manual_upload.provider.dart';
|
import 'package:immich_mobile/widgets/backup/upload_stats.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';
|
|
||||||
|
|
||||||
class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
|
class CurrentUploadingAssetInfoBox extends StatelessWidget {
|
||||||
const CurrentUploadingAssetInfoBox({super.key});
|
const CurrentUploadingAssetInfoBox({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context) {
|
||||||
var isManualUpload = ref.watch(backupProvider).backupProgress ==
|
return ListTile(
|
||||||
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(
|
|
||||||
isThreeLine: true,
|
isThreeLine: true,
|
||||||
leading: AnimatedCrossFade(
|
leading: Icon(
|
||||||
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(
|
|
||||||
Icons.image_outlined,
|
Icons.image_outlined,
|
||||||
color: context.primaryColor,
|
color: context.primaryColor,
|
||||||
size: 30,
|
size: 30,
|
||||||
),
|
),
|
||||||
),
|
|
||||||
crossFadeState: isShowThumbnail.value
|
|
||||||
? CrossFadeState.showFirst
|
|
||||||
: CrossFadeState.showSecond,
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
),
|
|
||||||
title: Row(
|
title: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -277,21 +28,17 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
|
|||||||
"backup_controller_page_uploading_file_info",
|
"backup_controller_page_uploading_file_info",
|
||||||
style: context.textTheme.titleSmall,
|
style: context.textTheme.titleSmall,
|
||||||
).tr(),
|
).tr(),
|
||||||
if (ref.watch(errorBackupListProvider).isNotEmpty) buildErrorChip(),
|
const BackupErrorChip(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
children: [
|
children: [
|
||||||
if (Platform.isIOS) buildiCloudDownloadProgerssBar(),
|
if (Platform.isIOS) const IcloudDownloadProgressBar(),
|
||||||
buildUploadProgressBar(),
|
const BackupUploadProgressBar(),
|
||||||
buildUploadStats(),
|
const BackupUploadStats(),
|
||||||
Padding(
|
const BackupAssetInfoTable(),
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: buildAssetInfoTable(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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