From 41593eecda2a524e22bb307e29f3e596effe75ac Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Thu, 24 Jul 2025 17:10:21 +0530 Subject: [PATCH] feat: icons, design, ownership and what not --- .../photos/assets/2.0x/auto-add-people.png | Bin 0 -> 693 bytes .../assets/2.0x/edit-auto-add-people.png | Bin 0 -> 674 bytes .../photos/assets/3.0x/auto-add-people.png | Bin 0 -> 920 bytes .../assets/3.0x/edit-auto-add-people.png | Bin 0 -> 907 bytes mobile/apps/photos/assets/auto-add-people.png | Bin 0 -> 401 bytes .../photos/assets/edit-auto-add-people.png | Bin 0 -> 379 bytes mobile/apps/photos/ios/Podfile.lock | 116 +++++++++--------- .../lib/events/smart_album_syncing_event.dart | 11 ++ .../apps/photos/lib/gateways/entity_gw.dart | 2 + .../lib/models/collection/collection.dart | 5 + .../lib/services/collections_service.dart | 8 +- .../photos/lib/services/entity_service.dart | 2 +- .../lib/services/smart_albums_service.dart | 91 ++++++++++---- mobile/apps/photos/lib/theme/ente_theme.dart | 2 +- .../collections/album/smart_album_people.dart | 12 +- .../actions/smart_albums_status_widget.dart | 115 +++++++++++++++++ .../ui/viewer/gallery/collection_page.dart | 4 + .../gallery/gallery_app_bar_widget.dart | 12 +- mobile/apps/photos/pubspec.lock | 116 +++++++++--------- mobile/apps/photos/pubspec.yaml | 1 + 20 files changed, 347 insertions(+), 150 deletions(-) create mode 100644 mobile/apps/photos/assets/2.0x/auto-add-people.png create mode 100644 mobile/apps/photos/assets/2.0x/edit-auto-add-people.png create mode 100644 mobile/apps/photos/assets/3.0x/auto-add-people.png create mode 100644 mobile/apps/photos/assets/3.0x/edit-auto-add-people.png create mode 100644 mobile/apps/photos/assets/auto-add-people.png create mode 100644 mobile/apps/photos/assets/edit-auto-add-people.png create mode 100644 mobile/apps/photos/lib/events/smart_album_syncing_event.dart create mode 100644 mobile/apps/photos/lib/ui/viewer/actions/smart_albums_status_widget.dart diff --git a/mobile/apps/photos/assets/2.0x/auto-add-people.png b/mobile/apps/photos/assets/2.0x/auto-add-people.png new file mode 100644 index 0000000000000000000000000000000000000000..d2b64f1eb6434c3243bd7bbcf72b77451dbb65fe GIT binary patch literal 693 zcmV;m0!safP)Q z?|lyllgXE45{3X9{Bdj{4vFSelQfT+bXO9EG&aun9FP| zp*)o#Bi6+^im(_2gt$>_8%;ta2;+zwL?n$Y&K8-V2j;>CmIH`6u}=VvbLh#WMPK( z6_snAn5z`r;Kb0EP;eq~W0jq1J~uhLM*Hv+#(^CYm-dTo$B;agxrbK>AGr|Z)_rZ1 zcRMQGY2L%1&nZ*>jCM%u77*ed?b}ERJNVOq?dDQ}O%8o4J&CXb>RVe)pc{j^bx-hP z<=Ex$hk(?MF|qDjr<=DKNskFdub&*}ee4JUUlVs)E-^k7WP|bxJ04ODkHm-~^UT*} zNP7zP9!)VU%B&}|%C1eBf)Mu3&iB1CUV(2iWrV=LJ%#SnsxN#38?n<+{(mc|8#5_uZnXX*cgB)@E3kUJd>@Q}Y4 zL5bDqnQ^vdY?`L#3&od#>*R)fUrsTH(kH6K4P{Tfuq5`|<=Ux9s`()MJ~W zin&7!oWd!D{creUHfR;c2u&dm{#k>-&P5S>fJvzSHx8V49D6+Vuc*f;f8Q@OA5etN b2LBsBAB^FNnzFgV00000NkvXXu0mjffBrJX literal 0 HcmV?d00001 diff --git a/mobile/apps/photos/assets/2.0x/edit-auto-add-people.png b/mobile/apps/photos/assets/2.0x/edit-auto-add-people.png new file mode 100644 index 0000000000000000000000000000000000000000..c5fd75c23b2f5f601f00bb3a804f58b7bf9ecf50 GIT binary patch literal 674 zcmV;T0$u%yP)Iq| ztcyAJY0(P^X;BMBlaL6)FyeXJ*%)J={IMb%E7~m8r#ua&y}Sb(HG z{APAE0`apC1ePE`U}0fl;S+I(ypXnywtH=BZL5y8TpK%UyEMONd?HBOgSJZBYou}6 zeN)$LQQD4(7wNJRGZRkQ4oEL_mcoB)yCJ{W?ocl<0UUJp7*D8adyEK+Jz+Yrt)1{b z+Gk-dVn-7_C$ZT@PdR6YEcu)+1kQ{V#kWWVLAGjA!tx;s zn>|h=iB=F$3L4&7>LcWj^hZQOf<~)>x_5%QeT)#nV`O8#!GrTukO>PJU4z6rvq2aI z(hu_rfvh7Nk~|BQwkM>!>x2M`hz1IzL!s_Ge#{)v?}S^E#@Bi3*+xiE=ZDPS8-$O7 z1nkiFs|+aby;Z~c2-CxH!}RSGQbC2`yP9n6ngD_@aD60nhY?=917Uw`{(9qzz&=7( zP2Li9AS3uADVtod4}|`7;Qu}yB`GWM*;&}9;R5c_k+ZDJ=N{i2g|C)0AHm9zeviCm z*Os)aEu%~Di)W=Kt}~&($XnKSGp@FbF2NT|8ey0xOGEts5Av3^-HZzY;CW+PWcWa+ z=VJ-~$Sy5=gm9@#us?(6_WWgB&tRV^_>Ky~UK0PUgx}Pn1vQr@4(TEyo%WS8_L=fticd6i^;W!(? zErc|}S%^*e>;$(E>iKOt7-C#j8TFd=MZE&%{y@CD3gX>ILO-}%QLm29sQ00sVc&q` uz}LRCaQ>f;d|wJe9Vq9x)wHm%FamE`>Pqvin#yhf0000nTH+)(ibPuAuNj}eJ6vK} zAo)lTq(uP_9z1yPiTHxNkg;cDPsX;!HWRyW8tu*4@A2;&J`rSWXRJ5&H_+I3KbBQ3 z%2;bLI>7@SP=Q7|6o$^@Wv0Wj6VBr`{+_3vEke9H-)H`w5xEp3puw_T zt%tw(Q4QZmxILUV=50Ir6wqURRFmyp6F`VeT-Ss)DDcDE6K;>Ky<%J$SR!;Y-rHhG zWCS@ezR3kkAS|Z?f0lGqjBiYvoz9YqHQdpW)7RDJ1z#P`C(AX7VCA^}guK36%e9m3 zMwj3}!b0b`&V+s;zb~JYeKYnQ@8?xw4hRb^jsn{}q|ClHBm?xH7uYu$5(vY5Y$4C= zDSV?K*w^6N*59Pe!;4L$KKOi#qwhHWA54Srur9?8_ARAG00jHmrceij>-+s30_b4x z!5Zc=C$?#uY(HrgJW;UsUeV)93mW#^Lil*n(I5cV>Avr?tCaMUc1(Zw5)vd?g8h7m zuX!!*iP*tD%?QgdCj?^Kh+GOSDVlISQALmL6xVYu9_doy-9jd|M*`MP|98lXhJ17h ziC7ceBj0YUhfHjX#7N%r;O{lkv4cF637L>QyXN`L%Ni#=g=K=<;Qf6}zNf=-Q$vu6 zO_HeA&`5hA)>`Ulg}yxsL9jnC2(fv#S028__XLD^;qyjIk9=C(5W>*V9{z%9R@On_ z)1#udZF$5rh7Rap?*zWaS)E5|p0Hdyys6c6#jv+;UDT_dzFyGd58c2002ovPDHLkV1gn$tx^C0 literal 0 HcmV?d00001 diff --git a/mobile/apps/photos/assets/auto-add-people.png b/mobile/apps/photos/assets/auto-add-people.png new file mode 100644 index 0000000000000000000000000000000000000000..9e42dbc6163ca856426f8dec80eb45da93378bcf GIT binary patch literal 401 zcmV;C0dD?@P)_`-2tRTAYmN{q4Rlwo!J@C?XC8H z2KX|5I%qPa;_Le2F$QFGEzf;LtkL>oeL+V3h9|AgQlnkDU2f*20SK5~XU zBezz^BX@Jqo{YxnAjS#p{rXh!eA*J$JD-F>>+_Y1&Rcli0{WkEN_tr<w7@}g veXO^gv&MXKT|Tg$6A?>zT(P1{vX5~Em#l@I|MU~-00000NkvXXu0mjfGoPUE literal 0 HcmV?d00001 diff --git a/mobile/apps/photos/assets/edit-auto-add-people.png b/mobile/apps/photos/assets/edit-auto-add-people.png new file mode 100644 index 0000000000000000000000000000000000000000..1eb01a05df1d9acf4bf06f25a34a287514dc2197 GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`j)FbFd;%$g$s6l5$8 za(7}_cTVOdki(Mh=`%Uj26&@BQ=hr!yKS8#)D7OZ~fF9rux4>-^g1cRy=Z ze9oDy=6a)NVp@)O+G|0#NoMJ3J68J?>PTG5)H=H%^hn?JZ>+(~B~O*8Z_L{{&D&C7 zc~kN`i5T_T=JRvgzm#fm=|4Vns3FR5%GS2;`@ZW=Uf0r`KAmIbLARV~TN~K_uKDp$ ztB2F}`fsPTpKY8OW8ZLIc3>>~v3Hri3|I521y2Rc&raEOxANiwo@NWdRf+<~)wMke z4!)m}y3tLh$f_^-vx7pP*8)dIl@}BKS6wRM6Hc@&ZML}bPFVdQ&MBb@0D6Lq&;S4c literal 0 HcmV?d00001 diff --git a/mobile/apps/photos/ios/Podfile.lock b/mobile/apps/photos/ios/Podfile.lock index 612dc72301..55224eaaf9 100644 --- a/mobile/apps/photos/ios/Podfile.lock +++ b/mobile/apps/photos/ios/Podfile.lock @@ -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 diff --git a/mobile/apps/photos/lib/events/smart_album_syncing_event.dart b/mobile/apps/photos/lib/events/smart_album_syncing_event.dart new file mode 100644 index 0000000000..bad2a36953 --- /dev/null +++ b/mobile/apps/photos/lib/events/smart_album_syncing_event.dart @@ -0,0 +1,11 @@ +import 'package:photos/events/event.dart'; + +class SmartAlbumSyncingEvent extends Event { + int? collectionId; + bool isSyncing; + + SmartAlbumSyncingEvent({ + this.collectionId, + this.isSyncing = false, + }); +} diff --git a/mobile/apps/photos/lib/gateways/entity_gw.dart b/mobile/apps/photos/lib/gateways/entity_gw.dart index 0e4b8bb2bc..7cbf4331f7 100644 --- a/mobile/apps/photos/lib/gateways/entity_gw.dart +++ b/mobile/apps/photos/lib/gateways/entity_gw.dart @@ -45,6 +45,7 @@ class EntityGateway { Future 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(), }, diff --git a/mobile/apps/photos/lib/models/collection/collection.dart b/mobile/apps/photos/lib/models/collection/collection.dart index e51d3972bf..8d68b73374 100644 --- a/mobile/apps/photos/lib/models/collection/collection.dart +++ b/mobile/apps/photos/lib/models/collection/collection.dart @@ -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; diff --git a/mobile/apps/photos/lib/services/collections_service.dart b/mobile/apps/photos/lib/services/collections_service.dart index 86ed68924b..ad4a0c2dfb 100644 --- a/mobile/apps/photos/lib/services/collections_service.dart +++ b/mobile/apps/photos/lib/services/collections_service.dart @@ -1403,8 +1403,9 @@ class CollectionsService { Future addOrCopyToCollection( int dstCollectionID, - List files, - ) async { + List 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> filesByCollection = {}; final Map> fileSeenByCollection = {}; diff --git a/mobile/apps/photos/lib/services/entity_service.dart b/mobile/apps/photos/lib/services/entity_service.dart index d03c82bfeb..25793ac0d7 100644 --- a/mobile/apps/photos/lib/services/entity_service.dart +++ b/mobile/apps/photos/lib/services/entity_service.dart @@ -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, diff --git a/mobile/apps/photos/lib/services/smart_albums_service.dart b/mobile/apps/photos/lib/services/smart_albums_service.dart index cd5dfefd21..cef9614347 100644 --- a/mobile/apps/photos/lib/services/smart_albums_service.dart +++ b/mobile/apps/photos/lib/services/smart_albums_service.dart @@ -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>? _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> _fetchAndCacheSaConfigs() async { @@ -78,10 +81,29 @@ class SmartAlbumsService { Future 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 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 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 _addOrUpdateEntity( EntityType type, Map 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 _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 } diff --git a/mobile/apps/photos/lib/theme/ente_theme.dart b/mobile/apps/photos/lib/theme/ente_theme.dart index 0bcc2261ac..fccb8036af 100644 --- a/mobile/apps/photos/lib/theme/ente_theme.dart +++ b/mobile/apps/photos/lib/theme/ente_theme.dart @@ -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; } } diff --git a/mobile/apps/photos/lib/ui/collections/album/smart_album_people.dart b/mobile/apps/photos/lib/ui/collections/album/smart_album_people.dart index d6de7f8bf6..e9911e93ec 100644 --- a/mobile/apps/photos/lib/ui/collections/album/smart_album_people.dart +++ b/mobile/apps/photos/lib/ui/collections/album/smart_album_people.dart @@ -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 { ); } } + + Bus.instance.fire( + CollectionUpdatedEvent( + widget.collectionId, + [], + "smart_album_people", + ), + ); } } newConfig = currentConfig!.getUpdatedConfig( @@ -142,7 +152,7 @@ class _SmartAlbumPeopleState extends State { } await smartAlbumsService.saveConfig(newConfig); - smartAlbumsService.syncSmartAlbums().ignore(); + unawaited(smartAlbumsService.syncSmartAlbums()); await dialog.hide(); Navigator.pop(context); diff --git a/mobile/apps/photos/lib/ui/viewer/actions/smart_albums_status_widget.dart b/mobile/apps/photos/lib/ui/viewer/actions/smart_albums_status_widget.dart new file mode 100644 index 0000000000..ed293f4447 --- /dev/null +++ b/mobile/apps/photos/lib/ui/viewer/actions/smart_albums_status_widget.dart @@ -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 createState() => + _SmartAlbumsStatusWidgetState(); +} + +class _SmartAlbumsStatusWidgetState extends State + with TickerProviderStateMixin { + (int, bool)? _syncingCollection; + StreamSubscription? 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().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(), + ); + } +} diff --git a/mobile/apps/photos/lib/ui/viewer/gallery/collection_page.dart b/mobile/apps/photos/lib/ui/viewer/gallery/collection_page.dart index aff40ef777..ddea445113 100644 --- a/mobile/apps/photos/lib/ui/viewer/gallery/collection_page.dart +++ b/mobile/apps/photos/lib/ui/viewer/gallery/collection_page.dart @@ -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, diff --git a/mobile/apps/photos/lib/ui/viewer/gallery/gallery_app_bar_widget.dart b/mobile/apps/photos/lib/ui/viewer/gallery/gallery_app_bar_widget.dart index 7bacdd3c0b..5e97ea84cd 100644 --- a/mobile/apps/photos/lib/ui/viewer/gallery/gallery_app_bar_widget.dart +++ b/mobile/apps/photos/lib/ui/viewer/gallery/gallery_app_bar_widget.dart @@ -387,9 +387,9 @@ class _GalleryAppBarWidgetState extends State { ); } - 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 { 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( diff --git a/mobile/apps/photos/pubspec.lock b/mobile/apps/photos/pubspec.lock index a5d14c3829..f3a4746484 100644 --- a/mobile/apps/photos/pubspec.lock +++ b/mobile/apps/photos/pubspec.lock @@ -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" diff --git a/mobile/apps/photos/pubspec.yaml b/mobile/apps/photos/pubspec.yaml index 19bf6b4b0c..08b619e189 100644 --- a/mobile/apps/photos/pubspec.yaml +++ b/mobile/apps/photos/pubspec.yaml @@ -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