// ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:async'; import 'dart:convert'; import 'package:background_downloader/background_downloader.dart'; import 'package:collection/collection.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/services/exp_backup.service.dart'; import 'package:immich_mobile/services/upload.service.dart'; class ExpUploadStatus { final String taskId; final String filename; final double progress; ExpUploadStatus({ required this.taskId, required this.filename, required this.progress, }); ExpUploadStatus copyWith({ String? taskId, String? filename, double? progress, }) { return ExpUploadStatus( taskId: taskId ?? this.taskId, filename: filename ?? this.filename, progress: progress ?? this.progress, ); } Map toMap() { return { 'taskId': taskId, 'filename': filename, 'progress': progress, }; } factory ExpUploadStatus.fromMap(Map map) { return ExpUploadStatus( taskId: map['taskId'] as String, filename: map['filename'] as String, progress: map['progress'] as double, ); } String toJson() => json.encode(toMap()); factory ExpUploadStatus.fromJson(String source) => ExpUploadStatus.fromMap(json.decode(source) as Map); @override String toString() => 'ExpUploadStatus(taskId: $taskId, filename: $filename, progress: $progress)'; @override bool operator ==(covariant ExpUploadStatus other) { if (identical(this, other)) return true; return other.taskId == taskId && other.filename == filename && other.progress == progress; } @override int get hashCode => taskId.hashCode ^ filename.hashCode ^ progress.hashCode; } class ExpBackupState { final int totalCount; final int backupCount; final int remainderCount; final Map uploadItems; ExpBackupState({ required this.totalCount, required this.backupCount, required this.remainderCount, required this.uploadItems, }); ExpBackupState copyWith({ int? totalCount, int? backupCount, int? remainderCount, Map? uploadItems, }) { return ExpBackupState( totalCount: totalCount ?? this.totalCount, backupCount: backupCount ?? this.backupCount, remainderCount: remainderCount ?? this.remainderCount, uploadItems: uploadItems ?? this.uploadItems, ); } Map toMap() { return { 'totalCount': totalCount, 'backupCount': backupCount, 'remainderCount': remainderCount, 'uploadItems': uploadItems, }; } factory ExpBackupState.fromMap(Map map) { return ExpBackupState( totalCount: map['totalCount'] as int, backupCount: map['backupCount'] as int, remainderCount: map['remainderCount'] as int, uploadItems: Map.from( (map['uploadItems'] as Map).map( (key, value) => MapEntry( key, ExpUploadStatus.fromMap(value as Map), ), ), ), ); } String toJson() => json.encode(toMap()); factory ExpBackupState.fromJson(String source) => ExpBackupState.fromMap(json.decode(source) as Map); @override String toString() { return 'ExpBackupState(totalCount: $totalCount, backupCount: $backupCount, remainderCount: $remainderCount, uploadItems: $uploadItems)'; } @override bool operator ==(covariant ExpBackupState other) { if (identical(this, other)) return true; final mapEquals = const DeepCollectionEquality().equals; return other.totalCount == totalCount && other.backupCount == backupCount && other.remainderCount == remainderCount && mapEquals(other.uploadItems, uploadItems); } @override int get hashCode { return totalCount.hashCode ^ backupCount.hashCode ^ remainderCount.hashCode ^ uploadItems.hashCode; } } final expBackupProvider = StateNotifierProvider((ref) { return ExpBackupNotifier( ref.watch(expBackupServiceProvider), ref.watch(uploadServiceProvider), ); }); class ExpBackupNotifier extends StateNotifier { ExpBackupNotifier( this._backupService, this._uploadService, ) : super( ExpBackupState( totalCount: 0, backupCount: 0, remainderCount: 0, uploadItems: {}, ), ) { { _uploadService.taskStatusStream.listen(_handleTaskStatusUpdate); _uploadService.taskProgressStream.listen(_handleTaskProgressUpdate); } } final ExpBackupService _backupService; final UploadService _uploadService; StreamSubscription? _statusSubscription; StreamSubscription? _progressSubscription; void _handleTaskStatusUpdate(TaskStatusUpdate update) { switch (update.status) { case TaskStatus.complete: state = state.copyWith( backupCount: state.backupCount + 1, remainderCount: state.remainderCount - 1, ); break; default: break; } } void _handleTaskProgressUpdate(TaskProgressUpdate update) {} Future getBackupStatus() async { // await _backgroundSyncManager.syncRemote(); final [totalCount, backupCount, remainderCount] = await Future.wait([ _backupService.getTotalCount(), _backupService.getBackupCount(), _backupService.getRemainderCount(), ]); state = state.copyWith( totalCount: totalCount, backupCount: backupCount, remainderCount: remainderCount, ); } Future backup() { return _backupService.backup(); } Future cancel() { return _backupService.cancel(); } Future getDataInfo() async { final a = await FileDownloader().database.allRecordsWithStatus( TaskStatus.enqueued, group: kBackupGroup, ); final b = await FileDownloader().allTasks( group: kBackupGroup, ); print("ALl tasks: ${b.length}"); } Future resume() async { await FileDownloader().start(); } @override void dispose() { _statusSubscription?.cancel(); _progressSubscription?.cancel(); super.dispose(); } }