feat: icons, design, ownership and what not

This commit is contained in:
Prateek Sunal
2025-07-24 17:10:21 +05:30
parent b59a23d0ac
commit 41593eecda
20 changed files with 347 additions and 150 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

View File

@@ -304,7 +304,7 @@ DEPENDENCIES:
- workmanager (from `.symlinks/plugins/workmanager/ios`)
SPEC REPOS:
https://github.com/ente-io/ffmpeg-kit-custom-repo-ios.git:
https://github.com/ente-io/ffmpeg-kit-custom-repo-ios:
- ffmpeg_kit_custom
trunk:
- Firebase
@@ -445,83 +445,83 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/workmanager/ios"
SPEC CHECKSUMS:
app_links: f3e17e4ee5e357b39d8b95290a9b2c299fca71c6
battery_info: b6c551049266af31556b93c9d9b9452cfec0219f
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
cupertino_http: 947a233f40cfea55167a49f2facc18434ea117ba
dart_ui_isolate: d5bcda83ca4b04f129d70eb90110b7a567aece14
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c
dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
ffmpeg_kit_custom: 682b4f2f1ff1f8abae5a92f6c3540f2441d5be99
ffmpeg_kit_flutter: 9dce4803991478c78c6fb9f972703301101095fe
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
ffmpeg_kit_flutter: 915b345acc97d4142e8a9a8549d177ff10f043f5
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf
firebase_core: 6e223dfa350b2edceb729cea505eaaef59330682
firebase_messaging: 07fde77ae28c08616a1d4d870450efc2b38cf40d
firebase_core: 6cbed78b4f298ed103a9fd034e6dbc846320480f
firebase_messaging: 5e0adf2eb18b0ee59aa0c109314c091a0497ecac
FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d
FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629
FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917
FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_email_sender: e03bdda7637bcd3539bfe718fddd980e9508efaa
flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
flutter_sodium: a00383520fc689c688b66fd3092984174712493e
flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987
flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
launcher_icon_switcher: 8e0ad2131a20c51c1dd939896ee32e70cd845b37
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
image_editor_common: 3de87e7c4804f4ae24c8f8a998362b98c105cac1
in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
launcher_icon_switcher: 84c218d233505aa7d8655d8fa61a3ba802c022da
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
maps_launcher: 2e5b6a2d664ec6c27f82ffa81b74228d770ab203
media_extension: 6618f07abd762cdbfaadf1b0c56a287e820f0c84
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91
motionphoto: 8b65ce50c7d7ff3c767534fc3768b2eed9ac24e4
move_to_background: cd3091014529ec7829e342ad2d75c0a11f4378a5
maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
media_extension: 671e2567880d96c95c65c9a82ccceed8f2e309fd
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
motion_sensors: 741e702c17467b9569a92165dda8d4d88c6167f1
motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1
move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
native_video_player: 29ab24a926804ac8c4a57eb6d744c7d927c2bc3e
objective_c: 77e887b5ba1827970907e10e832eec1683f3431d
onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997
native_video_player: 6809dec117e8997161dbfb42a6f90d6df71a504d
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b
open_mail_app: 70273c53f768beefdafbe310c3d9086e4da3cb02
open_mail_app: 7314a609e88eed22d53671279e189af7a0ab0f11
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413
privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
SDWebImage: f29024626962457f3470184232766516dee8dfea
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
sentry_flutter: 2df8b0aab7e4aba81261c230cbea31c82a62dd1b
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sqlite3: 3c950dc86011117c307eb0b28c4a7bb449dce9f1
sqlite3_flutter_libs: 069c435986dd4b63461aecd68f4b30be4a9e9daa
system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
thermal: a9261044101ae8f532fa29cab4e8270b51b3f55c
ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
video_thumbnail: 94ba6705afbaa120b77287080424930f23ea0c40
volume_controller: 2e3de73d6e7e81a0067310d17fb70f2f86d71ac7
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
sqlite3_flutter_libs: 3c323550ef3b928bc0aa9513c841e45a7d242832
system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
thermal: d4c48be750d1ddbab36b0e2dcb2471531bc8df41
ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
video_thumbnail: 584ccfa55d8fd2f3d5507218b0a18d84c839c620
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
workmanager: 01be2de7f184bd15de93a1812936a2b7f42ef07e
PODFILE CHECKSUM: a8ef88ad74ba499756207e7592c6071a96756d18

View File

@@ -0,0 +1,11 @@
import 'package:photos/events/event.dart';
class SmartAlbumSyncingEvent extends Event {
int? collectionId;
bool isSyncing;
SmartAlbumSyncingEvent({
this.collectionId,
this.isSyncing = false,
});
}

View File

@@ -45,6 +45,7 @@ class EntityGateway {
Future<EntityData> createEntity(
EntityType type,
String? id,
String encryptedData,
String header,
) async {
@@ -52,6 +53,7 @@ class EntityGateway {
"/user-entity/entity",
data: {
"encryptedData": encryptedData,
if (id != null) "id": id,
"header": header,
"type": type.typeToString(),
},

View File

@@ -139,6 +139,11 @@ class Collection {
return (owner.id ?? -100) == userID;
}
bool canAutoAdd(int userID) {
return (owner.id ?? -100) == userID ||
getRole(userID) == CollectionParticipantRole.collaborator;
}
bool isDownloadEnabledForPublicLink() {
if (publicURLs.isEmpty) {
return false;

View File

@@ -1403,8 +1403,9 @@ class CollectionsService {
Future<void> addOrCopyToCollection(
int dstCollectionID,
List<EnteFile> files,
) async {
List<EnteFile> files, {
bool toCopy = true,
}) async {
final splitResult = FilesSplit.split(files, _config.getUserID()!);
if (splitResult.pendingUploads.isNotEmpty) {
throw ArgumentError('File should be already uploaded');
@@ -1425,6 +1426,9 @@ class CollectionsService {
);
await _addToCollection(dstCollectionID, filesToAdd);
}
if (!toCopy) {
return;
}
// group files by collectionID
final Map<int, List<EnteFile>> filesByCollection = {};
final Map<int, Set<int>> fileSeenByCollection = {};

View File

@@ -83,7 +83,7 @@ class EntityService {
late LocalEntityData localData;
final EntityData data = id == null || addWithCustomID
? await _gateway.createEntity(type, encryptedData, header)
? await _gateway.createEntity(type, id, encryptedData, header)
: await _gateway.updateEntity(type, id, encryptedData, header);
localData = LocalEntityData(
id: data.id,

View File

@@ -3,14 +3,15 @@ import "dart:convert";
import "package:logging/logging.dart";
import "package:photos/core/configuration.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/smart_album_syncing_event.dart";
import "package:photos/models/api/entity/type.dart";
import "package:photos/models/collection/smart_album_config.dart";
import "package:photos/models/file/file.dart";
import "package:photos/models/local_entity_data.dart";
import "package:photos/service_locator.dart" show entityService;
import "package:photos/services/collections_service.dart";
import "package:photos/services/search_service.dart";
import "package:photos/ui/actions/collection/collection_file_actions.dart";
import "package:photos/ui/actions/collection/collection_sharing_actions.dart";
class SmartAlbumsService {
final _logger = Logger((SmartAlbumsService).toString());
@@ -19,6 +20,8 @@ class SmartAlbumsService {
Future<Map<int, SmartAlbumConfig>>? _cachedConfigsFuture;
(int, bool)? syncingCollection;
void clearCache() {
_cachedConfigsFuture = null;
_lastCacheRefreshTime = 0;
@@ -35,7 +38,7 @@ class SmartAlbumsService {
_cachedConfigsFuture = null; // Invalidate cache
}
_cachedConfigsFuture ??= _fetchAndCacheSaConfigs();
return await _cachedConfigsFuture!;
return _cachedConfigsFuture!;
}
Future<Map<int, SmartAlbumConfig>> _fetchAndCacheSaConfigs() async {
@@ -78,10 +81,29 @@ class SmartAlbumsService {
Future<void> syncSmartAlbums() async {
final cachedConfigs = await getSmartConfigs();
final userId = Configuration.instance.getUserID();
for (final entry in cachedConfigs.entries) {
final collectionId = entry.key;
final config = entry.value;
final collection =
CollectionsService.instance.getCollectionByID(collectionId)!;
if (!collection.canAutoAdd(userId!)) {
_logger.warning(
"Deleting collection config ($collectionId) as user does not have permission",
);
await _deleteEntry(
userId: userId,
collectionId: collectionId,
);
continue;
}
syncingCollection = (collectionId, false);
Bus.instance.fire(
SmartAlbumSyncingEvent(collectionId: collectionId, isSyncing: false),
);
final infoMap = config.infoMap;
@@ -91,6 +113,9 @@ class SmartAlbumsService {
config.personIDs.toList(),
);
Set<EnteFile> toBeSynced = {};
var newConfig = config;
for (final personId in config.personIDs) {
// compares current updateAt with last added file's updatedAt
if (updatedAtMap[personId] == null ||
@@ -99,7 +124,7 @@ class SmartAlbumsService {
continue;
}
final toBeSynced = (await SearchService.instance
final fileIds = (await SearchService.instance
.getClusterFilesForPersonID(personId))
.entries
.expand((e) => e.value)
@@ -107,35 +132,43 @@ class SmartAlbumsService {
..removeWhere(
(e) =>
e.uploadedFileID == null ||
config.infoMap[personId]!.addedFiles.contains(e.uploadedFileID),
config.infoMap[personId]!.addedFiles
.contains(e.uploadedFileID) ||
e.ownerID != userId,
);
if (toBeSynced.isNotEmpty) {
final CollectionActions collectionActions =
CollectionActions(CollectionsService.instance);
toBeSynced = {...toBeSynced, ...fileIds};
final result = await collectionActions.addToCollection(
null,
newConfig = await newConfig.addFiles(
personId,
updatedAtMap[personId]!,
toBeSynced.map((e) => e.uploadedFileID!).toSet(),
);
}
syncingCollection = (collectionId, true);
Bus.instance.fire(
SmartAlbumSyncingEvent(collectionId: collectionId, isSyncing: true),
);
if (toBeSynced.isNotEmpty) {
try {
await CollectionsService.instance.addOrCopyToCollection(
toCopy: false,
collectionId,
false,
selectedFiles: toBeSynced,
toBeSynced.toList(),
);
if (result) {
final newConfig = await config.addFiles(
personId,
updatedAtMap[personId]!,
toBeSynced.map((e) => e.uploadedFileID!).toSet(),
);
await saveConfig(newConfig);
}
}
await saveConfig(newConfig);
} catch (_) {}
}
}
syncingCollection = null;
Bus.instance.fire(SmartAlbumSyncingEvent());
}
Future<void> saveConfig(SmartAlbumConfig config) async {
final userId = Configuration.instance.getUserID();
final userId = Configuration.instance.getUserID()!;
await _addOrUpdateEntity(
EntityType.smartAlbum,
@@ -151,15 +184,21 @@ class SmartAlbumsService {
return cachedConfigs[collectionId];
}
String getId({required int collectionId, required int userId}) =>
"sa_${userId}_$collectionId";
/// Wrapper method for entityService.addOrUpdate that handles cache refresh
Future<LocalEntityData> _addOrUpdateEntity(
EntityType type,
Map<String, dynamic> jsonMap, {
required int collectionId,
bool addWithCustomID = false,
int? userId,
required int userId,
}) async {
final id = "sa_${userId!}_$collectionId";
final id = getId(
collectionId: collectionId,
userId: userId,
);
final result = await entityService.addOrUpdate(
type,
jsonMap,
@@ -172,8 +211,10 @@ class SmartAlbumsService {
}
Future<void> _deleteEntry({
required String id,
required int userId,
required int collectionId,
}) async {
final id = getId(collectionId: collectionId, userId: userId);
await entityService.deleteEntry(id);
_lastCacheRefreshTime = 0; // Invalidate cache
}

View File

@@ -19,7 +19,7 @@ class EnteTheme {
required this.shadowButton,
});
bool isDark(BuildContext context) {
static bool isDark(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark;
}
}

View File

@@ -1,7 +1,9 @@
import "dart:async";
import 'package:flutter/material.dart';
import "package:photos/core/event_bus.dart";
import "package:photos/db/files_db.dart";
import "package:photos/events/collection_updated_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/collection/smart_album_config.dart";
import "package:photos/models/selected_people.dart";
@@ -134,6 +136,14 @@ class _SmartAlbumPeopleState extends State<SmartAlbumPeople> {
);
}
}
Bus.instance.fire(
CollectionUpdatedEvent(
widget.collectionId,
[],
"smart_album_people",
),
);
}
}
newConfig = currentConfig!.getUpdatedConfig(
@@ -142,7 +152,7 @@ class _SmartAlbumPeopleState extends State<SmartAlbumPeople> {
}
await smartAlbumsService.saveConfig(newConfig);
smartAlbumsService.syncSmartAlbums().ignore();
unawaited(smartAlbumsService.syncSmartAlbums());
await dialog.hide();
Navigator.pop(context);

View File

@@ -0,0 +1,115 @@
import "dart:async";
import 'package:flutter/material.dart';
import "package:flutter_spinkit/flutter_spinkit.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/smart_album_syncing_event.dart";
import "package:photos/generated/l10n.dart";
import 'package:photos/models/collection/collection.dart';
import "package:photos/service_locator.dart";
import "package:photos/theme/ente_theme.dart";
class SmartAlbumsStatusWidget extends StatefulWidget {
final Collection? collection;
const SmartAlbumsStatusWidget({
this.collection,
super.key,
});
@override
State<SmartAlbumsStatusWidget> createState() =>
_SmartAlbumsStatusWidgetState();
}
class _SmartAlbumsStatusWidgetState extends State<SmartAlbumsStatusWidget>
with TickerProviderStateMixin {
(int, bool)? _syncingCollection;
StreamSubscription<SmartAlbumSyncingEvent>? subscription;
void updateData(SmartAlbumSyncingEvent event) {
if (mounted) {
setState(() {
if (event.collectionId != null) {
_syncingCollection = (event.collectionId!, event.isSyncing);
} else {
_syncingCollection = null;
}
});
}
}
@override
void initState() {
super.initState();
_syncingCollection = smartAlbumsService.syncingCollection;
subscription = Bus.instance.on<SmartAlbumSyncingEvent>().listen(updateData);
}
@override
void dispose() {
subscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
final colorScheme = getEnteColorScheme(context);
final textTheme = getEnteTextTheme(context);
return AnimatedCrossFade(
firstCurve: Curves.easeInOutExpo,
secondCurve: Curves.easeInOutExpo,
sizeCurve: Curves.easeInOutExpo,
crossFadeState: !(_syncingCollection == null ||
_syncingCollection!.$1 != widget.collection?.id)
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: const Duration(milliseconds: 400),
secondChild: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12)
.copyWith(left: 14),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: EnteTheme.isDark(context)
? Colors.white.withOpacity(0.08)
: Colors.black.withOpacity(0.65),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
child: SpinKitFadingCircle(
size: 18,
color: _syncingCollection?.$2 ?? true
? const Color(0xFF08C225)
: const Color(0xFFF78426),
controller: AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
),
),
),
const SizedBox(width: 8),
Text(
(_syncingCollection?.$2 ?? true)
? S.of(context).addingPhotos
: S.of(context).gettingReady,
style: textTheme.small.copyWith(
color: colorScheme.backdropBase,
),
),
],
),
),
const SizedBox(height: 50),
],
),
firstChild: const SizedBox.shrink(),
);
}
}

View File

@@ -14,6 +14,7 @@ import "package:photos/models/search/hierarchical/hierarchical_search_filter.dar
import 'package:photos/models/selected_files.dart';
import 'package:photos/services/ignored_files_service.dart';
import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import "package:photos/ui/viewer/actions/smart_albums_status_widget.dart";
import "package:photos/ui/viewer/gallery/collect_photos_bottom_buttons.dart";
import "package:photos/ui/viewer/gallery/empty_album_state.dart";
import 'package:photos/ui/viewer/gallery/empty_state.dart';
@@ -153,6 +154,9 @@ class CollectionPage extends StatelessWidget {
);
},
),
SmartAlbumsStatusWidget(
collection: c.collection,
),
FileSelectionOverlayBar(
galleryType,
_selectedFiles,

View File

@@ -387,9 +387,9 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
);
}
final int userID = Configuration.instance.getUserID()!;
final int userId = Configuration.instance.getUserID()!;
isQuickLink = widget.collection?.isQuickLinkCollection() ?? false;
if (galleryType.canAddFiles(widget.collection, userID)) {
if (galleryType.canAddFiles(widget.collection, userId)) {
actions.add(
Tooltip(
message: S.of(context).addFiles,
@@ -528,14 +528,18 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
context.l10n.playOnTv,
icon: Icons.tv_outlined,
),
if (widget.collection != null)
if (widget.collection?.canAutoAdd(userId) ?? false)
EntePopupMenuItemAsync(
(value) => (value?[widget.collection!.id]?.personIDs.isEmpty ?? true)
? S.of(context).autoAddPeople
: S.of(context).editAutoAddPeople,
value: AlbumPopupAction.autoAddPhotos,
future: smartAlbumsService.getSmartConfigs,
icon: (value) => Icons.add,
iconWidget: (value) => Image.asset(
(value?[widget.collection!.id]?.personIDs.isEmpty ?? true)
? "assets/auto-add-people.png"
: "assets/edit-auto-add-people.png",
),
),
if (galleryType.canDelete())
EntePopupMenuItem(

View File

@@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
url: "https://pub.dev"
source: hosted
version: "76.0.0"
version: "72.0.0"
_flutterfire_internals:
dependency: transitive
description:
@@ -21,7 +21,7 @@ packages:
dependency: transitive
description: dart
source: sdk
version: "0.3.3"
version: "0.3.2"
adaptive_theme:
dependency: "direct main"
description:
@@ -34,10 +34,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
url: "https://pub.dev"
source: hosted
version: "6.11.0"
version: "6.7.0"
android_intent_plus:
dependency: "direct main"
description:
@@ -130,10 +130,10 @@ packages:
dependency: "direct main"
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
version: "2.11.0"
battery_info:
dependency: "direct main"
description:
@@ -155,10 +155,10 @@ packages:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.1"
brotli:
dependency: transitive
description:
@@ -268,10 +268,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
@@ -301,10 +301,10 @@ packages:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.1"
code_builder:
dependency: transitive
description:
@@ -317,10 +317,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.19.1"
version: "1.18.0"
computer:
dependency: "direct main"
description:
@@ -619,10 +619,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.1"
fast_base58:
dependency: "direct main"
description:
@@ -668,10 +668,10 @@ packages:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
version: "7.0.0"
file_saver:
dependency: "direct main"
description:
@@ -1073,7 +1073,7 @@ packages:
source: git
version: "0.2.0"
flutter_spinkit:
dependency: transitive
dependency: "direct main"
description:
name: flutter_spinkit
sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472
@@ -1416,18 +1416,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
@@ -1536,10 +1536,10 @@ packages:
dependency: transitive
description:
name: macros
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
url: "https://pub.dev"
source: hosted
version: "0.1.3-main.0"
version: "0.1.2-main.4"
maps_launcher:
dependency: "direct main"
description:
@@ -1552,10 +1552,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.17"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
@@ -1645,10 +1645,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.16.0"
version: "1.15.0"
mgrs_dart:
dependency: transitive
description:
@@ -1859,10 +1859,10 @@ packages:
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.9.0"
path_drawing:
dependency: transitive
description:
@@ -2019,10 +2019,10 @@ packages:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
@@ -2068,10 +2068,10 @@ packages:
dependency: transitive
description:
name: process
sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d"
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
version: "5.0.2"
proj4dart:
dependency: transitive
description:
@@ -2309,7 +2309,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
version: "0.0.99"
source_gen:
dependency: transitive
description:
@@ -2346,10 +2346,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
version: "1.10.0"
sprintf:
dependency: transitive
description:
@@ -2434,10 +2434,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
version: "1.11.1"
step_progress_indicator:
dependency: "direct main"
description:
@@ -2450,10 +2450,10 @@ packages:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.2"
stream_transform:
dependency: transitive
description:
@@ -2466,10 +2466,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.2.0"
styled_text:
dependency: "direct main"
description:
@@ -2522,34 +2522,34 @@ packages:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e"
sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
url: "https://pub.dev"
source: hosted
version: "1.25.15"
version: "1.25.7"
test_api:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.4"
version: "0.7.2"
test_core:
dependency: transitive
description:
name: test_core
sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa"
sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
url: "https://pub.dev"
source: hosted
version: "0.6.8"
version: "0.6.4"
thermal:
dependency: "direct main"
description:
@@ -2813,10 +2813,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.3.1"
version: "14.2.5"
volume_controller:
dependency: transitive
description:
@@ -2877,10 +2877,10 @@ packages:
dependency: transitive
description:
name: webdriver
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
url: "https://pub.dev"
source: hosted
version: "3.0.4"
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
@@ -2978,5 +2978,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.7.0-0 <4.0.0"
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View File

@@ -103,6 +103,7 @@ dependencies:
# If not resolved and we need to upgrade, write a migration script.
flutter_secure_storage: 9.0.0
flutter_sodium:
flutter_spinkit: ^5.2.1
flutter_staggered_grid_view: ^0.6.2
flutter_svg: ^2.0.10+1
flutter_timezone: ^4.1.0