diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 81cf8a252..544f1e2b0 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -9,6 +9,7 @@ import 'package:photos/models/file_load_result.dart'; import 'package:photos/models/file_type.dart'; import 'package:photos/models/location.dart'; import 'package:photos/models/magic_metadata.dart'; +import 'package:photos/services/feature_flag_service.dart'; import 'package:sqflite/sqflite.dart'; import 'package:sqflite_migration/sqflite_migration.dart'; @@ -95,7 +96,8 @@ class FilesDB { // this opens the database (and creates it if it doesn't exist) Future _initDatabase() async { - final Directory documentsDirectory = await getApplicationDocumentsDirectory(); + final Directory documentsDirectory = + await getApplicationDocumentsDirectory(); final String path = join(documentsDirectory.path, _databaseName); _logger.info("DB path " + path); return await openDatabaseWithMigration(path, dbConfig); @@ -430,6 +432,26 @@ class FilesDB { return FileLoadResult(deduplicatedFiles, files.length == limit); } + Future> getCollectionIDsOfHiddenFiles( + int ownerID, { + int visibility = kVisibilityArchive, + }) async { + final db = await instance.database; + final results = await db.query( + table, + where: + '$columnOwnerID = ? AND $columnMMdVisibility = ? AND $columnCollectionID != -1', + columns: [columnCollectionID], + whereArgs: [ownerID, visibility], + distinct: true, + ); + Set collectionIDsOfHiddenFiles = {}; + for (var result in results) { + collectionIDsOfHiddenFiles.add(result['collection_id']); + } + return collectionIDsOfHiddenFiles; + } + Future getAllLocalAndUploadedFiles( int startTime, int endTime, @@ -529,14 +551,26 @@ class FilesDB { int endTime, { int limit, bool asc, + int visibility = kVisibilityVisible, }) async { final db = await instance.database; final order = (asc ?? false ? 'ASC' : 'DESC'); + String whereClause; + List whereArgs; + if (FeatureFlagService.instance.isInternalUserOrDebugBuild()) { + whereClause = + '$columnCollectionID = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnMMdVisibility = ?'; + whereArgs = [collectionID, startTime, endTime, visibility]; + } else { + whereClause = + '$columnCollectionID = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ?'; + whereArgs = [collectionID, startTime, endTime]; + } + final results = await db.query( table, - where: - '$columnCollectionID = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ?', - whereArgs: [collectionID, startTime, endTime], + where: whereClause, + whereArgs: whereArgs, orderBy: '$columnCreationTime ' + order + ', $columnModificationTime ' + order, limit: limit, @@ -1006,9 +1040,23 @@ class FilesDB { } Future> getLatestCollectionFiles() async { - final db = await instance.database; - final rows = await db.rawQuery( - ''' + String query; + if (FeatureFlagService.instance.isInternalUserOrDebugBuild()) { + query = ''' + SELECT $table.* + FROM $table + INNER JOIN + ( + SELECT $columnCollectionID, MAX($columnCreationTime) AS max_creation_time + FROM $table + WHERE ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1 AND $columnMMdVisibility = $kVisibilityVisible) + GROUP BY $columnCollectionID + ) latest_files + ON $table.$columnCollectionID = latest_files.$columnCollectionID + AND $table.$columnCreationTime = latest_files.max_creation_time; + '''; + } else { + query = ''' SELECT $table.* FROM $table INNER JOIN @@ -1020,7 +1068,12 @@ class FilesDB { ) latest_files ON $table.$columnCollectionID = latest_files.$columnCollectionID AND $table.$columnCreationTime = latest_files.max_creation_time; - ''', + '''; + } + + final db = await instance.database; + final rows = await db.rawQuery( + query, ); final files = _convertToFiles(rows); // TODO: Do this de-duplication within the SQL Query diff --git a/lib/services/feature_flag_service.dart b/lib/services/feature_flag_service.dart index a1ff5ca94..fb71ebc87 100644 --- a/lib/services/feature_flag_service.dart +++ b/lib/services/feature_flag_service.dart @@ -86,15 +86,15 @@ class FeatureFlagService { bool enableSearch() { try { - return _isInternalUserOrDebugBuild() || _getFeatureFlags().enableSearch; + return isInternalUserOrDebugBuild() || _getFeatureFlags().enableSearch; } catch (e) { _logger.severe("failed to getSearchFeatureFlag", e); return FFDefault.enableSearch; } } - bool _isInternalUserOrDebugBuild() { - final String email = Configuration.instance.getEmail(); + bool isInternalUserOrDebugBuild() { + String email = Configuration.instance.getEmail(); return (email != null && email.endsWith("@ente.io")) || kDebugMode; } diff --git a/lib/ui/viewer/gallery/gallery_app_bar_widget.dart b/lib/ui/viewer/gallery/gallery_app_bar_widget.dart index 531211d99..a26bc1bb1 100644 --- a/lib/ui/viewer/gallery/gallery_app_bar_widget.dart +++ b/lib/ui/viewer/gallery/gallery_app_bar_widget.dart @@ -4,12 +4,16 @@ import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:photos/core/configuration.dart'; import 'package:photos/core/event_bus.dart'; +import 'package:photos/db/files_db.dart'; +import 'package:photos/ente_theme_data.dart'; import 'package:photos/events/subscription_purchased_event.dart'; import 'package:photos/models/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/feature_flag_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/utils/dialog_util.dart'; @@ -128,8 +132,24 @@ class _GalleryAppBarWidgetState extends State { message: "Share", child: IconButton( icon: Icon(Icons.adaptive.share), - onPressed: () { - _showShareCollectionDialog(); + onPressed: () async { + if (FeatureFlagService.instance.isInternalUserOrDebugBuild() && + await _collectionHasHiddenFiles(widget.collection.id)) { + final choice = await showChoiceDialog( + context, + 'Share hidden items?', + "Looks like you're trying to share an album that has some hidden items.\n\nThese hidden items can be seen by the recipient.", + firstAction: "Cancel", + secondAction: "Share anyway", + secondActionColor: + Theme.of(context).colorScheme.defaultTextColor, + ); + if (choice == DialogUserChoice.secondChoice) { + _showShareCollectionDialog(); + } + } else { + _showShareCollectionDialog(); + } }, ), ), @@ -225,4 +245,12 @@ class _GalleryAppBarWidgetState extends State { showGenericErrorDialog(context); } } + + Future _collectionHasHiddenFiles(int collectionID) async { + final collectionIDsWithHiddenFiles = + await FilesDB.instance.getCollectionIDsOfHiddenFiles( + Configuration.instance.getUserID(), + ); + return collectionIDsWithHiddenFiles.contains(collectionID); + } }