Add option to free up space for a device folder
This commit is contained in:
parent
cb8962f011
commit
2732b399d4
4 changed files with 151 additions and 4 deletions
|
@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:photos/db/files_db.dart';
|
||||
import 'package:photos/models/backup_status.dart';
|
||||
import 'package:photos/models/device_collection.dart';
|
||||
import 'package:photos/models/file.dart';
|
||||
import 'package:photos/models/file_load_result.dart';
|
||||
|
@ -322,6 +323,31 @@ extension DeviceFiles on FilesDB {
|
|||
return FileLoadResult(dedupe, files.length == limit);
|
||||
}
|
||||
|
||||
Future<BackedUpFileIDs> getBackedUpForDeviceCollection(
|
||||
String pathID,
|
||||
int ownerID,
|
||||
) async {
|
||||
final db = await database;
|
||||
const String rawQuery = '''
|
||||
SELECT ${FilesDB.columnLocalID}, ${FilesDB.columnUploadedFileID}
|
||||
FROM ${FilesDB.filesTable}
|
||||
WHERE ${FilesDB.columnLocalID} IS NOT NULL AND
|
||||
(${FilesDB.columnOwnerID} IS NULL OR ${FilesDB.columnOwnerID} = ?)
|
||||
AND (${FilesDB.columnUploadedFileID} IS NOT NULL AND ${FilesDB.columnUploadedFileID} IS NOT -1)
|
||||
AND
|
||||
${FilesDB.columnLocalID} IN
|
||||
(SELECT id FROM device_files where path_id = ?)
|
||||
''';
|
||||
final results = await db.rawQuery(rawQuery, [ownerID, pathID]);
|
||||
final localIDs = <String>{};
|
||||
final uploadedIDs = <int>{};
|
||||
for (final result in results) {
|
||||
localIDs.add(result[FilesDB.columnLocalID]);
|
||||
uploadedIDs.add(result[FilesDB.columnUploadedFileID]);
|
||||
}
|
||||
return BackedUpFileIDs(localIDs.toList(), uploadedIDs.toList());
|
||||
}
|
||||
|
||||
Future<List<DeviceCollection>> getDeviceCollections({
|
||||
bool includeCoverThumbnail = false,
|
||||
}) async {
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:photos/core/constants.dart';
|
|||
import 'package:photos/core/errors.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/core/network.dart';
|
||||
import 'package:photos/db/device_files_db.dart';
|
||||
import 'package:photos/db/files_db.dart';
|
||||
import 'package:photos/events/permission_granted_event.dart';
|
||||
import 'package:photos/events/subscription_purchased_event.dart';
|
||||
|
@ -206,8 +207,16 @@ class SyncService {
|
|||
);
|
||||
}
|
||||
|
||||
Future<BackupStatus> getBackupStatus() async {
|
||||
final ids = await FilesDB.instance.getBackedUpIDs();
|
||||
Future<BackupStatus> getBackupStatus({String pathID}) async {
|
||||
BackedUpFileIDs ids;
|
||||
if (pathID == null) {
|
||||
ids = await FilesDB.instance.getBackedUpIDs();
|
||||
} else {
|
||||
ids = await FilesDB.instance.getBackedUpForDeviceCollection(
|
||||
pathID,
|
||||
Configuration.instance.getUserID(),
|
||||
);
|
||||
}
|
||||
final size = await _getFileSize(ids.uploadedIDs);
|
||||
return BackupStatus(ids.localIDs, size);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -9,18 +10,24 @@ import 'package:photos/core/configuration.dart';
|
|||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/events/subscription_purchased_event.dart';
|
||||
import 'package:photos/models/backup_status.dart';
|
||||
import 'package:photos/models/collection.dart';
|
||||
import 'package:photos/models/device_collection.dart';
|
||||
import 'package:photos/models/gallery_type.dart';
|
||||
import 'package:photos/models/magic_metadata.dart';
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/ui/common/dialogs.dart';
|
||||
import 'package:photos/ui/common/rename_dialog.dart';
|
||||
import 'package:photos/ui/sharing/share_collection_widget.dart';
|
||||
import 'package:photos/ui/tools/free_space_page.dart';
|
||||
import 'package:photos/utils/data_util.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/magic_util.dart';
|
||||
import 'package:photos/utils/navigation_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class GalleryAppBarWidget extends StatefulWidget {
|
||||
final GalleryType type;
|
||||
|
@ -154,6 +161,93 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
|||
}
|
||||
}
|
||||
|
||||
// todo: In the new design, clicking on free up space will directly open
|
||||
// the free up space page and show loading indicator while calculating
|
||||
// the space which can be claimed up. This code duplication should be removed
|
||||
// whenever we move to the new design for free up space.
|
||||
Future<dynamic> _deleteDeviceAlbum(BuildContext context) async {
|
||||
final dialog = createProgressDialog(context, "Calculating...");
|
||||
await dialog.show();
|
||||
BackupStatus status;
|
||||
try {
|
||||
status = await SyncService.instance
|
||||
.getBackupStatus(pathID: widget.deviceCollection.id);
|
||||
} catch (e) {
|
||||
await dialog.hide();
|
||||
showGenericErrorDialog(context);
|
||||
return;
|
||||
}
|
||||
|
||||
await dialog.hide();
|
||||
if (status.localIDs.isEmpty) {
|
||||
showErrorDialog(
|
||||
context,
|
||||
"✨ All clear",
|
||||
"You've no files in this folder that can be deleted",
|
||||
);
|
||||
} else {
|
||||
final bool result = await routeToPage(context, FreeSpacePage(status));
|
||||
if (result == true) {
|
||||
_showSpaceFreedDialog(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _showSpaceFreedDialog(BackupStatus status) {
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: const Text("Success"),
|
||||
content: Text(
|
||||
"You have successfully freed up " + formatBytes(status.size) + "!",
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
"Rate us",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.greenAlternative,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
// TODO: Replace with https://pub.dev/packages/in_app_review
|
||||
if (Platform.isAndroid) {
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/apps/details?id=io.ente.photos",
|
||||
);
|
||||
} else {
|
||||
launchUrlString(
|
||||
"https://apps.apple.com/in/app/ente-photos/id1542026904",
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text(
|
||||
"Ok",
|
||||
),
|
||||
onPressed: () {
|
||||
if (Platform.isIOS) {
|
||||
showToast(
|
||||
context,
|
||||
"Also empty \"Recently Deleted\" from \"Settings\" -> \"Storage\" to claim the freed space",
|
||||
);
|
||||
}
|
||||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
showConfettiDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
barrierColor: Colors.black87,
|
||||
confettiAlignment: Alignment.topCenter,
|
||||
useRootNavigator: true,
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _getDefaultActions(BuildContext context) {
|
||||
final List<Widget> actions = <Widget>[];
|
||||
if (Configuration.instance.hasConfiguredAccount() &&
|
||||
|
@ -242,6 +336,22 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (widget.type == GalleryType.localFolder) {
|
||||
items.add(
|
||||
PopupMenuItem(
|
||||
value: 5,
|
||||
child: Row(
|
||||
children: const [
|
||||
Icon(Icons.logout),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
),
|
||||
Text("Free up device space"),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (items.isNotEmpty) {
|
||||
actions.add(
|
||||
PopupMenuButton(
|
||||
|
@ -263,6 +373,8 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
|||
await _trashCollection();
|
||||
} else if (value == 4) {
|
||||
await _leaveAlbum(context);
|
||||
} else if (value == 5) {
|
||||
await _deleteDeviceAlbum(context);
|
||||
} else {
|
||||
showToast(context, "Something went wrong");
|
||||
}
|
||||
|
|
|
@ -338,7 +338,7 @@ Future<bool> deleteLocalFiles(
|
|||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
if (androidInfo.version.sdkInt < android11SDKINT) {
|
||||
deletedIDs
|
||||
.addAll(await _deleteLocalFilesInBatches(context, localAssetIDs));
|
||||
.addAll(await deleteLocalFilesInBatches(context, localAssetIDs));
|
||||
} else {
|
||||
deletedIDs
|
||||
.addAll(await _deleteLocalFilesInOneShot(context, localAssetIDs));
|
||||
|
@ -384,7 +384,7 @@ Future<List<String>> _deleteLocalFilesInOneShot(
|
|||
return deletedIDs;
|
||||
}
|
||||
|
||||
Future<List<String>> _deleteLocalFilesInBatches(
|
||||
Future<List<String>> deleteLocalFilesInBatches(
|
||||
BuildContext context,
|
||||
List<String> localIDs,
|
||||
) async {
|
||||
|
|
Loading…
Reference in a new issue