diff --git a/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png
index bfdc42157d..153b05b109 100644
Binary files a/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-hdpi/splash.png b/mobile/android/app/src/main/res/drawable-hdpi/splash.png
index bfdc42157d..153b05b109 100644
Binary files a/mobile/android/app/src/main/res/drawable-hdpi/splash.png and b/mobile/android/app/src/main/res/drawable-hdpi/splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png
index 3911d58c35..358b349d23 100644
Binary files a/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-mdpi/splash.png b/mobile/android/app/src/main/res/drawable-mdpi/splash.png
index 3911d58c35..358b349d23 100644
Binary files a/mobile/android/app/src/main/res/drawable-mdpi/splash.png and b/mobile/android/app/src/main/res/drawable-mdpi/splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png
index bfdc42157d..153b05b109 100644
Binary files a/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png
index 3911d58c35..358b349d23 100644
Binary files a/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png
index 3d26dfd83c..5bd6530afa 100644
Binary files a/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png
index e9641f3f28..86ec272c98 100644
Binary files a/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png
index 254e7716e5..f467da24d2 100644
Binary files a/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png
index 3d26dfd83c..5bd6530afa 100644
Binary files a/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/splash.png b/mobile/android/app/src/main/res/drawable-xhdpi/splash.png
index 3d26dfd83c..5bd6530afa 100644
Binary files a/mobile/android/app/src/main/res/drawable-xhdpi/splash.png and b/mobile/android/app/src/main/res/drawable-xhdpi/splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png
index e9641f3f28..86ec272c98 100644
Binary files a/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png b/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png
index e9641f3f28..86ec272c98 100644
Binary files a/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png and b/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png
index 254e7716e5..f467da24d2 100644
Binary files a/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png
index 254e7716e5..f467da24d2 100644
Binary files a/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png and b/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png differ
diff --git a/mobile/android/app/src/main/res/drawable/notification_icon.png b/mobile/android/app/src/main/res/drawable/notification_icon.png
index dbaecfac8d..fc0086775a 100644
Binary files a/mobile/android/app/src/main/res/drawable/notification_icon.png and b/mobile/android/app/src/main/res/drawable/notification_icon.png differ
diff --git a/mobile/assets/splash-screen-icon.png b/mobile/assets/splash-screen-icon.png
index 5857817eac..5ccda51ae9 100644
Binary files a/mobile/assets/splash-screen-icon.png and b/mobile/assets/splash-screen-icon.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-1024x1024@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-1024x1024@1x.png
deleted file mode 100644
index e6bae73ea5..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-1024x1024@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@1x.png
deleted file mode 100644
index bb28b6a74f..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@2x.png
deleted file mode 100644
index edb8f95896..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@3x.png
deleted file mode 100644
index a713469b6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-20x20@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@1x.png
deleted file mode 100644
index cc98c8dbf8..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@2x.png
deleted file mode 100644
index 119692c5d1..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@3x.png
deleted file mode 100644
index ed6d5a382b..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-29x29@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@1x.png
deleted file mode 100644
index edb8f95896..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@2x.png
deleted file mode 100644
index 10e0242d59..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@3x.png
deleted file mode 100644
index aea4e77fc3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-40x40@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-50x50@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-50x50@1x.png
deleted file mode 100644
index ef16e5d8d3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-50x50@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-50x50@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-50x50@2x.png
deleted file mode 100644
index 65890b669d..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-50x50@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-57x57@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-57x57@1x.png
deleted file mode 100644
index 8ee523aabb..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-57x57@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-57x57@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-57x57@2x.png
deleted file mode 100644
index 2294b68ed0..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-57x57@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-60x60@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-60x60@2x.png
deleted file mode 100644
index aea4e77fc3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-60x60@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-60x60@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-60x60@3x.png
deleted file mode 100644
index 5d4fec318f..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-60x60@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-72x72@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-72x72@1x.png
deleted file mode 100644
index 730f69093a..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-72x72@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-72x72@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-72x72@2x.png
deleted file mode 100644
index 6d804c6329..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-72x72@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-76x76@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-76x76@1x.png
deleted file mode 100644
index 12bf9e7022..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-76x76@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-76x76@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-76x76@2x.png
deleted file mode 100644
index fd483027e7..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-76x76@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-83.5x83.5@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-83.5x83.5@2x.png
deleted file mode 100644
index ab2316f7d1..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/AppIcon-dev-83.5x83.5@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json
deleted file mode 100644
index 624ea89d6b..0000000000
--- a/mobile/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json
+++ /dev/null
@@ -1 +0,0 @@
-{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-dev-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-dev-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-dev-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-dev-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-dev-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-dev-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-dev-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-dev-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-dev-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-dev-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-dev-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-dev-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-dev-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-dev-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-dev-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-dev-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-dev-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-dev-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-dev-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-dev-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-dev-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-dev-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-dev-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-dev-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-dev-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index d36b1fab2d..0000000000
--- a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,122 +0,0 @@
-{
- "images" : [
- {
- "size" : "20x20",
- "idiom" : "iphone",
- "filename" : "Icon-App-20x20@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "20x20",
- "idiom" : "iphone",
- "filename" : "Icon-App-20x20@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "29x29",
- "idiom" : "iphone",
- "filename" : "Icon-App-29x29@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "29x29",
- "idiom" : "iphone",
- "filename" : "Icon-App-29x29@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "29x29",
- "idiom" : "iphone",
- "filename" : "Icon-App-29x29@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "40x40",
- "idiom" : "iphone",
- "filename" : "Icon-App-40x40@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "40x40",
- "idiom" : "iphone",
- "filename" : "Icon-App-40x40@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "Icon-App-60x60@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "Icon-App-60x60@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "20x20",
- "idiom" : "ipad",
- "filename" : "Icon-App-20x20@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "20x20",
- "idiom" : "ipad",
- "filename" : "Icon-App-20x20@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "29x29",
- "idiom" : "ipad",
- "filename" : "Icon-App-29x29@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "29x29",
- "idiom" : "ipad",
- "filename" : "Icon-App-29x29@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "40x40",
- "idiom" : "ipad",
- "filename" : "Icon-App-40x40@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "40x40",
- "idiom" : "ipad",
- "filename" : "Icon-App-40x40@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "76x76",
- "idiom" : "ipad",
- "filename" : "Icon-App-76x76@1x.png",
- "scale" : "1x"
- },
- {
- "size" : "76x76",
- "idiom" : "ipad",
- "filename" : "Icon-App-76x76@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "83.5x83.5",
- "idiom" : "ipad",
- "filename" : "Icon-App-83.5x83.5@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "1024x1024",
- "idiom" : "ios-marketing",
- "filename" : "Icon-App-1024x1024@1x.png",
- "scale" : "1x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
deleted file mode 100644
index dae37bd184..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
deleted file mode 100644
index 96121f23e3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
deleted file mode 100644
index 01c27d8e6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
deleted file mode 100644
index 40900845dc..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
deleted file mode 100644
index 1817589a70..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
deleted file mode 100644
index 0e7b036ecd..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
deleted file mode 100644
index adc33edcf0..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
deleted file mode 100644
index 01c27d8e6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
deleted file mode 100644
index 6d9a9a00ce..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
deleted file mode 100644
index dac316a97e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
deleted file mode 100644
index dac316a97e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
deleted file mode 100644
index 9b3595b796..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
deleted file mode 100644
index 8c9f7e31cd..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
deleted file mode 100644
index 5f0e507c6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
deleted file mode 100644
index 5ef5ee48c0..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/Contents.json b/mobile/ios/Runner/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..73c00596a7
--- /dev/null
+++ b/mobile/ios/Runner/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/Contents.json
index 396f679201..d8f8ecfb6f 100644
--- a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/Contents.json
+++ b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/Contents.json
@@ -1 +1,38 @@
-{"images":[{"size":"20x20","idiom":"iphone","filename":"IconDark-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"IconDark-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"IconDark-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"IconDark-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"IconDark-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"IconDark-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"IconDark-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"IconDark-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"IconDark-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"IconDark-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"IconDark-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconDark-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconDark-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"IconDark-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"IconDark-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"IconDark-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"IconDark-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"IconDark-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"IconDark-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"IconDark-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"IconDark-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"IconDark-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"IconDark-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"IconDark-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"IconDark-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
+{
+ "images" : [
+ {
+ "filename" : "IconDarkAny.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "IconDarkDark.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "filename" : "IconDarkTinted.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-1024x1024@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-1024x1024@1x.png
deleted file mode 100644
index 67ac1a11b6..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-1024x1024@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@1x.png
deleted file mode 100644
index f9b8d4ec14..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@2x.png
deleted file mode 100644
index da8733853f..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@3x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@3x.png
deleted file mode 100644
index aaf5b943ad..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-20x20@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@1x.png
deleted file mode 100644
index f0f89fefc9..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@2x.png
deleted file mode 100644
index edaef5ec5d..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@3x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@3x.png
deleted file mode 100644
index 7c2f28ca68..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-29x29@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@1x.png
deleted file mode 100644
index da8733853f..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@2x.png
deleted file mode 100644
index 904cb38279..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@3x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@3x.png
deleted file mode 100644
index e016412765..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-40x40@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-50x50@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-50x50@1x.png
deleted file mode 100644
index 487c1cdb1b..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-50x50@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-50x50@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-50x50@2x.png
deleted file mode 100644
index 6b51e9c167..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-50x50@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-57x57@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-57x57@1x.png
deleted file mode 100644
index b3bd3e807b..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-57x57@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-57x57@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-57x57@2x.png
deleted file mode 100644
index a6199d9564..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-57x57@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-60x60@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-60x60@2x.png
deleted file mode 100644
index e016412765..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-60x60@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-60x60@3x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-60x60@3x.png
deleted file mode 100644
index 0ac53878e7..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-60x60@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-72x72@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-72x72@1x.png
deleted file mode 100644
index 7adf5f5915..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-72x72@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-72x72@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-72x72@2x.png
deleted file mode 100644
index 72db153a35..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-72x72@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-76x76@1x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-76x76@1x.png
deleted file mode 100644
index de6b7a2bd6..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-76x76@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-76x76@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-76x76@2x.png
deleted file mode 100644
index f50bb58f46..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-76x76@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-83.5x83.5@2x.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-83.5x83.5@2x.png
deleted file mode 100644
index 5c67dfff7f..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDark-83.5x83.5@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkAny.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkAny.png
new file mode 100644
index 0000000000..5ce8a224d7
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkAny.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkDark.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkDark.png
new file mode 100644
index 0000000000..5ce8a224d7
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkDark.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkTinted.png b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkTinted.png
new file mode 100644
index 0000000000..3c561bf11e
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconDark.appiconset/IconDarkTinted.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/Contents.json
index f77b2bd70a..839660a4c8 100644
--- a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/Contents.json
+++ b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/Contents.json
@@ -1 +1,38 @@
-{"images":[{"size":"20x20","idiom":"iphone","filename":"IconGreen-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"IconGreen-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"IconGreen-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"IconGreen-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"IconGreen-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"IconGreen-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"IconGreen-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"IconGreen-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"IconGreen-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"IconGreen-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"IconGreen-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconGreen-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconGreen-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"IconGreen-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"IconGreen-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"IconGreen-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"IconGreen-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"IconGreen-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"IconGreen-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"IconGreen-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"IconGreen-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"IconGreen-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"IconGreen-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"IconGreen-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"IconGreen-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
+{
+ "images" : [
+ {
+ "filename" : "IconGreenAny.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "IconGreenDark.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "filename" : "IconGreenTinted.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-1024x1024@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-1024x1024@1x.png
deleted file mode 100644
index 2f65011626..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-1024x1024@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@1x.png
deleted file mode 100644
index 16077fe01c..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@2x.png
deleted file mode 100644
index 031d4b89d2..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@3x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@3x.png
deleted file mode 100644
index ca83c2170a..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-20x20@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@1x.png
deleted file mode 100644
index b3f51ae134..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@2x.png
deleted file mode 100644
index 1814cff481..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@3x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@3x.png
deleted file mode 100644
index a143d3bf42..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-29x29@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@1x.png
deleted file mode 100644
index 031d4b89d2..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@2x.png
deleted file mode 100644
index 7f0f4aaf77..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@3x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@3x.png
deleted file mode 100644
index 4eb408919d..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-40x40@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-50x50@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-50x50@1x.png
deleted file mode 100644
index c80c05206d..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-50x50@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-50x50@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-50x50@2x.png
deleted file mode 100644
index d08253d8e3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-50x50@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-57x57@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-57x57@1x.png
deleted file mode 100644
index c5ba38bfc3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-57x57@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-57x57@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-57x57@2x.png
deleted file mode 100644
index 63ffbaf455..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-57x57@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-60x60@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-60x60@2x.png
deleted file mode 100644
index 4eb408919d..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-60x60@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-60x60@3x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-60x60@3x.png
deleted file mode 100644
index 195599a726..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-60x60@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-72x72@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-72x72@1x.png
deleted file mode 100644
index b142919718..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-72x72@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-72x72@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-72x72@2x.png
deleted file mode 100644
index cbfe3e99ea..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-72x72@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-76x76@1x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-76x76@1x.png
deleted file mode 100644
index 11407f37db..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-76x76@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-76x76@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-76x76@2x.png
deleted file mode 100644
index 2185570d0e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-76x76@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-83.5x83.5@2x.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-83.5x83.5@2x.png
deleted file mode 100644
index fa0a47e5e0..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreen-83.5x83.5@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenAny.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenAny.png
new file mode 100644
index 0000000000..2141faf134
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenAny.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenDark.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenDark.png
new file mode 100644
index 0000000000..5ce8a224d7
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenDark.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenTinted.png b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenTinted.png
new file mode 100644
index 0000000000..3c561bf11e
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconGreen.appiconset/IconGreenTinted.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/Contents.json
index 7f6b53bb55..fbd4b126bd 100644
--- a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/Contents.json
+++ b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/Contents.json
@@ -1 +1,38 @@
-{"images":[{"size":"20x20","idiom":"iphone","filename":"IconLight-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"IconLight-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"IconLight-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"IconLight-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"IconLight-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"IconLight-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"IconLight-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"IconLight-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"IconLight-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"IconLight-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"IconLight-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconLight-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconLight-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"IconLight-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"IconLight-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"IconLight-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"IconLight-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"IconLight-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"IconLight-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"IconLight-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"IconLight-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"IconLight-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"IconLight-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"IconLight-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"IconLight-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
+{
+ "images" : [
+ {
+ "filename" : "IconLightAny.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "IconLightDark.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "filename" : "IconLightTinted.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-1024x1024@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-1024x1024@1x.png
deleted file mode 100644
index 9e237712a2..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-1024x1024@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@1x.png
deleted file mode 100644
index 0278077e70..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@2x.png
deleted file mode 100644
index a1334bd91b..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@3x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@3x.png
deleted file mode 100644
index c362988466..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-20x20@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@1x.png
deleted file mode 100644
index 23fa3efda3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@2x.png
deleted file mode 100644
index f64a394849..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@3x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@3x.png
deleted file mode 100644
index 42d10cb046..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-29x29@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@1x.png
deleted file mode 100644
index a1334bd91b..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@2x.png
deleted file mode 100644
index 7c9059f853..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@3x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@3x.png
deleted file mode 100644
index 30ab15b65c..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-40x40@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-50x50@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-50x50@1x.png
deleted file mode 100644
index ff599f74be..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-50x50@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-50x50@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-50x50@2x.png
deleted file mode 100644
index 1fa7cf8532..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-50x50@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-57x57@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-57x57@1x.png
deleted file mode 100644
index cc4bafafff..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-57x57@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-57x57@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-57x57@2x.png
deleted file mode 100644
index ee5d8f261e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-57x57@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-60x60@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-60x60@2x.png
deleted file mode 100644
index 30ab15b65c..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-60x60@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-60x60@3x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-60x60@3x.png
deleted file mode 100644
index 8025b5dfff..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-60x60@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-72x72@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-72x72@1x.png
deleted file mode 100644
index 23f492ceb2..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-72x72@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-72x72@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-72x72@2x.png
deleted file mode 100644
index 818e285071..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-72x72@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-76x76@1x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-76x76@1x.png
deleted file mode 100644
index f82f98e196..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-76x76@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-76x76@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-76x76@2x.png
deleted file mode 100644
index 96e3b45fb2..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-76x76@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-83.5x83.5@2x.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-83.5x83.5@2x.png
deleted file mode 100644
index 44acc1f155..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLight-83.5x83.5@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightAny.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightAny.png
new file mode 100644
index 0000000000..5ca195643b
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightAny.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightDark.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightDark.png
new file mode 100644
index 0000000000..5ce8a224d7
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightDark.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightTinted.png b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightTinted.png
new file mode 100644
index 0000000000..3c561bf11e
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconLight.appiconset/IconLightTinted.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/Contents.json
index 0284920359..28ea4fb2e9 100644
--- a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/Contents.json
+++ b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/Contents.json
@@ -1 +1,38 @@
-{"images":[{"size":"20x20","idiom":"iphone","filename":"IconOG-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"IconOG-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"IconOG-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"IconOG-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"IconOG-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"IconOG-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"IconOG-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"IconOG-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"IconOG-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"IconOG-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"IconOG-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconOG-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconOG-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"IconOG-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"IconOG-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"IconOG-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"IconOG-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"IconOG-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"IconOG-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"IconOG-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"IconOG-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"IconOG-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"IconOG-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"IconOG-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"IconOG-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
\ No newline at end of file
+{
+ "images" : [
+ {
+ "filename" : "IconOGAny.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "IconOGDark.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "filename" : "IconOGTinted.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-1024x1024@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-1024x1024@1x.png
deleted file mode 100644
index dae37bd184..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-1024x1024@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@1x.png
deleted file mode 100644
index 96121f23e3..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@2x.png
deleted file mode 100644
index 01c27d8e6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@3x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@3x.png
deleted file mode 100644
index 40900845dc..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-20x20@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@1x.png
deleted file mode 100644
index 1817589a70..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@2x.png
deleted file mode 100644
index 0e7b036ecd..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@3x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@3x.png
deleted file mode 100644
index adc33edcf0..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-29x29@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@1x.png
deleted file mode 100644
index 01c27d8e6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@2x.png
deleted file mode 100644
index 6d9a9a00ce..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@3x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@3x.png
deleted file mode 100644
index dac316a97e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-40x40@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-50x50@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-50x50@1x.png
deleted file mode 100644
index 3c0a425b76..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-50x50@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-50x50@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-50x50@2x.png
deleted file mode 100644
index 2ac2f4cfd8..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-50x50@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-57x57@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-57x57@1x.png
deleted file mode 100644
index fa74d3904c..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-57x57@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-57x57@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-57x57@2x.png
deleted file mode 100644
index 24556e75e7..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-57x57@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-60x60@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-60x60@2x.png
deleted file mode 100644
index dac316a97e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-60x60@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-60x60@3x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-60x60@3x.png
deleted file mode 100644
index 9b3595b796..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-60x60@3x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-72x72@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-72x72@1x.png
deleted file mode 100644
index a76fbefc65..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-72x72@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-72x72@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-72x72@2x.png
deleted file mode 100644
index f9653a30a2..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-72x72@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-76x76@1x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-76x76@1x.png
deleted file mode 100644
index 8c9f7e31cd..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-76x76@1x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-76x76@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-76x76@2x.png
deleted file mode 100644
index 5f0e507c6e..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-76x76@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-83.5x83.5@2x.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-83.5x83.5@2x.png
deleted file mode 100644
index 5ef5ee48c0..0000000000
Binary files a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOG-83.5x83.5@2x.png and /dev/null differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGAny.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGAny.png
new file mode 100644
index 0000000000..7a0504b429
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGAny.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGDark.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGDark.png
new file mode 100644
index 0000000000..9bc5fb6721
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGDark.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGtinted.png b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGtinted.png
new file mode 100644
index 0000000000..9bc5fb6721
Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/IconOG.appiconset/IconOGtinted.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
index 3911d58c35..358b349d23 100644
Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
index 3d26dfd83c..5bd6530afa 100644
Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
index e9641f3f28..86ec272c98 100644
Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/mobile/lib/generated/intl/messages_ar.dart b/mobile/lib/generated/intl/messages_ar.dart
index be85a7dc78..3ef715f7a2 100644
--- a/mobile/lib/generated/intl/messages_ar.dart
+++ b/mobile/lib/generated/intl/messages_ar.dart
@@ -74,10 +74,14 @@ class MessageLookup extends MessageLookupByLibrary {
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
"sorry": MessageLookupByLibrary.simpleMessage("Ų§ŁŁ
Ų¹Ų°Ų±Ų©"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"terminate": MessageLookupByLibrary.simpleMessage("Ų„ŁŁŲ§Ų”"),
"terminateSession":
MessageLookupByLibrary.simpleMessage("Ų„ŁŁŲ§Ų” Ų§ŁŲ¬ŁŲ³Ų©Ų"),
"thisDevice": MessageLookupByLibrary.simpleMessage("ŁŲ°Ų§ Ų§ŁŲ¬ŁŲ§Ų²"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Ų³ŁŲ¤ŲÆŁ ŁŲ°Ų§ Ų„ŁŁ ŲŖŲ³Ų¬ŁŁ Ų®Ų±ŁŲ¬Ł Ł
Ł Ų§ŁŲ¬ŁŲ§Ų² Ų§ŁŲŖŲ§ŁŁ:"),
diff --git a/mobile/lib/generated/intl/messages_be.dart b/mobile/lib/generated/intl/messages_be.dart
index 5a381a58b0..1c1debfec2 100644
--- a/mobile/lib/generated/intl/messages_be.dart
+++ b/mobile/lib/generated/intl/messages_be.dart
@@ -267,6 +267,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease":
MessageLookupByLibrary.simpleMessage(
"ŠŠµŠ¼Š°Š³ŃŃŠ¼Š° згенеŃŃŃŠ°Š²Š°ŃŃ ŠŗŠ»ŃŃŃ Š±ŃŃŠæŠµŠŗŃ Š½Š° гŃŃŠ°Š¹ ŠæŃŃŠ»Š°Š“зе.\n\nŠŠ°ŃŃŠ³ŃŃŃŃŃŠ¹ŃеŃŃ Š· ŃŠ½Ńай ŠæŃŃŠ»Š°Š“Ń."),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"status": MessageLookupByLibrary.simpleMessage("Š”ŃŠ°Š½"),
"storageInGB": m2,
"strongStrength": MessageLookupByLibrary.simpleMessage("ŠŠ°Š“зейнŃ"),
@@ -280,6 +282,8 @@ class MessageLookup extends MessageLookupByLibrary {
"termsOfServicesTitle": MessageLookupByLibrary.simpleMessage("УмовŃ"),
"theme": MessageLookupByLibrary.simpleMessage("Тема"),
"thisDevice": MessageLookupByLibrary.simpleMessage("ŠŃŃŠ° ŠæŃŃŠ»Š°Š“а"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"ŠŃŃŠ° Š“Š·ŠµŃŠ½Š½Šµ завŃŃŃŃŃŃ ŃŠµŠ°Š½Ń на наŃŃŃŠæŠ½Š°Š¹ ŠæŃŃŠ»Š°Š“зе:"),
diff --git a/mobile/lib/generated/intl/messages_bg.dart b/mobile/lib/generated/intl/messages_bg.dart
index a9ba192553..209a49fb30 100644
--- a/mobile/lib/generated/intl/messages_bg.dart
+++ b/mobile/lib/generated/intl/messages_bg.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_ca.dart b/mobile/lib/generated/intl/messages_ca.dart
index 84bd2f9cee..de87b53ea9 100644
--- a/mobile/lib/generated/intl/messages_ca.dart
+++ b/mobile/lib/generated/intl/messages_ca.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_cs.dart b/mobile/lib/generated/intl/messages_cs.dart
index a37e950e18..5ac2e0935c 100644
--- a/mobile/lib/generated/intl/messages_cs.dart
+++ b/mobile/lib/generated/intl/messages_cs.dart
@@ -55,6 +55,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_da.dart b/mobile/lib/generated/intl/messages_da.dart
index 643e07680f..b5f62965a7 100644
--- a/mobile/lib/generated/intl/messages_da.dart
+++ b/mobile/lib/generated/intl/messages_da.dart
@@ -337,6 +337,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease":
MessageLookupByLibrary.simpleMessage(
"Beklager, vi kunne ikke generere sikre krypteringsnøgler pÄ denne enhed.\n\nForsøg venligst at oprette en konto fra en anden enhed."),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"status": MessageLookupByLibrary.simpleMessage("Status"),
"storageInGB": m2,
"strongStrength": MessageLookupByLibrary.simpleMessage("StƦrkt"),
@@ -351,6 +353,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Betingelser"),
"theyAlsoGetXGb": m9,
"thisDevice": MessageLookupByLibrary.simpleMessage("Denne enhed"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Dette vil logge dig ud af fĆølgende enhed:"),
diff --git a/mobile/lib/generated/intl/messages_de.dart b/mobile/lib/generated/intl/messages_de.dart
index 342921c92d..f133f65b6e 100644
--- a/mobile/lib/generated/intl/messages_de.dart
+++ b/mobile/lib/generated/intl/messages_de.dart
@@ -1851,6 +1851,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Ćlteste zuerst"),
"sparkleSuccess":
MessageLookupByLibrary.simpleMessage("⨠Abgeschlossen"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Wiederherstellung starten"),
"startBackup":
@@ -1945,6 +1947,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Dies ist deine Verifizierungs-ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Dadurch wirst du von folgendem GerƤt abgemeldet:"),
diff --git a/mobile/lib/generated/intl/messages_el.dart b/mobile/lib/generated/intl/messages_el.dart
index 1d2301bc68..a0db9af0ee 100644
--- a/mobile/lib/generated/intl/messages_el.dart
+++ b/mobile/lib/generated/intl/messages_el.dart
@@ -49,6 +49,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart
index 1640b095ea..053c845954 100644
--- a/mobile/lib/generated/intl/messages_en.dart
+++ b/mobile/lib/generated/intl/messages_en.dart
@@ -38,6 +38,8 @@ class MessageLookup extends MessageLookupByLibrary {
static String m16(albumName) => "Added successfully to ${albumName}";
+ static String m95(name) => "Admiring ${name}";
+
static String m17(count) =>
"${Intl.plural(count, zero: 'No Participants', one: '1 Participant', other: '${count} Participants')}";
@@ -46,6 +48,8 @@ class MessageLookup extends MessageLookupByLibrary {
static String m19(freeAmount, storageUnit) =>
"${freeAmount} ${storageUnit} free";
+ static String m96(name) => "Scenery with ${name}";
+
static String m20(paymentProvider) =>
"Please cancel your existing subscription from ${paymentProvider} first";
@@ -100,8 +104,12 @@ class MessageLookup extends MessageLookupByLibrary {
static String m36(email) =>
"${email} does not have an Ente account.\n\nSend them an invite to share photos.";
+ static String m97(name) => "Embracing ${name}";
+
static String m37(text) => "Extra photos found for ${text}";
+ static String m98(name) => "Feasting with ${name}";
+
static String m38(count, formattedNumber) =>
"${Intl.plural(count, one: '1 file', other: '${formattedNumber} files')} on this device have been backed up safely";
@@ -124,9 +132,13 @@ class MessageLookup extends MessageLookupByLibrary {
static String m44(currentlyProcessing, totalCount) =>
"Processing ${currentlyProcessing} / ${totalCount}";
+ static String m99(name) => "Hiking with ${name}";
+
static String m45(count) =>
"${Intl.plural(count, one: '${count} item', other: '${count} items')}";
+ static String m100(name) => "Last time with ${name}";
+
static String m46(email) =>
"${email} has invited you to be a trusted contact";
@@ -152,12 +164,18 @@ class MessageLookup extends MessageLookupByLibrary {
static String m54(familyAdminEmail) =>
"Please contact ${familyAdminEmail} to change your code.";
+ static String m101(name) => "Party with ${name}";
+
static String m0(passwordStrengthValue) =>
"Password strength: ${passwordStrengthValue}";
static String m55(providerName) =>
"Please talk to ${providerName} support if you were charged";
+ static String m102(name, age) => "${name} is ${age}!";
+
+ static String m103(name, age) => "${name} turning ${age} soon";
+
static String m1(count) =>
"${Intl.plural(count, zero: 'No photos', one: '1 photo', other: '${count} photos')}";
@@ -171,6 +189,8 @@ class MessageLookup extends MessageLookupByLibrary {
static String m59(toEmail) => "Please send the logs to \n${toEmail}";
+ static String m104(name) => "Posing with ${name}";
+
static String m60(folderName) => "Processing ${folderName}...";
static String m61(storeName) => "Rate us on ${storeName}";
@@ -193,6 +213,8 @@ class MessageLookup extends MessageLookupByLibrary {
static String m68(endDate) => "Subscription renews on ${endDate}";
+ static String m105(name) => "Road trip with ${name}";
+
static String m69(count) =>
"${Intl.plural(count, one: '${count} result found', other: '${count} results found')}";
@@ -204,6 +226,8 @@ class MessageLookup extends MessageLookupByLibrary {
static String m71(count, yourCount) =>
"${count} selected (${yourCount} yours)";
+ static String m106(name) => "Selfies with ${name}";
+
static String m72(verificationID) =>
"Here\'s my verification ID: ${verificationID} for ente.io.";
@@ -226,6 +250,10 @@ class MessageLookup extends MessageLookupByLibrary {
static String m78(fileType) => "This ${fileType} will be deleted from Ente.";
+ static String m107(name) => "Sports with ${name}";
+
+ static String m108(name) => "Spotlight on ${name}";
+
static String m2(storageAmountInGB) => "${storageAmountInGB} GB";
static String m79(
@@ -249,9 +277,18 @@ class MessageLookup extends MessageLookupByLibrary {
static String m84(email) => "This is ${email}\'s Verification ID";
+ static String m109(count) =>
+ "${Intl.plural(count, one: 'This week, ${count} year ago', other: 'This week, ${count} years ago')}";
+
+ static String m110(dateFormat) => "${dateFormat} through the years";
+
static String m85(count) =>
"${Intl.plural(count, zero: 'Soon', one: '1 day', other: '${count} days')}";
+ static String m111(year) => "Trip in ${year}";
+
+ static String m112(location) => "Trip to ${location}";
+
static String m86(email) =>
"You have been invited to be a legacy contact by ${email}.";
@@ -274,6 +311,8 @@ class MessageLookup extends MessageLookupByLibrary {
static String m93(count) =>
"${Intl.plural(count, one: '${count} year ago', other: '${count} years ago')}";
+ static String m113(name) => "You and ${name}";
+
static String m94(storageSaved) =>
"You have successfully freed up ${storageSaved}!";
@@ -333,6 +372,7 @@ class MessageLookup extends MessageLookupByLibrary {
"addedSuccessfullyTo": m16,
"addingToFavorites":
MessageLookupByLibrary.simpleMessage("Adding to favorites..."),
+ "admiringThem": m95,
"advanced": MessageLookupByLibrary.simpleMessage("Advanced"),
"advancedSettings": MessageLookupByLibrary.simpleMessage("Advanced"),
"after1Day": MessageLookupByLibrary.simpleMessage("After 1 day"),
@@ -475,6 +515,7 @@ class MessageLookup extends MessageLookupByLibrary {
"availableStorageSpace": m19,
"backedUpFolders":
MessageLookupByLibrary.simpleMessage("Backed up folders"),
+ "backgroundWithThem": m96,
"backup": MessageLookupByLibrary.simpleMessage("Backup"),
"backupFailed": MessageLookupByLibrary.simpleMessage("Backup failed"),
"backupFile": MessageLookupByLibrary.simpleMessage("Backup file"),
@@ -486,6 +527,7 @@ class MessageLookup extends MessageLookupByLibrary {
"backupStatusDescription": MessageLookupByLibrary.simpleMessage(
"Items that have been backed up will show up here"),
"backupVideos": MessageLookupByLibrary.simpleMessage("Backup videos"),
+ "beach": MessageLookupByLibrary.simpleMessage("Sand and sea"),
"birthday": MessageLookupByLibrary.simpleMessage("Birthday"),
"blackFridaySale":
MessageLookupByLibrary.simpleMessage("Black Friday Sale"),
@@ -556,6 +598,7 @@ class MessageLookup extends MessageLookupByLibrary {
"checking": MessageLookupByLibrary.simpleMessage("Checking..."),
"checkingModels":
MessageLookupByLibrary.simpleMessage("Checking models..."),
+ "city": MessageLookupByLibrary.simpleMessage("In the city"),
"claimFreeStorage":
MessageLookupByLibrary.simpleMessage("Claim free storage"),
"claimMore": MessageLookupByLibrary.simpleMessage("Claim more!"),
@@ -821,6 +864,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Email verification"),
"emailYourLogs":
MessageLookupByLibrary.simpleMessage("Email your logs"),
+ "embracingThem": m97,
"emergencyContacts":
MessageLookupByLibrary.simpleMessage("Emergency Contacts"),
"empty": MessageLookupByLibrary.simpleMessage("Empty"),
@@ -932,6 +976,7 @@ class MessageLookup extends MessageLookupByLibrary {
"faq": MessageLookupByLibrary.simpleMessage("FAQ"),
"faqs": MessageLookupByLibrary.simpleMessage("FAQs"),
"favorite": MessageLookupByLibrary.simpleMessage("Favorite"),
+ "feastingWithThem": m98,
"feedback": MessageLookupByLibrary.simpleMessage("Feedback"),
"file": MessageLookupByLibrary.simpleMessage("File"),
"fileFailedToSaveToGallery": MessageLookupByLibrary.simpleMessage(
@@ -955,6 +1000,7 @@ class MessageLookup extends MessageLookupByLibrary {
"findThemQuickly":
MessageLookupByLibrary.simpleMessage("Find them quickly"),
"flip": MessageLookupByLibrary.simpleMessage("Flip"),
+ "food": MessageLookupByLibrary.simpleMessage("Culinary delight"),
"forYourMemories":
MessageLookupByLibrary.simpleMessage("for your memories"),
"forgotPassword":
@@ -988,6 +1034,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Please allow access to all photos in the Settings app"),
"grantPermission":
MessageLookupByLibrary.simpleMessage("Grant permission"),
+ "greenery": MessageLookupByLibrary.simpleMessage("The green life"),
"groupNearbyPhotos":
MessageLookupByLibrary.simpleMessage("Group nearby photos"),
"guestView": MessageLookupByLibrary.simpleMessage("Guest view"),
@@ -1008,6 +1055,7 @@ class MessageLookup extends MessageLookupByLibrary {
"hideSharedItemsFromHomeGallery": MessageLookupByLibrary.simpleMessage(
"Hide shared items from home gallery"),
"hiding": MessageLookupByLibrary.simpleMessage("Hiding..."),
+ "hikingWithThem": m99,
"hostedAtOsmFrance":
MessageLookupByLibrary.simpleMessage("Hosted at OSM France"),
"howItWorks": MessageLookupByLibrary.simpleMessage("How it works"),
@@ -1082,7 +1130,10 @@ class MessageLookup extends MessageLookupByLibrary {
"kindlyHelpUsWithThisInformation": MessageLookupByLibrary.simpleMessage(
"Kindly help us with this information"),
"language": MessageLookupByLibrary.simpleMessage("Language"),
+ "lastTimeWithThem": m100,
"lastUpdated": MessageLookupByLibrary.simpleMessage("Last updated"),
+ "lastYearsTrip":
+ MessageLookupByLibrary.simpleMessage("Last year\'s trip"),
"leave": MessageLookupByLibrary.simpleMessage("Leave"),
"leaveAlbum": MessageLookupByLibrary.simpleMessage("Leave album"),
"leaveFamily": MessageLookupByLibrary.simpleMessage("Leave family"),
@@ -1228,9 +1279,11 @@ class MessageLookup extends MessageLookupByLibrary {
"moments": MessageLookupByLibrary.simpleMessage("Moments"),
"month": MessageLookupByLibrary.simpleMessage("month"),
"monthly": MessageLookupByLibrary.simpleMessage("Monthly"),
+ "moon": MessageLookupByLibrary.simpleMessage("In the moonlight"),
"moreDetails": MessageLookupByLibrary.simpleMessage("More details"),
"mostRecent": MessageLookupByLibrary.simpleMessage("Most recent"),
"mostRelevant": MessageLookupByLibrary.simpleMessage("Most relevant"),
+ "mountains": MessageLookupByLibrary.simpleMessage("Over the hills"),
"moveItem": m50,
"moveSelectedPhotosToOneDate": MessageLookupByLibrary.simpleMessage(
"Move selected photos to one date"),
@@ -1303,6 +1356,7 @@ class MessageLookup extends MessageLookupByLibrary {
"onDevice": MessageLookupByLibrary.simpleMessage("On device"),
"onEnte": MessageLookupByLibrary.simpleMessage(
"On ente"),
+ "onTheRoad": MessageLookupByLibrary.simpleMessage("On the road again"),
"onlyFamilyAdminCanChangeCode": m54,
"onlyThem": MessageLookupByLibrary.simpleMessage("Only them"),
"oops": MessageLookupByLibrary.simpleMessage("Oops"),
@@ -1332,6 +1386,7 @@ class MessageLookup extends MessageLookupByLibrary {
"pairingComplete":
MessageLookupByLibrary.simpleMessage("Pairing complete"),
"panorama": MessageLookupByLibrary.simpleMessage("Panorama"),
+ "partyWithThem": m101,
"passKeyPendingVerification": MessageLookupByLibrary.simpleMessage(
"Verification is still pending"),
"passkey": MessageLookupByLibrary.simpleMessage("Passkey"),
@@ -1363,7 +1418,10 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Permanently delete"),
"permanentlyDeleteFromDevice": MessageLookupByLibrary.simpleMessage(
"Permanently delete from device?"),
+ "personIsAge": m102,
"personName": MessageLookupByLibrary.simpleMessage("Person name"),
+ "personTurningAge": m103,
+ "pets": MessageLookupByLibrary.simpleMessage("Furry companions"),
"photoDescriptions":
MessageLookupByLibrary.simpleMessage("Photo descriptions"),
"photoGridSize":
@@ -1418,6 +1476,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Please wait for sometime before retrying"),
"pleaseWaitThisWillTakeAWhile": MessageLookupByLibrary.simpleMessage(
"Please wait, this will take a while."),
+ "posingWithThem": m104,
"preparingLogs":
MessageLookupByLibrary.simpleMessage("Preparing logs..."),
"preserveMore": MessageLookupByLibrary.simpleMessage("Preserve more"),
@@ -1570,6 +1629,7 @@ class MessageLookup extends MessageLookupByLibrary {
"reviewSuggestions":
MessageLookupByLibrary.simpleMessage("Review suggestions"),
"right": MessageLookupByLibrary.simpleMessage("Right"),
+ "roadtripWithThem": m105,
"rotate": MessageLookupByLibrary.simpleMessage("Rotate"),
"rotateLeft": MessageLookupByLibrary.simpleMessage("Rotate left"),
"rotateRight": MessageLookupByLibrary.simpleMessage("Rotate right"),
@@ -1675,6 +1735,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"selectedPhotos": m7,
"selectedPhotosWithYours": m71,
+ "selfiesWithThem": m106,
"send": MessageLookupByLibrary.simpleMessage("Send"),
"sendEmail": MessageLookupByLibrary.simpleMessage("Send email"),
"sendInvite": MessageLookupByLibrary.simpleMessage("Send invite"),
@@ -1778,6 +1839,10 @@ class MessageLookup extends MessageLookupByLibrary {
"sortNewestFirst": MessageLookupByLibrary.simpleMessage("Newest first"),
"sortOldestFirst": MessageLookupByLibrary.simpleMessage("Oldest first"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Success"),
+ "sportsWithThem": m107,
+ "spotlightOnThem": m108,
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Start recovery"),
"startBackup": MessageLookupByLibrary.simpleMessage("Start backup"),
@@ -1812,6 +1877,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Successfully unhid"),
"suggestFeatures":
MessageLookupByLibrary.simpleMessage("Suggest features"),
+ "sunrise": MessageLookupByLibrary.simpleMessage("On the horizon"),
"support": MessageLookupByLibrary.simpleMessage("Support"),
"syncProgress": m82,
"syncStopped": MessageLookupByLibrary.simpleMessage("Sync stopped"),
@@ -1866,6 +1932,9 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"This is your Verification ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
+ "thisWeekXYearsAgo": m109,
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"This will log you out of the following device:"),
@@ -1877,6 +1946,7 @@ class MessageLookup extends MessageLookupByLibrary {
"thisWillRemovePublicLinksOfAllSelectedQuickLinks":
MessageLookupByLibrary.simpleMessage(
"This will remove public links of all selected quick links."),
+ "throughTheYears": m110,
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen":
MessageLookupByLibrary.simpleMessage(
"To enable app lock, please setup device passcode or screen lock in your system settings."),
@@ -1892,6 +1962,8 @@ class MessageLookup extends MessageLookupByLibrary {
"trash": MessageLookupByLibrary.simpleMessage("Trash"),
"trashDaysLeft": m85,
"trim": MessageLookupByLibrary.simpleMessage("Trim"),
+ "tripInYear": m111,
+ "tripToLocation": m112,
"trustedContacts":
MessageLookupByLibrary.simpleMessage("Trusted contacts"),
"trustedInviteBody": m86,
@@ -2025,6 +2097,7 @@ class MessageLookup extends MessageLookupByLibrary {
"yesResetPerson":
MessageLookupByLibrary.simpleMessage("Yes, reset person"),
"you": MessageLookupByLibrary.simpleMessage("You"),
+ "youAndThem": m113,
"youAreOnAFamilyPlan":
MessageLookupByLibrary.simpleMessage("You are on a family plan!"),
"youAreOnTheLatestVersion": MessageLookupByLibrary.simpleMessage(
diff --git a/mobile/lib/generated/intl/messages_es.dart b/mobile/lib/generated/intl/messages_es.dart
index c4d2a8c60a..b04da60fbb 100644
--- a/mobile/lib/generated/intl/messages_es.dart
+++ b/mobile/lib/generated/intl/messages_es.dart
@@ -1868,6 +1868,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("MƔs antiguos primero"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Ćxito"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Iniciar la recuperación"),
"startBackup":
@@ -1961,6 +1963,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Esta es tu ID de verificación"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Esto cerrarÔ la sesión del siguiente dispositivo:"),
diff --git a/mobile/lib/generated/intl/messages_et.dart b/mobile/lib/generated/intl/messages_et.dart
index 4cf41f1736..a36752fdd9 100644
--- a/mobile/lib/generated/intl/messages_et.dart
+++ b/mobile/lib/generated/intl/messages_et.dart
@@ -254,6 +254,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Uuemad eespool"),
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Vanemad eespool"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"storage": MessageLookupByLibrary.simpleMessage("MƤluruum"),
"storageBreakupFamily":
MessageLookupByLibrary.simpleMessage("Perekond"),
@@ -270,6 +272,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Tingimused"),
"theme": MessageLookupByLibrary.simpleMessage("Teema"),
"thisDevice": MessageLookupByLibrary.simpleMessage("See seade"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same."),
diff --git a/mobile/lib/generated/intl/messages_fa.dart b/mobile/lib/generated/intl/messages_fa.dart
index 7b9333fcbd..fb7d670540 100644
--- a/mobile/lib/generated/intl/messages_fa.dart
+++ b/mobile/lib/generated/intl/messages_fa.dart
@@ -389,6 +389,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Ų§ŪŲŖŲÆŲ§ Ų¬ŲÆŪŲÆŲŖŲ±ŪŁ"),
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Ų§ŪŲŖŲÆŲ§ ŁŲÆŪŁ
ŪāŲŖŲ±ŪŁ"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startBackup":
MessageLookupByLibrary.simpleMessage("Ų“Ų±ŁŲ¹ پؓتŪŲØŲ§Ł ŚÆŪŲ±Ū"),
"status": MessageLookupByLibrary.simpleMessage("ŁŲ¶Ų¹ŪŲŖ"),
@@ -414,6 +416,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("ŲÆŲ§ŁŁŁŲÆ Ś©Ų§Ł
Ł ŁŲ“ŲÆ"),
"theme": MessageLookupByLibrary.simpleMessage("ŲŖŁ
"),
"thisDevice": MessageLookupByLibrary.simpleMessage("Ų§ŪŁ ŲÆŲ³ŲŖŚÆŲ§Ł"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"ŲØŲ§ Ų§ŪŁ کار Ų“Ł
Ų§ Ų§Ų² ŲÆŲ³ŲŖŚÆŲ§Ł Ų²ŪŲ± Ų®Ų§Ų±Ų¬ Ł
ŪāŲ“ŁŪŲÆ:"),
diff --git a/mobile/lib/generated/intl/messages_fr.dart b/mobile/lib/generated/intl/messages_fr.dart
index b9b1aeae34..575439474d 100644
--- a/mobile/lib/generated/intl/messages_fr.dart
+++ b/mobile/lib/generated/intl/messages_fr.dart
@@ -1893,6 +1893,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Plus ancien en premier"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Succès"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("DƩmarrer la rƩcupƩration"),
"startBackup":
@@ -1988,6 +1990,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Ceci est votre ID de vƩrification"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Cela vous dƩconnectera de l\'appareil suivant :"),
diff --git a/mobile/lib/generated/intl/messages_gu.dart b/mobile/lib/generated/intl/messages_gu.dart
index 16e8999d69..21b9a034a4 100644
--- a/mobile/lib/generated/intl/messages_gu.dart
+++ b/mobile/lib/generated/intl/messages_gu.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_he.dart b/mobile/lib/generated/intl/messages_he.dart
index fed778501e..a76c05098e 100644
--- a/mobile/lib/generated/intl/messages_he.dart
+++ b/mobile/lib/generated/intl/messages_he.dart
@@ -848,6 +848,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("×××©× ×××תר ×§×××"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠×צ×××"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startBackup": MessageLookupByLibrary.simpleMessage("××Ŗ×× ×××××"),
"storage": MessageLookupByLibrary.simpleMessage("×××”××"),
"storageBreakupFamily": MessageLookupByLibrary.simpleMessage("×שפ××"),
@@ -887,6 +889,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("×× ×××× ××××××Ŗ ש××"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage("×× ×× ×Ŗ×§ ×××Ŗ× ××××ש×ר ×××:"),
"thisWillLogYouOutOfThisDevice":
diff --git a/mobile/lib/generated/intl/messages_hi.dart b/mobile/lib/generated/intl/messages_hi.dart
index dd54fb6dbe..0a5b0dcd6a 100644
--- a/mobile/lib/generated/intl/messages_hi.dart
+++ b/mobile/lib/generated/intl/messages_hi.dart
@@ -119,10 +119,14 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"ą¤ą„ą¤ ą¤ą¤”़बऔ़ ą¤¹ą„ą¤ ą¤¹ą„ą„¤ ą¤ą„पया ą¤¦ą„ą¤¬ą¤¾ą¤°ą¤¾ ą¤Ŗą„ą¤°ą¤Æą¤¾ą¤ø ą¤ą¤°ą„ą¤ą„¤"),
"sorry": MessageLookupByLibrary.simpleMessage("ą¤ą„षमा ą¤ą¤°ą„ą¤!"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"terminate": MessageLookupByLibrary.simpleMessage("ą¤°ą¤¦ą„ą¤¦ ą¤ą¤°ą„ą¤"),
"terminateSession":
MessageLookupByLibrary.simpleMessage("ą¤øą„ą¤¶ą¤Ø ą¤°ą¤¦ą„ą¤¦ ą¤ą¤°ą„ą¤?"),
"thisDevice": MessageLookupByLibrary.simpleMessage("यह ą¤”ą¤æą¤µą¤¾ą¤ą¤ø"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"ą¤ą¤øą¤øą„ ą¤ą¤Ŗ ą¤ą¤Ø ą¤”ą¤æą¤µą¤¾ą¤ą¤øą„ą¤ ą¤øą„ ą¤²ą„ą¤ ą¤ą¤ą¤ ą¤¹ą„ ą¤ą¤¾ą¤ą¤ą¤ą„:"),
diff --git a/mobile/lib/generated/intl/messages_hu.dart b/mobile/lib/generated/intl/messages_hu.dart
index 06f95ad74f..72a47f10d1 100644
--- a/mobile/lib/generated/intl/messages_hu.dart
+++ b/mobile/lib/generated/intl/messages_hu.dart
@@ -66,6 +66,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same."),
diff --git a/mobile/lib/generated/intl/messages_id.dart b/mobile/lib/generated/intl/messages_id.dart
index 746fab8327..ed8740da74 100644
--- a/mobile/lib/generated/intl/messages_id.dart
+++ b/mobile/lib/generated/intl/messages_id.dart
@@ -1326,6 +1326,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortNewestFirst": MessageLookupByLibrary.simpleMessage("Terbaru dulu"),
"sortOldestFirst": MessageLookupByLibrary.simpleMessage("Terlama dulu"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Berhasil"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startBackup":
MessageLookupByLibrary.simpleMessage("Mulai pencadangan"),
"status": MessageLookupByLibrary.simpleMessage("Status"),
@@ -1400,6 +1402,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Ini adalah ID Verifikasi kamu"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Ini akan mengeluarkan akunmu dari perangkat berikut:"),
diff --git a/mobile/lib/generated/intl/messages_it.dart b/mobile/lib/generated/intl/messages_it.dart
index 31ff24ed1a..543ebf787a 100644
--- a/mobile/lib/generated/intl/messages_it.dart
+++ b/mobile/lib/generated/intl/messages_it.dart
@@ -1791,6 +1791,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Prima le più vecchie"),
"sparkleSuccess":
MessageLookupByLibrary.simpleMessage("⨠Operazione riuscita"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Avvia il recupero"),
"startBackup": MessageLookupByLibrary.simpleMessage("Avvia backup"),
@@ -1883,6 +1885,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Questo ĆØ il tuo ID di verifica"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Verrai disconnesso dai seguenti dispositivi:"),
diff --git a/mobile/lib/generated/intl/messages_ja.dart b/mobile/lib/generated/intl/messages_ja.dart
index 4bac9a9fa7..367cc1100c 100644
--- a/mobile/lib/generated/intl/messages_ja.dart
+++ b/mobile/lib/generated/intl/messages_ja.dart
@@ -1585,6 +1585,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortNewestFirst": MessageLookupByLibrary.simpleMessage("ę°ććé "),
"sortOldestFirst": MessageLookupByLibrary.simpleMessage("å¤ćé "),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("ęåāØ"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("ćŖć«ććŖćéå§"),
"startBackup": MessageLookupByLibrary.simpleMessage("ćććÆć¢ćććéå§"),
@@ -1662,6 +1664,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("ćććÆććŖćć®čŖčؼIDć§ć"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage("仄äøć®ććć¤ć¹ćććć°ć¢ć¦ććć¾ć:"),
"thisWillLogYouOutOfThisDevice":
diff --git a/mobile/lib/generated/intl/messages_km.dart b/mobile/lib/generated/intl/messages_km.dart
index 985bc1fd81..0a6ce004f9 100644
--- a/mobile/lib/generated/intl/messages_km.dart
+++ b/mobile/lib/generated/intl/messages_km.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_ko.dart b/mobile/lib/generated/intl/messages_ko.dart
index d710580623..be8625e623 100644
--- a/mobile/lib/generated/intl/messages_ko.dart
+++ b/mobile/lib/generated/intl/messages_ko.dart
@@ -68,6 +68,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same."),
diff --git a/mobile/lib/generated/intl/messages_lt.dart b/mobile/lib/generated/intl/messages_lt.dart
index ebfe671bef..2ae2983178 100644
--- a/mobile/lib/generated/intl/messages_lt.dart
+++ b/mobile/lib/generated/intl/messages_lt.dart
@@ -1578,6 +1578,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("SeniausiÄ
pirmiausiai"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠SÄkmÄ"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("PradÄti atkÅ«rimÄ
"),
"startBackup": MessageLookupByLibrary.simpleMessage(
@@ -1652,6 +1654,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("Tai ā jÅ«sų patvirtinimo ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Tai jus atjungs nuo toliau nurodyto ÄÆrenginio:"),
diff --git a/mobile/lib/generated/intl/messages_ml.dart b/mobile/lib/generated/intl/messages_ml.dart
index ec7aa280e4..ff781c6868 100644
--- a/mobile/lib/generated/intl/messages_ml.dart
+++ b/mobile/lib/generated/intl/messages_ml.dart
@@ -149,6 +149,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortAlbumsBy":
MessageLookupByLibrary.simpleMessage("ą“ą“Ŗąµą“°ą“ą“¾ą“°ą“ ą“
ą“ąµą“ąµą“ąµą“"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("āØ ą“øą“«ą“²ą“"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"strongStrength": MessageLookupByLibrary.simpleMessage("ą“¶ą“ąµą“¤ą“"),
"success": MessageLookupByLibrary.simpleMessage("ą“øą“«ą“²ą“"),
"support": MessageLookupByLibrary.simpleMessage("ą“Ŗą“æą“Øąµą“¤ąµą“£"),
@@ -157,6 +159,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("ą“Øą“æą“¬ą“Øąµą“§ą“Øą“ąµ¾"),
"thankYou": MessageLookupByLibrary.simpleMessage("ą“Øą“Øąµą“¦ą“æ"),
"thisDevice": MessageLookupByLibrary.simpleMessage("ą“ ą“ą“Ŗą“ą“°ą“£ą“"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same."),
diff --git a/mobile/lib/generated/intl/messages_nl.dart b/mobile/lib/generated/intl/messages_nl.dart
index e0a5d2ce04..5bd3e8c1ea 100644
--- a/mobile/lib/generated/intl/messages_nl.dart
+++ b/mobile/lib/generated/intl/messages_nl.dart
@@ -1848,6 +1848,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Nieuwste eerst"),
"sortOldestFirst": MessageLookupByLibrary.simpleMessage("Oudste eerst"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Succes"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Herstel starten"),
"startBackup": MessageLookupByLibrary.simpleMessage("Back-up starten"),
@@ -1940,6 +1942,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("Dit is uw verificatie-ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Dit zal je uitloggen van het volgende apparaat:"),
diff --git a/mobile/lib/generated/intl/messages_no.dart b/mobile/lib/generated/intl/messages_no.dart
index c6b217ea08..fa13faccb0 100644
--- a/mobile/lib/generated/intl/messages_no.dart
+++ b/mobile/lib/generated/intl/messages_no.dart
@@ -419,6 +419,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"Beklager, vi kunne ikke generere sikre nøkler pÄ denne enheten.\n\nvennligst registrer deg fra en annen enhet."),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Suksess"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"status": MessageLookupByLibrary.simpleMessage("Status"),
"strongStrength": MessageLookupByLibrary.simpleMessage("Sterkt"),
"tapToCopy":
@@ -436,6 +438,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Dette er din bekreftelses-ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Dette vil logge deg ut av fĆølgende enhet:"),
diff --git a/mobile/lib/generated/intl/messages_pl.dart b/mobile/lib/generated/intl/messages_pl.dart
index 36a477f014..4d32415fd5 100644
--- a/mobile/lib/generated/intl/messages_pl.dart
+++ b/mobile/lib/generated/intl/messages_pl.dart
@@ -1793,6 +1793,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Od najstarszych"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Sukces"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Rozpocznij odzyskiwanie"),
"startBackup": MessageLookupByLibrary.simpleMessage(
@@ -1884,6 +1886,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"To jest Twój Identyfikator Weryfikacji"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"To wyloguje CiÄ z tego urzÄ
dzenia:"),
diff --git a/mobile/lib/generated/intl/messages_pt.dart b/mobile/lib/generated/intl/messages_pt.dart
index 3d4cf0844d..3a250ecb55 100644
--- a/mobile/lib/generated/intl/messages_pt.dart
+++ b/mobile/lib/generated/intl/messages_pt.dart
@@ -1836,6 +1836,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Antigos primeiro"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Sucesso"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Iniciar recuperação"),
"startBackup":
@@ -1928,6 +1930,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Este é o seu ID de verificação"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Isso farĆ” vocĆŖ sair do dispositivo a seguir:"),
diff --git a/mobile/lib/generated/intl/messages_ro.dart b/mobile/lib/generated/intl/messages_ro.dart
index 2a0b9f2167..b9fc7139bf 100644
--- a/mobile/lib/generated/intl/messages_ro.dart
+++ b/mobile/lib/generated/intl/messages_ro.dart
@@ -1809,6 +1809,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Cele mai vechi primele"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Succes"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("ĆncepeČi recuperarea"),
"startBackup":
@@ -1899,6 +1901,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Acesta este ID-ul dvs. de verificare"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"UrmeazÄ sÄ vÄ deconectaČi de pe urmÄtorul dispozitiv:"),
diff --git a/mobile/lib/generated/intl/messages_ru.dart b/mobile/lib/generated/intl/messages_ru.dart
index a2fe3b2c7d..a2b6149094 100644
--- a/mobile/lib/generated/intl/messages_ru.dart
+++ b/mobile/lib/generated/intl/messages_ru.dart
@@ -1700,6 +1700,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Š”Š½Š°ŃŠ°Š»Š° ŃŃŠ°ŃŃŠµ"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("āØ Š£ŃŠæŠµŃŠ½Š¾"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startBackup": MessageLookupByLibrary.simpleMessage(
"ŠŠ°ŃаŃŃ ŃŠµŠ·ŠµŃвное ŠŗŠ¾ŠæŠøŃование"),
"status": MessageLookupByLibrary.simpleMessage("Š”ŃŠ°ŃŃŃ"),
@@ -1784,6 +1786,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"ŠŃо Š²Š°Ń ŠøŠ“ŠµŠ½ŃŠøŃŠøŠŗŠ°ŃŠ¾Ń ŠæŠ¾Š“ŃŠ²ŠµŃжГениŃ"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"ŠŃ Š²ŃŠ¹Š“ŠµŃŠµ ŠøŠ· ŃŠæŠøŃŠŗŠ° ŃŠ»ŠµŠ“ŃŃŃŠøŃ
ŃŃŃŃŠ¾Š¹ŃŃŠ²:"),
diff --git a/mobile/lib/generated/intl/messages_sl.dart b/mobile/lib/generated/intl/messages_sl.dart
index 447a6c38e3..ec46090eaa 100644
--- a/mobile/lib/generated/intl/messages_sl.dart
+++ b/mobile/lib/generated/intl/messages_sl.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_sv.dart b/mobile/lib/generated/intl/messages_sv.dart
index 856bd342fa..08f11cbc18 100644
--- a/mobile/lib/generated/intl/messages_sv.dart
+++ b/mobile/lib/generated/intl/messages_sv.dart
@@ -638,6 +638,8 @@ class MessageLookup extends MessageLookupByLibrary {
"TyvƤrr, vi kunde inte generera sƤkra nycklar pƄ den hƤr enheten.\n\nVƤnligen registrera dig frƄn en annan enhet."),
"sort": MessageLookupByLibrary.simpleMessage("Sortera"),
"sortAlbumsBy": MessageLookupByLibrary.simpleMessage("Sortera efter"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"status": MessageLookupByLibrary.simpleMessage("Status"),
"storageBreakupYou": MessageLookupByLibrary.simpleMessage("Du"),
"storageInGB": m2,
@@ -668,6 +670,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Detta Ƥr ditt verifierings-ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Detta kommer att logga ut dig frƄn fƶljande enhet:"),
diff --git a/mobile/lib/generated/intl/messages_ta.dart b/mobile/lib/generated/intl/messages_ta.dart
index 5d75cde490..0b2e3e577c 100644
--- a/mobile/lib/generated/intl/messages_ta.dart
+++ b/mobile/lib/generated/intl/messages_ta.dart
@@ -76,6 +76,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same."),
diff --git a/mobile/lib/generated/intl/messages_te.dart b/mobile/lib/generated/intl/messages_te.dart
index b282c236d1..3eca5887bb 100644
--- a/mobile/lib/generated/intl/messages_te.dart
+++ b/mobile/lib/generated/intl/messages_te.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_th.dart b/mobile/lib/generated/intl/messages_th.dart
index ffadc1adde..94400b311a 100644
--- a/mobile/lib/generated/intl/messages_th.dart
+++ b/mobile/lib/generated/intl/messages_th.dart
@@ -330,6 +330,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"ąø”ąøµąøąø²ąøąøąø¢ą¹ąø²ąøąøąø“ąøąøąø„ąø²ąø ą¹ąøąø£ąøąø„ąøąøąøąøµąøąøąø£ąø±ą¹ąø"),
"sorry": MessageLookupByLibrary.simpleMessage("ąøąøąøąø ัย"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"status": MessageLookupByLibrary.simpleMessage("ąøŖąøąø²ąøąø°"),
"storageBreakupFamily":
MessageLookupByLibrary.simpleMessage("ąøąø£ąøąøąøąø£ąø±ąø§"),
@@ -348,6 +350,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"ąøąøµąø¢ą¹ąøąø²ąø£ąøąø¹ą¹ąøąø·ąøąøąøµą¹ąøąøøąøąøą¹ąøąøą¹ąø”ą¹ąøąø¹ąøąøą¹ąøąø"),
"thisDevice": MessageLookupByLibrary.simpleMessage("ąøąøøąøąøąø£ąøą¹ąøąøµą¹"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same."),
diff --git a/mobile/lib/generated/intl/messages_ti.dart b/mobile/lib/generated/intl/messages_ti.dart
index f889f36ec0..2b5dd741f9 100644
--- a/mobile/lib/generated/intl/messages_ti.dart
+++ b/mobile/lib/generated/intl/messages_ti.dart
@@ -50,6 +50,10 @@ class MessageLookup extends MessageLookupByLibrary {
"Selected items will be removed from this person, but not deleted from your library."),
"shiftDatesAndTime":
MessageLookupByLibrary.simpleMessage("Shift dates and time"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillMakeTheDateAndTimeOfAllSelected":
MessageLookupByLibrary.simpleMessage(
"This will make the date and time of all selected photos the same.")
diff --git a/mobile/lib/generated/intl/messages_tr.dart b/mobile/lib/generated/intl/messages_tr.dart
index 3886130565..2cf9cbc061 100644
--- a/mobile/lib/generated/intl/messages_tr.dart
+++ b/mobile/lib/generated/intl/messages_tr.dart
@@ -1829,6 +1829,8 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Yeniden eskiye"),
"sortOldestFirst": MessageLookupByLibrary.simpleMessage("Ćnce en eski"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠BaÅarılı"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("Kurtarmayı baÅlat"),
"startBackup":
@@ -1922,6 +1924,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("DoÄrulama kimliÄiniz"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Bu, sizi aÅaÄıdaki cihazdan ƧıkıŠyapacak:"),
diff --git a/mobile/lib/generated/intl/messages_uk.dart b/mobile/lib/generated/intl/messages_uk.dart
index 33d5f9c7d3..100a5a7593 100644
--- a/mobile/lib/generated/intl/messages_uk.dart
+++ b/mobile/lib/generated/intl/messages_uk.dart
@@ -1782,6 +1782,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("Š”ŠæŠ¾ŃŠ°ŃŠŗŃ Š½Š°Š¹ŃŃŠ°ŃŃŃŃ"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("āØ Š£ŃŠæŃŃŠ½Š¾"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("ŠŠ¾ŃŠ°ŃŠø Š²ŃŠ“новленнŃ"),
"startBackup":
@@ -1872,6 +1874,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId": MessageLookupByLibrary.simpleMessage(
"Це Š²Š°Ń ŠŠ“ŠµŠ½ŃŠøŃŃŠŗŠ°ŃŠ¾Ń ŠæŃŠ“ŃŠ²ŠµŃГженнŃ"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Це ŠæŃизвеГе Го виŃ
Š¾Š“Ń Š½Š° наŃŃŃŠæŠ½Š¾Š¼Ń ŠæŃŠøŃŃŃŠ¾Ń:"),
diff --git a/mobile/lib/generated/intl/messages_vi.dart b/mobile/lib/generated/intl/messages_vi.dart
index 5601b4139e..c672284ae5 100644
--- a/mobile/lib/generated/intl/messages_vi.dart
+++ b/mobile/lib/generated/intl/messages_vi.dart
@@ -1756,6 +1756,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortOldestFirst":
MessageLookupByLibrary.simpleMessage("CÅ© nhįŗ„t trʰį»c"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠Thà nh cÓng"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("BįŗÆt Äįŗ§u khĆ“i phỄc"),
"startBackup": MessageLookupByLibrary.simpleMessage("BįŗÆt Äįŗ§u sao lʰu"),
@@ -1843,6 +1845,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("ÄĆ¢y lĆ ID xĆ”c minh cį»§a bįŗ”n"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage(
"Äiį»u nĆ y sįŗ½ ÄÄng xuįŗ„t bįŗ”n khį»i thiįŗæt bį» sau:"),
diff --git a/mobile/lib/generated/intl/messages_zh.dart b/mobile/lib/generated/intl/messages_zh.dart
index eefcd9f3dc..08b8ec8507 100644
--- a/mobile/lib/generated/intl/messages_zh.dart
+++ b/mobile/lib/generated/intl/messages_zh.dart
@@ -1494,6 +1494,8 @@ class MessageLookup extends MessageLookupByLibrary {
"sortNewestFirst": MessageLookupByLibrary.simpleMessage("ęę°åØå"),
"sortOldestFirst": MessageLookupByLibrary.simpleMessage("ęę§åØå"),
"sparkleSuccess": MessageLookupByLibrary.simpleMessage("⨠ęå"),
+ "spotlightOnYourself":
+ MessageLookupByLibrary.simpleMessage("Spotlight on yourself"),
"startAccountRecoveryTitle":
MessageLookupByLibrary.simpleMessage("å¼å§ę¢å¤"),
"startBackup": MessageLookupByLibrary.simpleMessage("å¼å§å¤ä»½"),
@@ -1568,6 +1570,8 @@ class MessageLookup extends MessageLookupByLibrary {
"thisIsPersonVerificationId": m84,
"thisIsYourVerificationId":
MessageLookupByLibrary.simpleMessage("čæęÆęØēéŖčÆ ID"),
+ "thisWeekThroughTheYears":
+ MessageLookupByLibrary.simpleMessage("This week through the years"),
"thisWillLogYouOutOfTheFollowingDevice":
MessageLookupByLibrary.simpleMessage("čæå°ä½æęØåØä»„äøč®¾å¤äøéåŗē»å½ļ¼"),
"thisWillLogYouOutOfThisDevice":
diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart
index da9a2b4676..d5a4d214ac 100644
--- a/mobile/lib/generated/l10n.dart
+++ b/mobile/lib/generated/l10n.dart
@@ -11413,6 +11413,318 @@ class S {
args: [],
);
}
+
+ /// `{dateFormat} through the years`
+ String throughTheYears(Object dateFormat) {
+ return Intl.message(
+ '$dateFormat through the years',
+ name: 'throughTheYears',
+ desc: '',
+ args: [dateFormat],
+ );
+ }
+
+ /// `This week through the years`
+ String get thisWeekThroughTheYears {
+ return Intl.message(
+ 'This week through the years',
+ name: 'thisWeekThroughTheYears',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `{count, plural, =1 {This week, {count} year ago} other {This week, {count} years ago}}`
+ String thisWeekXYearsAgo(num count) {
+ return Intl.plural(
+ count,
+ one: 'This week, $count year ago',
+ other: 'This week, $count years ago',
+ name: 'thisWeekXYearsAgo',
+ desc: '',
+ args: [count],
+ );
+ }
+
+ /// `You and {name}`
+ String youAndThem(Object name) {
+ return Intl.message(
+ 'You and $name',
+ name: 'youAndThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Admiring {name}`
+ String admiringThem(Object name) {
+ return Intl.message(
+ 'Admiring $name',
+ name: 'admiringThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Embracing {name}`
+ String embracingThem(Object name) {
+ return Intl.message(
+ 'Embracing $name',
+ name: 'embracingThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Party with {name}`
+ String partyWithThem(Object name) {
+ return Intl.message(
+ 'Party with $name',
+ name: 'partyWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Hiking with {name}`
+ String hikingWithThem(Object name) {
+ return Intl.message(
+ 'Hiking with $name',
+ name: 'hikingWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Feasting with {name}`
+ String feastingWithThem(Object name) {
+ return Intl.message(
+ 'Feasting with $name',
+ name: 'feastingWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Selfies with {name}`
+ String selfiesWithThem(Object name) {
+ return Intl.message(
+ 'Selfies with $name',
+ name: 'selfiesWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Posing with {name}`
+ String posingWithThem(Object name) {
+ return Intl.message(
+ 'Posing with $name',
+ name: 'posingWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Scenery with {name}`
+ String backgroundWithThem(Object name) {
+ return Intl.message(
+ 'Scenery with $name',
+ name: 'backgroundWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Sports with {name}`
+ String sportsWithThem(Object name) {
+ return Intl.message(
+ 'Sports with $name',
+ name: 'sportsWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Road trip with {name}`
+ String roadtripWithThem(Object name) {
+ return Intl.message(
+ 'Road trip with $name',
+ name: 'roadtripWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Spotlight on yourself`
+ String get spotlightOnYourself {
+ return Intl.message(
+ 'Spotlight on yourself',
+ name: 'spotlightOnYourself',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Spotlight on {name}`
+ String spotlightOnThem(Object name) {
+ return Intl.message(
+ 'Spotlight on $name',
+ name: 'spotlightOnThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `{name} is {age}!`
+ String personIsAge(Object name, Object age) {
+ return Intl.message(
+ '$name is $age!',
+ name: 'personIsAge',
+ desc: '',
+ args: [name, age],
+ );
+ }
+
+ /// `{name} turning {age} soon`
+ String personTurningAge(Object name, Object age) {
+ return Intl.message(
+ '$name turning $age soon',
+ name: 'personTurningAge',
+ desc: '',
+ args: [name, age],
+ );
+ }
+
+ /// `Last time with {name}`
+ String lastTimeWithThem(Object name) {
+ return Intl.message(
+ 'Last time with $name',
+ name: 'lastTimeWithThem',
+ desc: '',
+ args: [name],
+ );
+ }
+
+ /// `Trip to {location}`
+ String tripToLocation(Object location) {
+ return Intl.message(
+ 'Trip to $location',
+ name: 'tripToLocation',
+ desc: '',
+ args: [location],
+ );
+ }
+
+ /// `Trip in {year}`
+ String tripInYear(Object year) {
+ return Intl.message(
+ 'Trip in $year',
+ name: 'tripInYear',
+ desc: '',
+ args: [year],
+ );
+ }
+
+ /// `Last year's trip`
+ String get lastYearsTrip {
+ return Intl.message(
+ 'Last year\'s trip',
+ name: 'lastYearsTrip',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `On the horizon`
+ String get sunrise {
+ return Intl.message(
+ 'On the horizon',
+ name: 'sunrise',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Over the hills`
+ String get mountains {
+ return Intl.message(
+ 'Over the hills',
+ name: 'mountains',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `The green life`
+ String get greenery {
+ return Intl.message(
+ 'The green life',
+ name: 'greenery',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Sand and sea`
+ String get beach {
+ return Intl.message(
+ 'Sand and sea',
+ name: 'beach',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `In the city`
+ String get city {
+ return Intl.message(
+ 'In the city',
+ name: 'city',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `In the moonlight`
+ String get moon {
+ return Intl.message(
+ 'In the moonlight',
+ name: 'moon',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `On the road again`
+ String get onTheRoad {
+ return Intl.message(
+ 'On the road again',
+ name: 'onTheRoad',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Culinary delight`
+ String get food {
+ return Intl.message(
+ 'Culinary delight',
+ name: 'food',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Furry companions`
+ String get pets {
+ return Intl.message(
+ 'Furry companions',
+ name: 'pets',
+ desc: '',
+ args: [],
+ );
+ }
}
class AppLocalizationDelegate extends LocalizationsDelegate {
diff --git a/mobile/lib/l10n/intl_ar.arb b/mobile/lib/l10n/intl_ar.arb
index c42158fb9c..0c9770a16a 100644
--- a/mobile/lib/l10n/intl_ar.arb
+++ b/mobile/lib/l10n/intl_ar.arb
@@ -38,5 +38,7 @@
"shiftDatesAndTime": "Shift dates and time",
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_be.arb b/mobile/lib/l10n/intl_be.arb
index 8b72ff9184..609239746d 100644
--- a/mobile/lib/l10n/intl_be.arb
+++ b/mobile/lib/l10n/intl_be.arb
@@ -215,5 +215,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_bg.arb b/mobile/lib/l10n/intl_bg.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_bg.arb
+++ b/mobile/lib/l10n/intl_bg.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ca.arb b/mobile/lib/l10n/intl_ca.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_ca.arb
+++ b/mobile/lib/l10n/intl_ca.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_cs.arb b/mobile/lib/l10n/intl_cs.arb
index 9c8222ea1d..67deea0b41 100644
--- a/mobile/lib/l10n/intl_cs.arb
+++ b/mobile/lib/l10n/intl_cs.arb
@@ -18,5 +18,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_da.arb b/mobile/lib/l10n/intl_da.arb
index ae644018b6..ac47e125a7 100644
--- a/mobile/lib/l10n/intl_da.arb
+++ b/mobile/lib/l10n/intl_da.arb
@@ -258,5 +258,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_de.arb b/mobile/lib/l10n/intl_de.arb
index 77ae8c4b95..bf52d682dd 100644
--- a/mobile/lib/l10n/intl_de.arb
+++ b/mobile/lib/l10n/intl_de.arb
@@ -1688,5 +1688,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_el.arb b/mobile/lib/l10n/intl_el.arb
index e0c97ff543..34a315866c 100644
--- a/mobile/lib/l10n/intl_el.arb
+++ b/mobile/lib/l10n/intl_el.arb
@@ -15,5 +15,7 @@
"shiftDatesAndTime": "Shift dates and time",
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb
index bb3371f2d0..de7d90f924 100644
--- a/mobile/lib/l10n/intl_en.arb
+++ b/mobile/lib/l10n/intl_en.arb
@@ -1700,5 +1700,36 @@
},
"appIcon": "App icon",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
-}
\ No newline at end of file
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "throughTheYears": "{dateFormat} through the years",
+ "thisWeekThroughTheYears": "This week through the years",
+ "thisWeekXYearsAgo": "{count, plural, =1 {This week, {count} year ago} other {This week, {count} years ago}}",
+ "youAndThem": "You and {name}",
+ "admiringThem": "Admiring {name}",
+ "embracingThem": "Embracing {name}",
+ "partyWithThem": "Party with {name}",
+ "hikingWithThem": "Hiking with {name}",
+ "feastingWithThem": "Feasting with {name}",
+ "selfiesWithThem": "Selfies with {name}",
+ "posingWithThem": "Posing with {name}",
+ "backgroundWithThem": "Scenery with {name}",
+ "sportsWithThem": "Sports with {name}",
+ "roadtripWithThem": "Road trip with {name}",
+ "spotlightOnYourself": "Spotlight on yourself",
+ "spotlightOnThem": "Spotlight on {name}",
+ "personIsAge": "{name} is {age}!",
+ "personTurningAge": "{name} turning {age} soon",
+ "lastTimeWithThem": "Last time with {name}",
+ "tripToLocation": "Trip to {location}",
+ "tripInYear": "Trip in {year}",
+ "lastYearsTrip": "Last year's trip",
+ "sunrise": "On the horizon",
+ "mountains": "Over the hills",
+ "greenery": "The green life",
+ "beach": "Sand and sea",
+ "city": "In the city",
+ "moon": "In the moonlight",
+ "onTheRoad": "On the road again",
+ "food": "Culinary delight",
+ "pets": "Furry companions"
+}
diff --git a/mobile/lib/l10n/intl_es.arb b/mobile/lib/l10n/intl_es.arb
index e6d9cdcfd6..ddae581d06 100644
--- a/mobile/lib/l10n/intl_es.arb
+++ b/mobile/lib/l10n/intl_es.arb
@@ -1689,5 +1689,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_et.arb b/mobile/lib/l10n/intl_et.arb
index 099579a313..5dc1464a5c 100644
--- a/mobile/lib/l10n/intl_et.arb
+++ b/mobile/lib/l10n/intl_et.arb
@@ -234,5 +234,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_fa.arb b/mobile/lib/l10n/intl_fa.arb
index fc92b92f46..691afcf2a0 100644
--- a/mobile/lib/l10n/intl_fa.arb
+++ b/mobile/lib/l10n/intl_fa.arb
@@ -324,5 +324,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_fr.arb b/mobile/lib/l10n/intl_fr.arb
index badfa74d54..987520c49d 100644
--- a/mobile/lib/l10n/intl_fr.arb
+++ b/mobile/lib/l10n/intl_fr.arb
@@ -1689,5 +1689,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_gu.arb b/mobile/lib/l10n/intl_gu.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_gu.arb
+++ b/mobile/lib/l10n/intl_gu.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_he.arb b/mobile/lib/l10n/intl_he.arb
index dd5db1c0a0..f556b9425b 100644
--- a/mobile/lib/l10n/intl_he.arb
+++ b/mobile/lib/l10n/intl_he.arb
@@ -830,5 +830,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_hi.arb b/mobile/lib/l10n/intl_hi.arb
index e52744a169..1ce96592d7 100644
--- a/mobile/lib/l10n/intl_hi.arb
+++ b/mobile/lib/l10n/intl_hi.arb
@@ -64,5 +64,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_hu.arb b/mobile/lib/l10n/intl_hu.arb
index 7a28363da2..6de4b5fd03 100644
--- a/mobile/lib/l10n/intl_hu.arb
+++ b/mobile/lib/l10n/intl_hu.arb
@@ -26,5 +26,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_id.arb b/mobile/lib/l10n/intl_id.arb
index e35d627651..a67cdb2e56 100644
--- a/mobile/lib/l10n/intl_id.arb
+++ b/mobile/lib/l10n/intl_id.arb
@@ -1146,5 +1146,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_it.arb b/mobile/lib/l10n/intl_it.arb
index e97ea4e504..dddb3a4355 100644
--- a/mobile/lib/l10n/intl_it.arb
+++ b/mobile/lib/l10n/intl_it.arb
@@ -1615,5 +1615,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ja.arb b/mobile/lib/l10n/intl_ja.arb
index d3f4b0d52c..a32237a62a 100644
--- a/mobile/lib/l10n/intl_ja.arb
+++ b/mobile/lib/l10n/intl_ja.arb
@@ -1689,5 +1689,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_km.arb b/mobile/lib/l10n/intl_km.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_km.arb
+++ b/mobile/lib/l10n/intl_km.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ko.arb b/mobile/lib/l10n/intl_ko.arb
index a5ada71974..4f49a81b99 100644
--- a/mobile/lib/l10n/intl_ko.arb
+++ b/mobile/lib/l10n/intl_ko.arb
@@ -28,5 +28,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_lt.arb b/mobile/lib/l10n/intl_lt.arb
index cd2ef1180d..4b6aff9088 100644
--- a/mobile/lib/l10n/intl_lt.arb
+++ b/mobile/lib/l10n/intl_lt.arb
@@ -1436,5 +1436,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ml.arb b/mobile/lib/l10n/intl_ml.arb
index 35c7598463..cd66d1bd56 100644
--- a/mobile/lib/l10n/intl_ml.arb
+++ b/mobile/lib/l10n/intl_ml.arb
@@ -115,5 +115,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_nl.arb b/mobile/lib/l10n/intl_nl.arb
index b6b6c439ad..55d2839001 100644
--- a/mobile/lib/l10n/intl_nl.arb
+++ b/mobile/lib/l10n/intl_nl.arb
@@ -1689,5 +1689,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_no.arb b/mobile/lib/l10n/intl_no.arb
index bc0e78bb61..ba108fb7ba 100644
--- a/mobile/lib/l10n/intl_no.arb
+++ b/mobile/lib/l10n/intl_no.arb
@@ -386,5 +386,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_pl.arb b/mobile/lib/l10n/intl_pl.arb
index 6b5d1f5eef..5e68d96be4 100644
--- a/mobile/lib/l10n/intl_pl.arb
+++ b/mobile/lib/l10n/intl_pl.arb
@@ -1613,5 +1613,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_pt.arb b/mobile/lib/l10n/intl_pt.arb
index efbf51cb82..4f9c533651 100644
--- a/mobile/lib/l10n/intl_pt.arb
+++ b/mobile/lib/l10n/intl_pt.arb
@@ -1690,5 +1690,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ro.arb b/mobile/lib/l10n/intl_ro.arb
index 56c3fe5956..b38db6a294 100644
--- a/mobile/lib/l10n/intl_ro.arb
+++ b/mobile/lib/l10n/intl_ro.arb
@@ -1592,5 +1592,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ru.arb b/mobile/lib/l10n/intl_ru.arb
index 36dbbc2147..4aa7617240 100644
--- a/mobile/lib/l10n/intl_ru.arb
+++ b/mobile/lib/l10n/intl_ru.arb
@@ -1477,5 +1477,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_sl.arb b/mobile/lib/l10n/intl_sl.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_sl.arb
+++ b/mobile/lib/l10n/intl_sl.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_sv.arb b/mobile/lib/l10n/intl_sv.arb
index c5252f67c2..c9c6c009d7 100644
--- a/mobile/lib/l10n/intl_sv.arb
+++ b/mobile/lib/l10n/intl_sv.arb
@@ -555,5 +555,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ta.arb b/mobile/lib/l10n/intl_ta.arb
index 5096949a13..5925e40925 100644
--- a/mobile/lib/l10n/intl_ta.arb
+++ b/mobile/lib/l10n/intl_ta.arb
@@ -31,5 +31,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_te.arb b/mobile/lib/l10n/intl_te.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_te.arb
+++ b/mobile/lib/l10n/intl_te.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_th.arb b/mobile/lib/l10n/intl_th.arb
index 405c109319..3ad3132ebb 100644
--- a/mobile/lib/l10n/intl_th.arb
+++ b/mobile/lib/l10n/intl_th.arb
@@ -311,5 +311,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_ti.arb b/mobile/lib/l10n/intl_ti.arb
index 332450d365..a00b52609d 100644
--- a/mobile/lib/l10n/intl_ti.arb
+++ b/mobile/lib/l10n/intl_ti.arb
@@ -15,5 +15,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_tr.arb b/mobile/lib/l10n/intl_tr.arb
index 60ee45be3a..d20ce04be4 100644
--- a/mobile/lib/l10n/intl_tr.arb
+++ b/mobile/lib/l10n/intl_tr.arb
@@ -1689,5 +1689,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_uk.arb b/mobile/lib/l10n/intl_uk.arb
index bcf868d353..f7104fb110 100644
--- a/mobile/lib/l10n/intl_uk.arb
+++ b/mobile/lib/l10n/intl_uk.arb
@@ -1600,5 +1600,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_vi.arb b/mobile/lib/l10n/intl_vi.arb
index 07741c5f23..073e71b89b 100644
--- a/mobile/lib/l10n/intl_vi.arb
+++ b/mobile/lib/l10n/intl_vi.arb
@@ -1612,5 +1612,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/l10n/intl_zh.arb b/mobile/lib/l10n/intl_zh.arb
index 2318c8cf0e..a7ec50b958 100644
--- a/mobile/lib/l10n/intl_zh.arb
+++ b/mobile/lib/l10n/intl_zh.arb
@@ -1689,5 +1689,7 @@
"photosKeepRelativeTimeDifference": "Photos keep relative time difference",
"photocountPhotos": "$photoCount photos",
"notThisPerson": "Not this person?",
- "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library."
+ "selectedItemsWillBeRemovedFromThisPerson": "Selected items will be removed from this person, but not deleted from your library.",
+ "thisWeekThroughTheYears": "This week through the years",
+ "spotlightOnYourself": "Spotlight on yourself"
}
\ No newline at end of file
diff --git a/mobile/lib/models/memories/clip_memory.dart b/mobile/lib/models/memories/clip_memory.dart
index 7ec73aa5db..181920eb3b 100644
--- a/mobile/lib/models/memories/clip_memory.dart
+++ b/mobile/lib/models/memories/clip_memory.dart
@@ -1,9 +1,9 @@
+import "package:photos/generated/l10n.dart";
import "package:photos/models/memories/memory.dart";
import "package:photos/models/memories/smart_memory.dart";
enum ClipMemoryType {
sunrise,
- sunset,
mountains,
greenery,
beach,
@@ -18,8 +18,6 @@ ClipMemoryType clipMemoryTypeFromString(String type) {
switch (type) {
case "sunrise":
return ClipMemoryType.sunrise;
- case "sunset":
- return ClipMemoryType.sunset;
case "mountains":
return ClipMemoryType.mountains;
case "greenery":
@@ -44,9 +42,7 @@ ClipMemoryType clipMemoryTypeFromString(String type) {
String clipQuery(ClipMemoryType clipMemoryType) {
switch (clipMemoryType) {
case ClipMemoryType.sunrise:
- return "Photo of an absolutely stunning sunrise";
- case ClipMemoryType.sunset:
- return "Photo of an absolutely stunning sunset";
+ return "Photo of an absolutely stunning sunrise or sunset";
case ClipMemoryType.mountains:
return "Photo of a beautiful mountain range";
case ClipMemoryType.greenery:
@@ -66,28 +62,26 @@ String clipQuery(ClipMemoryType clipMemoryType) {
}
}
-String clipTitle(ClipMemoryType clipMemoryType) {
+String clipTitle(S s, ClipMemoryType clipMemoryType) {
switch (clipMemoryType) {
case ClipMemoryType.sunrise:
- return "Sunrise";
- case ClipMemoryType.sunset:
- return "Sunset";
+ return s.sunrise;
case ClipMemoryType.mountains:
- return "Mountains";
+ return s.mountains;
case ClipMemoryType.greenery:
- return "Greenery";
+ return s.greenery;
case ClipMemoryType.beach:
- return "Beach";
+ return s.beach;
case ClipMemoryType.city:
- return "City";
+ return s.city;
case ClipMemoryType.moon:
- return "Moon";
+ return s.moon;
case ClipMemoryType.onTheRoad:
- return "On the Road";
+ return s.onTheRoad;
case ClipMemoryType.food:
- return "Food";
+ return s.food;
case ClipMemoryType.pets:
- return "Pets";
+ return s.pets;
}
}
@@ -96,7 +90,6 @@ class ClipMemory extends SmartMemory {
ClipMemory(
List memories,
- String title,
int firstDateToShow,
int lastDateToShow,
this.clipMemoryType, {
@@ -105,27 +98,13 @@ class ClipMemory extends SmartMemory {
}) : super(
memories,
MemoryType.clip,
- title,
+ '',
firstDateToShow,
lastDateToShow,
);
- ClipMemory copyWith({
- List? memories,
- String? title,
- int? firstDateToShow,
- int? lastDateToShow,
- int? firstCreationTime,
- int? lastCreationTime,
- }) {
- return ClipMemory(
- memories ?? this.memories,
- title ?? this.title,
- firstDateToShow ?? this.firstDateToShow,
- lastDateToShow ?? this.lastDateToShow,
- clipMemoryType,
- firstCreationTime: firstCreationTime ?? this.firstCreationTime,
- lastCreationTime: lastCreationTime ?? this.lastCreationTime,
- );
+ @override
+ String createTitle(S s, String languageCode) {
+ return clipTitle(s, clipMemoryType);
}
}
diff --git a/mobile/lib/models/memories/filler_memory.dart b/mobile/lib/models/memories/filler_memory.dart
index 3e4e02b2c2..7fd597980c 100644
--- a/mobile/lib/models/memories/filler_memory.dart
+++ b/mobile/lib/models/memories/filler_memory.dart
@@ -1,10 +1,13 @@
+import "package:photos/generated/l10n.dart";
import "package:photos/models/memories/memory.dart";
import "package:photos/models/memories/smart_memory.dart";
class FillerMemory extends SmartMemory {
+ // For creating the title
+ int yearsAgo;
FillerMemory(
List memories,
- String title,
+ this.yearsAgo,
int firstDateToShow,
int lastDateToShow, {
int? firstCreationTime,
@@ -12,8 +15,13 @@ class FillerMemory extends SmartMemory {
}) : super(
memories,
MemoryType.filler,
- title,
+ 'filler',
firstDateToShow,
lastDateToShow,
);
+
+ @override
+ String createTitle(S s, String languageCode) {
+ return s.yearsAgo(yearsAgo);
+ }
}
diff --git a/mobile/lib/models/memories/people_memory.dart b/mobile/lib/models/memories/people_memory.dart
index 7902746eb3..83f6b1a363 100644
--- a/mobile/lib/models/memories/people_memory.dart
+++ b/mobile/lib/models/memories/people_memory.dart
@@ -1,3 +1,4 @@
+import "package:photos/generated/l10n.dart";
import "package:photos/models/memories/memory.dart";
import "package:photos/models/memories/smart_memory.dart";
@@ -45,9 +46,9 @@ enum PeopleActivity {
String activityQuery(PeopleActivity activity) {
switch (activity) {
case PeopleActivity.admiring:
- return "Photo of two people lovingly admiring or looking at each other";
+ return "Photo of two people admiring or looking at each other in a loving but non-intimate and non-physical way";
case PeopleActivity.embracing:
- return "Photo of people hugging or embracing each other lovingly";
+ return "Photo of people hugging or embracing each other lovingly, without inappropriately kissing or other intimate actions";
case PeopleActivity.party:
return "Photo of people celebrating together";
case PeopleActivity.hiking:
@@ -55,7 +56,7 @@ String activityQuery(PeopleActivity activity) {
case PeopleActivity.feast:
return "Photo of people having a big feast together";
case PeopleActivity.selfies:
- return "Happy and nostalgic selfie with people";
+ return "Happy and nostalgic selfie with people, clearly taken from the front camera of a phone";
case PeopleActivity.posing:
return "Photo of people posing together in a funny manner for the camera";
case PeopleActivity.background:
@@ -67,71 +68,104 @@ String activityQuery(PeopleActivity activity) {
}
}
-String activityTitle(PeopleActivity activity, String personName) {
+String activityTitle(S s, PeopleActivity activity, String personName) {
switch (activity) {
case PeopleActivity.admiring:
- return "Admiring $personName";
+ return s.admiringThem(personName);
case PeopleActivity.embracing:
- return "Embracing $personName";
+ return s.embracingThem(personName);
case PeopleActivity.party:
- return "Party with $personName";
+ return s.partyWithThem(personName);
case PeopleActivity.hiking:
- return "Hiking with $personName";
+ return s.hikingWithThem(personName);
case PeopleActivity.feast:
- return "Feasting with $personName";
+ return s.feastingWithThem(personName);
case PeopleActivity.selfies:
- return "Selfies with $personName";
+ return s.selfiesWithThem(personName);
case PeopleActivity.posing:
- return "Posing with $personName";
+ return s.posingWithThem(personName);
case PeopleActivity.background:
- return "You, $personName, and what a background!";
+ return s.backgroundWithThem(personName);
case PeopleActivity.sports:
- return "Sports with $personName";
+ return s.sportsWithThem(personName);
case PeopleActivity.roadtrip:
- return "Road trip with $personName";
+ return s.roadtripWithThem(personName);
}
}
class PeopleMemory extends SmartMemory {
final String personID;
final PeopleMemoryType peopleMemoryType;
+ final PeopleActivity? activity;
+ final String? personName;
+ final bool? isBirthday;
+ final int? newAge;
PeopleMemory(
List memories,
- String title,
int firstDateToShow,
int lastDateToShow,
this.peopleMemoryType,
- this.personID, {
+ this.personID,
+ this.personName, {
super.firstCreationTime,
super.lastCreationTime,
+ this.activity,
+ this.isBirthday,
+ this.newAge,
}) : super(
memories,
MemoryType.people,
- title,
+ '',
firstDateToShow,
lastDateToShow,
);
PeopleMemory copyWith({
- List? memories,
- String? title,
int? firstDateToShow,
int? lastDateToShow,
- PeopleMemoryType? peopleMemoryType,
- String? personID,
- int? firstCreationTime,
- int? lastCreationTime,
+ bool? isBirthday,
+ int? newAge,
}) {
return PeopleMemory(
- memories ?? this.memories,
- title ?? this.title,
+ memories,
firstDateToShow ?? this.firstDateToShow,
lastDateToShow ?? this.lastDateToShow,
- peopleMemoryType ?? this.peopleMemoryType,
- personID ?? this.personID,
- firstCreationTime: firstCreationTime ?? this.firstCreationTime,
- lastCreationTime: lastCreationTime ?? this.lastCreationTime,
+ peopleMemoryType,
+ personID,
+ personName,
+ firstCreationTime: firstCreationTime,
+ lastCreationTime: lastCreationTime,
+ activity: activity,
+ isBirthday: isBirthday ?? this.isBirthday,
+ newAge: newAge ?? this.newAge,
);
}
+
+ @override
+ String createTitle(S s, String languageCode) {
+ switch (peopleMemoryType) {
+ case PeopleMemoryType.youAndThem:
+ assert(personName != null);
+ return s.youAndThem(personName!);
+ case PeopleMemoryType.doingSomethingTogether:
+ assert(activity != null);
+ assert(personName != null);
+ return activityTitle(s, activity!, personName!);
+ case PeopleMemoryType.spotlight:
+ if (personName == null) {
+ return s.spotlightOnYourself;
+ } else if (newAge == null) {
+ return s.spotlightOnThem(personName!);
+ } else {
+ if (isBirthday!) {
+ return s.personIsAge(personName!, newAge!);
+ } else {
+ return s.personTurningAge(personName!, newAge!);
+ }
+ }
+ case PeopleMemoryType.lastTimeYouSawThem:
+ return s.lastTimeWithThem(personName!);
+ }
+ }
}
diff --git a/mobile/lib/models/memories/smart_memory.dart b/mobile/lib/models/memories/smart_memory.dart
index 030d4fd8a2..b05ff64959 100644
--- a/mobile/lib/models/memories/smart_memory.dart
+++ b/mobile/lib/models/memories/smart_memory.dart
@@ -1,3 +1,4 @@
+import "package:photos/generated/l10n.dart";
import "package:photos/models/memories/memory.dart";
enum MemoryType {
@@ -56,6 +57,10 @@ class SmartMemory {
return now >= firstDateToShow && now <= lastDateToShow;
}
+ String createTitle(S s, String languageCode) {
+ throw UnimplementedError("createTitle must be implemented in subclass");
+ }
+
int averageCreationTime() {
if (firstCreationTime != null && lastCreationTime != null) {
return (firstCreationTime! + lastCreationTime!) ~/ 2;
diff --git a/mobile/lib/models/memories/time_memory.dart b/mobile/lib/models/memories/time_memory.dart
index 7dafef90ec..e723224aba 100644
--- a/mobile/lib/models/memories/time_memory.dart
+++ b/mobile/lib/models/memories/time_memory.dart
@@ -1,19 +1,53 @@
+import "package:intl/intl.dart";
+import "package:photos/generated/l10n.dart";
import "package:photos/models/memories/memory.dart";
import "package:photos/models/memories/smart_memory.dart";
class TimeMemory extends SmartMemory {
+ // For computing the title
+ DateTime? day;
+ DateTime? month;
+ int? yearsAgo;
+
TimeMemory(
List memories,
- String title,
int firstDateToShow,
int lastDateToShow, {
+ this.day,
+ this.month,
+ this.yearsAgo,
int? firstCreationTime,
int? lastCreationTime,
}) : super(
memories,
MemoryType.time,
- title,
+ '',
firstDateToShow,
lastDateToShow,
);
+
+ @override
+ String createTitle(S s, String languageCode) {
+ if (day != null) {
+ final dayFormat = DateFormat.MMMd(languageCode).format(day!);
+ if (yearsAgo != null) {
+ return "$dayFormat, " + s.yearsAgo(yearsAgo!);
+ } else {
+ return s.throughTheYears(dayFormat);
+ }
+ }
+ if (month != null) {
+ final monthFormat = DateFormat.MMMM(languageCode).format(month!);
+ if (yearsAgo != null) {
+ return "$monthFormat, " + s.yearsAgo(yearsAgo!);
+ } else {
+ return s.throughTheYears(monthFormat);
+ }
+ }
+ if (yearsAgo != null) {
+ return s.thisWeekXYearsAgo(yearsAgo!);
+ } else {
+ return s.thisWeekThroughTheYears;
+ }
+ }
}
diff --git a/mobile/lib/models/memories/trip_memory.dart b/mobile/lib/models/memories/trip_memory.dart
index 8763d20c1e..43480ded3b 100644
--- a/mobile/lib/models/memories/trip_memory.dart
+++ b/mobile/lib/models/memories/trip_memory.dart
@@ -1,3 +1,4 @@
+import "package:photos/generated/l10n.dart";
import "package:photos/models/location/location.dart";
import "package:photos/models/memories/memory.dart";
import "package:photos/models/memories/smart_memory.dart";
@@ -5,39 +6,60 @@ import "package:photos/models/memories/smart_memory.dart";
class TripMemory extends SmartMemory {
final Location location;
+ // Stuff for the title
+ String? locationName;
+ int? tripYear;
+
TripMemory(
List memories,
- String title,
int firstDateToShow,
int lastDateToShow,
this.location, {
+ this.locationName,
+ this.tripYear,
super.firstCreationTime,
super.lastCreationTime,
}) : super(
memories,
MemoryType.trips,
- title,
+ '',
firstDateToShow,
lastDateToShow,
);
TripMemory copyWith({
List? memories,
- String? title,
int? firstDateToShow,
int? lastDateToShow,
- Location? location,
- int? firstCreationTime,
- int? lastCreationTime,
+ String? locationName,
+ int? tripYear,
}) {
return TripMemory(
memories ?? this.memories,
- title ?? this.title,
firstDateToShow ?? this.firstDateToShow,
lastDateToShow ?? this.lastDateToShow,
- location ?? this.location,
- firstCreationTime: firstCreationTime ?? this.firstCreationTime,
- lastCreationTime: lastCreationTime ?? this.lastCreationTime,
+ location,
+ locationName: locationName ?? this.locationName,
+ tripYear: tripYear ?? this.tripYear,
+ firstCreationTime: firstCreationTime,
+ lastCreationTime: lastCreationTime,
);
}
+
+ @override
+ String createTitle(S s, String languageCode) {
+ assert(locationName != null || tripYear != null);
+ if (locationName != null) {
+ if (locationName!.toLowerCase().contains("base")) return locationName!;
+ return s.tripToLocation(locationName!);
+ }
+ if (tripYear != null) {
+ if (tripYear == DateTime.now().year - 1) {
+ return s.lastYearsTrip;
+ } else {
+ return s.tripInYear(tripYear!);
+ }
+ }
+ throw ArgumentError("TripMemory must have a location name or trip year");
+ }
}
diff --git a/mobile/lib/services/memories_cache_service.dart b/mobile/lib/services/memories_cache_service.dart
index 4d6e0da42c..481b3b8fe4 100644
--- a/mobile/lib/services/memories_cache_service.dart
+++ b/mobile/lib/services/memories_cache_service.dart
@@ -143,7 +143,7 @@ class MemoriesCacheService {
try {
if ((!_shouldUpdate && !forced) || _isUpdateInProgress) {
_logger.info(
- "No update needed as shouldUpdate: $_shouldUpdate, forced: $forced and isUpdateInProgress $_isUpdateInProgress",
+ "No update needed (shouldUpdate: $_shouldUpdate, forced: $forced, isUpdateInProgress $_isUpdateInProgress)",
);
if (_isUpdateInProgress) {
int waitingTime = 0;
@@ -154,7 +154,9 @@ class MemoriesCacheService {
}
return;
}
- _logger.info("updating memories cache");
+ _logger.info(
+ "Updating memories cache (shouldUpdate: $_shouldUpdate, forced: $forced, isUpdateInProgress $_isUpdateInProgress)",
+ );
_isUpdateInProgress = true;
final EnteWatch? w =
kDebugMode ? EnteWatch("MemoriesCacheService") : null;
diff --git a/mobile/lib/services/smart_memories_service.dart b/mobile/lib/services/smart_memories_service.dart
index dfefe1cbdc..21d1a8ef14 100644
--- a/mobile/lib/services/smart_memories_service.dart
+++ b/mobile/lib/services/smart_memories_service.dart
@@ -13,6 +13,8 @@ import "package:photos/core/constants.dart";
import "package:photos/db/memories_db.dart";
import "package:photos/db/ml/db.dart";
import "package:photos/extensions/stop_watch.dart";
+import "package:photos/generated/l10n.dart";
+import "package:photos/l10n/l10n.dart";
import "package:photos/models/base_location.dart";
import "package:photos/models/file/file.dart";
import "package:photos/models/location/location.dart";
@@ -111,11 +113,13 @@ class SmartMemoriesService {
}
_logger.finest('clipPositiveTextVector and clipPeopleActivityVectors $t');
- // final locale = await getLocale();
- // TODO: lau: locale with DateFormat is not working well in computer, fix later
+ final local = await getLocale();
+ final languageCode = local?.languageCode ?? "en";
+ final s = await S.load(local!);
+ _logger.finest('get locale and S $t');
_logger.finest('all data fetched $t at ${DateTime.now()}, to computer');
- return Computer.shared().compute(
+ final memoriesResult = await Computer.shared().compute(
_allMemoriesCalculations,
param: {
"allFiles": allFiles,
@@ -133,7 +137,11 @@ class SmartMemoriesService {
"clipPeopleActivityVectors": clipPeopleActivityVectors,
"clipMemoryTypeVectors": clipMemoryTypeVectors,
},
- );
+ ) as MemoriesResult;
+ for (final memory in memoriesResult.memories) {
+ memory.title = memory.createTitle(s, languageCode);
+ }
+ return memoriesResult;
} catch (e, s) {
_logger.severe("Error calculating smart memories", e, s);
return MemoriesResult([], []);
@@ -210,6 +218,7 @@ class SmartMemoriesService {
}
dev.log('arguments from indirect data calculated $t');
dev.log('starting actual memory calculations ${DateTime.now()}');
+ dev.log("All files length at start: ${allFiles.length} $t");
final List memories = [];
@@ -333,8 +342,7 @@ class SmartMemoriesService {
currentTime.add(kMemoriesUpdateFrequency).microsecondsSinceEpoch;
w?.log('allFiles setup');
- // Get ordered list of important people (all named, from most to least files)
- if (persons.length < 5) return []; // Stop if not enough named persons
+ // Get ordered (random) list of important people
final personIdToPerson = {};
final personIdToFaceIDs = >{};
final personIdToFileIDs = >{};
@@ -355,11 +363,7 @@ class SmartMemoriesService {
.where((person) => !person.data.isHidden)
.map((p) => p.remoteID)
.toList();
- orderedImportantPersonsID.sort((a, b) {
- final aFaces = personIdToFaceIDs[a]!.length;
- final bFaces = personIdToFaceIDs[b]!.length;
- return bFaces.compareTo(aFaces);
- });
+ orderedImportantPersonsID.shuffle(Random());
w?.log('orderedImportantPersonsID setup');
// Check if the user has assignmed "me"
@@ -393,10 +397,6 @@ class SmartMemoriesService {
}
}
if (spotlightFiles.length > 5) {
- String title = "Spotlight on $personName";
- if (isMeAssigned && meID == personID) {
- title = "Spotlight on yourself";
- }
final selectSpotlightMemories = await _bestSelectionPeople(
spotlightFiles.map((f) => Memory.fromFile(f, seenTimes)).toList(),
fileIDToImageEmbedding: fileIDToImageEmbedding,
@@ -404,11 +404,11 @@ class SmartMemoriesService {
);
final spotlightMemory = PeopleMemory(
selectSpotlightMemories,
- title,
nowInMicroseconds,
windowEnd,
PeopleMemoryType.spotlight,
personID,
+ (isMeAssigned && meID == personID) ? null : personName,
);
personToMemories
.putIfAbsent(personID, () => {})
@@ -429,7 +429,7 @@ class SmartMemoriesService {
}
}
if (youAndThemFiles.length > 5) {
- final String title = "You and $personName";
+ // final String title = "You and $personName";
final selectYouAndThemMemories = await _bestSelectionPeople(
youAndThemFiles.map((f) => Memory.fromFile(f, seenTimes)).toList(),
fileIDToImageEmbedding: fileIDToImageEmbedding,
@@ -437,11 +437,11 @@ class SmartMemoriesService {
);
final youAndThemMemory = PeopleMemory(
selectYouAndThemMemories,
- title,
nowInMicroseconds,
windowEnd,
PeopleMemoryType.youAndThem,
personID,
+ personName,
);
personToMemories.putIfAbsent(personID, () => {}).putIfAbsent(
PeopleMemoryType.youAndThem,
@@ -485,7 +485,6 @@ class SmartMemoriesService {
}
}
if (activityFiles.length > 5) {
- final String title = activityTitle(activity, personName);
final selectActivityMemories = await _bestSelectionPeople(
activityFiles.map((f) => Memory.fromFile(f, seenTimes)).toList(),
fileIDToImageEmbedding: fileIDToImageEmbedding,
@@ -493,11 +492,12 @@ class SmartMemoriesService {
);
final activityMemory = PeopleMemory(
selectActivityMemories,
- title,
nowInMicroseconds,
windowEnd,
PeopleMemoryType.doingSomethingTogether,
personID,
+ personName,
+ activity: activity,
);
personToMemories
.putIfAbsent(personID, () => {})
@@ -540,16 +540,15 @@ class SmartMemoriesService {
}
}
if (longAgo && lastTimeYouSawThemFiles.length >= 2 && meID != personID) {
- final String title = "Last time with $personName";
final lastTimeMemory = PeopleMemory(
lastTimeYouSawThemFiles
.map((f) => Memory.fromFile(f, seenTimes))
.toList(),
- title,
nowInMicroseconds,
windowEnd,
PeopleMemoryType.lastTimeYouSawThem,
personID,
+ personName,
lastCreationTime: lastCreationTime,
);
personToMemories.putIfAbsent(personID, () => {}).putIfAbsent(
@@ -583,17 +582,15 @@ class SmartMemoriesService {
DateTime(currentTime.year, birthdate.month, birthdate.day);
final daysTillBirthday = thisBirthday.difference(currentTime).inDays;
if (daysTillBirthday < 7 && daysTillBirthday >= 0) {
- final personName = person.data.name;
final int newAge = currentTime.year - birthdate.year;
final spotlightMem =
personMemories[PeopleMemoryType.spotlight]?.first;
- if (spotlightMem != null) {
- final String firstTitle = "$personName turning $newAge!";
- final String secondTitle = "$personName is $newAge!";
+ if (spotlightMem != null && spotlightMem.personName != null) {
final thisBirthday = birthdate.copyWith(year: currentTime.year);
memoryResults.add(
spotlightMem.copyWith(
- title: firstTitle,
+ isBirthday: false,
+ newAge: newAge,
firstDateToShow: thisBirthday
.subtract(const Duration(days: 6))
.microsecondsSinceEpoch,
@@ -602,7 +599,8 @@ class SmartMemoriesService {
);
memoryResults.add(
spotlightMem.copyWith(
- title: secondTitle,
+ isBirthday: true,
+ newAge: newAge,
firstDateToShow: thisBirthday.microsecondsSinceEpoch,
lastDateToShow:
thisBirthday.add(kDayItself).microsecondsSinceEpoch,
@@ -746,7 +744,6 @@ class SmartMemoriesService {
});
clipTypeToMemory[clipMemoryType] = ClipMemory(
clipFiles.take(10).map((f) => Memory.fromFile(f, seenTimes)).toList(),
- clipTitle(clipMemoryType),
nowInMicroseconds,
windowEnd,
clipMemoryType,
@@ -764,7 +761,7 @@ class SmartMemoriesService {
// Loop through the clip types and add based on rotation
clipMemoriesLoop:
- for (final clipMemoryType in ClipMemoryType.values) {
+ for (final clipMemoryType in ClipMemoryType.values..shuffle()) {
final clipMemory = clipTypeToMemory[clipMemoryType];
if (clipMemory == null) continue;
for (final shownLog in shownClip) {
@@ -941,7 +938,6 @@ class SmartMemoriesService {
currentBlockFiles,
seenTimes,
),
- 'Trip1',
0,
0,
location,
@@ -968,7 +964,6 @@ class SmartMemoriesService {
tripLocations.add(
TripMemory(
Memory.fromFiles(currentBlockFiles, seenTimes),
- 'Trip2',
0,
0,
location,
@@ -1002,7 +997,6 @@ class SmartMemoriesService {
)) {
mergedTrips[idx] = TripMemory(
otherTrip.memories + trip.memories,
- 'Trip3',
0,
0,
otherTrip.location,
@@ -1020,7 +1014,6 @@ class SmartMemoriesService {
mergedTrips.add(
TripMemory(
trip.memories,
- 'Trip4',
0,
0,
trip.location,
@@ -1057,10 +1050,10 @@ class SmartMemoriesService {
memoryResults.add(
TripMemory(
Memory.fromFiles(baseLocation.files, seenTimes),
- name,
nowInMicroseconds,
windowEnd,
baseLocation.location,
+ locationName: name,
),
);
}
@@ -1070,12 +1063,6 @@ class SmartMemoriesService {
).year;
final String? locationName =
_tryFindLocationName(trip.memories, cities);
- String name = "Trip in $year";
- if (locationName != null) {
- name = "Trip to $locationName";
- } else if (year == currentTime.year - 1) {
- name = "Last year's trip";
- }
final photoSelection = await _bestSelection(
trip.memories,
fileIdToFaces: fileIdToFaces,
@@ -1086,7 +1073,8 @@ class SmartMemoriesService {
memoryResults.add(
trip.copyWith(
memories: photoSelection,
- title: name,
+ tripYear: year,
+ locationName: locationName,
firstDateToShow: nowInMicroseconds,
lastDateToShow: windowEnd,
),
@@ -1129,13 +1117,6 @@ class SmartMemoriesService {
.year;
final String? locationName =
_tryFindLocationName(trip.memories, cities);
- String name =
- "Trip in $year"; // TODO lau: extract strings for translation
- if (locationName != null) {
- name = "Trip to $locationName";
- } else if (year == currentTime.year - 1) {
- name = "Last year's trip";
- }
final photoSelection = await _bestSelection(
trip.memories,
fileIdToFaces: fileIdToFaces,
@@ -1162,7 +1143,8 @@ class SmartMemoriesService {
memoryResults.add(
trip.copyWith(
memories: photoSelection,
- title: name,
+ tripYear: year,
+ locationName: locationName,
firstDateToShow: firstDateToShow,
lastDateToShow: lastDateToShow,
),
@@ -1206,12 +1188,6 @@ class SmartMemoriesService {
).year;
final String? locationName =
_tryFindLocationName(trip.memories, cities);
- String name = "Trip in $year";
- if (locationName != null) {
- name = "Trip to $locationName";
- } else if (year == currentTime.year - 1) {
- name = "Last year's trip";
- }
final photoSelection = await _bestSelection(
trip.memories,
fileIdToFaces: fileIdToFaces,
@@ -1222,7 +1198,8 @@ class SmartMemoriesService {
memoryResults.add(
trip.copyWith(
memories: photoSelection,
- title: name,
+ tripYear: year,
+ locationName: locationName,
firstDateToShow: nowInMicroseconds,
lastDateToShow: windowEnd,
),
@@ -1302,7 +1279,7 @@ class SmartMemoriesService {
memoryResult.add(
TimeMemory(
photoSelection,
- "${DateFormat.MMMd().format(date)} through the years",
+ day: date,
date.subtract(kMemoriesMargin).microsecondsSinceEpoch,
date.add(kDayItself).microsecondsSinceEpoch,
),
@@ -1321,12 +1298,11 @@ class SmartMemoriesService {
fileIDToImageEmbedding: fileIDToImageEmbedding,
clipPositiveTextVector: clipPositiveTextVector,
);
- final name =
- "${DateFormat.MMMd().format(date)}, ${currentTime.year - date.year} years ago";
memoryResult.add(
TimeMemory(
photoSelection,
- name,
+ day: date,
+ yearsAgo: currentTime.year - date.year,
showDate.subtract(kMemoriesMargin).microsecondsSinceEpoch,
showDate.add(kDayItself).microsecondsSinceEpoch,
),
@@ -1370,11 +1346,10 @@ class SmartMemoriesService {
fileIDToImageEmbedding: fileIDToImageEmbedding,
clipPositiveTextVector: clipPositiveTextVector,
);
- const name = "This week through the years";
+ // const name = "This week through the years";
memoryResult.add(
TimeMemory(
photoSelection,
- name,
currentTime.subtract(kMemoriesMargin).microsecondsSinceEpoch,
currentTime.add(kMemoriesUpdateFrequency).microsecondsSinceEpoch,
),
@@ -1393,12 +1368,10 @@ class SmartMemoriesService {
fileIDToImageEmbedding: fileIDToImageEmbedding,
clipPositiveTextVector: clipPositiveTextVector,
);
- final name = "This week, ${currentTime.year - date.year} years ago";
-
memoryResult.add(
TimeMemory(
photoSelection,
- name,
+ yearsAgo: currentTime.year - date.year,
currentTime.subtract(kMemoriesMargin).microsecondsSinceEpoch,
currentTime
.add(kMemoriesUpdateFrequency)
@@ -1448,14 +1421,13 @@ class SmartMemoriesService {
fileIDToImageEmbedding: fileIDToImageEmbedding,
clipPositiveTextVector: clipPositiveTextVector,
);
- final monthName = DateFormat.MMMM().format(DateTime(year, currentMonth));
final daysLeftInMonth =
DateTime(currentYear, currentMonth + 1, 0).day - currentTime.day + 1;
- final name = monthName + ", ${currentTime.year - year} years ago";
memoryResult.add(
TimeMemory(
photoSelection,
- name,
+ month: DateTime(year, currentMonth),
+ yearsAgo: currentTime.year - year,
currentTime.microsecondsSinceEpoch,
currentTime
.add(Duration(days: daysLeftInMonth))
@@ -1476,15 +1448,12 @@ class SmartMemoriesService {
fileIDToImageEmbedding: fileIDToImageEmbedding,
clipPositiveTextVector: clipPositiveTextVector,
);
- final monthName =
- DateFormat.MMMM().format(DateTime(currentTime.year, currentMonth));
final daysLeftInMonth =
DateTime(currentYear, currentMonth + 1, 0).day - currentTime.day + 1;
- final name = monthName + " through the years";
memoryResult.add(
TimeMemory(
photoSelection,
- name,
+ month: DateTime(currentYear, currentMonth),
currentTime.microsecondsSinceEpoch,
currentTime.add(Duration(days: daysLeftInMonth)).microsecondsSinceEpoch,
),
@@ -1542,7 +1511,7 @@ class SmartMemoriesService {
);
final fillerMemory = FillerMemory(
memories,
- "filler",
+ yearAgo,
nowInMicroseconds,
windowEnd,
);
diff --git a/mobile/lib/services/sync/local_sync_service.dart b/mobile/lib/services/sync/local_sync_service.dart
index a0bc54437e..aa630c2d73 100644
--- a/mobile/lib/services/sync/local_sync_service.dart
+++ b/mobile/lib/services/sync/local_sync_service.dart
@@ -296,10 +296,12 @@ class LocalSyncService {
files,
conflictAlgorithm: SqliteAsyncConflictAlgorithm.ignore,
);
- _logger.info('Inserted ${files.length} files');
- Bus.instance.fire(
- LocalPhotosUpdatedEvent(allFiles, source: "loadedPhoto"),
- );
+ _logger.info('Inserted ${files.length} out of ${allFiles.length} files');
+ if (allFiles.isNotEmpty) {
+ Bus.instance.fire(
+ LocalPhotosUpdatedEvent(allFiles, source: "loadedPhoto"),
+ );
+ }
}
await _prefs.setInt(kDbUpdationTimeKey, toTime);
}
diff --git a/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart b/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart
index 46acde870d..cec969abba 100644
--- a/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart
+++ b/mobile/lib/ui/settings/debug/ml_debug_section_widget.dart
@@ -299,6 +299,26 @@ class _MLDebugSectionWidgetState extends State {
},
),
sectionOptionSpacing,
+ MenuItemWidget(
+ captionedTextWidget: const CaptionedTextWidget(
+ title: "Clear memories cache",
+ ),
+ pressedColor: getEnteColorScheme(context).fillFaint,
+ trailingIcon: Icons.chevron_right_outlined,
+ trailingIconIsMuted: true,
+ onTap: () async {
+ try {
+ final now = DateTime.now();
+ await memoriesCacheService.clearMemoriesCache();
+ final duration = DateTime.now().difference(now);
+ showShortToast(context, "Done in ${duration.inSeconds} seconds");
+ } catch (e, s) {
+ logger.warning('Clear memories cache failed', e, s);
+ await showGenericErrorDialog(context: context, error: e);
+ }
+ },
+ ),
+ sectionOptionSpacing,
MenuItemWidget(
captionedTextWidget: const CaptionedTextWidget(
title: "Sync person mappings ",
diff --git a/web/apps/auth/src/pages/_app.tsx b/web/apps/auth/src/pages/_app.tsx
index ba6939fb20..4933d53356 100644
--- a/web/apps/auth/src/pages/_app.tsx
+++ b/web/apps/auth/src/pages/_app.tsx
@@ -16,7 +16,7 @@ import { authTheme } from "@/base/components/utils/theme";
import { BaseContext, deriveBaseContext } from "@/base/context";
import { logStartupBanner } from "@/base/log-web";
import HTTPService from "@ente/shared/network/HTTPService";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import "@fontsource-variable/inter";
import { CssBaseline } from "@mui/material";
@@ -33,7 +33,7 @@ const App: React.FC = ({ Component, pageProps }) => {
const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog();
useEffect(() => {
- const user = getData(LS_KEYS.USER) as User | undefined | null;
+ const user = getData("user") as User | undefined | null;
logStartupBanner(user?.id);
HTTPService.setHeaders({ "X-Client-Package": clientPackageName });
}, []);
diff --git a/web/apps/auth/src/pages/auth.tsx b/web/apps/auth/src/pages/auth.tsx
index eb4ddee58a..597fe6f103 100644
--- a/web/apps/auth/src/pages/auth.tsx
+++ b/web/apps/auth/src/pages/auth.tsx
@@ -12,7 +12,6 @@ import { useBaseContext } from "@/base/context";
import { isHTTP401Error } from "@/base/http";
import log from "@/base/log";
import { masterKeyFromSessionIfLoggedIn } from "@/base/session";
-import { AUTH_PAGES as PAGES } from "@ente/shared/constants/pages";
import LogoutOutlinedIcon from "@mui/icons-material/LogoutOutlined";
import {
Box,
@@ -42,7 +41,7 @@ const Page: React.FC = () => {
const fetchCodes = async () => {
const masterKey = await masterKeyFromSessionIfLoggedIn();
if (!masterKey) {
- stashRedirect(PAGES.AUTH);
+ stashRedirect("/auth");
void router.push("/");
return;
}
diff --git a/web/apps/auth/src/pages/index.tsx b/web/apps/auth/src/pages/index.tsx
index c3d16a7ce9..b3c524edf9 100644
--- a/web/apps/auth/src/pages/index.tsx
+++ b/web/apps/auth/src/pages/index.tsx
@@ -1,10 +1,9 @@
-import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages";
import { useRouter } from "next/router";
import React, { useEffect } from "react";
const Page: React.FC = () => {
const router = useRouter();
- useEffect(() => void router.push(PAGES.LOGIN), [router]);
+ useEffect(() => void router.push("/login"), [router]);
return <>>;
};
diff --git a/web/apps/photos/src/components/AuthenticateUser.tsx b/web/apps/photos/src/components/AuthenticateUser.tsx
index 08dae2728a..7788d8190a 100644
--- a/web/apps/photos/src/components/AuthenticateUser.tsx
+++ b/web/apps/photos/src/components/AuthenticateUser.tsx
@@ -9,7 +9,7 @@ import log from "@/base/log";
import VerifyMasterPasswordForm, {
type VerifyMasterPasswordFormProps,
} from "@ente/shared/components/VerifyMasterPasswordForm";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import type { KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useCallback, useEffect, useState } from "react";
@@ -60,12 +60,12 @@ export const AuthenticateUser: React.FC = ({
useEffect(() => {
const main = async () => {
try {
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
if (!user) {
throw Error("User not found");
}
setUser(user);
- const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
+ const keyAttributes = getData("keyAttributes");
if (
(!user?.token && !user?.encryptedToken) ||
(keyAttributes && !keyAttributes.memLimit)
diff --git a/web/apps/photos/src/components/Collections/CollectionShare.tsx b/web/apps/photos/src/components/Collections/CollectionShare.tsx
index 72730911b4..540330ff51 100644
--- a/web/apps/photos/src/components/Collections/CollectionShare.tsx
+++ b/web/apps/photos/src/components/Collections/CollectionShare.tsx
@@ -25,7 +25,7 @@ import type {
PublicURL,
UpdatePublicURL,
} from "@/media/collection";
-import { COLLECTION_ROLE, type CollectionUser } from "@/media/collection";
+import { type CollectionUser } from "@/media/collection";
import { PublicLinkCreated } from "@/new/photos/components/share/PublicLinkCreated";
import { avatarTextColor } from "@/new/photos/services/avatar";
import type { CollectionSummary } from "@/new/photos/services/collection/ui";
@@ -153,12 +153,12 @@ function SharingDetails({ collection, type }) {
: collection.owner?.email;
const collaborators = collection.sharees
- ?.filter((sharee) => sharee.role === COLLECTION_ROLE.COLLABORATOR)
+ ?.filter((sharee) => sharee.role == "COLLABORATOR")
.map((sharee) => sharee.email);
const viewers =
collection.sharees
- ?.filter((sharee) => sharee.role === COLLECTION_ROLE.VIEWER)
+ ?.filter((sharee) => sharee.role == "VIEWER")
.map((sharee) => sharee.email) || [];
const isOwner = galleryContext.user?.id === collection.owner?.id;
@@ -345,17 +345,15 @@ const EmailShare: React.FC = ({ collection, onRootClose }) => {
const closeManageEmailShare = () => setManageEmailShareView(false);
const openManageEmailShare = () => setManageEmailShareView(true);
- const participantType = useRef<
- COLLECTION_ROLE.COLLABORATOR | COLLECTION_ROLE.VIEWER
- >(undefined);
+ const participantType = useRef<"COLLABORATOR" | "VIEWER">(undefined);
const openAddCollab = () => {
- participantType.current = COLLECTION_ROLE.COLLABORATOR;
+ participantType.current = "COLLABORATOR";
openAddParticipant();
};
const openAddViewer = () => {
- participantType.current = COLLECTION_ROLE.VIEWER;
+ participantType.current = "VIEWER";
openAddParticipant();
};
@@ -469,7 +467,7 @@ interface AddParticipantProps {
open: boolean;
onClose: () => void;
onRootClose: () => void;
- type: COLLECTION_ROLE.VIEWER | COLLECTION_ROLE.COLLABORATOR;
+ type: "VIEWER" | "COLLABORATOR";
}
const AddParticipant: React.FC = ({
@@ -541,7 +539,7 @@ const AddParticipant: React.FC = ({
{...{ onClose }}
onRootClose={handleRootClose}
title={
- type === COLLECTION_ROLE.VIEWER
+ type == "VIEWER"
? t("add_viewers")
: t("add_collaborators")
}
@@ -554,7 +552,7 @@ const AddParticipant: React.FC = ({
placeholder={t("enter_email")}
fieldType="email"
buttonText={
- type === COLLECTION_ROLE.VIEWER
+ type == "VIEWER"
? t("add_viewers")
: t("add_collaborators")
}
@@ -818,19 +816,17 @@ const ManageEmailShare: React.FC = ({
const closeAddParticipant = () => setAddParticipantView(false);
const openAddParticipant = () => setAddParticipantView(true);
- const participantType = useRef<
- COLLECTION_ROLE.COLLABORATOR | COLLECTION_ROLE.VIEWER
- >(null);
+ const participantType = useRef<"COLLABORATOR" | "VIEWER">(null);
const selectedParticipant = useRef(null);
const openAddCollab = () => {
- participantType.current = COLLECTION_ROLE.COLLABORATOR;
+ participantType.current = "COLLABORATOR";
openAddParticipant();
};
const openAddViewer = () => {
- participantType.current = COLLECTION_ROLE.VIEWER;
+ participantType.current = "VIEWER";
openAddParticipant();
};
@@ -857,12 +853,12 @@ const ManageEmailShare: React.FC = ({
const isOwner = galleryContext.user.id === collection.owner?.id;
const collaborators = collection.sharees
- ?.filter((sharee) => sharee.role === COLLECTION_ROLE.COLLABORATOR)
+ ?.filter((sharee) => sharee.role == "COLLABORATOR")
.map((sharee) => sharee.email);
const viewers =
collection.sharees
- ?.filter((sharee) => sharee.role === COLLECTION_ROLE.VIEWER)
+ ?.filter((sharee) => sharee.role == "VIEWER")
.map((sharee) => sharee.email) || [];
const openManageParticipant = (email) => {
diff --git a/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx b/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx
index 119c4f7107..b0000ec873 100644
--- a/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx
+++ b/web/apps/photos/src/components/Collections/GalleryBarAndListHeader.tsx
@@ -15,15 +15,11 @@ import {
type CollectionSummaries,
} from "@/new/photos/services/collection/ui";
import { includes } from "@/utils/type-guards";
-import {
- getData,
- LS_KEYS,
- removeData,
-} from "@ente/shared/storage/localStorage";
+import { getData, removeData } from "@ente/shared/storage/localStorage";
import { AllAlbums } from "components/Collections/AllAlbums";
import { SetCollectionNamerAttributes } from "components/Collections/CollectionNamer";
import { CollectionShare } from "components/Collections/CollectionShare";
-import { ITEM_TYPE, TimeStampListItem } from "components/FileList";
+import { TimeStampListItem } from "components/FileList";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { sortCollectionSummaries } from "services/collectionService";
import { SetFilesDownloadProgressAttributesCreator } from "types/gallery";
@@ -167,7 +163,7 @@ export const GalleryBarAndListHeader: React.FC = ({
) : (
<>>
),
- itemType: ITEM_TYPE.HEADER,
+ tag: "header",
height: 68,
});
}, [
@@ -252,7 +248,7 @@ const useCollectionsSortByLocalState = (initialValue: CollectionsSortBy) => {
//
// This migration added Sep 2024, can be removed after a bit (esp
// since it effectively runs on each app start). (tag: Migration).
- const oldData = getData(LS_KEYS.COLLECTION_SORT_BY);
+ const oldData = getData("collectionSortBy");
if (oldData) {
let newValue: CollectionsSortBy | undefined;
switch (oldData.value) {
@@ -270,7 +266,7 @@ const useCollectionsSortByLocalState = (initialValue: CollectionsSortBy) => {
localStorage.setItem(key, newValue);
setValue(newValue);
}
- removeData(LS_KEYS.COLLECTION_SORT_BY);
+ removeData("collectionSortBy");
}
}
}, []);
diff --git a/web/apps/photos/src/components/Export.tsx b/web/apps/photos/src/components/Export.tsx
index 1fe4708d79..3864dc02e2 100644
--- a/web/apps/photos/src/components/Export.tsx
+++ b/web/apps/photos/src/components/Export.tsx
@@ -51,7 +51,9 @@ export const Export: React.FC = ({
allCollectionsNameByID,
}) => {
const { showMiniDialog } = useBaseContext();
- const [exportStage, setExportStage] = useState(ExportStage.INIT);
+ const [exportStage, setExportStage] = useState(
+ ExportStage.init,
+ );
const [exportFolder, setExportFolder] = useState("");
const [continuousExport, setContinuousExport] = useState(false);
const [exportProgress, setExportProgress] = useState({
@@ -224,8 +226,8 @@ function ExportDirectory({ exportFolder, changeExportDirectory, exportStage }) {
{exportFolder ? (
<>
- {exportStage === ExportStage.FINISHED ||
- exportStage === ExportStage.INIT ? (
+ {exportStage === ExportStage.finished ||
+ exportStage === ExportStage.init ? (
@@ -303,15 +305,15 @@ const ExportDynamicContent = ({
allCollectionsNameByID: Map;
}) => {
switch (exportStage) {
- case ExportStage.INIT:
+ case ExportStage.init:
return ;
- case ExportStage.MIGRATION:
- case ExportStage.STARTING:
- case ExportStage.EXPORTING_FILES:
- case ExportStage.RENAMING_COLLECTION_FOLDERS:
- case ExportStage.TRASHING_DELETED_FILES:
- case ExportStage.TRASHING_DELETED_COLLECTIONS:
+ case ExportStage.migration:
+ case ExportStage.starting:
+ case ExportStage.exportingFiles:
+ case ExportStage.renamingCollectionFolders:
+ case ExportStage.trashingDeletedFiles:
+ case ExportStage.trashingDeletedCollections:
return (
);
- case ExportStage.FINISHED:
+ case ExportStage.finished:
return (
{
return (
- props.exportStage === ExportStage.STARTING ||
- props.exportStage === ExportStage.MIGRATION ||
- props.exportStage === ExportStage.RENAMING_COLLECTION_FOLDERS ||
- props.exportStage === ExportStage.TRASHING_DELETED_FILES ||
- props.exportStage === ExportStage.TRASHING_DELETED_COLLECTIONS
+ props.exportStage === ExportStage.starting ||
+ props.exportStage === ExportStage.migration ||
+ props.exportStage === ExportStage.renamingCollectionFolders ||
+ props.exportStage === ExportStage.trashingDeletedFiles ||
+ props.exportStage === ExportStage.trashingDeletedCollections
);
};
return (
@@ -35,18 +35,18 @@ export default function ExportInProgress(props: Props) {
- {props.exportStage === ExportStage.STARTING ? (
+ {props.exportStage === ExportStage.starting ? (
t("export_starting")
- ) : props.exportStage === ExportStage.MIGRATION ? (
+ ) : props.exportStage === ExportStage.migration ? (
t("preparing")
) : props.exportStage ===
- ExportStage.RENAMING_COLLECTION_FOLDERS ? (
+ ExportStage.renamingCollectionFolders ? (
t("renaming_album_folders")
) : props.exportStage ===
- ExportStage.TRASHING_DELETED_FILES ? (
+ ExportStage.trashingDeletedFiles ? (
t("trashing_deleted_files")
) : props.exportStage ===
- ExportStage.TRASHING_DELETED_COLLECTIONS ? (
+ ExportStage.trashingDeletedCollections ? (
t("trashing_deleted_albums")
) : (
= ({
useEffect(() => {
setTimeStampList((timeStampList) => {
timeStampList = timeStampList ?? [];
- const hasHeader =
- timeStampList.length > 0 &&
- timeStampList[0].itemType === ITEM_TYPE.HEADER;
-
+ const hasHeader = timeStampList[0]?.tag == "header";
if (hasHeader) {
return timeStampList;
}
@@ -289,8 +283,8 @@ export const FileList: React.FC = ({
timeStampList = timeStampList ?? [];
const hasFooter =
timeStampList.length > 0 &&
- timeStampList[timeStampList.length - 1].itemType ===
- ITEM_TYPE.MARKETING_FOOTER;
+ timeStampList[timeStampList.length - 1]?.tag ==
+ "publicAlbumsFooter";
if (hasFooter) {
return timeStampList;
}
@@ -334,12 +328,12 @@ export const FileList: React.FC = ({
currentDate = item.file.metadata.creationTime / 1000;
timeStampList.push({
- itemType: ITEM_TYPE.TIME,
+ tag: "date",
date: item.timelineDateString,
id: currentDate.toString(),
});
timeStampList.push({
- itemType: ITEM_TYPE.FILE,
+ tag: "file",
items: [item],
itemStartIndex: index,
});
@@ -350,7 +344,7 @@ export const FileList: React.FC = ({
} else {
listItemIndex = 1;
timeStampList.push({
- itemType: ITEM_TYPE.FILE,
+ tag: "file",
items: [item],
itemStartIndex: index,
});
@@ -367,7 +361,7 @@ export const FileList: React.FC = ({
} else {
listItemIndex = 1;
timeStampList.push({
- itemType: ITEM_TYPE.FILE,
+ tag: "file",
items: [item],
itemStartIndex: index,
});
@@ -399,7 +393,6 @@ export const FileList: React.FC = ({
const getEmptyListItem = () => {
return {
- itemType: ITEM_TYPE.OTHER,
item: (
@@ -433,104 +426,99 @@ export const FileList: React.FC = ({
return sum;
})();
return {
- itemType: ITEM_TYPE.OTHER,
item: <>>,
height: Math.max(height - fileListHeight - footerHeight, 0),
};
};
- const getAppDownloadFooter = () => {
- return {
- itemType: ITEM_TYPE.MARKETING_FOOTER,
- height: FOOTER_HEIGHT,
- item: (
-
-
-
- ),
- b: (
-
- ),
- }}
- />
-
-
- ),
- };
- };
+ const getAppDownloadFooter = (): TimeStampListItem => ({
+ tag: "publicAlbumsFooter",
+ height: FOOTER_HEIGHT,
+ item: (
+
+
+
+ ),
+ b: (
+
+ ),
+ }}
+ />
+
+
+ ),
+ });
- const getAlbumsFooter = () => {
- return {
- itemType: ITEM_TYPE.MARKETING_FOOTER,
- height: publicCollectionGalleryContext.referralCode
- ? ALBUM_FOOTER_HEIGHT_WITH_REFERRAL
- : ALBUM_FOOTER_HEIGHT,
- item: (
-
- {/* Make the entire area tappable, otherwise it is hard to
- get at on mobile devices. */}
-
-
-
+ const getAlbumsFooter = (): TimeStampListItem => ({
+ tag: "publicAlbumsFooter",
+ height: publicCollectionGalleryContext.referralCode
+ ? ALBUM_FOOTER_HEIGHT_WITH_REFERRAL
+ : ALBUM_FOOTER_HEIGHT,
+ item: (
+
+ {/* Make the entire area tappable, otherwise it is hard to
+ get at on mobile devices. */}
+
+
+
+
+ ),
+ }}
+ values={{ url: "ente.io" }}
+ />
+
+
+ {publicCollectionGalleryContext.referralCode ? (
+
+
- ),
+ i18nKey={"sharing_referral_code"}
+ values={{
+ referralCode:
+ publicCollectionGalleryContext.referralCode,
}}
- values={{ url: "ente.io" }}
/>
-
- {publicCollectionGalleryContext.referralCode ? (
-
-
-
-
-
- ) : null}
-
-
- ),
- };
- };
+
+ ) : null}
+
+
+ ),
+ });
/**
* Checks and merge multiple dates into a single row.
@@ -546,7 +534,7 @@ export const FileList: React.FC = ({
const currItem = items[index];
// If the current item is of type time, then it is not part of an ongoing date.
// So, there is a possibility of merge.
- if (currItem.itemType === ITEM_TYPE.TIME) {
+ if (currItem.tag == "date") {
// If new list pointer is not at the end of list then
// we can add more items to the same list.
if (newList[newIndex]) {
@@ -601,7 +589,7 @@ export const FileList: React.FC = ({
for (let i = 0; i < newList.length; i++) {
const currItem = newList[i];
const nextItem = newList[i + 1];
- if (currItem.itemType === ITEM_TYPE.TIME) {
+ if (currItem.tag == "date") {
if (currItem.dates.length > 1) {
currItem.groups = currItem.dates.map((item) => item.span);
nextItem.groups = currItem.groups;
@@ -612,10 +600,10 @@ export const FileList: React.FC = ({
};
const getItemSize = (timeStampList) => (index) => {
- switch (timeStampList[index].itemType) {
- case ITEM_TYPE.TIME:
+ switch (timeStampList[index].tag) {
+ case "date":
return DATE_CONTAINER_HEIGHT;
- case ITEM_TYPE.FILE:
+ case "file":
return listItemHeight;
default:
return timeStampList[index].height;
@@ -623,8 +611,8 @@ export const FileList: React.FC = ({
};
const generateKey = (index) => {
- switch (timeStampList[index].itemType) {
- case ITEM_TYPE.FILE:
+ switch (timeStampList[index].tag) {
+ case "file":
return `${timeStampList[index].items[0].file.id}-${
timeStampList[index].items.slice(-1)[0].file.id
}`;
@@ -798,8 +786,8 @@ export const FileList: React.FC = ({
// Enhancement: This logic doesn't work on the shared album screen, the
// galleryContext.selectedFile is always null there.
const haveSelection = (galleryContext.selectedFile?.count ?? 0) > 0;
- switch (listItem.itemType) {
- case ITEM_TYPE.TIME:
+ switch (listItem.tag) {
+ case "date":
return listItem.dates ? (
listItem.dates
.map((item) => [
@@ -842,7 +830,7 @@ export const FileList: React.FC = ({
{listItem.date}
);
- case ITEM_TYPE.FILE: {
+ case "file": {
const ret = listItem.items.map((item, idx) =>
getThumbnail(
item,
diff --git a/web/apps/photos/src/components/FileListWithViewer.tsx b/web/apps/photos/src/components/FileListWithViewer.tsx
index d4a206c614..b9ead88ba2 100644
--- a/web/apps/photos/src/components/FileListWithViewer.tsx
+++ b/web/apps/photos/src/components/FileListWithViewer.tsx
@@ -11,10 +11,6 @@ import { styled } from "@mui/material";
import { t } from "i18next";
import { useCallback, useMemo, useState } from "react";
import AutoSizer from "react-virtualized-auto-sizer";
-import {
- addToFavorites,
- removeFromFavorites,
-} from "services/collectionService";
import uploadManager from "services/upload/uploadManager";
import { SetFilesDownloadProgressAttributesCreator } from "types/gallery";
import { downloadSingleFile } from "utils/file";
@@ -30,19 +26,6 @@ export type FileListWithViewerProps = {
*/
files: EnteFile[];
enableDownload?: boolean;
- /**
- * Called when the component wants to update the in-memory, unsynced,
- * favorite status of a file.
- *
- * For more details, see {@link unsyncedFavoriteUpdates} in the gallery
- * reducer's documentation.
- *
- * Not set in the context of the shared albums app.
- */
- onMarkUnsyncedFavoriteUpdate?: (
- fileID: number,
- isFavorite: boolean,
- ) => void;
/**
* Called when the component wants to mark the given files as deleted in the
* the in-memory, unsynced, state maintained by the top level gallery.
@@ -79,10 +62,12 @@ export type FileListWithViewerProps = {
| "user"
| "isInIncomingSharedCollection"
| "isInHiddenSection"
- | "fileCollectionIDs"
- | "allCollectionsNameByID"
+ | "fileNormalCollectionIDs"
+ | "collectionNameByID"
+ | "pendingFavoriteUpdates"
| "pendingVisibilityUpdates"
| "onVisualFeedback"
+ | "onToggleFavorite"
| "onFileVisibilityUpdate"
| "onSelectCollection"
| "onSelectPerson"
@@ -108,16 +93,17 @@ export const FileListWithViewer: React.FC = ({
favoriteFileIDs,
isInIncomingSharedCollection,
isInHiddenSection,
- fileCollectionIDs,
- allCollectionsNameByID,
+ fileNormalCollectionIDs,
+ collectionNameByID,
+ pendingFavoriteUpdates,
pendingVisibilityUpdates,
setFilesDownloadProgressAttributesCreator,
- onFileVisibilityUpdate,
- onMarkUnsyncedFavoriteUpdate,
- onMarkTempDeleted,
onSetOpenFileViewer,
onSyncWithRemote,
onVisualFeedback,
+ onToggleFavorite,
+ onFileVisibilityUpdate,
+ onMarkTempDeleted,
onSelectCollection,
onSelectPerson,
}) => {
@@ -149,20 +135,6 @@ export const FileListWithViewer: React.FC = ({
[onSyncWithRemote],
);
- const handleToggleFavorite = useMemo(() => {
- return favoriteFileIDs && onMarkUnsyncedFavoriteUpdate
- ? async (file: EnteFile) => {
- const isFavorite = favoriteFileIDs!.has(file.id);
- await (isFavorite ? removeFromFavorites : addToFavorites)(
- file,
- true,
- );
- // See: [Note: File viewer update and dispatch]
- onMarkUnsyncedFavoriteUpdate(file.id, !isFavorite);
- }
- : undefined;
- }, [favoriteFileIDs, onMarkUnsyncedFavoriteUpdate]);
-
const handleDownload = useCallback(
(file: EnteFile) => {
const setSingleFileDownloadProgress =
@@ -221,16 +193,17 @@ export const FileListWithViewer: React.FC = ({
isInHiddenSection,
isInIncomingSharedCollection,
favoriteFileIDs,
- fileCollectionIDs,
- allCollectionsNameByID,
+ fileNormalCollectionIDs,
+ collectionNameByID,
+ pendingFavoriteUpdates,
pendingVisibilityUpdates,
onVisualFeedback,
+ onToggleFavorite,
onFileVisibilityUpdate,
onSelectCollection,
onSelectPerson,
}}
onTriggerSyncWithRemote={handleTriggerSyncWithRemote}
- onToggleFavorite={handleToggleFavorite}
onDownload={handleDownload}
onDelete={handleDelete}
onSaveEditedImageCopy={handleSaveEditedImageCopy}
diff --git a/web/apps/photos/src/components/UploadProgress.tsx b/web/apps/photos/src/components/UploadProgress.tsx
index 94bc2e46e3..fa8b2232e3 100644
--- a/web/apps/photos/src/components/UploadProgress.tsx
+++ b/web/apps/photos/src/components/UploadProgress.tsx
@@ -1,6 +1,6 @@
import { FilledIconButton } from "@/base/components/mui";
import { useBaseContext } from "@/base/context";
-import { UPLOAD_RESULT, type UploadPhase } from "@/gallery/services/upload";
+import { type UploadPhase, type UploadResult } from "@/gallery/services/upload";
import { SpaceBetweenFlex } from "@ente/shared/components/Container";
import CloseIcon from "@mui/icons-material/Close";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
@@ -265,13 +265,12 @@ function UploadProgressDialog() {
useEffect(() => {
if (
- finishedUploads.get(UPLOAD_RESULT.ALREADY_UPLOADED)?.length > 0 ||
- finishedUploads.get(UPLOAD_RESULT.BLOCKED)?.length > 0 ||
- finishedUploads.get(UPLOAD_RESULT.FAILED)?.length > 0 ||
- finishedUploads.get(UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE)
- ?.length > 0 ||
- finishedUploads.get(UPLOAD_RESULT.TOO_LARGE)?.length > 0 ||
- finishedUploads.get(UPLOAD_RESULT.UNSUPPORTED)?.length > 0
+ finishedUploads.get("alreadyUploaded")?.length > 0 ||
+ finishedUploads.get("blocked")?.length > 0 ||
+ finishedUploads.get("failed")?.length > 0 ||
+ finishedUploads.get("largerThanAvailableStorage")?.length > 0 ||
+ finishedUploads.get("tooLarge")?.length > 0 ||
+ finishedUploads.get("unsupported")?.length > 0
) {
setHasUnUploadedFiles(true);
} else {
@@ -290,13 +289,11 @@ function UploadProgressDialog() {
{uploadPhase === "uploading" && }
@@ -306,12 +303,12 @@ function UploadProgressDialog() {
)}
}
/>
@@ -457,7 +452,7 @@ const NotUploadSectionHeader = styled("div")(
);
interface ResultSectionProps {
- uploadResult: UPLOAD_RESULT;
+ uploadResult: UploadResult;
sectionTitle: string;
sectionInfo?: React.ReactNode;
}
@@ -552,8 +547,8 @@ const DoneFooter: React.FC = () => {
return (
{uploadPhase == "done" &&
- (finishedUploads?.get(UPLOAD_RESULT.FAILED)?.length > 0 ||
- finishedUploads?.get(UPLOAD_RESULT.BLOCKED)?.length > 0 ? (
+ (finishedUploads?.get("failed")?.length > 0 ||
+ finishedUploads?.get("blocked")?.length > 0 ? (
diff --git a/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx b/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx
index e9bc01a1fc..6e75c9e93c 100644
--- a/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx
+++ b/web/apps/photos/src/components/pages/gallery/SelectedFileOptions.tsx
@@ -23,15 +23,13 @@ import VisibilityOffOutlinedIcon from "@mui/icons-material/VisibilityOffOutlined
import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined";
import { IconButton, Tooltip, Typography } from "@mui/material";
import { t } from "i18next";
-import { COLLECTION_OPS_TYPE } from "utils/collection";
-import { FILE_OPS_TYPE } from "utils/file";
+import { type CollectionOp } from "utils/collection";
+import { type FileOp } from "utils/file";
interface Props {
- handleCollectionOps: (
- opsType: COLLECTION_OPS_TYPE,
- ) => (...args: any[]) => void;
- handleFileOps: (opsType: FILE_OPS_TYPE) => (...args: any[]) => void;
- showCreateCollectionModal: (opsType: COLLECTION_OPS_TYPE) => () => void;
+ handleCollectionOp: (op: CollectionOp) => (...args: any[]) => void;
+ handleFileOp: (op: FileOp) => (...args: any[]) => void;
+ showCreateCollectionModal: (op: CollectionOp) => () => void;
/**
* Callback to open a dialog where the user can choose a collection.
*
@@ -78,8 +76,8 @@ interface Props {
const SelectedFileOptions = ({
showCreateCollectionModal,
onOpenCollectionSelector,
- handleCollectionOps,
- handleFileOps,
+ handleCollectionOp,
+ handleFileOp,
selectedCollection,
count,
ownCount,
@@ -99,10 +97,8 @@ const SelectedFileOptions = ({
const addToCollection = () =>
onOpenCollectionSelector({
action: "add",
- onSelectCollection: handleCollectionOps(COLLECTION_OPS_TYPE.ADD),
- onCreateCollection: showCreateCollectionModal(
- COLLECTION_OPS_TYPE.ADD,
- ),
+ onSelectCollection: handleCollectionOp("add"),
+ onCreateCollection: showCreateCollectionModal("add"),
relatedCollectionID:
isInSearchMode || peopleMode ? undefined : activeCollectionID,
});
@@ -114,7 +110,7 @@ const SelectedFileOptions = ({
continue: {
text: t("move_to_trash"),
color: "critical",
- action: handleFileOps(FILE_OPS_TYPE.TRASH),
+ action: handleFileOp("trash"),
},
});
@@ -125,19 +121,15 @@ const SelectedFileOptions = ({
continue: {
text: t("delete"),
color: "critical",
- action: handleFileOps(FILE_OPS_TYPE.DELETE_PERMANENTLY),
+ action: handleFileOp("deletePermanently"),
},
});
const restoreHandler = () =>
onOpenCollectionSelector({
action: "restore",
- onSelectCollection: handleCollectionOps(
- COLLECTION_OPS_TYPE.RESTORE,
- ),
- onCreateCollection: showCreateCollectionModal(
- COLLECTION_OPS_TYPE.RESTORE,
- ),
+ onSelectCollection: handleCollectionOp("restore"),
+ onCreateCollection: showCreateCollectionModal("restore"),
});
const removeFromCollectionHandler = () => {
@@ -150,9 +142,7 @@ const SelectedFileOptions = ({
color: "primary",
action: () =>
- handleCollectionOps(COLLECTION_OPS_TYPE.REMOVE)(
- selectedCollection,
- ),
+ handleCollectionOp("remove")(selectedCollection),
},
});
} else {
@@ -163,9 +153,7 @@ const SelectedFileOptions = ({
text: t("yes_remove"),
color: "critical",
action: () =>
- handleCollectionOps(COLLECTION_OPS_TYPE.REMOVE)(
- selectedCollection,
- ),
+ handleCollectionOp("remove")(selectedCollection),
},
});
}
@@ -174,10 +162,8 @@ const SelectedFileOptions = ({
const moveToCollection = () => {
onOpenCollectionSelector({
action: "move",
- onSelectCollection: handleCollectionOps(COLLECTION_OPS_TYPE.MOVE),
- onCreateCollection: showCreateCollectionModal(
- COLLECTION_OPS_TYPE.MOVE,
- ),
+ onSelectCollection: handleCollectionOp("move"),
+ onCreateCollection: showCreateCollectionModal("move"),
relatedCollectionID:
isInSearchMode || peopleMode ? undefined : activeCollectionID,
});
@@ -186,10 +172,8 @@ const SelectedFileOptions = ({
const unhideToCollection = () => {
onOpenCollectionSelector({
action: "unhide",
- onSelectCollection: handleCollectionOps(COLLECTION_OPS_TYPE.UNHIDE),
- onCreateCollection: showCreateCollectionModal(
- COLLECTION_OPS_TYPE.UNHIDE,
- ),
+ onSelectCollection: handleCollectionOp("unhide"),
+ onCreateCollection: showCreateCollectionModal("unhide"),
});
};
@@ -210,16 +194,12 @@ const SelectedFileOptions = ({
{isInSearchMode ? (
<>
-
+
-
+
@@ -229,14 +209,12 @@ const SelectedFileOptions = ({
-
+
-
+
@@ -249,9 +227,7 @@ const SelectedFileOptions = ({
) : peopleMode ? (
<>
-
+
@@ -261,14 +237,12 @@ const SelectedFileOptions = ({
-
+
-
+
@@ -294,9 +268,7 @@ const SelectedFileOptions = ({
) : isUncategorizedCollection ? (
<>
-
+
@@ -313,7 +285,7 @@ const SelectedFileOptions = ({
>
) : isIncomingSharedCollection ? (
-
+
@@ -325,9 +297,7 @@ const SelectedFileOptions = ({
-
+
@@ -341,28 +311,20 @@ const SelectedFileOptions = ({
) : (
<>
-
+
{!isFavoriteCollection &&
activeCollectionID != ARCHIVE_SECTION && (
-
+
)}
-
+
@@ -373,18 +335,14 @@ const SelectedFileOptions = ({
{activeCollectionID === ARCHIVE_SECTION && (
-
+
)}
{activeCollectionID === ALL_SECTION && (
-
+
@@ -409,7 +367,7 @@ const SelectedFileOptions = ({
>
)}
-
+
diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx
index e5fb376ae5..79ca24fcd0 100644
--- a/web/apps/photos/src/pages/_app.tsx
+++ b/web/apps/photos/src/pages/_app.tsx
@@ -32,7 +32,6 @@ import HTTPService from "@ente/shared/network/HTTPService";
import {
getData,
isLocalStorageAndIndexedDBMismatch,
- LS_KEYS,
} from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import "@fontsource-variable/inter";
@@ -66,7 +65,7 @@ const App: React.FC = ({ Component, pageProps }) => {
const logout = useCallback(() => void photosLogout(), []);
useEffect(() => {
- const user = getData(LS_KEYS.USER) as User | undefined | null;
+ const user = getData("user") as User | undefined | null;
logStartupBanner(user?.id);
HTTPService.setHeaders({ "X-Client-Package": clientPackageName });
void isLocalStorageAndIndexedDBMismatch().then((mismatch) => {
@@ -126,11 +125,11 @@ const App: React.FC = ({ Component, pageProps }) => {
useEffect(() => {
const query = new URLSearchParams(window.location.search);
const needsFamilyRedirect = query.get("redirect") == "families";
- if (needsFamilyRedirect && getData(LS_KEYS.USER)?.token)
+ if (needsFamilyRedirect && getData("user")?.token)
redirectToFamilyPortal();
router.events.on("routeChangeStart", () => {
- if (needsFamilyRedirect && getData(LS_KEYS.USER)?.token) {
+ if (needsFamilyRedirect && getData("user")?.token) {
redirectToFamilyPortal();
// https://github.com/vercel/next.js/issues/2476#issuecomment-573460710
diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx
index 66a8f654fd..948644c669 100644
--- a/web/apps/photos/src/pages/gallery.tsx
+++ b/web/apps/photos/src/pages/gallery.tsx
@@ -68,10 +68,9 @@ import {
} from "@/new/photos/services/user-details";
import { usePhotosAppContext } from "@/new/photos/types/context";
import { FlexWrapper } from "@ente/shared/components/Container";
-import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages";
import { getRecoveryKey } from "@ente/shared/crypto/helpers";
import { CustomError } from "@ente/shared/error";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import {
getToken,
isFirstLogin,
@@ -79,11 +78,7 @@ import {
setIsFirstLogin,
setJustSignedUp,
} from "@ente/shared/storage/localStorage/helpers";
-import {
- SESSION_KEYS,
- clearKeys,
- getKey,
-} from "@ente/shared/storage/sessionStorage";
+import { clearKeys, getKey } from "@ente/shared/storage/sessionStorage";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import FileUploadOutlinedIcon from "@mui/icons-material/FileUploadOutlined";
import MenuIcon from "@mui/icons-material/Menu";
@@ -94,7 +89,7 @@ import CollectionNamer, {
} from "components/Collections/CollectionNamer";
import { GalleryBarAndListHeader } from "components/Collections/GalleryBarAndListHeader";
import { Export } from "components/Export";
-import { ITEM_TYPE, TimeStampListItem } from "components/FileList";
+import { TimeStampListItem } from "components/FileList";
import { FileListWithViewer } from "components/FileListWithViewer";
import {
FilesDownloadProgress,
@@ -111,10 +106,12 @@ import { createContext, useCallback, useEffect, useRef, useState } from "react";
import { FileWithPath } from "react-dropzone";
import { Trans } from "react-i18next";
import {
+ addToFavorites,
constructEmailList,
constructUserIDToEmailMap,
createAlbum,
createUnCategorizedCollection,
+ removeFromFavorites,
} from "services/collectionService";
import exportService from "services/export";
import uploadManager from "services/upload/uploadManager";
@@ -126,11 +123,11 @@ import {
SetFilesDownloadProgressAttributesCreator,
} from "types/gallery";
import {
- COLLECTION_OPS_TYPE,
getSelectedCollection,
- handleCollectionOps,
+ handleCollectionOp,
+ type CollectionOp,
} from "utils/collection";
-import { FILE_OPS_TYPE, getSelectedFiles, handleFileOps } from "utils/file";
+import { getSelectedFiles, handleFileOp, type FileOp } from "utils/file";
const defaultGalleryContext: GalleryContextType = {
setActiveCollectionID: () => null,
@@ -254,13 +251,24 @@ const Page: React.FC = () => {
[],
);
- // TODO: Temp
- const user = state.user;
- const familyData = state.familyData;
- const collections = state.collections;
- const files = state.files;
- const hiddenFiles = state.hiddenFiles;
- const collectionSummaries = state.collectionSummaries;
+ // Local aliases.
+ const {
+ user,
+ familyData,
+ normalCollections,
+ normalFiles,
+ hiddenFiles,
+ favoriteFileIDs,
+ collectionNameByID,
+ fileNormalCollectionIDs,
+ normalCollectionSummaries,
+ pendingFavoriteUpdates,
+ pendingVisibilityUpdates,
+ isInSearchMode,
+ filteredFiles,
+ } = state;
+
+ // Derived aliases.
const barMode = state.view?.type ?? "albums";
const activeCollectionID =
state.view?.type == "people"
@@ -271,8 +279,6 @@ const Page: React.FC = () => {
const activePerson =
state.view?.type == "people" ? state.view.activePerson : undefined;
const activePersonID = activePerson?.id;
- const isInSearchMode = state.isInSearchMode;
- const filteredFiles = state.filteredFiles;
if (process.env.NEXT_PUBLIC_ENTE_TRACE) console.log("render", state);
@@ -292,10 +298,10 @@ const Page: React.FC = () => {
};
useEffect(() => {
- const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
+ const key = getKey("encryptionKey");
const token = getToken();
if (!key || !token) {
- stashRedirect(PAGES.GALLERY);
+ stashRedirect("/gallery");
router.push("/");
return;
}
@@ -315,15 +321,15 @@ const Page: React.FC = () => {
showPlanSelector();
}
setIsFirstLogin(false);
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
// TODO: Pass entire snapshot to reducer?
const familyData = userDetailsSnapshot()?.familyData;
dispatch({
type: "mount",
user,
familyData,
- allCollections: await getAllLocalCollections(),
- files: await getLocalFiles("normal"),
+ collections: await getAllLocalCollections(),
+ normalFiles: await getLocalFiles("normal"),
hiddenFiles: await getLocalFiles("hidden"),
trashedFiles: await getLocalTrashedFiles(),
});
@@ -346,26 +352,35 @@ const Page: React.FC = () => {
};
}, []);
- useEffect(
- () => setSearchCollectionsAndFiles({ collections, files }),
- [collections, files],
- );
+ useEffect(() => {
+ setSearchCollectionsAndFiles({
+ collections: normalCollections,
+ files: normalFiles,
+ });
+ }, [normalCollections, normalFiles]);
useEffect(() => {
- if (!collections || !user) {
+ if (!user || !normalCollections) {
return;
}
- const userIdToEmailMap = constructUserIDToEmailMap(user, collections);
+ const userIdToEmailMap = constructUserIDToEmailMap(
+ user,
+ normalCollections,
+ );
setUserIDToEmailMap(userIdToEmailMap);
- }, [collections]);
+ }, [user, normalCollections]);
useEffect(() => {
- if (!user || !collections) {
+ if (!user || !normalCollections) {
return;
}
- const emailList = constructEmailList(user, collections, familyData);
+ const emailList = constructEmailList(
+ user,
+ normalCollections,
+ familyData,
+ );
setEmailList(emailList);
- }, [user, collections, familyData]);
+ }, [user, normalCollections, familyData]);
useEffect(() => {
collectionNamerAttributes && setCollectionNamerView(true);
@@ -385,7 +400,7 @@ const Page: React.FC = () => {
}, [activeCollectionID, router.isReady]);
useEffect(() => {
- if (router.isReady && getKey(SESSION_KEYS.ENCRYPTION_KEY)) {
+ if (router.isReady && getKey("encryptionKey")) {
handleSubscriptionCompletionRedirectIfNeeded(
showMiniDialog,
showLoadingBar,
@@ -408,7 +423,7 @@ const Page: React.FC = () => {
fileCount={state.searchResults?.length ?? 0}
/>
),
- itemType: ITEM_TYPE.HEADER,
+ tag: "header",
});
}
}, [isInSearchMode, state.searchSuggestion, state.searchResults]);
@@ -520,22 +535,27 @@ const Page: React.FC = () => {
const handleFileAndCollectionSyncWithRemote = useCallback(async () => {
const didUpdateFiles = await syncCollectionAndFiles({
- onSetCollections: (normalCollections, hiddenCollections) =>
+ onSetCollections: (
+ collections,
+ normalCollections,
+ hiddenCollections,
+ ) =>
dispatch({
type: "setCollections",
+ collections,
normalCollections,
hiddenCollections,
}),
onResetNormalFiles: (files) =>
- dispatch({ type: "setFiles", files }),
+ dispatch({ type: "setNormalFiles", files }),
onFetchNormalFiles: (files) =>
- dispatch({ type: "fetchFiles", files }),
- onResetHiddenFiles: (hiddenFiles) =>
- dispatch({ type: "setHiddenFiles", hiddenFiles }),
- onFetchHiddenFiles: (hiddenFiles) =>
- dispatch({ type: "fetchHiddenFiles", hiddenFiles }),
- onResetTrashedFiles: (trashedFiles) =>
- dispatch({ type: "setTrashedFiles", trashedFiles }),
+ dispatch({ type: "fetchNormalFiles", files }),
+ onResetHiddenFiles: (files) =>
+ dispatch({ type: "setHiddenFiles", files }),
+ onFetchHiddenFiles: (files) =>
+ dispatch({ type: "fetchHiddenFiles", files }),
+ onResetTrashedFiles: (files) =>
+ dispatch({ type: "setTrashedFiles", files }),
});
if (didUpdateFiles) {
exportService.onLocalFilesUpdated();
@@ -578,7 +598,7 @@ const Page: React.FC = () => {
break;
case CustomError.KEY_MISSING:
clearKeys();
- router.push(PAGES.CREDENTIALS);
+ router.push("/credentials");
break;
default:
log.error("syncWithRemote failed", e);
@@ -659,20 +679,20 @@ const Page: React.FC = () => {
}, []);
const collectionOpsHelper =
- (ops: COLLECTION_OPS_TYPE) => async (collection: Collection) => {
+ (op: CollectionOp) => async (collection: Collection) => {
showLoadingBar();
try {
setOpenCollectionSelector(false);
const selectedFiles = getSelectedFiles(selected, filteredFiles);
const toProcessFiles =
- ops === COLLECTION_OPS_TYPE.REMOVE
+ op == "remove"
? selectedFiles
: selectedFiles.filter(
(file) => file.ownerID === user.id,
);
if (toProcessFiles.length > 0) {
- await handleCollectionOps(
- ops,
+ await handleCollectionOp(
+ op,
collection,
toProcessFiles,
selected.collectionID,
@@ -687,21 +707,21 @@ const Page: React.FC = () => {
}
};
- const fileOpsHelper = (ops: FILE_OPS_TYPE) => async () => {
+ const fileOpHelper = (op: FileOp) => async () => {
showLoadingBar();
try {
// passing files here instead of filteredData for hide ops because we want to move all files copies to hidden collection
const selectedFiles = getSelectedFiles(
selected,
- ops === FILE_OPS_TYPE.HIDE ? files : filteredFiles,
+ op == "hide" ? normalFiles : filteredFiles,
);
const toProcessFiles =
- ops === FILE_OPS_TYPE.DOWNLOAD
+ op == "download"
? selectedFiles
: selectedFiles.filter((file) => file.ownerID === user.id);
if (toProcessFiles.length > 0) {
- await handleFileOps(
- ops,
+ await handleFileOp(
+ op,
toProcessFiles,
handleMarkTempDeleted,
() => dispatch({ type: "clearTempDeleted" }),
@@ -723,12 +743,12 @@ const Page: React.FC = () => {
}
};
- const showCreateCollectionModal = (ops: COLLECTION_OPS_TYPE) => {
+ const showCreateCollectionModal = (op: CollectionOp) => {
const callback = async (collectionName: string) => {
try {
showLoadingBar();
const collection = await createAlbum(collectionName);
- await collectionOpsHelper(ops)(collection);
+ await collectionOpsHelper(op)(collection);
} catch (e) {
onGenericError(e);
} finally {
@@ -751,7 +771,7 @@ const Page: React.FC = () => {
if (type == "collection" || type == "person") {
if (type == "collection") {
dispatch({
- type: "showNormalOrHiddenCollectionSummary",
+ type: "showCollectionSummary",
collectionSummaryID: searchOption.suggestion.collectionID,
});
} else {
@@ -781,11 +801,7 @@ const Page: React.FC = () => {
const handleSetActiveCollectionID = (
collectionSummaryID: number | undefined,
- ) =>
- dispatch({
- type: "showNormalOrHiddenCollectionSummary",
- collectionSummaryID,
- });
+ ) => dispatch({ type: "showCollectionSummary", collectionSummaryID });
const handleChangeBarMode = (mode: GalleryBarMode) =>
mode == "people"
@@ -801,6 +817,29 @@ const Page: React.FC = () => {
});
};
+ const handleToggleFavorite = useCallback(
+ async (file: EnteFile) => {
+ const fileID = file.id;
+ const isFavorite = favoriteFileIDs.has(fileID);
+
+ dispatch({ type: "addPendingFavoriteUpdate", fileID });
+ try {
+ await (isFavorite ? removeFromFavorites : addToFavorites)(
+ file,
+ true,
+ );
+ dispatch({
+ type: "unsyncedFavoriteUpdate",
+ fileID,
+ isFavorite: !isFavorite,
+ });
+ } finally {
+ dispatch({ type: "removePendingFavoriteUpdate", fileID });
+ }
+ },
+ [favoriteFileIDs],
+ );
+
const handleFileViewerFileVisibilityUpdate = useCallback(
async (file: EnteFile, visibility: ItemVisibility) => {
const fileID = file.id;
@@ -822,16 +861,6 @@ const Page: React.FC = () => {
[],
);
- const handleMarkUnsyncedFavoriteUpdate = useCallback(
- (fileID: number, isFavorite: boolean) =>
- dispatch({
- type: "markUnsyncedFavoriteUpdate",
- fileID,
- isFavorite,
- }),
- [],
- );
-
const handleMarkTempDeleted = useCallback(
(files: EnteFile[]) => dispatch({ type: "markTempDeleted", files }),
[],
@@ -840,7 +869,7 @@ const Page: React.FC = () => {
const handleSelectCollection = useCallback(
(collectionID: number) =>
dispatch({
- type: "showNormalOrHiddenCollectionSummary",
+ type: "showCollectionSummary",
collectionSummaryID: collectionID,
}),
[],
@@ -914,10 +943,10 @@ const Page: React.FC = () => {
open={openCollectionSelector}
onClose={handleCloseCollectionSelector}
attributes={collectionSelectorAttributes}
- collectionSummaries={collectionSummaries}
+ collectionSummaries={normalCollectionSummaries}
collectionForCollectionID={(id) =>
findCollectionCreatingUncategorizedIfNeeded(
- collections,
+ normalCollections,
id,
)
}
@@ -942,8 +971,8 @@ const Page: React.FC = () => {
>
{showSelectionBar ? (
{
activeCollectionID={activeCollectionID}
selectedCollection={getSelectedCollection(
selected.collectionID,
- collections,
+ normalCollections,
)}
isFavoriteCollection={
- collectionSummaries.get(activeCollectionID)
- ?.type == "favorites"
+ normalCollectionSummaries.get(
+ activeCollectionID,
+ )?.type == "favorites"
}
isUncategorizedCollection={
- collectionSummaries.get(activeCollectionID)
- ?.type == "uncategorized"
+ normalCollectionSummaries.get(
+ activeCollectionID,
+ )?.type == "uncategorized"
}
isIncomingSharedCollection={
- collectionSummaries.get(activeCollectionID)
- ?.type == "incomingShareCollaborator" ||
- collectionSummaries.get(activeCollectionID)
- ?.type == "incomingShareViewer"
+ normalCollectionSummaries.get(
+ activeCollectionID,
+ )?.type == "incomingShareCollaborator" ||
+ normalCollectionSummaries.get(
+ activeCollectionID,
+ )?.type == "incomingShareViewer"
}
isInSearchMode={isInSearchMode}
isInHiddenSection={barMode == "hidden-albums"}
@@ -1001,26 +1034,26 @@ const Page: React.FC = () => {
{
setCollectionNamerAttributes={setCollectionNamerAttributes}
setShouldDisableDropzone={setShouldDisableDropzone}
onUploadFile={(file) =>
- dispatch({ type: "uploadFile", file })
+ dispatch({ type: "uploadNormalFile", file })
}
onShowPlanSelector={showPlanSelector}
setCollections={(collections) =>
dispatch({ type: "setNormalCollections", collections })
}
isFirstUpload={areOnlySystemCollections(
- collectionSummaries,
+ normalCollectionSummaries,
)}
showSessionExpiredMessage={showSessionExpiredDialog}
{...{
@@ -1054,7 +1087,7 @@ const Page: React.FC = () => {
/>
{
{!isInSearchMode &&
!isFirstLoad &&
- !files?.length &&
+ !normalFiles?.length &&
!hiddenFiles?.length &&
activeCollectionID === ALL_SECTION ? (
@@ -1079,35 +1112,34 @@ const Page: React.FC = () => {
files={filteredFiles}
enableDownload={true}
showAppDownloadBanner={
- files.length < 30 && !isInSearchMode
+ normalFiles.length < 30 && !isInSearchMode
}
selectable={true}
selected={selected}
setSelected={setSelected}
activeCollectionID={activeCollectionID}
activePersonID={activePerson?.id}
- fileCollectionIDs={state.fileCollectionIDs}
- allCollectionsNameByID={state.allCollectionsNameByID}
isInIncomingSharedCollection={
- collectionSummaries.get(activeCollectionID)?.type ==
- "incomingShareCollaborator" ||
- collectionSummaries.get(activeCollectionID)?.type ==
- "incomingShareViewer"
+ normalCollectionSummaries.get(activeCollectionID)
+ ?.type == "incomingShareCollaborator" ||
+ normalCollectionSummaries.get(activeCollectionID)
+ ?.type == "incomingShareViewer"
}
isInHiddenSection={barMode == "hidden-albums"}
- pendingVisibilityUpdates={
- state.pendingVisibilityUpdates
- }
- favoriteFileIDs={state.favoriteFileIDs}
+ {...{
+ favoriteFileIDs,
+ collectionNameByID,
+ fileNormalCollectionIDs,
+ pendingFavoriteUpdates,
+ pendingVisibilityUpdates,
+ }}
setFilesDownloadProgressAttributesCreator={
setFilesDownloadProgressAttributesCreator
}
+ onToggleFavorite={handleToggleFavorite}
onFileVisibilityUpdate={
handleFileViewerFileVisibilityUpdate
}
- onMarkUnsyncedFavoriteUpdate={
- handleMarkUnsyncedFavoriteUpdate
- }
onMarkTempDeleted={handleMarkTempDeleted}
onSetOpenFileViewer={setIsFileViewerOpen}
onSyncWithRemote={handleSyncWithRemote}
@@ -1118,7 +1150,7 @@ const Page: React.FC = () => {
)}
{
currentURL.pathname = router.pathname;
if (
currentURL.host === albumsURL.host &&
- currentURL.pathname !== PAGES.SHARED_ALBUMS
+ currentURL.pathname != "/shared-albums"
) {
handleAlbumsRedirect(currentURL);
} else {
@@ -53,7 +52,7 @@ const Page: React.FC = () => {
const end = currentURL.hash.lastIndexOf("&");
const hash = currentURL.hash.slice(1, end !== -1 ? end : undefined);
await router.replace({
- pathname: PAGES.SHARED_ALBUMS,
+ pathname: "/shared-albums",
search: currentURL.search,
hash: hash,
});
@@ -61,8 +60,8 @@ const Page: React.FC = () => {
};
const handleNormalRedirect = async () => {
- const user = getData(LS_KEYS.USER);
- let key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
+ const user = getData("user");
+ let key = getKey("encryptionKey");
const electron = globalThis.electron;
if (!key && electron) {
try {
@@ -71,18 +70,14 @@ const Page: React.FC = () => {
log.error("Failed to read master key from safe storage", e);
}
if (key) {
- await saveKeyInSessionStore(
- SESSION_KEYS.ENCRYPTION_KEY,
- key,
- true,
- );
+ await saveKeyInSessionStore("encryptionKey", key, true);
}
}
const token = getToken();
if (key && token) {
- await router.push(PAGES.GALLERY);
+ await router.push("/gallery");
} else if (user?.email) {
- await router.push(PAGES.VERIFY);
+ await router.push("/verify");
}
await initLocalForage();
setLoading(false);
@@ -107,8 +102,8 @@ const Page: React.FC = () => {
const signUp = () => setShowLogin(false);
const login = () => setShowLogin(true);
- const redirectToSignupPage = () => router.push(PAGES.SIGNUP);
- const redirectToLoginPage = () => router.push(PAGES.LOGIN);
+ const redirectToSignupPage = () => router.push("/signup");
+ const redirectToLoginPage = () => router.push("/login");
return (
diff --git a/web/apps/photos/src/pages/shared-albums.tsx b/web/apps/photos/src/pages/shared-albums.tsx
index 5a5873f210..143394c1d9 100644
--- a/web/apps/photos/src/pages/shared-albums.tsx
+++ b/web/apps/photos/src/pages/shared-albums.tsx
@@ -43,7 +43,6 @@ import { CenteredFlex } from "@ente/shared/components/Container";
import SingleInputForm, {
type SingleInputFormProps,
} from "@ente/shared/components/SingleInputForm";
-import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages";
import { CustomError, parseSharingErrorCodes } from "@ente/shared/error";
import AddPhotoAlternateOutlinedIcon from "@mui/icons-material/AddPhotoAlternateOutlined";
import CloseIcon from "@mui/icons-material/Close";
@@ -51,7 +50,7 @@ import DownloadIcon from "@mui/icons-material/Download";
import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined";
import { Box, Button, IconButton, Stack, styled, Tooltip } from "@mui/material";
import Typography from "@mui/material/Typography";
-import { ITEM_TYPE, TimeStampListItem } from "components/FileList";
+import { TimeStampListItem } from "components/FileList";
import { FileListWithViewer } from "components/FileListWithViewer";
import {
FilesDownloadProgress,
@@ -185,7 +184,7 @@ export default function PublicCollectionGallery() {
if (currentURL.pathname !== "/") {
router.replace(
{
- pathname: PAGES.SHARED_ALBUMS,
+ pathname: "/shared-albums",
search: currentURL.search,
hash: currentURL.hash,
},
@@ -266,7 +265,7 @@ export default function PublicCollectionGallery() {
}}
/>
),
- itemType: ITEM_TYPE.HEADER,
+ tag: "header",
height: 68,
});
}, [publicCollection, publicFiles]);
@@ -280,7 +279,6 @@ export default function PublicCollectionGallery() {
),
- itemType: ITEM_TYPE.FOOTER,
height: 104,
}
: null,
@@ -522,8 +520,6 @@ export default function PublicCollectionGallery() {
selected={selected}
setSelected={setSelected}
activeCollectionID={ALL_SECTION}
- fileCollectionIDs={undefined}
- allCollectionsNameByID={undefined}
setFilesDownloadProgressAttributesCreator={
setFilesDownloadProgressAttributesCreator
}
diff --git a/web/apps/photos/src/services/collectionService.ts b/web/apps/photos/src/services/collectionService.ts
index d4e4c9b7b5..f0e58f74d9 100644
--- a/web/apps/photos/src/services/collectionService.ts
+++ b/web/apps/photos/src/services/collectionService.ts
@@ -8,12 +8,12 @@ import {
CollectionMagicMetadata,
CollectionMagicMetadataProps,
CollectionPublicMagicMetadata,
- CollectionType,
+ CollectionSubType,
+ type CollectionType,
CreatePublicAccessTokenRequest,
EncryptedCollection,
PublicURL,
RemoveFromCollectionRequest,
- SUB_TYPE,
UpdatePublicURL,
} from "@/media/collection";
import { EncryptedMagicMetadata, EnteFile } from "@/media/file";
@@ -40,7 +40,7 @@ import {
import type { FamilyData } from "@/new/photos/services/user-details";
import { batch } from "@/utils/array";
import HTTPService from "@ente/shared/network/HTTPService";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { getActualKey } from "@ente/shared/user";
import type { User } from "@ente/shared/user/types";
@@ -58,7 +58,7 @@ const FAVORITE_COLLECTION_NAME = "Favorites";
const REQUEST_BATCH_SIZE = 1000;
export const createAlbum = (albumName: string) => {
- return createCollection(albumName, CollectionType.album);
+ return createCollection(albumName, "album");
};
const createCollection = async (
@@ -136,7 +136,7 @@ const postCollection = async (
};
export const createFavoritesCollection = () => {
- return createCollection(FAVORITE_COLLECTION_NAME, CollectionType.favorites);
+ return createCollection(FAVORITE_COLLECTION_NAME, "favorites");
};
export const addToFavorites = async (
@@ -190,7 +190,7 @@ export const removeFromCollection = async (
allFiles?: EnteFile[],
) => {
try {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
const nonUserFiles = [];
const userFiles = [];
for (const file of toRemoveFiles) {
@@ -232,7 +232,7 @@ export const removeUserFiles = async (
const collections = await getLocalCollections();
const collectionsMap = new Map(collections.map((c) => [c.id, c]));
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
for (const [targetCollectionID, files] of groupedFiles.entries()) {
const targetCollection = collectionsMap.get(targetCollectionID);
@@ -469,7 +469,7 @@ export const renameCollection = async (
) => {
if (isQuickLinkCollection(collection)) {
// Convert quick link collection to normal collection on rename
- await changeCollectionSubType(collection, SUB_TYPE.DEFAULT);
+ await changeCollectionSubType(collection, CollectionSubType.default);
}
const token = getToken();
const cryptoWorker = await sharedCryptoWorker();
@@ -604,7 +604,7 @@ export const updateShareableURL = async (
export const getFavCollection = async () => {
const collections = await getLocalCollections();
for (const collection of collections) {
- if (collection.type === CollectionType.favorites) {
+ if (collection.type == "favorites") {
return collection;
}
}
@@ -662,17 +662,14 @@ export async function getUncategorizedCollection(
collections = await getLocalCollections();
}
const uncategorizedCollection = collections.find(
- (collection) => collection.type === CollectionType.uncategorized,
+ (collection) => collection.type == "uncategorized",
);
return uncategorizedCollection;
}
export function createUnCategorizedCollection() {
- return createCollection(
- UNCATEGORIZED_COLLECTION_NAME,
- CollectionType.uncategorized,
- );
+ return createCollection(UNCATEGORIZED_COLLECTION_NAME, "uncategorized");
}
export async function getDefaultHiddenCollection(): Promise {
@@ -685,8 +682,8 @@ export async function getDefaultHiddenCollection(): Promise {
}
export function createHiddenCollection() {
- return createCollection(HIDDEN_COLLECTION_NAME, CollectionType.album, {
- subType: SUB_TYPE.DEFAULT_HIDDEN,
+ return createCollection(HIDDEN_COLLECTION_NAME, "album", {
+ subType: CollectionSubType.defaultHidden,
visibility: ItemVisibility.hidden,
});
}
diff --git a/web/apps/photos/src/services/export/index.ts b/web/apps/photos/src/services/export/index.ts
index 1b6afd4512..525cb74211 100644
--- a/web/apps/photos/src/services/export/index.ts
+++ b/web/apps/photos/src/services/export/index.ts
@@ -21,7 +21,7 @@ import { getAllLocalFiles } from "@/new/photos/services/files";
import { safeDirectoryName, safeFileName } from "@/new/photos/utils/native-fs";
import { PromiseQueue } from "@/utils/promise";
import { CustomError } from "@ente/shared/error";
-import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
+import { getData, setData } from "@ente/shared/storage/localStorage";
import i18n from "i18next";
import { migrateExport, type ExportRecord } from "./migration";
@@ -34,16 +34,18 @@ const exportRecordFileName = "export_status.json";
*/
const exportDirectoryName = "Ente Photos";
-export enum ExportStage {
- INIT = 0,
- MIGRATION = 1,
- STARTING = 2,
- EXPORTING_FILES = 3,
- TRASHING_DELETED_FILES = 4,
- RENAMING_COLLECTION_FOLDERS = 5,
- TRASHING_DELETED_COLLECTIONS = 6,
- FINISHED = 7,
-}
+export const ExportStage = {
+ init: 0,
+ migration: 1,
+ starting: 2,
+ exportingFiles: 3,
+ trashingDeletedFiles: 4,
+ renamingCollectionFolders: 5,
+ trashingDeletedCollections: 6,
+ finished: 7,
+} as const;
+
+export type ExportStage = (typeof ExportStage)[keyof typeof ExportStage];
export interface ExportProgress {
success: number;
@@ -63,7 +65,7 @@ export type FileExportNames = Record;
export const NULL_EXPORT_RECORD: ExportRecord = {
version: 3,
lastAttemptTimestamp: null,
- stage: ExportStage.INIT,
+ stage: ExportStage.init,
fileExportNames: {},
collectionExportNames: {},
};
@@ -120,7 +122,7 @@ class ExportService {
if (this.exportSettings) {
return this.exportSettings;
}
- const exportSettings = getData(LS_KEYS.EXPORT);
+ const exportSettings = getData("export");
this.exportSettings = exportSettings;
return exportSettings;
} catch (e) {
@@ -134,7 +136,7 @@ class ExportService {
const exportSettings = this.getExportSettings();
const newSettings = { ...exportSettings, ...newData };
this.exportSettings = newSettings;
- setData(LS_KEYS.EXPORT, newSettings);
+ setData("export", newSettings);
} catch (e) {
log.error("updateExportSettings failed", e);
throw e;
@@ -239,23 +241,23 @@ class ExportService {
async preExport(exportFolder: string) {
await this.verifyExportFolderExists(exportFolder);
const exportRecord = await this.getExportRecord(exportFolder);
- await this.updateExportStage(ExportStage.MIGRATION);
+ await this.updateExportStage(ExportStage.migration);
await this.runMigration(
exportFolder,
exportRecord,
this.updateExportProgress.bind(this),
);
- await this.updateExportStage(ExportStage.STARTING);
+ await this.updateExportStage(ExportStage.starting);
}
async postExport() {
try {
const exportFolder = this.getExportSettings()?.folder;
if (!(await this.exportFolderExists(exportFolder))) {
- this.uiUpdater.setExportStage(ExportStage.INIT);
+ this.uiUpdater.setExportStage(ExportStage.init);
return;
}
- await this.updateExportStage(ExportStage.FINISHED);
+ await this.updateExportStage(ExportStage.finished);
await this.updateLastExportTime(Date.now());
const exportRecord = await this.getExportRecord(exportFolder);
@@ -401,7 +403,7 @@ class ExportService {
});
};
if (renamedCollections?.length > 0) {
- this.updateExportStage(ExportStage.RENAMING_COLLECTION_FOLDERS);
+ this.updateExportStage(ExportStage.renamingCollectionFolders);
log.info(`renaming ${renamedCollections.length} collections`);
await this.collectionRenamer(
exportFolder,
@@ -412,7 +414,7 @@ class ExportService {
}
if (removedFileUIDs?.length > 0) {
- this.updateExportStage(ExportStage.TRASHING_DELETED_FILES);
+ this.updateExportStage(ExportStage.trashingDeletedFiles);
log.info(`trashing ${removedFileUIDs.length} files`);
await this.fileTrasher(
exportFolder,
@@ -422,7 +424,7 @@ class ExportService {
);
}
if (filesToExport?.length > 0) {
- this.updateExportStage(ExportStage.EXPORTING_FILES);
+ this.updateExportStage(ExportStage.exportingFiles);
log.info(`exporting ${filesToExport.length} files`);
await this.fileExporter(
filesToExport,
@@ -435,9 +437,7 @@ class ExportService {
);
}
if (deletedExportedCollections?.length > 0) {
- this.updateExportStage(
- ExportStage.TRASHING_DELETED_COLLECTIONS,
- );
+ this.updateExportStage(ExportStage.trashingDeletedCollections);
log.info(
`removing ${deletedExportedCollections.length} collections`,
);
@@ -1449,7 +1449,7 @@ const parseLivePhotoExportName = (
};
const isExportInProgress = (exportStage: ExportStage) =>
- exportStage > ExportStage.INIT && exportStage < ExportStage.FINISHED;
+ exportStage > ExportStage.init && exportStage < ExportStage.finished;
/**
* Move {@link fileName} in {@link collectionName} to the special per-collection
diff --git a/web/apps/photos/src/services/export/migration.ts b/web/apps/photos/src/services/export/migration.ts
index b5113ea226..b982a34f1f 100644
--- a/web/apps/photos/src/services/export/migration.ts
+++ b/web/apps/photos/src/services/export/migration.ts
@@ -15,7 +15,7 @@ import {
sanitizeFilename,
} from "@/new/photos/utils/native-fs";
import { wait } from "@/utils/promise";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { getIDBasedSortedFiles, getPersonalFiles } from "utils/file";
import {
@@ -135,7 +135,7 @@ async function migrationV0ToV1(
return;
}
const collectionIDPathMap = new Map();
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
const localFiles = mergeMetadata(await getAllLocalFiles());
const localCollections = await getLocalCollections();
const personalFiles = getIDBasedSortedFiles(
@@ -170,7 +170,7 @@ async function migrationV2ToV3(
if (!exportRecord?.exportedFiles) {
return;
}
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
const localFiles = mergeMetadata(await getAllLocalFiles());
const personalFiles = getIDBasedSortedFiles(
getPersonalFiles(localFiles, user),
diff --git a/web/apps/photos/src/services/upload/upload-service.ts b/web/apps/photos/src/services/upload/upload-service.ts
index 35e59e445d..3c539c6ced 100644
--- a/web/apps/photos/src/services/upload/upload-service.ts
+++ b/web/apps/photos/src/services/upload/upload-service.ts
@@ -14,7 +14,7 @@ import {
import type { UploadItem } from "@/gallery/services/upload";
import {
RANDOM_PERCENTAGE_PROGRESS_FOR_PUT,
- UPLOAD_RESULT,
+ type UploadResult,
} from "@/gallery/services/upload";
import {
detectFileTypeInfoFromChunk,
@@ -528,7 +528,7 @@ type MakeProgressTracker = (
) => unknown;
interface UploadResponse {
- uploadResult: UPLOAD_RESULT;
+ uploadResult: UploadResult;
uploadedFile?: EncryptedEnteFile | EnteFile;
}
@@ -549,7 +549,7 @@ export const uploader = async (
abortIfCancelled: () => void,
makeProgessTracker: MakeProgressTracker,
): Promise => {
- log.info(`Uploading ${fileName}`);
+ log.info(`Upload ${fileName} | start`);
try {
/*
* We read the file four times:
@@ -574,7 +574,7 @@ export const uploader = async (
} catch (e) {
if (isFileTypeNotSupportedError(e)) {
log.error(`Not uploading ${fileName}`, e);
- return { uploadResult: UPLOAD_RESULT.UNSUPPORTED };
+ return { uploadResult: "unsupported" };
}
throw e;
}
@@ -582,8 +582,7 @@ export const uploader = async (
const { fileTypeInfo, fileSize, lastModifiedMs } = assetDetails;
const maxFileSize = 4 * 1024 * 1024 * 1024; /* 4 GB */
- if (fileSize >= maxFileSize)
- return { uploadResult: UPLOAD_RESULT.TOO_LARGE };
+ if (fileSize >= maxFileSize) return { uploadResult: "tooLarge" };
abortIfCancelled();
@@ -608,7 +607,7 @@ export const uploader = async (
);
if (matchInSameCollection) {
return {
- uploadResult: UPLOAD_RESULT.ALREADY_UPLOADED,
+ uploadResult: "alreadyUploaded",
uploadedFile: matchInSameCollection,
};
} else {
@@ -616,10 +615,7 @@ export const uploader = async (
const symlink = Object.assign({}, anyMatch);
symlink.collectionID = collection.id;
await addToCollection(collection, [symlink]);
- return {
- uploadResult: UPLOAD_RESULT.ADDED_SYMLINK,
- uploadedFile: symlink,
- };
+ return { uploadResult: "addedSymlink", uploadedFile: symlink };
}
}
@@ -669,8 +665,8 @@ export const uploader = async (
return {
uploadResult: metadata.hasStaticThumbnail
- ? UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL
- : UPLOAD_RESULT.UPLOADED,
+ ? "uploadedWithStaticThumbnail"
+ : "uploaded",
uploadedFile: uploadedFile,
};
} catch (e) {
@@ -683,13 +679,11 @@ export const uploader = async (
const error = handleUploadError(e);
switch (error.message) {
case CustomError.ETAG_MISSING:
- return { uploadResult: UPLOAD_RESULT.BLOCKED };
+ return { uploadResult: "blocked" };
case CustomError.FILE_TOO_LARGE:
- return {
- uploadResult: UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE,
- };
+ return { uploadResult: "largerThanAvailableStorage" };
default:
- return { uploadResult: UPLOAD_RESULT.FAILED };
+ return { uploadResult: "failed" };
}
}
};
diff --git a/web/apps/photos/src/services/upload/uploadManager.ts b/web/apps/photos/src/services/upload/uploadManager.ts
index 5674144d91..13e9ba6748 100644
--- a/web/apps/photos/src/services/upload/uploadManager.ts
+++ b/web/apps/photos/src/services/upload/uploadManager.ts
@@ -9,9 +9,9 @@ import { ComlinkWorker } from "@/base/worker/comlink-worker";
import type { UploadItem } from "@/gallery/services/upload";
import {
RANDOM_PERCENTAGE_PROGRESS_FOR_PUT,
- UPLOAD_RESULT,
shouldDisableCFUploadProxy,
type UploadPhase,
+ type UploadResult,
} from "@/gallery/services/upload";
import type { Collection } from "@/media/collection";
import {
@@ -64,14 +64,14 @@ export interface InProgressUpload {
export interface FinishedUpload {
localFileID: FileID;
- result: UPLOAD_RESULT;
+ result: UploadResult;
}
export type InProgressUploads = Map;
-export type FinishedUploads = Map;
+export type FinishedUploads = Map;
-export type SegregatedFinishedUploads = Map;
+export type SegregatedFinishedUploads = Map;
export interface ProgressUpdater {
setPercentComplete: React.Dispatch>;
@@ -161,7 +161,7 @@ class UIService {
this.setTotalFileCount(count);
this.filesUploadedCount = 0;
this.inProgressUploads = new Map();
- this.finishedUploads = new Map();
+ this.finishedUploads = new Map();
this.updateProgressBarUI();
}
@@ -205,7 +205,7 @@ class UIService {
this.updateProgressBarUI();
}
- moveFileToResultList(key: number, uploadResult: UPLOAD_RESULT) {
+ moveFileToResultList(key: number, uploadResult: UploadResult) {
this.finishedUploads.set(key, uploadResult);
this.inProgressUploads.delete(key);
this.updateProgressBarUI();
@@ -595,39 +595,36 @@ class UploadManager {
private async postUploadTask(
uploadableItem: UploadableUploadItem,
- uploadResult: UPLOAD_RESULT,
+ uploadResult: UploadResult,
uploadedFile: EncryptedEnteFile | EnteFile | undefined,
) {
- const key = UPLOAD_RESULT[uploadResult];
- log.info(
- `Uploaded ${uploadableItem.fileName} with result ${uploadResult} (${key})`,
- );
+ log.info(`Upload ${uploadableItem.fileName} | ${uploadResult}`);
try {
const electron = globalThis.electron;
if (electron) await markUploaded(electron, uploadableItem);
let decryptedFile: EnteFile;
switch (uploadResult) {
- case UPLOAD_RESULT.FAILED:
- case UPLOAD_RESULT.BLOCKED:
+ case "failed":
+ case "blocked":
this.failedItems.push(uploadableItem);
break;
- case UPLOAD_RESULT.ALREADY_UPLOADED:
+ case "alreadyUploaded":
decryptedFile = uploadedFile as EnteFile;
break;
- case UPLOAD_RESULT.ADDED_SYMLINK:
+ case "addedSymlink":
decryptedFile = uploadedFile as EnteFile;
- uploadResult = UPLOAD_RESULT.UPLOADED;
+ uploadResult = "uploaded";
break;
- case UPLOAD_RESULT.UPLOADED:
- case UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL:
+ case "uploaded":
+ case "uploadedWithStaticThumbnail":
decryptedFile = await decryptFile(
uploadedFile as EncryptedEnteFile,
uploadableItem.collection.key,
);
break;
- case UPLOAD_RESULT.UNSUPPORTED:
- case UPLOAD_RESULT.TOO_LARGE:
+ case "unsupported":
+ case "tooLarge":
// no-op
break;
default:
@@ -635,9 +632,9 @@ class UploadManager {
}
if (
[
- UPLOAD_RESULT.ADDED_SYMLINK,
- UPLOAD_RESULT.UPLOADED,
- UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL,
+ "addedSymlink",
+ "uploaded",
+ "uploadedWithStaticThumbnail",
].includes(uploadResult)
) {
const uploadItem =
@@ -645,9 +642,8 @@ class UploadManager {
uploadableItem.livePhotoAssets.image;
if (
uploadItem &&
- (uploadResult == UPLOAD_RESULT.UPLOADED ||
- uploadResult ==
- UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL)
+ (uploadResult == "uploaded" ||
+ uploadResult == "uploadedWithStaticThumbnail")
) {
indexNewUpload(decryptedFile, uploadItem);
}
@@ -661,12 +657,12 @@ class UploadManager {
return uploadResult;
} catch (e) {
log.error("failed to do post file upload action", e);
- return UPLOAD_RESULT.FAILED;
+ return "failed";
}
}
private async watchFolderCallback(
- fileUploadResult: UPLOAD_RESULT,
+ fileUploadResult: UploadResult,
fileWithCollection: ClusteredUploadItem,
uploadedFile: EncryptedEnteFile,
) {
diff --git a/web/apps/photos/src/services/userService.ts b/web/apps/photos/src/services/userService.ts
index 30e5f2cdb8..30f9c3ac37 100644
--- a/web/apps/photos/src/services/userService.ts
+++ b/web/apps/photos/src/services/userService.ts
@@ -4,7 +4,7 @@ import { apiURL } from "@/base/origins";
import type { UserDetails } from "@/new/photos/services/user-details";
import { ApiError } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { HttpStatusCode } from "axios";
@@ -36,7 +36,7 @@ export const isTokenValid = async (token: string) => {
try {
await putAttributes(
token,
- getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES),
+ getData("originalKeyAttributes"),
);
} catch (e) {
log.error("put attribute failed", e);
diff --git a/web/apps/photos/src/services/watch.ts b/web/apps/photos/src/services/watch.ts
index 0430d0a644..f0720247e4 100644
--- a/web/apps/photos/src/services/watch.ts
+++ b/web/apps/photos/src/services/watch.ts
@@ -11,7 +11,7 @@ import type {
FolderWatch,
FolderWatchSyncedFile,
} from "@/base/types/ipc";
-import { UPLOAD_RESULT } from "@/gallery/services/upload";
+import { type UploadResult } from "@/gallery/services/upload";
import type { Collection } from "@/media/collection";
import { EncryptedEnteFile } from "@/media/file";
import {
@@ -324,7 +324,7 @@ class FolderWatcher {
* {@link upload} gets uploaded.
*/
async onFileUpload(
- fileUploadResult: UPLOAD_RESULT,
+ fileUploadResult: UploadResult,
item: UploadItemWithCollection,
file: EncryptedEnteFile,
) {
@@ -333,10 +333,10 @@ class FolderWatcher {
// file on disk).
if (
[
- UPLOAD_RESULT.ADDED_SYMLINK,
- UPLOAD_RESULT.UPLOADED,
- UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL,
- UPLOAD_RESULT.ALREADY_UPLOADED,
+ "addedSymlink",
+ "uploaded",
+ "uploadedWithStaticThumbnail",
+ "alreadyUploaded",
].includes(fileUploadResult)
) {
if (item.isLivePhoto) {
@@ -354,11 +354,7 @@ class FolderWatcher {
file,
);
}
- } else if (
- [UPLOAD_RESULT.UNSUPPORTED, UPLOAD_RESULT.TOO_LARGE].includes(
- fileUploadResult,
- )
- ) {
+ } else if (["unsupported", "tooLarge"].includes(fileUploadResult)) {
if (item.isLivePhoto) {
this.unUploadableFilePaths.add(
ensureString(item.livePhotoAssets.image),
diff --git a/web/apps/photos/src/utils/collection.ts b/web/apps/photos/src/utils/collection.ts
index c60f45db68..0f6e66379b 100644
--- a/web/apps/photos/src/utils/collection.ts
+++ b/web/apps/photos/src/utils/collection.ts
@@ -3,12 +3,10 @@ import { joinPath } from "@/base/file-name";
import log from "@/base/log";
import { updateMagicMetadata } from "@/gallery/services/magic-metadata";
import {
- COLLECTION_ROLE,
type Collection,
CollectionMagicMetadataProps,
CollectionPublicMagicMetadataProps,
- CollectionType,
- SUB_TYPE,
+ CollectionSubType,
} from "@/media/collection";
import { EnteFile } from "@/media/file";
import { ItemVisibility } from "@/media/file-metadata";
@@ -28,7 +26,7 @@ import {
} from "@/new/photos/services/collections";
import { getAllLocalFiles, getLocalFiles } from "@/new/photos/services/files";
import { safeDirectoryName } from "@/new/photos/utils/native-fs";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { t } from "i18next";
import {
@@ -45,41 +43,34 @@ import {
} from "types/gallery";
import { downloadFilesWithProgress } from "utils/file";
-export enum COLLECTION_OPS_TYPE {
- ADD,
- MOVE,
- REMOVE,
- RESTORE,
- UNHIDE,
-}
-export async function handleCollectionOps(
- type: COLLECTION_OPS_TYPE,
+export type CollectionOp = "add" | "move" | "remove" | "restore" | "unhide";
+
+export async function handleCollectionOp(
+ op: CollectionOp,
collection: Collection,
selectedFiles: EnteFile[],
selectedCollectionID: number,
) {
- switch (type) {
- case COLLECTION_OPS_TYPE.ADD:
+ switch (op) {
+ case "add":
await addToCollection(collection, selectedFiles);
break;
- case COLLECTION_OPS_TYPE.MOVE:
+ case "move":
await moveToCollection(
selectedCollectionID,
collection,
selectedFiles,
);
break;
- case COLLECTION_OPS_TYPE.REMOVE:
+ case "remove":
await removeFromCollection(collection.id, selectedFiles);
break;
- case COLLECTION_OPS_TYPE.RESTORE:
+ case "restore":
await restoreToCollection(collection, selectedFiles);
break;
- case COLLECTION_OPS_TYPE.UNHIDE:
+ case "unhide":
await unhideToCollection(collection, selectedFiles);
break;
- default:
- throw Error("Invalid collection operation");
}
}
@@ -207,7 +198,7 @@ export const changeCollectionVisibility = async (
visibility,
};
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
if (collection.owner.id === user.id) {
const updatedMagicMetadata = await updateMagicMetadata(
updatedMagicMetadataProps,
@@ -282,7 +273,7 @@ export const changeCollectionOrder = async (
export const changeCollectionSubType = async (
collection: Collection,
- subType: SUB_TYPE,
+ subType: CollectionSubType,
) => {
try {
const updatedMagicMetadataProps: CollectionMagicMetadataProps = {
@@ -302,7 +293,7 @@ export const changeCollectionSubType = async (
};
export const getUserOwnedCollections = (collections: Collection[]) => {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
if (!user?.id) {
throw Error("user missing");
}
@@ -310,11 +301,11 @@ export const getUserOwnedCollections = (collections: Collection[]) => {
};
export const isQuickLinkCollection = (collection: Collection) =>
- collection.magicMetadata?.data.subType === SUB_TYPE.QUICK_LINK_COLLECTION;
+ collection.magicMetadata?.data.subType == CollectionSubType.quicklink;
export function isIncomingViewerShare(collection: Collection, user: User) {
const sharee = collection.sharees?.find((sharee) => sharee.id === user.id);
- return sharee?.role === COLLECTION_ROLE.VIEWER;
+ return sharee?.role == "VIEWER";
}
export function isValidMoveTarget(
@@ -337,9 +328,9 @@ export function isValidReplacementAlbum(
) {
return (
collection.name === wantedCollectionName &&
- (collection.type === CollectionType.album ||
- collection.type === CollectionType.folder ||
- collection.type === CollectionType.uncategorized) &&
+ (collection.type == "album" ||
+ collection.type == "folder" ||
+ collection.type == "uncategorized") &&
!isHiddenCollection(collection) &&
!isQuickLinkCollection(collection) &&
!isIncomingShare(collection, user)
@@ -350,7 +341,7 @@ export const getOrCreateAlbum = async (
albumName: string,
existingCollections: Collection[],
) => {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
if (!user?.id) {
throw Error("user missing");
}
diff --git a/web/apps/photos/src/utils/file/index.ts b/web/apps/photos/src/utils/file/index.ts
index 8e92807c97..4d87dad5a5 100644
--- a/web/apps/photos/src/utils/file/index.ts
+++ b/web/apps/photos/src/utils/file/index.ts
@@ -17,7 +17,7 @@ import { FileType } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
import { deleteFromTrash, moveToTrash } from "@/new/photos/services/collection";
import { safeFileName } from "@/new/photos/utils/native-fs";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { t } from "i18next";
import {
@@ -30,16 +30,15 @@ import {
SetFilesDownloadProgressAttributesCreator,
} from "types/gallery";
-export enum FILE_OPS_TYPE {
- DOWNLOAD,
- FIX_TIME,
- ARCHIVE,
- UNARCHIVE,
- HIDE,
- TRASH,
- DELETE_PERMANENTLY,
- SET_FAVORITE,
-}
+export type FileOp =
+ | "download"
+ | "fixTime"
+ | "favorite"
+ | "archive"
+ | "unarchive"
+ | "hide"
+ | "trash"
+ | "deletePermanently";
export async function downloadFile(file: EnteFile) {
try {
@@ -317,7 +316,7 @@ async function downloadFileDesktop(
}
export const isImageOrVideo = (fileType: FileType) =>
- [FileType.image, FileType.video].includes(fileType);
+ fileType == FileType.image || fileType == FileType.video;
export const getArchivedFiles = (files: EnteFile[]) => {
return files.filter(isArchivedFile).map((file) => file.id);
@@ -329,7 +328,7 @@ export const createTypedObjectURL = async (blob: Blob, fileName: string) => {
};
export const getUserOwnedFiles = (files: EnteFile[]) => {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
if (!user?.id) {
throw Error("user missing");
}
@@ -375,8 +374,8 @@ export const shouldShowAvatar = (file: EnteFile, user: User) => {
}
};
-export const handleFileOps = async (
- ops: FILE_OPS_TYPE,
+export const handleFileOp = async (
+ op: FileOp,
files: EnteFile[],
markTempDeleted: (files: EnteFile[]) => void,
clearTempDeleted: () => void,
@@ -385,35 +384,8 @@ export const handleFileOps = async (
fixCreationTime: (files: EnteFile[]) => void,
setFilesDownloadProgressAttributesCreator: SetFilesDownloadProgressAttributesCreator,
) => {
- switch (ops) {
- case FILE_OPS_TYPE.TRASH:
- try {
- markTempDeleted(files);
- await moveToTrash(files);
- } catch (e) {
- clearTempDeleted();
- throw e;
- }
- break;
- case FILE_OPS_TYPE.DELETE_PERMANENTLY:
- try {
- markTempDeleted(files);
- await deleteFromTrash(files.map((file) => file.id));
- } catch (e) {
- clearTempDeleted();
- throw e;
- }
- break;
- case FILE_OPS_TYPE.HIDE:
- try {
- markTempHidden(files);
- await moveToHiddenCollection(files);
- } catch (e) {
- clearTempHidden();
- throw e;
- }
- break;
- case FILE_OPS_TYPE.DOWNLOAD: {
+ switch (op) {
+ case "download": {
const setSelectedFileDownloadProgressAttributes =
setFilesDownloadProgressAttributesCreator(
t("files_count", { count: files.length }),
@@ -424,17 +396,44 @@ export const handleFileOps = async (
);
break;
}
- case FILE_OPS_TYPE.FIX_TIME:
+ case "fixTime":
fixCreationTime(files);
break;
- case FILE_OPS_TYPE.ARCHIVE:
+ case "favorite":
+ await addMultipleToFavorites(files);
+ break;
+ case "archive":
await changeFilesVisibility(files, ItemVisibility.archived);
break;
- case FILE_OPS_TYPE.UNARCHIVE:
+ case "unarchive":
await changeFilesVisibility(files, ItemVisibility.visible);
break;
- case FILE_OPS_TYPE.SET_FAVORITE:
- await addMultipleToFavorites(files);
+ case "hide":
+ try {
+ markTempHidden(files);
+ await moveToHiddenCollection(files);
+ } catch (e) {
+ clearTempHidden();
+ throw e;
+ }
+ break;
+ case "trash":
+ try {
+ markTempDeleted(files);
+ await moveToTrash(files);
+ } catch (e) {
+ clearTempDeleted();
+ throw e;
+ }
+ break;
+ case "deletePermanently":
+ try {
+ markTempDeleted(files);
+ await deleteFromTrash(files.map((file) => file.id));
+ } catch (e) {
+ clearTempDeleted();
+ throw e;
+ }
break;
}
};
diff --git a/web/docs/dependencies.md b/web/docs/dependencies.md
index 4ae5094eba..89007cc56a 100644
--- a/web/docs/dependencies.md
+++ b/web/docs/dependencies.md
@@ -133,8 +133,10 @@ For showing the app's UI in multiple languages, we use the
[i18next](https://www.i18next.com), specifically its three components
- [i18next](https://github.com/i18next/i18next): The core `i18next` library.
+
- [react-i18next](https://github.com/i18next/react-i18next): React specific
support in `i18next`.
+
- [i18next-http-backend](https://github.com/i18next/i18next-http-backend): Adds
support for initializing `i18next` with JSON file containing the translation
in a particular language, fetched at runtime.
@@ -173,7 +175,9 @@ via [@fontsource-variable/inter](https://fontsource.org/fonts/inter/install).
layer on top of web workers to make them more easier to use.
- [idb](https://github.com/jakearchibald/idb) provides a promise API over the
- browser-native IndexedDB APIs.
+ browser-native IndexedDB APIs. Older code (the file and collection store),
+ uses [localForage](https://github.com/localForage/localForage) for IndexedDB
+ access.
> For more details about IDB and its role, see [storage.md](storage.md).
diff --git a/web/docs/storage.md b/web/docs/storage.md
index 0a1ed94d68..c5077bcd5a 100644
--- a/web/docs/storage.md
+++ b/web/docs/storage.md
@@ -41,6 +41,7 @@ For more details, see:
- https://web.dev/articles/indexeddb
- https://github.com/jakearchibald/idb
+- https://github.com/localForage/localForage
## OPFS
diff --git a/web/packages/accounts/components/LoginContents.tsx b/web/packages/accounts/components/LoginContents.tsx
index 88c6456e75..17e01da37b 100644
--- a/web/packages/accounts/components/LoginContents.tsx
+++ b/web/packages/accounts/components/LoginContents.tsx
@@ -2,7 +2,6 @@ import {
AccountsPageFooter,
AccountsPageTitle,
} from "@/accounts/components/layouts/centered-paper";
-import { PAGES } from "@/accounts/constants/pages";
import { getSRPAttributes } from "@/accounts/services/srp-remote";
import { sendOTT } from "@/accounts/services/user";
import { LinkButton } from "@/base/components/LinkButton";
@@ -11,7 +10,7 @@ import log from "@/base/log";
import SingleInputForm, {
type SingleInputFormProps,
} from "@ente/shared/components/SingleInputForm";
-import { LS_KEYS, setData, setLSUser } from "@ente/shared/storage/localStorage";
+import { setData, setLSUser } from "@ente/shared/storage/localStorage";
import { Input, Stack, Typography } from "@mui/material";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -54,11 +53,11 @@ export const LoginContents: React.FC = ({
throw e;
}
await setLSUser({ email });
- void router.push(PAGES.VERIFY);
+ void router.push("/verify");
} else {
await setLSUser({ email });
- setData(LS_KEYS.SRP_ATTRIBUTES, srpAttributes);
- void router.push(PAGES.CREDENTIALS);
+ setData("srpAttributes", srpAttributes);
+ void router.push("/credentials");
}
} catch (e) {
log.error("Login failed", e);
diff --git a/web/packages/accounts/components/SignUpContents.tsx b/web/packages/accounts/components/SignUpContents.tsx
index a8d9061de2..270c4fb7b3 100644
--- a/web/packages/accounts/components/SignUpContents.tsx
+++ b/web/packages/accounts/components/SignUpContents.tsx
@@ -1,4 +1,3 @@
-import { PAGES } from "@/accounts/constants/pages";
import { generateKeyAndSRPAttributes } from "@/accounts/services/srp";
import { sendOTT } from "@/accounts/services/user";
import { isWeakPassword } from "@/accounts/utils/password";
@@ -6,7 +5,7 @@ import { LinkButton } from "@/base/components/LinkButton";
import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { isMuseumHTTPError } from "@/base/http";
import log from "@/base/log";
-import { LS_KEYS, setLSUser } from "@ente/shared//storage/localStorage";
+import { setLSUser } from "@ente/shared//storage/localStorage";
import { VerticallyCentered } from "@ente/shared/components/Container";
import ShowHidePassword from "@ente/shared/components/Form/ShowHidePassword";
import {
@@ -18,7 +17,6 @@ import {
setJustSignedUp,
setLocalReferralSource,
} from "@ente/shared/storage/localStorage/helpers";
-import { SESSION_KEYS } from "@ente/shared/storage/sessionStorage";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import {
Box,
@@ -109,20 +107,17 @@ export const SignUpContents: React.FC = ({
const { keyAttributes, masterKey, srpSetupAttributes } =
await generateKeyAndSRPAttributes(passphrase);
- setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes);
- setData(LS_KEYS.SRP_SETUP_ATTRIBUTES, srpSetupAttributes);
+ setData("originalKeyAttributes", keyAttributes);
+ setData("srpSetupAttributes", srpSetupAttributes);
await generateAndSaveIntermediateKeyAttributes(
passphrase,
keyAttributes,
masterKey,
);
- await saveKeyInSessionStore(
- SESSION_KEYS.ENCRYPTION_KEY,
- masterKey,
- );
+ await saveKeyInSessionStore("encryptionKey", masterKey);
setJustSignedUp(true);
- void router.push(PAGES.VERIFY);
+ void router.push("/verify");
} catch (e) {
setFieldError("confirm", t("password_generation_failed"));
throw e;
diff --git a/web/packages/accounts/constants/pages.ts b/web/packages/accounts/constants/pages.ts
deleted file mode 100644
index ea4896142f..0000000000
--- a/web/packages/accounts/constants/pages.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export enum PAGES {
- ROOT = "/",
- CHANGE_PASSWORD = "/change-password",
- CREDENTIALS = "/credentials",
- GENERATE = "/generate",
- LOGIN = "/login",
- RECOVER = "/recover",
- SIGNUP = "/signup",
- TWO_FACTOR_SETUP = "/two-factor/setup",
- TWO_FACTOR_VERIFY = "/two-factor/verify",
- TWO_FACTOR_RECOVER = "/two-factor/recover",
- // PASSKEY_RECOVER = "/passkeys/recover",
- VERIFY = "/verify",
- SHARED_ALBUMS = "/shared-albums",
-}
diff --git a/web/packages/accounts/pages/change-email.tsx b/web/packages/accounts/pages/change-email.tsx
index 8d372dc5a6..8196739fe4 100644
--- a/web/packages/accounts/pages/change-email.tsx
+++ b/web/packages/accounts/pages/change-email.tsx
@@ -10,7 +10,7 @@ import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { isHTTPErrorWithStatus } from "@/base/http";
import log from "@/base/log";
import { VerticallyCentered } from "@ente/shared/components/Container";
-import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage";
+import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import { Alert, Box, TextField } from "@mui/material";
import { Formik, type FormikHelpers } from "formik";
import { t } from "i18next";
@@ -23,7 +23,7 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
if (!user?.token) {
void router.push("/");
}
@@ -86,7 +86,7 @@ const ChangeEmailForm: React.FC = () => {
try {
setLoading(true);
await changeEmail(email, ott!);
- await setLSUser({ ...getData(LS_KEYS.USER), email });
+ await setLSUser({ ...getData("user"), email });
setLoading(false);
void goToApp();
} catch (e) {
diff --git a/web/packages/accounts/pages/change-password.tsx b/web/packages/accounts/pages/change-password.tsx
index e19d6aff7a..f7be5204d7 100644
--- a/web/packages/accounts/pages/change-password.tsx
+++ b/web/packages/accounts/pages/change-password.tsx
@@ -6,7 +6,6 @@ import {
import SetPasswordForm, {
type SetPasswordFormProps,
} from "@/accounts/components/SetPasswordForm";
-import { PAGES } from "@/accounts/constants/pages";
import { appHomeRoute, stashRedirect } from "@/accounts/services/redirect";
import {
convertBase64ToBuffer,
@@ -27,8 +26,7 @@ import {
generateLoginSubKey,
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
-import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
-import { SESSION_KEYS } from "@ente/shared/storage/sessionStorage";
+import { getData, setData } from "@ente/shared/storage/localStorage";
import { getActualKey } from "@ente/shared/user";
import type { KEK, KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
@@ -42,10 +40,10 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
setUser(user);
if (!user?.token) {
- stashRedirect(PAGES.CHANGE_PASSWORD);
+ stashRedirect("/change-password");
void router.push("/");
} else {
setToken(user.token);
@@ -58,7 +56,7 @@ const Page: React.FC = () => {
) => {
const cryptoWorker = await sharedCryptoWorker();
const key = await getActualKey();
- const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
+ const keyAttributes: KeyAttributes = getData("keyAttributes");
const kekSalt = await cryptoWorker.generateSaltToDeriveKey();
let kek: KEK;
try {
@@ -113,7 +111,7 @@ const Page: React.FC = () => {
if (user?.email) {
const srpAttributes = await getSRPAttributes(user.email);
if (srpAttributes) {
- setData(LS_KEYS.SRP_ATTRIBUTES, srpAttributes);
+ setData("srpAttributes", srpAttributes);
}
}
@@ -124,13 +122,13 @@ const Page: React.FC = () => {
key,
);
- await saveKeyInSessionStore(SESSION_KEYS.ENCRYPTION_KEY, key);
+ await saveKeyInSessionStore("encryptionKey", key);
redirectToAppHome();
};
const redirectToAppHome = () => {
- setData(LS_KEYS.SHOW_BACK_BUTTON, { value: true });
+ setData("showBackButton", { value: true });
void router.push(appHomeRoute);
};
@@ -143,7 +141,7 @@ const Page: React.FC = () => {
callback={onSubmit}
buttonText={t("change_password")}
/>
- {(getData(LS_KEYS.SHOW_BACK_BUTTON)?.value ?? true) && (
+ {(getData("showBackButton")?.value ?? true) && (
{t("go_back")}
diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx
index 922d36a477..cd483753fb 100644
--- a/web/packages/accounts/pages/credentials.tsx
+++ b/web/packages/accounts/pages/credentials.tsx
@@ -7,7 +7,6 @@ import {
import { SecondFactorChoice } from "@/accounts/components/SecondFactorChoice";
import { sessionExpiredDialogAttributes } from "@/accounts/components/utils/dialog";
import { useSecondFactorChoiceIfNeeded } from "@/accounts/components/utils/second-factor-choice";
-import { PAGES } from "@/accounts/constants/pages";
import {
openPasskeyVerificationURL,
passkeyVerificationRedirectURL,
@@ -42,23 +41,13 @@ import {
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
import { CustomError } from "@ente/shared/error";
-import {
- LS_KEYS,
- getData,
- setData,
- setLSUser,
-} from "@ente/shared/storage/localStorage";
+import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import {
getToken,
isFirstLogin,
setIsFirstLogin,
} from "@ente/shared/storage/localStorage/helpers";
-import {
- SESSION_KEYS,
- getKey,
- removeKey,
- setKey,
-} from "@ente/shared/storage/sessionStorage";
+import { getKey, removeKey, setKey } from "@ente/shared/storage/sessionStorage";
import type { KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -96,14 +85,8 @@ const Page: React.FC = () => {
case "valid":
break;
case "validButPasswordChanged":
- setData(
- LS_KEYS.KEY_ATTRIBUTES,
- session.updatedKeyAttributes,
- );
- setData(
- LS_KEYS.SRP_ATTRIBUTES,
- session.updatedSRPAttributes,
- );
+ setData("keyAttributes", session.updatedKeyAttributes);
+ setData("srpAttributes", session.updatedSRPAttributes);
// Set a flag that causes new interactive key attributes to
// be generated.
setIsFirstLogin(true);
@@ -121,13 +104,13 @@ const Page: React.FC = () => {
useEffect(() => {
const main = async () => {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
if (!user?.email) {
void router.push("/");
return;
}
setUser(user);
- let key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
+ let key = getKey("encryptionKey");
const electron = globalThis.electron;
if (!key && electron) {
try {
@@ -136,11 +119,7 @@ const Page: React.FC = () => {
log.error("Failed to read master key from safe storage", e);
}
if (key) {
- await saveKeyInSessionStore(
- SESSION_KEYS.ENCRYPTION_KEY,
- key,
- true,
- );
+ await saveKeyInSessionStore("encryptionKey", key, true);
}
}
const token = getToken();
@@ -148,22 +127,17 @@ const Page: React.FC = () => {
void router.push(appHomeRoute);
return;
}
- const kekEncryptedAttributes: B64EncryptionResult = getKey(
- SESSION_KEYS.KEY_ENCRYPTION_KEY,
- );
- const keyAttributes: KeyAttributes = getData(
- LS_KEYS.KEY_ATTRIBUTES,
- );
- const srpAttributes: SRPAttributes = getData(
- LS_KEYS.SRP_ATTRIBUTES,
- );
+ const kekEncryptedAttributes: B64EncryptionResult =
+ getKey("keyEncryptionKey");
+ const keyAttributes: KeyAttributes = getData("keyAttributes");
+ const srpAttributes: SRPAttributes = getData("srpAttributes");
if (token) {
setSessionValidityCheck(validateSession());
}
if (kekEncryptedAttributes && keyAttributes) {
- removeKey(SESSION_KEYS.KEY_ENCRYPTION_KEY);
+ removeKey("keyEncryptionKey");
const cryptoWorker = await sharedCryptoWorker();
const kek = await cryptoWorker.decryptB64(
kekEncryptedAttributes.encryptedData,
@@ -232,11 +206,8 @@ const Page: React.FC = () => {
if (passkeySessionID) {
const sessionKeyAttributes =
await cryptoWorker.generateKeyAndEncryptToB64(kek);
- setKey(
- SESSION_KEYS.KEY_ENCRYPTION_KEY,
- sessionKeyAttributes,
- );
- const user = getData(LS_KEYS.USER);
+ setKey("keyEncryptionKey", sessionKeyAttributes);
+ const user = getData("user");
await setLSUser({
...user,
passkeySessionID,
@@ -254,20 +225,17 @@ const Page: React.FC = () => {
} else if (twoFactorSessionID) {
const sessionKeyAttributes =
await cryptoWorker.generateKeyAndEncryptToB64(kek);
- setKey(
- SESSION_KEYS.KEY_ENCRYPTION_KEY,
- sessionKeyAttributes,
- );
- const user = getData(LS_KEYS.USER);
+ setKey("keyEncryptionKey", sessionKeyAttributes);
+ const user = getData("user");
await setLSUser({
...user,
twoFactorSessionID,
isTwoFactorEnabled: true,
});
- void router.push(PAGES.TWO_FACTOR_VERIFY);
+ void router.push("/two-factor/verify");
throw Error(CustomError.TWO_FACTOR_ENABLED);
} else {
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
await setLSUser({
...user,
token,
@@ -275,8 +243,7 @@ const Page: React.FC = () => {
id,
isTwoFactorEnabled: false,
});
- if (keyAttributes)
- setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
+ if (keyAttributes) setData("keyAttributes", keyAttributes);
return keyAttributes;
}
} catch (e) {
@@ -305,16 +272,15 @@ const Page: React.FC = () => {
key,
);
}
- await saveKeyInSessionStore(SESSION_KEYS.ENCRYPTION_KEY, key);
+ await saveKeyInSessionStore("encryptionKey", key);
await decryptAndStoreToken(keyAttributes, key);
try {
- let srpAttributes: SRPAttributes | null = getData(
- LS_KEYS.SRP_ATTRIBUTES,
- );
+ let srpAttributes: SRPAttributes | null =
+ getData("srpAttributes");
if (!srpAttributes && user) {
srpAttributes = await getSRPAttributes(user.email);
if (srpAttributes) {
- setData(LS_KEYS.SRP_ATTRIBUTES, srpAttributes);
+ setData("srpAttributes", srpAttributes);
}
}
log.debug(() => `userSRPSetupPending ${!srpAttributes}`);
@@ -379,7 +345,7 @@ const Page: React.FC = () => {
/>
- router.push(PAGES.RECOVER)}>
+ router.push("/recover")}>
{t("forgot_password")}
{t("change_email")}
diff --git a/web/packages/accounts/pages/generate.tsx b/web/packages/accounts/pages/generate.tsx
index 8010e7e378..e030bc9246 100644
--- a/web/packages/accounts/pages/generate.tsx
+++ b/web/packages/accounts/pages/generate.tsx
@@ -7,7 +7,6 @@ import { RecoveryKey } from "@/accounts/components/RecoveryKey";
import SetPasswordForm, {
type SetPasswordFormProps,
} from "@/accounts/components/SetPasswordForm";
-import { PAGES } from "@/accounts/constants/pages";
import { appHomeRoute } from "@/accounts/services/redirect";
import {
configureSRP,
@@ -22,12 +21,12 @@ import {
generateAndSaveIntermediateKeyAttributes,
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import {
justSignedUp,
setJustSignedUp,
} from "@ente/shared/storage/localStorage/helpers";
-import { SESSION_KEYS, getKey } from "@ente/shared/storage/sessionStorage";
+import { getKey } from "@ente/shared/storage/sessionStorage";
import type { KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -44,11 +43,9 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
- const key: string = getKey(SESSION_KEYS.ENCRYPTION_KEY);
- const keyAttributes: KeyAttributes = getData(
- LS_KEYS.ORIGINAL_KEY_ATTRIBUTES,
- );
- const user: User = getData(LS_KEYS.USER);
+ const key: string = getKey("encryptionKey");
+ const keyAttributes: KeyAttributes = getData("originalKeyAttributes");
+ const user: User = getData("user");
setUser(user);
if (!user?.token) {
void router.push("/");
@@ -60,7 +57,7 @@ const Page: React.FC = () => {
void router.push(appHomeRoute);
}
} else if (keyAttributes?.encryptedKey) {
- void router.push(PAGES.CREDENTIALS);
+ void router.push("/credentials");
} else {
setToken(user.token);
setLoading(false);
@@ -83,7 +80,7 @@ const Page: React.FC = () => {
keyAttributes,
masterKey,
);
- await saveKeyInSessionStore(SESSION_KEYS.ENCRYPTION_KEY, masterKey);
+ await saveKeyInSessionStore("encryptionKey", masterKey);
setJustSignedUp(true);
setOpenRecoveryKey(true);
} catch (e) {
diff --git a/web/packages/accounts/pages/login.tsx b/web/packages/accounts/pages/login.tsx
index a4927b61c9..b8d47cdf9c 100644
--- a/web/packages/accounts/pages/login.tsx
+++ b/web/packages/accounts/pages/login.tsx
@@ -1,9 +1,8 @@
import { AccountsPageContents } from "@/accounts/components/layouts/centered-paper";
import { LoginContents } from "@/accounts/components/LoginContents";
-import { PAGES } from "@/accounts/constants/pages";
import { LoadingIndicator } from "@/base/components/loaders";
import { customAPIHost } from "@/base/origins";
-import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
@@ -15,14 +14,14 @@ const Page: React.FC = () => {
useEffect(() => {
void customAPIHost().then(setHost);
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
if (user?.email) {
- void router.push(PAGES.VERIFY);
+ void router.push("/verify");
}
setLoading(false);
}, [router]);
- const onSignUp = () => void router.push(PAGES.SIGNUP);
+ const onSignUp = () => void router.push("/signup");
return loading ? (
diff --git a/web/packages/accounts/pages/passkeys/finish.tsx b/web/packages/accounts/pages/passkeys/finish.tsx
index 6babae304f..c6d667e78e 100644
--- a/web/packages/accounts/pages/passkeys/finish.tsx
+++ b/web/packages/accounts/pages/passkeys/finish.tsx
@@ -1,15 +1,9 @@
-import { PAGES } from "@/accounts/constants/pages";
import { unstashRedirect } from "@/accounts/services/redirect";
import { LoadingIndicator } from "@/base/components/loaders";
import { fromB64URLSafeNoPaddingString } from "@/base/crypto/libsodium";
import log from "@/base/log";
import { nullToUndefined } from "@/utils/transform";
-import {
- LS_KEYS,
- getData,
- setData,
- setLSUser,
-} from "@ente/shared/storage/localStorage";
+import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { useRouter } from "next/router";
import React, { useEffect } from "react";
@@ -96,8 +90,8 @@ const saveCredentialsAndNavigateTo = async (
// user is signing into an existing account).
const { keyAttributes, encryptedToken, token, id } = decodedResponse;
- await setLSUser({ ...getData(LS_KEYS.USER), token, encryptedToken, id });
- setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
+ await setLSUser({ ...getData("user"), token, encryptedToken, id });
+ setData("keyAttributes", keyAttributes);
- return unstashRedirect() ?? PAGES.CREDENTIALS;
+ return unstashRedirect() ?? "/credentials";
};
diff --git a/web/packages/accounts/pages/recover.tsx b/web/packages/accounts/pages/recover.tsx
index 7c69ea44a6..a1fd57d8da 100644
--- a/web/packages/accounts/pages/recover.tsx
+++ b/web/packages/accounts/pages/recover.tsx
@@ -3,7 +3,6 @@ import {
AccountsPageFooter,
AccountsPageTitle,
} from "@/accounts/components/layouts/centered-paper";
-import { PAGES } from "@/accounts/constants/pages";
import { appHomeRoute, stashRedirect } from "@/accounts/services/redirect";
import { sendOTT } from "@/accounts/services/user";
import { LinkButton } from "@/base/components/LinkButton";
@@ -17,8 +16,8 @@ import {
decryptAndStoreToken,
saveKeyInSessionStore,
} from "@ente/shared/crypto/helpers";
-import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
-import { SESSION_KEYS, getKey } from "@ente/shared/storage/sessionStorage";
+import { getData, setData } from "@ente/shared/storage/localStorage";
+import { getKey } from "@ente/shared/storage/sessionStorage";
import type { KeyAttributes, User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -39,21 +38,21 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
- const user: User = getData(LS_KEYS.USER);
- const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
- const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
+ const user: User = getData("user");
+ const keyAttributes: KeyAttributes = getData("keyAttributes");
+ const key = getKey("encryptionKey");
if (!user?.email) {
void router.push("/");
return;
}
if (!user?.encryptedToken && !user?.token) {
void sendOTT(user.email, undefined);
- stashRedirect(PAGES.RECOVER);
- void router.push(PAGES.VERIFY);
+ stashRedirect("/recover");
+ void router.push("/verify");
return;
}
if (!keyAttributes) {
- void router.push(PAGES.GENERATE);
+ void router.push("/generate");
} else if (key) {
void router.push(appHomeRoute);
} else {
@@ -86,11 +85,11 @@ const Page: React.FC = () => {
keyAttr.masterKeyDecryptionNonce!,
await cryptoWorker.fromHex(recoveryKey),
);
- await saveKeyInSessionStore(SESSION_KEYS.ENCRYPTION_KEY, masterKey);
+ await saveKeyInSessionStore("encryptionKey", masterKey);
await decryptAndStoreToken(keyAttr, masterKey);
- setData(LS_KEYS.SHOW_BACK_BUTTON, { value: false });
- void router.push(PAGES.CHANGE_PASSWORD);
+ setData("showBackButton", { value: false });
+ void router.push("/change-password");
} catch (e) {
log.error("password recovery failed", e);
setFieldError(t("incorrect_recovery_key"));
diff --git a/web/packages/accounts/pages/signup.tsx b/web/packages/accounts/pages/signup.tsx
index 4920053c24..86a43703ed 100644
--- a/web/packages/accounts/pages/signup.tsx
+++ b/web/packages/accounts/pages/signup.tsx
@@ -1,9 +1,8 @@
import { AccountsPageContents } from "@/accounts/components/layouts/centered-paper";
import { SignUpContents } from "@/accounts/components/SignUpContents";
-import { PAGES } from "@/accounts/constants/pages";
import { LoadingIndicator } from "@/base/components/loaders";
import { customAPIHost } from "@/base/origins";
-import { LS_KEYS, getData } from "@ente/shared//storage/localStorage";
+import { getData } from "@ente/shared//storage/localStorage";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
@@ -15,14 +14,14 @@ const Page: React.FC = () => {
useEffect(() => {
void customAPIHost().then(setHost);
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
if (user?.email) {
- void router.push(PAGES.VERIFY);
+ void router.push("/verify");
}
setLoading(false);
}, [router]);
- const onLogin = () => void router.push(PAGES.LOGIN);
+ const onLogin = () => void router.push("/login");
return loading ? (
diff --git a/web/packages/accounts/pages/two-factor/recover.tsx b/web/packages/accounts/pages/two-factor/recover.tsx
index 6f6f0e43c8..cb3e6148dc 100644
--- a/web/packages/accounts/pages/two-factor/recover.tsx
+++ b/web/packages/accounts/pages/two-factor/recover.tsx
@@ -3,7 +3,6 @@ import {
AccountsPageFooter,
AccountsPageTitle,
} from "@/accounts/components/layouts/centered-paper";
-import { PAGES } from "@/accounts/constants/pages";
import {
recoverTwoFactor,
removeTwoFactor,
@@ -19,12 +18,7 @@ import SingleInputForm, {
type SingleInputFormProps,
} from "@ente/shared/components/SingleInputForm";
import { ApiError } from "@ente/shared/error";
-import {
- LS_KEYS,
- getData,
- setData,
- setLSUser,
-} from "@ente/shared/storage/localStorage";
+import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { Link } from "@mui/material";
import { HttpStatusCode } from "axios";
import { t } from "i18next";
@@ -53,7 +47,7 @@ const Page: React.FC = ({ twoFactorType }) => {
const router = useRouter();
useEffect(() => {
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
const sid = user.passkeySessionID || user.twoFactorSessionID;
if (!user?.email || !sid) {
void router.push("/");
@@ -61,7 +55,7 @@ const Page: React.FC = ({ twoFactorType }) => {
!(user.isTwoFactorEnabled || user.isTwoFactorEnabledPasskey) &&
(user.encryptedToken || user.token)
) {
- void router.push(PAGES.GENERATE);
+ void router.push("/generate");
} else {
setSessionID(sid);
}
@@ -128,14 +122,14 @@ const Page: React.FC = ({ twoFactorType }) => {
);
const { keyAttributes, encryptedToken, token, id } = resp;
await setLSUser({
- ...getData(LS_KEYS.USER),
+ ...getData("user"),
token,
encryptedToken,
id,
isTwoFactorEnabled: false,
});
- setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
- void router.push(PAGES.CREDENTIALS);
+ setData("keyAttributes", keyAttributes);
+ void router.push("/credentials");
} catch (e) {
log.error("two factor recovery failed", e);
setFieldError(t("incorrect_recovery_key"));
diff --git a/web/packages/accounts/pages/two-factor/setup.tsx b/web/packages/accounts/pages/two-factor/setup.tsx
index c1333d3e55..bb24c291e0 100644
--- a/web/packages/accounts/pages/two-factor/setup.tsx
+++ b/web/packages/accounts/pages/two-factor/setup.tsx
@@ -8,7 +8,7 @@ import { LinkButton } from "@/base/components/LinkButton";
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
import { encryptWithRecoveryKey } from "@ente/shared/crypto/helpers";
-import { getData, LS_KEYS, setLSUser } from "@ente/shared/storage/localStorage";
+import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import { Paper, Stack, styled, Typography } from "@mui/material";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -35,7 +35,7 @@ const Page: React.FC = () => {
encryptedTwoFactorSecret,
twoFactorSecretDecryptionNonce,
});
- await setLSUser({ ...getData(LS_KEYS.USER), isTwoFactorEnabled: true });
+ await setLSUser({ ...getData("user"), isTwoFactorEnabled: true });
await router.push(appHomeRoute);
};
diff --git a/web/packages/accounts/pages/two-factor/verify.tsx b/web/packages/accounts/pages/two-factor/verify.tsx
index 8434969600..fce7f7bcd7 100644
--- a/web/packages/accounts/pages/two-factor/verify.tsx
+++ b/web/packages/accounts/pages/two-factor/verify.tsx
@@ -1,15 +1,9 @@
import { Verify2FACodeForm } from "@/accounts/components/Verify2FACodeForm";
-import { PAGES } from "@/accounts/constants/pages";
import { verifyTwoFactor } from "@/accounts/services/user";
import { LinkButton } from "@/base/components/LinkButton";
import { useBaseContext } from "@/base/context";
import { HTTPError } from "@/base/http";
-import {
- LS_KEYS,
- getData,
- setData,
- setLSUser,
-} from "@ente/shared/storage/localStorage";
+import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { t } from "i18next";
import { useRouter } from "next/router";
@@ -29,14 +23,14 @@ const Page: React.FC = () => {
const router = useRouter();
useEffect(() => {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
if (!user?.email || !user.twoFactorSessionID) {
void router.push("/");
} else if (
!user.isTwoFactorEnabled &&
(user.encryptedToken || user.token)
) {
- void router.push(PAGES.CREDENTIALS);
+ void router.push("/credentials");
} else {
setSessionID(user.twoFactorSessionID);
}
@@ -46,14 +40,9 @@ const Page: React.FC = () => {
try {
const resp = await verifyTwoFactor(otp, sessionID);
const { keyAttributes, encryptedToken, token, id } = resp;
- await setLSUser({
- ...getData(LS_KEYS.USER),
- token,
- encryptedToken,
- id,
- });
- setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes!);
- await router.push(unstashRedirect() ?? PAGES.CREDENTIALS);
+ await setLSUser({ ...getData("user"), token, encryptedToken, id });
+ setData("keyAttributes", keyAttributes!);
+ await router.push(unstashRedirect() ?? "/credentials");
} catch (e) {
if (e instanceof HTTPError && e.res.status == 404) {
logout();
@@ -71,9 +60,7 @@ const Page: React.FC = () => {
submitButtonText={t("verify")}
/>
- router.push(PAGES.TWO_FACTOR_RECOVER)}
- >
+ router.push("/two-factor/recover")}>
{t("lost_2fa_device")}
{t("change_email")}
diff --git a/web/packages/accounts/pages/verify.tsx b/web/packages/accounts/pages/verify.tsx
index d96d6b9009..41de21a019 100644
--- a/web/packages/accounts/pages/verify.tsx
+++ b/web/packages/accounts/pages/verify.tsx
@@ -6,7 +6,6 @@ import {
import { VerifyingPasskey } from "@/accounts/components/LoginComponents";
import { SecondFactorChoice } from "@/accounts/components/SecondFactorChoice";
import { useSecondFactorChoiceIfNeeded } from "@/accounts/components/utils/second-factor-choice";
-import { PAGES } from "@/accounts/constants/pages";
import {
openPasskeyVerificationURL,
passkeyVerificationRedirectURL,
@@ -28,12 +27,7 @@ import SingleInputForm, {
} from "@ente/shared/components/SingleInputForm";
import { ApiError } from "@ente/shared/error";
import localForage from "@ente/shared/storage/localForage";
-import {
- getData,
- LS_KEYS,
- setData,
- setLSUser,
-} from "@ente/shared/storage/localStorage";
+import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import {
getLocalReferralSource,
setIsFirstLogin,
@@ -64,7 +58,7 @@ const Page: React.FC = () => {
useEffect(() => {
const main = async () => {
- const user: User = getData(LS_KEYS.USER);
+ const user: User = getData("user");
const redirect = await redirectionIfNeeded(user);
if (redirect) {
@@ -97,7 +91,7 @@ const Page: React.FC = () => {
await verifyEmail(email, ott, cleanedReferral),
);
if (passkeySessionID) {
- const user = getData(LS_KEYS.USER);
+ const user = getData("user");
await setLSUser({
...user,
passkeySessionID,
@@ -123,7 +117,7 @@ const Page: React.FC = () => {
isTwoFactorEnabled: true,
});
setIsFirstLogin(true);
- void router.push(PAGES.TWO_FACTOR_VERIFY);
+ void router.push("/two-factor/verify");
} else {
await setLSUser({
email,
@@ -133,19 +127,18 @@ const Page: React.FC = () => {
isTwoFactorEnabled: false,
});
if (keyAttributes) {
- setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
- setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes);
+ setData("keyAttributes", keyAttributes);
+ setData("originalKeyAttributes", keyAttributes);
} else {
- if (getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES)) {
+ if (getData("originalKeyAttributes")) {
await putAttributes(
token!,
- getData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES),
+ getData("originalKeyAttributes"),
);
}
- if (getData(LS_KEYS.SRP_SETUP_ATTRIBUTES)) {
- const srpSetupAttributes: SRPSetupAttributes = getData(
- LS_KEYS.SRP_SETUP_ATTRIBUTES,
- );
+ if (getData("srpSetupAttributes")) {
+ const srpSetupAttributes: SRPSetupAttributes =
+ getData("srpSetupAttributes");
await configureSRP(srpSetupAttributes);
}
}
@@ -154,9 +147,9 @@ const Page: React.FC = () => {
const redirectURL = unstashRedirect();
if (keyAttributes?.encryptedKey) {
clearKeys();
- void router.push(redirectURL ?? PAGES.CREDENTIALS);
+ void router.push(redirectURL ?? "/credentials");
} else {
- void router.push(redirectURL ?? PAGES.GENERATE);
+ void router.push(redirectURL ?? "/generate");
}
}
} catch (e) {
@@ -272,14 +265,14 @@ const redirectionIfNeeded = async (user: User | undefined) => {
return "/";
}
- const keyAttributes: KeyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
+ const keyAttributes: KeyAttributes = getData("keyAttributes");
if (keyAttributes?.encryptedKey && (user.token || user.encryptedToken)) {
- return PAGES.CREDENTIALS;
+ return "/credentials";
}
// If we're coming here during the recover flow, do not redirect.
- if (stashedRedirect() == PAGES.RECOVER) return undefined;
+ if (stashedRedirect() == "/recover") return undefined;
// The user might have email verification disabled, but after previously
// entering their email on the login screen, they might've closed the tab
@@ -292,14 +285,14 @@ const redirectionIfNeeded = async (user: User | undefined) => {
// saved them). If they are present and indicate that email verification is
// not required, redirect to the password verification page.
- const srpAttributes: SRPAttributes = getData(LS_KEYS.SRP_ATTRIBUTES);
+ const srpAttributes: SRPAttributes = getData("srpAttributes");
if (srpAttributes && !srpAttributes.isEmailMFAEnabled) {
// Fetch the latest SRP attributes instead of relying on the potentially
// stale stored values. This is an infrequent scenario path, so extra
// API calls are fine.
const latestSRPAttributes = await getSRPAttributes(email);
if (latestSRPAttributes && !latestSRPAttributes.isEmailMFAEnabled) {
- return PAGES.CREDENTIALS;
+ return "/credentials";
}
}
diff --git a/web/packages/accounts/services/passkey.ts b/web/packages/accounts/services/passkey.ts
index 4094c7d4bf..8fe0cc7c6c 100644
--- a/web/packages/accounts/services/passkey.ts
+++ b/web/packages/accounts/services/passkey.ts
@@ -12,12 +12,7 @@ import log from "@/base/log";
import { apiURL } from "@/base/origins";
import { getRecoveryKey } from "@ente/shared/crypto/helpers";
import HTTPService from "@ente/shared/network/HTTPService";
-import {
- getData,
- LS_KEYS,
- setData,
- setLSUser,
-} from "@ente/shared/storage/localStorage";
+import { getData, setData, setLSUser } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { z } from "zod";
import { unstashRedirect } from "./redirect";
@@ -265,8 +260,8 @@ export const saveCredentialsAndNavigateTo = async (
// /passkeys/finish page.
const { id, encryptedToken, keyAttributes } = response;
- await setLSUser({ ...getData(LS_KEYS.USER), encryptedToken, id });
- setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes!);
+ await setLSUser({ ...getData("user"), encryptedToken, id });
+ setData("keyAttributes", keyAttributes!);
return unstashRedirect() ?? "/credentials";
};
diff --git a/web/packages/accounts/services/redirect.ts b/web/packages/accounts/services/redirect.ts
index 57a54b022c..ec748a6e6e 100644
--- a/web/packages/accounts/services/redirect.ts
+++ b/web/packages/accounts/services/redirect.ts
@@ -1,5 +1,4 @@
import { appName } from "@/base/app";
-import { AUTH_PAGES, PHOTOS_PAGES } from "@ente/shared/constants/pages";
/**
* The default page ("home route") for each of our apps.
@@ -8,9 +7,9 @@ import { AUTH_PAGES, PHOTOS_PAGES } from "@ente/shared/constants/pages";
*/
export const appHomeRoute: string = {
accounts: "/passkeys",
- auth: AUTH_PAGES.AUTH,
+ auth: "/auth",
cast: "/" /* The cast app doesn't use this, this is an arbitrary value. */,
- photos: PHOTOS_PAGES.GALLERY,
+ photos: "/gallery",
}[appName];
let _stashedRedirect: string | undefined;
diff --git a/web/packages/accounts/services/session.ts b/web/packages/accounts/services/session.ts
index 97c88c16f7..ee2a310beb 100644
--- a/web/packages/accounts/services/session.ts
+++ b/web/packages/accounts/services/session.ts
@@ -1,7 +1,7 @@
import { authenticatedRequestHeaders, HTTPError } from "@/base/http";
import { ensureLocalUser } from "@/base/local-user";
import { apiURL } from "@/base/origins";
-import { getData, LS_KEYS } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import type { KeyAttributes } from "@ente/shared/user/types";
import type { SRPAttributes } from "./srp-remote";
import { getSRPAttributes } from "./srp-remote";
@@ -85,7 +85,7 @@ export const checkSessionValidity = async (): Promise => {
// We should have these values locally if we reach here.
const email = ensureLocalUser().email;
- const localSRPAttributes = getData(LS_KEYS.SRP_ATTRIBUTES)!;
+ const localSRPAttributes = getData("srpAttributes")!;
// Fetch the remote SRP attributes.
//
diff --git a/web/packages/base/local-user.ts b/web/packages/base/local-user.ts
index c2a446eb3c..9bde1583a4 100644
--- a/web/packages/base/local-user.ts
+++ b/web/packages/base/local-user.ts
@@ -29,7 +29,7 @@ export type LocalUser = z.infer;
* The user's data is stored in the browser's localStorage.
*/
export const localUser = (): LocalUser | undefined => {
- // TODO(MR): duplicate of LS_KEYS.USER
+ // TODO: duplicate of getData("user")
const s = localStorage.getItem("user");
if (!s) return undefined;
return LocalUser.parse(JSON.parse(s));
diff --git a/web/packages/base/session.ts b/web/packages/base/session.ts
index b3c2e7fd82..b416b8ed9a 100644
--- a/web/packages/base/session.ts
+++ b/web/packages/base/session.ts
@@ -33,7 +33,7 @@ export const haveCredentialsInSession = () =>
* logged in, otherwise return `undefined`.
*/
export const masterKeyFromSessionIfLoggedIn = async () => {
- // TODO: Same value as the deprecated SESSION_KEYS.ENCRYPTION_KEY.
+ // TODO: Same value as the deprecated getKey("encryptionKey")
const value = sessionStorage.getItem("encryptionKey");
if (!value) return undefined;
diff --git a/web/packages/build-config/tsconfig-next.json b/web/packages/build-config/tsconfig-next.json
index a8257b0bba..af9dafc21a 100644
--- a/web/packages/build-config/tsconfig-next.json
+++ b/web/packages/build-config/tsconfig-next.json
@@ -2,7 +2,8 @@
/* A base TSConfig for typechecking our Next.js apps and packages. */
"extends": "@/build-config/tsconfig-typecheck.json",
"compilerOptions": {
- /* Next.js insists on adding these. Sigh. */
+ /* Next.js forcefully insists on adding these, which prevents us from
+ enabling the isolatedDeclarations option. Sigh. */
"allowJs": true,
"incremental": true,
/* MUI doesn't work with exactOptionalPropertyTypes yet. */
diff --git a/web/packages/gallery/components/FileInfo.tsx b/web/packages/gallery/components/FileInfo.tsx
index 2f5fb2dfce..076c283dde 100644
--- a/web/packages/gallery/components/FileInfo.tsx
+++ b/web/packages/gallery/components/FileInfo.tsx
@@ -128,10 +128,10 @@ export type FileInfoProps = ModalVisibilityProps & {
*/
allowMap?: boolean;
/**
- * If set, then a clickable chip will be shown for each collection that this
- * file is a part of.
+ * If set, then a clickable chip will be shown for each normal collection
+ * that this file is a part of.
*
- * Uses {@link fileCollectionIDs}, {@link allCollectionsNameByID} and
+ * Uses {@link fileCollectionIDs}, {@link collectionNameByID} and
* {@link onSelectCollection}, so all of those props should also be set for
* this to have an effect.
*/
@@ -147,7 +147,7 @@ export type FileInfoProps = ModalVisibilityProps & {
*
* Used when {@link showCollections} is set.
*/
- allCollectionsNameByID?: Map;
+ collectionNameByID?: Map;
/**
* Called when the action on the file info drawer has changed some the
* metadata for some file, and we need to sync with remote to get our
@@ -189,7 +189,7 @@ export const FileInfo: React.FC = ({
allowMap,
showCollections,
fileCollectionIDs,
- allCollectionsNameByID,
+ collectionNameByID,
onNeedsRemoteSync,
onUpdateCaption,
onSelectCollection,
@@ -339,13 +339,13 @@ export const FileInfo: React.FC = ({
)}
{showCollections &&
fileCollectionIDs &&
- allCollectionsNameByID &&
+ collectionNameByID &&
onSelectCollection && (
@@ -1003,14 +1003,14 @@ const ExifItem = styled("div")`
type AlbumsProps = Required<
Pick<
FileInfoProps,
- "fileCollectionIDs" | "allCollectionsNameByID" | "onSelectCollection"
+ "fileCollectionIDs" | "collectionNameByID" | "onSelectCollection"
>
> & { file: EnteFile };
const Albums: React.FC = ({
file,
fileCollectionIDs,
- allCollectionsNameByID,
+ collectionNameByID,
onSelectCollection,
}) => (
}>
@@ -1025,15 +1025,13 @@ const Albums: React.FC = ({
>
{fileCollectionIDs
.get(file.id)
- ?.filter((collectionID) =>
- allCollectionsNameByID.has(collectionID),
- )
+ ?.filter((collectionID) => collectionNameByID.has(collectionID))
.map((collectionID) => (
onSelectCollection(collectionID)}
>
- {allCollectionsNameByID.get(collectionID)}
+ {collectionNameByID.get(collectionID)}
))}
diff --git a/web/packages/gallery/components/viewer/FileViewer.tsx b/web/packages/gallery/components/viewer/FileViewer.tsx
index a01d3db249..643eb620bf 100644
--- a/web/packages/gallery/components/viewer/FileViewer.tsx
+++ b/web/packages/gallery/components/viewer/FileViewer.tsx
@@ -8,6 +8,7 @@ import { LoadingButton } from "@/base/components/mui/LoadingButton";
import { useIsSmallWidth } from "@/base/components/utils/hooks";
import { type ModalVisibilityProps } from "@/base/components/utils/modal";
import { useBaseContext } from "@/base/context";
+import { isDevBuild } from "@/base/env";
import { lowercaseExtension } from "@/base/file-name";
import { formattedListJoin, ut } from "@/base/i18n";
import type { LocalUser } from "@/base/local-user";
@@ -53,6 +54,7 @@ import React, {
useRef,
useState,
} from "react";
+import { hlsPlaylistForFile } from "../../services/video";
import {
fileInfoExifForFile,
updateItemDataAlt,
@@ -175,17 +177,28 @@ export type FileViewerProps = ModalVisibilityProps & {
/**
* File IDs of all the files that the user has marked as a favorite.
*
- * If this is not provided then the favorite toggle button will not be shown
- * in the file actions.
+ * See also {@link onToggleFavorite}.
*/
favoriteFileIDs?: Set;
+ /**
+ * File IDs of for which an update of its favorite status is pending (e.g.
+ * due to a toggle favorite action in the file viewer).
+ *
+ * See also {@link favoriteFileIDs} and {@link onToggleFavorite}.
+ */
+ pendingFavoriteUpdates?: Set;
/**
* File IDs of for which an update of its visibility is pending (e.g. due to
* a toggle archived action in the file viewer).
*
- * See also {@link pendingVisibilityUpdates}.
+ * See also {@link onFileVisibilityUpdate}.
*/
pendingVisibilityUpdates?: Set;
+ /**
+ * A mapping from file IDs to the IDs of the normal (non-hidden) collections
+ * that they are a part of.
+ */
+ fileNormalCollectionIDs?: FileInfoProps["fileCollectionIDs"];
/**
* Called when there was some update performed within the file viewer that
* necessitates us to sync with remote again to fetch the latest updates.
@@ -212,12 +225,9 @@ export type FileViewerProps = ModalVisibilityProps & {
* Called when the favorite status of given {@link file} should be toggled
* from its current value.
*
- * If this is not provided then the favorite toggle button will not be shown
- * in the file actions.
- *
- * See also {@link favoriteFileIDs}.
- *
- * See also: [Note: File viewer update and dispatch]
+ * The favorite toggle button is shown only if all three of
+ * {@link favoriteFileIDs}, {@link pendingFavoriteUpdates} and
+ * {@link onToggleFavorite} are provided.
*/
onToggleFavorite?: (file: EnteFile) => Promise;
/**
@@ -256,10 +266,7 @@ export type FileViewerProps = ModalVisibilityProps & {
onSaveEditedImageCopy?: ImageEditorOverlayProps["onSaveEditedCopy"];
} & Pick<
FileInfoProps,
- | "fileCollectionIDs"
- | "allCollectionsNameByID"
- | "onSelectCollection"
- | "onSelectPerson"
+ "collectionNameByID" | "onSelectCollection" | "onSelectPerson"
>;
/**
@@ -276,15 +283,16 @@ export const FileViewer: React.FC = ({
isInTrashSection,
isInHiddenSection,
favoriteFileIDs,
+ pendingFavoriteUpdates,
pendingVisibilityUpdates,
- fileCollectionIDs,
- allCollectionsNameByID,
+ fileNormalCollectionIDs,
+ collectionNameByID,
onTriggerSyncWithRemote,
onVisualFeedback,
onToggleFavorite,
+ onFileVisibilityUpdate,
onDownload,
onDelete,
- onFileVisibilityUpdate,
onSelectCollection,
onSelectPerson,
onSaveEditedImageCopy,
@@ -339,32 +347,9 @@ export const FileViewer: React.FC = ({
const [isFullscreen, setIsFullscreen] = useState(false);
- // Callbacks to be invoked (only once) the next time we get an update to the
- // `files` or `favoriteFileIDs` props.
- //
- // The callback is passed the latest values of the `files` prop.
- //
- // Both of those trace their way back to the same reducer, so they get
- // updated in tandem. When we delete files, only the `files` prop gets
- // updated, while when we toggle favoriets, only the `favoriteFileIDs` prop
- // gets updated.
- const [, setOnNextFilesOrFavoritesUpdate] = useState<
- ((files: EnteFile[]) => void)[]
- >([]);
-
// If `true`, then we need to trigger a sync with remote when we close.
const [, setNeedsSync] = useState(false);
- /**
- * Add a callback to be fired (only once) the next time we get an update to
- * the `files` prop.
- */
- const awaitNextFilesOrFavoritesUpdate = useCallback(
- (cb: (files: EnteFile[]) => void) =>
- setOnNextFilesOrFavoritesUpdate((cbs) => cbs.concat(cb)),
- [],
- );
-
const handleNeedsRemoteSync = useCallback(() => setNeedsSync(true), []);
const handleClose = useCallback(() => {
@@ -535,6 +520,15 @@ export const FileViewer: React.FC = ({
}
})();
+ if (
+ isDevBuild &&
+ process.env.NEXT_PUBLIC_ENTE_WIP_VIDEO_STREAMING
+ ) {
+ if (file.metadata.fileType == FileType.video) {
+ void hlsPlaylistForFile(file);
+ }
+ }
+
const annotation: FileViewerFileAnnotation = {
fileID,
isOwnFile,
@@ -586,35 +580,31 @@ export const FileViewer: React.FC = ({
const isFavorite = useCallback(
({ file }: FileViewerAnnotatedFile) => {
- if (!haveUser || !favoriteFileIDs || !onToggleFavorite) {
+ if (
+ !haveUser ||
+ !favoriteFileIDs ||
+ !pendingFavoriteUpdates ||
+ !onToggleFavorite
+ ) {
return undefined;
}
return favoriteFileIDs.has(file.id);
},
- [haveUser, favoriteFileIDs, onToggleFavorite],
+ [haveUser, favoriteFileIDs, pendingFavoriteUpdates, onToggleFavorite],
+ );
+
+ const isFavoritePending = useCallback(
+ ({ file }: FileViewerAnnotatedFile) =>
+ !!pendingFavoriteUpdates?.has(file.id),
+ [pendingFavoriteUpdates],
);
const toggleFavorite = useCallback(
- ({ file }: FileViewerAnnotatedFile) => {
- return new Promise((resolve) => {
- // See: [Note: File viewer update and dispatch]
- onToggleFavorite!(file)
- .then(
- () => awaitNextFilesOrFavoritesUpdate(() => resolve()),
- (e: unknown) => {
- onGenericError(e);
- resolve();
- },
- )
- .finally(handleNeedsRemoteSync);
- });
- },
- [
- onToggleFavorite,
- onGenericError,
- awaitNextFilesOrFavoritesUpdate,
- handleNeedsRemoteSync,
- ],
+ ({ file }: FileViewerAnnotatedFile) =>
+ onToggleFavorite!(file)
+ .catch(onGenericError)
+ .finally(handleNeedsRemoteSync),
+ [onToggleFavorite, onGenericError, handleNeedsRemoteSync],
);
const updateFullscreenStatus = useCallback(() => {
@@ -761,6 +751,7 @@ export const FileViewer: React.FC = ({
delegateRef.current = {
getFiles,
isFavorite,
+ isFavoritePending,
toggleFavorite,
shouldIgnoreKeyboardEvent,
performKeyAction,
@@ -772,12 +763,14 @@ export const FileViewer: React.FC = ({
const delegate = delegateRef.current!;
delegate.getFiles = getFiles;
delegate.isFavorite = isFavorite;
+ delegate.isFavoritePending = isFavoritePending;
delegate.toggleFavorite = toggleFavorite;
delegate.shouldIgnoreKeyboardEvent = shouldIgnoreKeyboardEvent;
delegate.performKeyAction = performKeyAction;
}, [
getFiles,
isFavorite,
+ isFavoritePending,
toggleFavorite,
shouldIgnoreKeyboardEvent,
performKeyAction,
@@ -831,13 +824,11 @@ export const FileViewer: React.FC = ({
return af;
});
+ }, [handleClose, files]);
- // - Used for favorite updates.
- setOnNextFilesOrFavoritesUpdate((cbs) => {
- cbs.forEach((cb) => cb(files));
- return [];
- });
- }, [handleClose, files, favoriteFileIDs]);
+ useEffect(() => {
+ psRef.current?.refreshCurrentSlideFavoriteButtonIfNeeded();
+ }, [favoriteFileIDs, pendingFavoriteUpdates]);
useEffect(() => {
if (open) {
@@ -904,12 +895,13 @@ export const FileViewer: React.FC = ({
exif={activeFileExif}
allowEdits={!!activeAnnotatedFile.annotation.isOwnFile}
allowMap={haveUser}
- showCollections={haveUser}
+ showCollections={haveUser && !isInHiddenSection}
+ fileCollectionIDs={fileNormalCollectionIDs}
+ collectionNameByID={collectionNameByID}
onNeedsRemoteSync={handleNeedsRemoteSync}
onUpdateCaption={handleUpdateCaption}
onSelectCollection={handleSelectCollection}
onSelectPerson={handleSelectPerson}
- {...{ fileCollectionIDs, allCollectionsNameByID }}
/>
boolean | undefined;
+ /**
+ * Return `true` if there is an inflight request to update the favorite
+ * status of the file.
+ */
+ isFavoritePending: (annotatedFile: FileViewerAnnotatedFile) => boolean;
/**
* Called when the user activates the toggle favorite action on a file.
*
@@ -609,21 +614,19 @@ export class FileViewerPhotoSwipe {
let favoriteButtonElement: HTMLButtonElement | undefined;
- /**
- * IDs of files for which a there is a favorite update in progress.
- */
- const pendingFavoriteUpdates = new Set();
+ const toggleFavorite = () =>
+ delegate.toggleFavorite(currentAnnotatedFile());
- const toggleFavorite = async () => {
- const af = currentAnnotatedFile();
- pendingFavoriteUpdates.add(af.file.id);
- updateFavoriteButton();
- await delegate.toggleFavorite(af);
- pendingFavoriteUpdates.delete(af.file.id);
- updateFavoriteButton();
- };
+ const updateFavoriteButtonIfNeeded = () => {
+ const favoriteIconFill = document.getElementById(
+ "pswp__icn-favorite-fill",
+ );
+ if (!favoriteIconFill) {
+ // Early return if we're not currently being shown, to implement
+ // the "IfNeeded" semantics.
+ return;
+ }
- const updateFavoriteButton = () => {
const button = favoriteButtonElement!;
const af = currentAnnotatedFile();
@@ -636,20 +639,24 @@ export class FileViewerPhotoSwipe {
}
// Update the button interactivity based on pending requests.
- button.disabled = pendingFavoriteUpdates.has(af.file.id);
+ button.disabled = delegate.isFavoritePending(af);
// Update the fill visibility based on the favorite status.
- const fill = document.getElementById("pswp__icn-favorite-fill");
- if (fill) {
- // Need a null check since we might've been closed meanwhile.
- showIf(fill, !!delegate.isFavorite(af));
- }
+ showIf(favoriteIconFill, !!delegate.isFavorite(af));
};
+ this.refreshCurrentSlideFavoriteButtonIfNeeded =
+ updateFavoriteButtonIfNeeded;
+
const handleToggleFavorite = () => void toggleFavorite();
const handleToggleFavoriteIfEnabled = () => {
- if (haveUser) handleToggleFavorite();
+ if (
+ haveUser &&
+ !delegate.isFavoritePending(currentAnnotatedFile())
+ ) {
+ handleToggleFavorite();
+ }
};
const handleDownload = () => onDownload(currentAnnotatedFile());
@@ -761,7 +768,7 @@ export class FileViewerPhotoSwipe {
// The cast should be safe (unless there is a
// PhotoSwipe bug) since we set isButton to true.
buttonElement as HTMLButtonElement;
- pswp.on("change", updateFavoriteButton);
+ pswp.on("change", updateFavoriteButtonIfNeeded);
},
onClick: handleToggleFavorite,
});
@@ -1036,6 +1043,15 @@ export class FileViewerPhotoSwipe {
this.pswp.refreshSlideContent(this.pswp.currIndex);
}
}
+
+ /**
+ * Refresh the favorite button (if indeed it is visible at all) on the
+ * current slide, asking the delegate for the latest state.
+ *
+ * We do this piecemeal update instead of a full refresh because a full
+ * refresh would cause, e.g., the pan and zoom to be reset.
+ */
+ refreshCurrentSlideFavoriteButtonIfNeeded: () => void;
}
const videoHTML = (url: string, disableDownload: boolean) => `
diff --git a/web/packages/new/photos/services/file-data.ts b/web/packages/gallery/services/file-data.ts
similarity index 81%
rename from web/packages/new/photos/services/file-data.ts
rename to web/packages/gallery/services/file-data.ts
index c7367ccbea..724db99a73 100644
--- a/web/packages/new/photos/services/file-data.ts
+++ b/web/packages/gallery/services/file-data.ts
@@ -18,7 +18,9 @@ import { z } from "zod";
* There are specialized APIs for fetching and uploading the originals and the
* thumbnails. But for the other associated data, we can use the file data APIs.
*/
-type FileDataType = "mldata" /* See: [Note: "mldata" format] */;
+type FileDataType =
+ | "mldata" /* See: [Note: "mldata" format] */
+ | "vid_preview" /* See: [Note: Video playlist and preview] */;
const RemoteFileData = z.object({
/**
@@ -61,7 +63,7 @@ type RemoteFileData = z.infer;
* payload, but we don't parse that information currently since the higher
* levels of our code that use this function handle such rare skips gracefully.
*/
-export const fetchFileData = async (
+export const fetchFilesData = async (
type: FileDataType,
fileIDs: number[],
): Promise => {
@@ -75,6 +77,27 @@ export const fetchFileData = async (
.data;
};
+/**
+ * A variant of {@link fetchFilesData} that fetches data for a single file.
+ *
+ * Unlike {@link fetchFilesData}, this uses a HTTP GET request.
+ *
+ * Returns `undefined` if no video preview has been generated for this file yet.
+ */
+export const fetchFileData = async (
+ type: FileDataType,
+ fileID: number,
+): Promise => {
+ const params = new URLSearchParams({ type, fileID: fileID.toString() });
+ const url = await apiURL("/files/data/fetch");
+ const res = await fetch(`${url}?${params.toString()}`, {
+ headers: await authenticatedRequestHeaders(),
+ });
+ if (res.status == 404) return undefined;
+ ensureOk(res);
+ return z.object({ data: RemoteFileData }).parse(await res.json()).data;
+};
+
/**
* Upload file data associated with the given file to remote.
*
diff --git a/web/packages/gallery/services/upload.ts b/web/packages/gallery/services/upload.ts
index e6b1040d73..36e5096814 100644
--- a/web/packages/gallery/services/upload.ts
+++ b/web/packages/gallery/services/upload.ts
@@ -94,17 +94,16 @@ export type UploadPhase =
| "cancelling"
| "done";
-export enum UPLOAD_RESULT {
- FAILED,
- ALREADY_UPLOADED,
- UNSUPPORTED,
- BLOCKED,
- TOO_LARGE,
- LARGER_THAN_AVAILABLE_STORAGE,
- UPLOADED,
- UPLOADED_WITH_STATIC_THUMBNAIL,
- ADDED_SYMLINK,
-}
+export type UploadResult =
+ | "failed"
+ | "alreadyUploaded"
+ | "unsupported"
+ | "blocked"
+ | "tooLarge"
+ | "largerThanAvailableStorage"
+ | "uploaded"
+ | "uploadedWithStaticThumbnail"
+ | "addedSymlink";
/**
* Return true to disable the upload of files via Cloudflare Workers.
diff --git a/web/packages/gallery/services/video.ts b/web/packages/gallery/services/video.ts
new file mode 100644
index 0000000000..ff769f9a2a
--- /dev/null
+++ b/web/packages/gallery/services/video.ts
@@ -0,0 +1,96 @@
+import { decryptBlob } from "@/base/crypto";
+import type { EncryptedBlob } from "@/base/crypto/types";
+import log from "@/base/log";
+import type { EnteFile } from "@/media/file";
+import { FileType } from "@/media/file-type";
+import { gunzip } from "@/new/photos/utils/gzip";
+import { ensurePrecondition } from "@/utils/ensure";
+import { z } from "zod";
+import { fetchFileData } from "./file-data";
+
+/**
+ * Return a HLS playlist that can be used to stream playback of thne given video
+ * {@link file}.
+ *
+ * @param file An {@link EnteFile} of type video.
+ *
+ * @returns The HLS playlist as a string, or `undefined` if there is no video
+ * preview associated with the given file.
+ *
+ * [Note: Video playlist and preview]
+ *
+ * In museum's ontology, there is a distinction between two concepts:
+ *
+ * S3 metadata is the data that museum uploads (on behalf of the client):
+ * - ML data.
+ * - Preview video playlist.
+ *
+ * S3 file data is the data that client uploads:
+ * - Preview video itself.
+ * - Additional preview images.
+ *
+ * Because of this separation, there are separate code paths dealing with the
+ * two parts we need to play streaming video:
+ *
+ * - The encrypted HLS playlist (which is stored as file data of type
+ * "vid_preview"),
+ *
+ * - And the encrypted video chunks that it (the playlist) refers to (which are
+ * stored as file preview data of type "vid_preview").
+ */
+export const hlsPlaylistForFile = async (file: EnteFile) => {
+ ensurePrecondition(file.metadata.fileType == FileType.video);
+
+ const playlistFileData = await fetchFileData("vid_preview", file.id);
+ if (!playlistFileData) return undefined;
+
+ // See: [Note: strict mode migration]
+ //
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ const { playlist } = await decryptPlaylistJSON(playlistFileData, file);
+
+ // [Note: HLS playlist format]
+ //
+ // The decrypted playlist is a regular HLS playlist for an encrypted media
+ // stream, except that it uses a placeholder "output.ts" which needs to be
+ // replaced with the URL of the actual encrypted video data. A single URL
+ // pointing to the entire encrypted video data suffices; the individual
+ // chunks are fetched by HTTP range requests.
+ //
+ // Here is an example of what the contents of the `playlist` variable might
+ // look like at this point:
+ //
+ // #EXTM3U
+ // #EXT-X-VERSION:4
+ // #EXT-X-TARGETDURATION:8
+ // #EXT-X-MEDIA-SEQUENCE:0
+ // #EXT-X-KEY:METHOD=AES-128,URI="data:text/plain;base64,XjvG7qeRrsOpPUbJPh2Ikg==",IV=0x00000000000000000000000000000000
+ // #EXTINF:8.333333,
+ // #EXT-X-BYTERANGE:3046928@0
+ // output.ts
+ // #EXTINF:8.333333,
+ // #EXT-X-BYTERANGE:3012704@3046928
+ // output.ts
+ // #EXTINF:2.200000,
+ // #EXT-X-BYTERANGE:834736@6059632
+ // output.ts
+ // #EXT-X-ENDLIST
+ //
+ log.debug(() => ["hlsPlaylistForFile", playlist]);
+ return file.id;
+};
+
+const PlaylistJSON = z.object({
+ /** The HLS playlist, as a string. */
+ playlist: z.string(),
+});
+
+const decryptPlaylistJSON = async (
+ encryptedPlaylist: EncryptedBlob,
+ file: EnteFile,
+) => {
+ const decryptedBytes = await decryptBlob(encryptedPlaylist, file.key);
+ const jsonString = await gunzip(decryptedBytes);
+ return PlaylistJSON.parse(JSON.parse(jsonString));
+};
diff --git a/web/packages/media/collection.ts b/web/packages/media/collection.ts
index a813afaed3..145789f9a2 100644
--- a/web/packages/media/collection.ts
+++ b/web/packages/media/collection.ts
@@ -6,24 +6,14 @@ import { ItemVisibility } from "@/media/file-metadata";
// TODO: Audit this file
-export enum CollectionType {
- folder = "folder",
- favorites = "favorites",
- album = "album",
- uncategorized = "uncategorized",
-}
+export type CollectionType = "folder" | "favorites" | "album" | "uncategorized";
-export enum COLLECTION_ROLE {
- VIEWER = "VIEWER",
- OWNER = "OWNER",
- COLLABORATOR = "COLLABORATOR",
- UNKNOWN = "UNKNOWN",
-}
+export type CollectionRole = "VIEWER" | "OWNER" | "COLLABORATOR" | "UNKNOWN";
export interface CollectionUser {
id: number;
email: string;
- role: COLLECTION_ROLE;
+ role: CollectionRole;
}
export interface EncryptedCollection {
@@ -112,15 +102,18 @@ export interface RemoveFromCollectionRequest {
fileIDs: number[];
}
-export enum SUB_TYPE {
- DEFAULT = 0,
- DEFAULT_HIDDEN = 1,
- QUICK_LINK_COLLECTION = 2,
-}
+export const CollectionSubType = {
+ default: 0,
+ defaultHidden: 1,
+ quicklink: 2,
+} as const;
+
+export type CollectionSubType =
+ (typeof CollectionSubType)[keyof typeof CollectionSubType];
export interface CollectionMagicMetadataProps {
visibility?: ItemVisibility;
- subType?: SUB_TYPE;
+ subType?: CollectionSubType;
order?: number;
}
diff --git a/web/packages/media/file-metadata.ts b/web/packages/media/file-metadata.ts
index 20e3da1eda..1b5b1f412a 100644
--- a/web/packages/media/file-metadata.ts
+++ b/web/packages/media/file-metadata.ts
@@ -175,14 +175,23 @@ export interface PrivateMagicMetadata {
/**
* The visibility of an Ente file or collection.
*/
-export enum ItemVisibility {
+export const ItemVisibility = {
/** The normal state - The item is visible. */
- visible = 0,
+ visible: 0,
/** The item has been archived. */
- archived = 1,
+ archived: 1,
/** The item has been hidden. */
- hidden = 2,
-}
+ hidden: 2,
+} as const;
+
+/**
+ * The visibility of an Ente file or collection.
+ *
+ * This is the erasable type. See the {@link ItemVisibility} object for the
+ * possible values and their symbolic constants.
+ */
+export type ItemVisibility =
+ (typeof ItemVisibility)[keyof typeof ItemVisibility];
/**
* Mutable public metadata associated with an {@link EnteFile}.
diff --git a/web/packages/media/file-type.ts b/web/packages/media/file-type.ts
index bb8ceeede3..e8dcf6b2c9 100644
--- a/web/packages/media/file-type.ts
+++ b/web/packages/media/file-type.ts
@@ -1,9 +1,18 @@
-/** The type of an {@link EnteFile}. */
-export enum FileType {
- /** An image (e.g. JPEG). */
- image = 0,
- /** A video (e.g. MP4). */
- video = 1,
+/**
+ * The type of an {@link EnteFile}.
+ *
+ * This is an object containing symbolic constant. There is also an eraseable
+ * TypeScript type type with the same name, {@link FileType}.
+ */
+export const FileType = {
+ /**
+ * An image (e.g. JPEG).
+ */
+ image: 0,
+ /**
+ * A video (e.g. MP4).
+ */
+ video: 1,
/**
* A live photo, aka motion photo.
*
@@ -11,7 +20,7 @@ export enum FileType {
* before and after when the image was taken. We preserve it as a zip
* containing both the parts.
*/
- livePhoto = 2,
+ livePhoto: 2,
/**
* An unknown file type.
*
@@ -20,8 +29,16 @@ export enum FileType {
* deal with the scenario that an EnteFile's type can be different from one
* of the above.
*/
- other = 3,
-}
+ other: 3,
+} as const;
+
+/**
+ * The type of an {@link EnteFile}.
+ *
+ * This is an eraseable TypeScript type. There is also a {@link FileType} object
+ * with the same name that contains the corresponding symbolic constants.
+ */
+export type FileType = (typeof FileType)[keyof typeof FileType];
export interface FileTypeInfo {
fileType: FileType;
diff --git a/web/packages/new/photos/components/FileDateTimePicker.tsx b/web/packages/new/photos/components/FileDateTimePicker.tsx
index a3e4a3e0e2..d90df26083 100644
--- a/web/packages/new/photos/components/FileDateTimePicker.tsx
+++ b/web/packages/new/photos/components/FileDateTimePicker.tsx
@@ -57,7 +57,6 @@ export const FileDateTimePicker: React.FC = ({
};
const handleClose = () => {
- console.log("handleClose");
setOpen(false);
onDidClose?.();
};
diff --git a/web/packages/new/photos/components/gallery/reducer.ts b/web/packages/new/photos/components/gallery/reducer.ts
index 6a4bf0732d..dc5d82e253 100644
--- a/web/packages/new/photos/components/gallery/reducer.ts
+++ b/web/packages/new/photos/components/gallery/reducer.ts
@@ -2,11 +2,7 @@ import {
isArchivedCollection,
isPinnedCollection,
} from "@/gallery/services/magic-metadata";
-import {
- COLLECTION_ROLE,
- CollectionType,
- type Collection,
-} from "@/media/collection";
+import { type Collection } from "@/media/collection";
import type { EnteFile, FilePrivateMagicMetadata } from "@/media/file";
import { mergeMetadata } from "@/media/file";
import { isArchivedFile } from "@/media/file-metadata";
@@ -124,7 +120,7 @@ export interface GalleryState {
/**
* The user's normal (non-hidden) collections.
*/
- collections: Collection[];
+ normalCollections: Collection[];
/**
* The user's hidden collections.
*/
@@ -136,9 +132,9 @@ export interface GalleryState {
* The list is sorted so that newer files are first.
*
* This property is expected to be of use only internal to the reducer;
- * external code likely needs {@link files} instead.
+ * external code likely needs {@link normalFiles} instead.
*/
- lastSyncedFiles: EnteFile[];
+ lastSyncedNormalFiles: EnteFile[];
/**
* The user's hidden files, without any unsynced modifications applied to
* them.
@@ -150,7 +146,7 @@ export interface GalleryState {
*/
lastSyncedHiddenFiles: EnteFile[];
/**
- * The user's files that are in Trash.
+ * The user's files that are in trash.
*
* The list is sorted so that newer files are first.
*/
@@ -177,7 +173,7 @@ export interface GalleryState {
* happen on the next "file sync", until then they remain as in-memory state
* in the reducer.
*/
- files: EnteFile[];
+ normalFiles: EnteFile[];
/**
* The user's hidden files, with any unsynced modifications also applied to
* them.
@@ -226,6 +222,8 @@ export interface GalleryState {
* File IDs of all the files that the user has marked as a favorite.
*
* Includes the effects of {@link unsyncedFavoriteUpdates}.
+ *
+ * For fast lookup, this is a set instead of a list.
*/
favoriteFileIDs: Set;
/**
@@ -233,21 +231,23 @@ export interface GalleryState {
*
* It will contain entries for all collections (both normal and hidden).
*/
- allCollectionsNameByID: Map;
+ collectionNameByID: Map;
/**
- * A map from file IDs to the IDs of the collections that they're a part of.
+ * A map from file IDs to the IDs of the normal (non-hidden) collections
+ * that they're a part of.
*/
- fileCollectionIDs: Map;
+ fileNormalCollectionIDs: Map;
/*--< Derived UI state >--*/
/**
- * A map of collections massage to a form suitable for being directly
- * consumed by the UI, indexed by the collection IDs.
+ * A map of normal (non-hidden) collections massaged into a form suitable
+ * for being directly consumed by the UI, indexed by the collection IDs.
*/
- collectionSummaries: Map;
+ normalCollectionSummaries: Map;
/**
- * A version of {@link collectionSummaries} but for hidden collections.
+ * A variant of {@link normalCollectionSummaries}, but for hidden
+ * collections.
*/
hiddenCollectionSummaries: Map;
@@ -267,9 +267,30 @@ export interface GalleryState {
* hidden.
*/
tempHiddenFileIDs: Set;
+ /**
+ * File (IDs) for which there is currently an in-flight favorite /
+ * unfavorite operation.
+ *
+ * See also {@link unsyncedFavoriteUpdates}.
+ */
+ pendingFavoriteUpdates: Set;
+ /**
+ * Updates to the favorite status of files (triggered by some interactive
+ * user action) that have already been made to applied to remote, but whose
+ * effects on remote have not yet been synced back to our local DB.
+ *
+ * Each entry from a file ID to its favorite status (`true` if it belongs to
+ * the user's favorites, false otherwise) which should be used for that file
+ * instead of what we get from our local DB.
+ *
+ * The next time a sync with remote completes, we clear this map since
+ * thereafter just deriving {@link favoriteFileIDs} from our local files
+ * would reflect the correct state on remote too.
+ */
+ unsyncedFavoriteUpdates: Map;
/**
* File (IDs) for which there is currently an in-flight archive / unarchive
- * operation trigged via the file viewer.
+ * operation.
*
* See also {@link unsyncedPrivateMagicMetadataUpdates}.
*/
@@ -287,32 +308,6 @@ export interface GalleryState {
* magic metadata.
*/
unsyncedPrivateMagicMetadataUpdates: Map;
- /**
- * Transient updates to the favorite status of files that have just been
- * toggled by the user in the file viewer, and on remote, but whose effects
- * on remote have not yet been synced back to our local DB.
- *
- * Each entry is from a file ID to `true` (if that file should be considered
- * as part of the favorites) or `false` (if that file should not be
- * considered as part of the favorites).
- *
- * When the user marks a file as a favorite (or unmarks it as a favorite),
- * we add an entry in this map so that we can give them immediate feedback
- * in the UI.
- *
- * The request to update the favorite status on remote proceeds in parallel.
- * If that request fails, we remove the entry from here.
- *
- * If the remote request succeeds, we still need to sync the files and
- * collections in our local DB with the remote state, but that happens in a
- * batch when the user exits the viewer. So until that point, these updates
- * remain in this in-flight updates map.
- *
- * Once the remote file + collection sync completes, we can clear this map
- * since just deriving {@link favoriteFileIDs} from our local files would
- * reflect the correct state on remote too.
- */
- unsyncedFavoriteUpdates: Map;
/*--< State that underlies transient UI state >--*/
@@ -412,28 +407,32 @@ export type GalleryAction =
type: "mount";
user: User;
familyData: FamilyData;
- allCollections: Collection[];
- files: EnteFile[];
+ collections: Collection[];
+ normalFiles: EnteFile[];
hiddenFiles: EnteFile[];
trashedFiles: EnteFile[];
}
- | { type: "setNormalCollections"; collections: Collection[] }
| {
type: "setCollections";
+ collections: Collection[];
normalCollections: Collection[];
hiddenCollections: Collection[];
}
- | { type: "setFiles"; files: EnteFile[] }
- | { type: "fetchFiles"; files: EnteFile[] }
- | { type: "uploadFile"; file: EnteFile }
- | { type: "setHiddenFiles"; hiddenFiles: EnteFile[] }
- | { type: "fetchHiddenFiles"; hiddenFiles: EnteFile[] }
- | { type: "setTrashedFiles"; trashedFiles: EnteFile[] }
+ | { type: "setNormalCollections"; collections: Collection[] }
+ | { type: "setNormalFiles"; files: EnteFile[] }
+ | { type: "fetchNormalFiles"; files: EnteFile[] }
+ | { type: "uploadNormalFile"; file: EnteFile }
+ | { type: "setHiddenFiles"; files: EnteFile[] }
+ | { type: "fetchHiddenFiles"; files: EnteFile[] }
+ | { type: "setTrashedFiles"; files: EnteFile[] }
| { type: "setPeopleState"; peopleState: PeopleState | undefined }
| { type: "markTempDeleted"; files: EnteFile[] }
| { type: "clearTempDeleted" }
| { type: "markTempHidden"; files: EnteFile[] }
| { type: "clearTempHidden" }
+ | { type: "addPendingFavoriteUpdate"; fileID: number }
+ | { type: "removePendingFavoriteUpdate"; fileID: number }
+ | { type: "unsyncedFavoriteUpdate"; fileID: number; isFavorite: boolean }
| { type: "addPendingVisibilityUpdate"; fileID: number }
| { type: "removePendingVisibilityUpdate"; fileID: number }
| {
@@ -441,21 +440,11 @@ export type GalleryAction =
fileID: number;
privateMagicMetadata: FilePrivateMagicMetadata;
}
- | {
- type: "markUnsyncedFavoriteUpdate";
- fileID: number;
- // Passing undefined clears any existing entry, concrete values add or
- // update one.
- isFavorite: boolean | undefined;
- }
| { type: "clearUnsyncedState" }
| { type: "showAll" }
| { type: "showHidden" }
| { type: "showAlbums" }
- | {
- type: "showNormalOrHiddenCollectionSummary";
- collectionSummaryID: number | undefined;
- }
+ | { type: "showCollectionSummary"; collectionSummaryID: number | undefined }
| { type: "showPeople" }
| { type: "showPerson"; personID: string }
| { type: "enterSearchMode"; searchSuggestion?: SearchSuggestion }
@@ -466,28 +455,29 @@ export type GalleryAction =
const initialGalleryState: GalleryState = {
user: undefined,
familyData: undefined,
- collections: [],
+ normalCollections: [],
hiddenCollections: [],
- lastSyncedFiles: [],
+ lastSyncedNormalFiles: [],
lastSyncedHiddenFiles: [],
trashedFiles: [],
peopleState: undefined,
- files: [],
+ normalFiles: [],
hiddenFiles: [],
archivedCollectionIDs: new Set(),
defaultHiddenCollectionIDs: new Set(),
hiddenFileIDs: new Set(),
archivedFileIDs: new Set(),
favoriteFileIDs: new Set(),
- allCollectionsNameByID: new Map(),
- fileCollectionIDs: new Map(),
- collectionSummaries: new Map(),
+ collectionNameByID: new Map(),
+ fileNormalCollectionIDs: new Map(),
+ normalCollectionSummaries: new Map(),
hiddenCollectionSummaries: new Map(),
tempDeletedFileIDs: new Set(),
tempHiddenFileIDs: new Set(),
+ pendingFavoriteUpdates: new Set(),
+ unsyncedFavoriteUpdates: new Map(),
pendingVisibilityUpdates: new Set(),
unsyncedPrivateMagicMetadataUpdates: new Map(),
- unsyncedFavoriteUpdates: new Map(),
selectedCollectionSummaryID: undefined,
selectedPersonID: undefined,
extraVisiblePerson: undefined,
@@ -507,42 +497,45 @@ const galleryReducer: React.Reducer = (
if (process.env.NEXT_PUBLIC_ENTE_TRACE) console.log("dispatch", action);
switch (action.type) {
case "mount": {
- const lastSyncedFiles = sortFiles(mergeMetadata(action.files));
+ const lastSyncedNormalFiles = sortFiles(
+ mergeMetadata(action.normalFiles),
+ );
const lastSyncedHiddenFiles = sortFiles(
mergeMetadata(action.hiddenFiles),
);
// During mount there are no unsynced updates, and we can directly
// use the provided files.
- const files = lastSyncedFiles;
+ const normalFiles = lastSyncedNormalFiles;
const hiddenFiles = lastSyncedHiddenFiles;
- const [hiddenCollections, collections] = splitByPredicate(
- action.allCollections,
+ const [hiddenCollections, normalCollections] = splitByPredicate(
+ action.collections,
isHiddenCollection,
);
const hiddenFileIDs = deriveHiddenFileIDs(hiddenFiles);
const archivedCollectionIDs =
- deriveArchivedCollectionIDs(collections);
+ deriveArchivedCollectionIDs(normalCollections);
const archivedFileIDs = deriveArchivedFileIDs(
archivedCollectionIDs,
- files,
+ normalFiles,
);
const view = {
type: "albums" as const,
activeCollectionSummaryID: ALL_SECTION,
activeCollection: undefined,
};
+
return stateByUpdatingFilteredFiles({
...state,
user: action.user,
familyData: action.familyData,
- collections,
+ normalCollections,
hiddenCollections,
- lastSyncedFiles,
+ lastSyncedNormalFiles,
lastSyncedHiddenFiles,
trashedFiles: action.trashedFiles,
- files,
+ normalFiles,
hiddenFiles,
archivedCollectionIDs,
defaultHiddenCollectionIDs:
@@ -550,18 +543,18 @@ const galleryReducer: React.Reducer = (
hiddenFileIDs,
archivedFileIDs,
favoriteFileIDs: deriveFavoriteFileIDs(
- collections,
- files,
+ normalCollections,
+ normalFiles,
state.unsyncedFavoriteUpdates,
),
- allCollectionsNameByID: createCollectionNameByID(
- action.allCollections,
+ collectionNameByID: createCollectionNameByID(
+ action.collections,
),
- fileCollectionIDs: createFileCollectionIDs(files),
- collectionSummaries: deriveCollectionSummaries(
+ fileNormalCollectionIDs: createFileCollectionIDs(normalFiles),
+ normalCollectionSummaries: deriveNormalCollectionSummaries(
action.user,
- collections,
- files,
+ normalCollections,
+ normalFiles,
action.trashedFiles,
archivedFileIDs,
),
@@ -574,71 +567,19 @@ const galleryReducer: React.Reducer = (
});
}
- case "setNormalCollections": {
- const collections = action.collections;
- const archivedCollectionIDs =
- deriveArchivedCollectionIDs(collections);
- const archivedFileIDs = deriveArchivedFileIDs(
- archivedCollectionIDs,
- state.files,
- );
- const collectionSummaries = deriveCollectionSummaries(
- state.user!,
- collections,
- state.files,
- state.trashedFiles,
- archivedFileIDs,
- );
-
- // Revalidate the active view if needed.
- let view = state.view;
- let selectedCollectionSummaryID = state.selectedCollectionSummaryID;
- if (state.view?.type == "albums") {
- ({ view, selectedCollectionSummaryID } =
- deriveAlbumsViewAndSelectedID(
- collections,
- collectionSummaries,
- selectedCollectionSummaryID,
- ));
- }
-
- return stateByUpdatingFilteredFiles({
- ...state,
- collections,
- archivedCollectionIDs,
- archivedFileIDs,
- favoriteFileIDs: deriveFavoriteFileIDs(
- collections,
- state.files,
- state.unsyncedFavoriteUpdates,
- ),
- allCollectionsNameByID: createCollectionNameByID(
- collections.concat(state.hiddenCollections),
- ),
- collectionSummaries,
- selectedCollectionSummaryID,
- pendingSearchSuggestions:
- enqueuePendingSearchSuggestionsIfNeeded(
- state.searchSuggestion,
- state.pendingSearchSuggestions,
- state.isInSearchMode,
- ),
- view,
- });
- }
-
case "setCollections": {
- const { normalCollections, hiddenCollections } = action;
+ const { collections, normalCollections, hiddenCollections } =
+ action;
const archivedCollectionIDs =
deriveArchivedCollectionIDs(normalCollections);
const archivedFileIDs = deriveArchivedFileIDs(
archivedCollectionIDs,
- state.files,
+ state.normalFiles,
);
- const collectionSummaries = deriveCollectionSummaries(
+ const normalCollectionSummaries = deriveNormalCollectionSummaries(
state.user!,
normalCollections,
- state.files,
+ state.normalFiles,
state.trashedFiles,
archivedFileIDs,
);
@@ -655,7 +596,7 @@ const galleryReducer: React.Reducer = (
({ view, selectedCollectionSummaryID } =
deriveAlbumsViewAndSelectedID(
normalCollections,
- collectionSummaries,
+ normalCollectionSummaries,
selectedCollectionSummaryID,
));
} else if (state.view?.type == "hidden-albums") {
@@ -669,7 +610,7 @@ const galleryReducer: React.Reducer = (
return stateByUpdatingFilteredFiles({
...state,
- collections: normalCollections,
+ normalCollections,
hiddenCollections,
archivedCollectionIDs,
defaultHiddenCollectionIDs:
@@ -677,13 +618,11 @@ const galleryReducer: React.Reducer = (
archivedFileIDs,
favoriteFileIDs: deriveFavoriteFileIDs(
normalCollections,
- state.files,
+ state.normalFiles,
state.unsyncedFavoriteUpdates,
),
- allCollectionsNameByID: createCollectionNameByID(
- normalCollections.concat(hiddenCollections),
- ),
- collectionSummaries,
+ collectionNameByID: createCollectionNameByID(collections),
+ normalCollectionSummaries,
hiddenCollectionSummaries,
selectedCollectionSummaryID,
pendingSearchSuggestions:
@@ -696,68 +635,121 @@ const galleryReducer: React.Reducer = (
});
}
- case "setFiles": {
+ case "setNormalCollections": {
+ const normalCollections = action.collections;
+ const archivedCollectionIDs =
+ deriveArchivedCollectionIDs(normalCollections);
+ const archivedFileIDs = deriveArchivedFileIDs(
+ archivedCollectionIDs,
+ state.normalFiles,
+ );
+ const normalCollectionSummaries = deriveNormalCollectionSummaries(
+ state.user!,
+ normalCollections,
+ state.normalFiles,
+ state.trashedFiles,
+ archivedFileIDs,
+ );
+
+ // Revalidate the active view if needed.
+ let view = state.view;
+ let selectedCollectionSummaryID = state.selectedCollectionSummaryID;
+ if (state.view?.type == "albums") {
+ ({ view, selectedCollectionSummaryID } =
+ deriveAlbumsViewAndSelectedID(
+ normalCollections,
+ normalCollectionSummaries,
+ selectedCollectionSummaryID,
+ ));
+ }
+
+ return stateByUpdatingFilteredFiles({
+ ...state,
+ normalCollections,
+ archivedCollectionIDs,
+ archivedFileIDs,
+ favoriteFileIDs: deriveFavoriteFileIDs(
+ normalCollections,
+ state.normalFiles,
+ state.unsyncedFavoriteUpdates,
+ ),
+ collectionNameByID: createCollectionNameByID(
+ normalCollections.concat(state.hiddenCollections),
+ ),
+ normalCollectionSummaries,
+ selectedCollectionSummaryID,
+ pendingSearchSuggestions:
+ enqueuePendingSearchSuggestionsIfNeeded(
+ state.searchSuggestion,
+ state.pendingSearchSuggestions,
+ state.isInSearchMode,
+ ),
+ view,
+ });
+ }
+
+ case "setNormalFiles": {
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
action.files,
);
-
- const lastSyncedFiles = sortFiles(mergeMetadata(action.files));
- const files = deriveNormalOrHiddenFiles(
- lastSyncedFiles,
+ const lastSyncedNormalFiles = sortFiles(
+ mergeMetadata(action.files),
+ );
+ const normalFiles = deriveFiles(
+ lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
- ...stateForUpdatedFiles(state, files),
- lastSyncedFiles,
+ ...stateForUpdatedNormalFiles(state, normalFiles),
+ lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
});
}
- case "fetchFiles": {
+ case "fetchNormalFiles": {
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
action.files,
);
-
- const lastSyncedFiles = sortFiles(
+ const lastSyncedNormalFiles = sortFiles(
mergeMetadata(
getLatestVersionFiles(
- state.lastSyncedFiles.concat(action.files),
+ state.lastSyncedNormalFiles.concat(action.files),
),
),
);
- const files = deriveNormalOrHiddenFiles(
- lastSyncedFiles,
+ const normalFiles = deriveFiles(
+ lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
- ...stateForUpdatedFiles(state, files),
- lastSyncedFiles,
+ ...stateForUpdatedNormalFiles(state, normalFiles),
+ lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
});
}
- case "uploadFile": {
+ case "uploadNormalFile": {
// TODO: Consider batching this instead of doing it per file
// upload to speed up uploads. Perf test first though.
- const lastSyncedFiles = sortFiles([
- ...state.lastSyncedFiles,
+ const lastSyncedNormalFiles = sortFiles([
+ ...state.lastSyncedNormalFiles,
action.file,
]);
- const files = deriveNormalOrHiddenFiles(
- lastSyncedFiles,
+ const normalFiles = deriveFiles(
+ lastSyncedNormalFiles,
state.unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles({
- ...stateForUpdatedFiles(state, files),
- lastSyncedFiles,
+ ...stateForUpdatedNormalFiles(state, normalFiles),
+ lastSyncedNormalFiles,
});
}
@@ -765,13 +757,12 @@ const galleryReducer: React.Reducer = (
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
- action.hiddenFiles,
+ action.files,
);
-
const lastSyncedHiddenFiles = sortFiles(
- mergeMetadata(action.hiddenFiles),
+ mergeMetadata(action.files),
);
- const hiddenFiles = deriveNormalOrHiddenFiles(
+ const hiddenFiles = deriveFiles(
lastSyncedHiddenFiles,
unsyncedPrivateMagicMetadataUpdates,
);
@@ -787,17 +778,16 @@ const galleryReducer: React.Reducer = (
const unsyncedPrivateMagicMetadataUpdates =
prunedUnsyncedPrivateMagicMetadataUpdates(
state.unsyncedPrivateMagicMetadataUpdates,
- action.hiddenFiles,
+ action.files,
);
-
const lastSyncedHiddenFiles = sortFiles(
mergeMetadata(
getLatestVersionFiles(
- state.lastSyncedHiddenFiles.concat(action.hiddenFiles),
+ state.lastSyncedHiddenFiles.concat(action.files),
),
),
);
- const hiddenFiles = deriveNormalOrHiddenFiles(
+ const hiddenFiles = deriveFiles(
lastSyncedHiddenFiles,
unsyncedPrivateMagicMetadataUpdates,
);
@@ -812,12 +802,12 @@ const galleryReducer: React.Reducer = (
case "setTrashedFiles":
return stateByUpdatingFilteredFiles({
...state,
- trashedFiles: action.trashedFiles,
- collectionSummaries: deriveCollectionSummaries(
+ trashedFiles: action.files,
+ normalCollectionSummaries: deriveNormalCollectionSummaries(
state.user!,
- state.collections,
- state.files,
- action.trashedFiles,
+ state.normalCollections,
+ state.normalFiles,
+ action.files,
state.archivedFileIDs,
),
});
@@ -875,6 +865,41 @@ const galleryReducer: React.Reducer = (
tempHiddenFileIDs: new Set(),
});
+ case "addPendingFavoriteUpdate": {
+ const pendingFavoriteUpdates = new Set(
+ state.pendingFavoriteUpdates,
+ );
+ pendingFavoriteUpdates.add(action.fileID);
+ return { ...state, pendingFavoriteUpdates };
+ }
+
+ case "removePendingFavoriteUpdate": {
+ const pendingFavoriteUpdates = new Set(
+ state.pendingFavoriteUpdates,
+ );
+ pendingFavoriteUpdates.delete(action.fileID);
+ return { ...state, pendingFavoriteUpdates };
+ }
+
+ case "unsyncedFavoriteUpdate": {
+ const unsyncedFavoriteUpdates = new Map(
+ state.unsyncedFavoriteUpdates,
+ );
+ unsyncedFavoriteUpdates.set(action.fileID, action.isFavorite);
+
+ // Skipping a call to stateByUpdatingFilteredFiles since it
+ // currently doesn't depend on favorites.
+ return {
+ ...state,
+ favoriteFileIDs: deriveFavoriteFileIDs(
+ state.normalCollections,
+ state.normalFiles,
+ unsyncedFavoriteUpdates,
+ ),
+ unsyncedFavoriteUpdates,
+ };
+ }
+
case "addPendingVisibilityUpdate": {
const pendingVisibilityUpdates = new Set(
state.pendingVisibilityUpdates,
@@ -901,63 +926,51 @@ const galleryReducer: React.Reducer = (
action.fileID,
action.privateMagicMetadata,
);
- const files = deriveNormalOrHiddenFiles(
- state.lastSyncedFiles,
+ const normalFiles = deriveFiles(
+ state.lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
+
return stateByUpdatingFilteredFiles({
- ...stateForUpdatedFiles(state, files),
+ ...stateForUpdatedNormalFiles(state, normalFiles),
unsyncedPrivateMagicMetadataUpdates,
});
}
- case "markUnsyncedFavoriteUpdate": {
- const unsyncedFavoriteUpdates = new Map(
- state.unsyncedFavoriteUpdates,
- );
- if (action.isFavorite === undefined) {
- unsyncedFavoriteUpdates.delete(action.fileID);
- } else {
- unsyncedFavoriteUpdates.set(action.fileID, action.isFavorite);
- }
- // Skipping a call to stateByUpdatingFilteredFiles since it
- // currently doesn't depend on favorites.
- return {
- ...state,
- favoriteFileIDs: deriveFavoriteFileIDs(
- state.collections,
- state.files,
- unsyncedFavoriteUpdates,
- ),
- unsyncedFavoriteUpdates,
- };
- }
-
case "clearUnsyncedState": {
+ const unsyncedFavoriteUpdates: GalleryState["unsyncedFavoriteUpdates"] =
+ new Map();
+ const favoriteFileIDs = deriveFavoriteFileIDs(
+ state.normalCollections,
+ state.normalFiles,
+ unsyncedFavoriteUpdates,
+ );
+
const unsyncedPrivateMagicMetadataUpdates: GalleryState["unsyncedPrivateMagicMetadataUpdates"] =
new Map();
-
- const files = deriveNormalOrHiddenFiles(
- state.lastSyncedFiles,
+ const normalFiles = deriveFiles(
+ state.lastSyncedNormalFiles,
unsyncedPrivateMagicMetadataUpdates,
);
- const hiddenFiles = deriveNormalOrHiddenFiles(
+ const hiddenFiles = deriveFiles(
state.lastSyncedHiddenFiles,
unsyncedPrivateMagicMetadataUpdates,
);
return stateByUpdatingFilteredFiles(
stateForUpdatedHiddenFiles(
- stateForUpdatedFiles(
+ stateForUpdatedNormalFiles(
{
...state,
+ favoriteFileIDs,
tempDeletedFileIDs: new Set(),
tempHiddenFileIDs: new Set(),
+ pendingFavoriteUpdates: new Set(),
pendingVisibilityUpdates: new Set(),
unsyncedPrivateMagicMetadataUpdates,
unsyncedFavoriteUpdates: new Map(),
},
- files,
+ normalFiles,
),
hiddenFiles,
),
@@ -1001,10 +1014,11 @@ const galleryReducer: React.Reducer = (
case "showAlbums": {
const { view, selectedCollectionSummaryID } =
deriveAlbumsViewAndSelectedID(
- state.collections,
- state.collectionSummaries,
+ state.normalCollections,
+ state.normalCollectionSummaries,
state.selectedCollectionSummaryID,
);
+
return stateByUpdatingFilteredFiles({
...state,
selectedCollectionSummaryID,
@@ -1018,7 +1032,7 @@ const galleryReducer: React.Reducer = (
});
}
- case "showNormalOrHiddenCollectionSummary":
+ case "showCollectionSummary":
return stateByUpdatingFilteredFiles({
...state,
selectedCollectionSummaryID: action.collectionSummaryID,
@@ -1037,7 +1051,7 @@ const galleryReducer: React.Reducer = (
: "albums",
activeCollectionSummaryID:
action.collectionSummaryID ?? ALL_SECTION,
- activeCollection: state.collections
+ activeCollection: state.normalCollections
.concat(state.hiddenCollections)
.find(({ id }) => id === action.collectionSummaryID),
},
@@ -1135,7 +1149,7 @@ export const useGalleryReducer = () =>
* Compute the effective files that we should use by overlaying the files we
* read from disk by any temporary unsynced updates.
*/
-const deriveNormalOrHiddenFiles = (
+const deriveFiles = (
files: EnteFile[],
unsyncedPrivateMagicMetadataUpdates: GalleryState["unsyncedPrivateMagicMetadataUpdates"],
) => {
@@ -1181,7 +1195,7 @@ const deriveHiddenFileIDs = (hiddenFiles: EnteFile[]) =>
*/
const deriveArchivedFileIDs = (
archivedCollectionIDs: GalleryState["archivedCollectionIDs"],
- files: GalleryState["files"],
+ files: GalleryState["normalFiles"],
) =>
new Set(
files
@@ -1203,7 +1217,7 @@ const deriveFavoriteFileIDs = (
) => {
let favoriteFileIDs = new Set();
for (const collection of collections) {
- if (collection.type === CollectionType.favorites) {
+ if (collection.type == "favorites") {
favoriteFileIDs = new Set(
files
.filter((file) => file.collectionID === collection.id)
@@ -1220,26 +1234,26 @@ const deriveFavoriteFileIDs = (
};
/**
- * Compute collection summaries from their dependencies.
+ * Compute normal (non-hidden) collection summaries from their dependencies.
*/
-const deriveCollectionSummaries = (
+const deriveNormalCollectionSummaries = (
user: User,
- collections: Collection[],
- files: EnteFile[],
+ normalCollections: Collection[],
+ normalFiles: EnteFile[],
trashedFiles: EnteFile[],
archivedFileIDs: Set,
) => {
- const collectionSummaries = createCollectionSummaries(
+ const normalCollectionSummaries = createCollectionSummaries(
user,
- collections,
- files,
+ normalCollections,
+ normalFiles,
);
- const uncategorizedCollection = collections.find(
- ({ type }) => type === CollectionType.uncategorized,
+ const uncategorizedCollection = normalCollections.find(
+ ({ type }) => type == "uncategorized",
);
if (!uncategorizedCollection) {
- collectionSummaries.set(DUMMY_UNCATEGORIZED_COLLECTION, {
+ normalCollectionSummaries.set(DUMMY_UNCATEGORIZED_COLLECTION, {
...pseudoCollectionOptionsForFiles([]),
id: DUMMY_UNCATEGORIZED_COLLECTION,
type: "uncategorized",
@@ -1248,15 +1262,18 @@ const deriveCollectionSummaries = (
});
}
- const allSectionFiles = findAllSectionVisibleFiles(files, archivedFileIDs);
- collectionSummaries.set(ALL_SECTION, {
+ const allSectionFiles = findAllSectionVisibleFiles(
+ normalFiles,
+ archivedFileIDs,
+ );
+ normalCollectionSummaries.set(ALL_SECTION, {
...pseudoCollectionOptionsForFiles(allSectionFiles),
id: ALL_SECTION,
type: "all",
attributes: ["all"],
name: t("section_all"),
});
- collectionSummaries.set(TRASH_SECTION, {
+ normalCollectionSummaries.set(TRASH_SECTION, {
...pseudoCollectionOptionsForFiles(trashedFiles),
id: TRASH_SECTION,
name: t("section_trash"),
@@ -1265,9 +1282,9 @@ const deriveCollectionSummaries = (
coverFile: undefined,
});
const archivedFiles = uniqueFilesByID(
- files.filter((file) => isArchivedFile(file)),
+ normalFiles.filter((file) => isArchivedFile(file)),
);
- collectionSummaries.set(ARCHIVE_SECTION, {
+ normalCollectionSummaries.set(ARCHIVE_SECTION, {
...pseudoCollectionOptionsForFiles(archivedFiles),
id: ARCHIVE_SECTION,
name: t("section_archive"),
@@ -1276,7 +1293,7 @@ const deriveCollectionSummaries = (
coverFile: undefined,
});
- return collectionSummaries;
+ return normalCollectionSummaries;
};
const pseudoCollectionOptionsForFiles = (files: EnteFile[]) => ({
@@ -1344,23 +1361,7 @@ const createCollectionSummaries = (
} else if (isPinnedCollection(collection)) {
type = "pinned";
} else {
- // Directly use the collection type
- // TODO: The constants can be aligned once collection type goes from
- // an enum to an union.
- switch (collection.type) {
- case CollectionType.folder:
- type = "folder";
- break;
- case CollectionType.favorites:
- type = "favorites";
- break;
- case CollectionType.album:
- type = "album";
- break;
- case CollectionType.uncategorized:
- type = "uncategorized";
- break;
- }
+ type = collection.type;
}
// This block of code duplicates the above. Such duplication is needed
@@ -1388,20 +1389,9 @@ const createCollectionSummaries = (
if (isPinnedCollection(collection)) {
attributes.push("pinned");
}
- switch (collection.type) {
- case CollectionType.folder:
- attributes.push("folder");
- break;
- case CollectionType.favorites:
- attributes.push("favorites");
- break;
- case CollectionType.album:
- attributes.push("album");
- break;
- case CollectionType.uncategorized:
- attributes.push("uncategorized");
- break;
- }
+ // TODO: Verify type before removing the null check.
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+ if (collection.type) attributes.push(collection.type);
let name: string;
if (type == "uncategorized") {
@@ -1467,7 +1457,7 @@ const isIncomingCollabShare = (collection: Collection, user: User) => {
// TODO: Need to audit the types
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const sharee = collection.sharees?.find((sharee) => sharee.id === user.id);
- return sharee?.role === COLLECTION_ROLE.COLLABORATOR;
+ return sharee?.role == "COLLABORATOR";
};
const isOutgoingShare = (collection: Collection, user: User) =>
@@ -1492,8 +1482,8 @@ const findAllSectionVisibleFiles = (
* changed.
*/
const deriveAlbumsViewAndSelectedID = (
- collections: GalleryState["collections"],
- collectionSummaries: GalleryState["collectionSummaries"],
+ collections: GalleryState["normalCollections"],
+ collectionSummaries: GalleryState["normalCollectionSummaries"],
selectedCollectionSummaryID: GalleryState["selectedCollectionSummaryID"],
) => {
// Make sure that the last selected ID is still valid by searching for it.
@@ -1631,30 +1621,34 @@ const derivePeopleView = (
/**
* Return a new state from the given {@link state} by recomputing all properties
- * that depend on file using the provided {@link files}.
+ * that depend on normal (non-hidden) files, using the provided
+ * {@link normalFiles}.
*
* Usually, we update state by manually dependency tracking on a fine grained
* basis, but it results in a duplicate code when the files themselves change,
* since they effect many things. This is a convenience function for updating
- * everything that needs to change when the files themselves change.
+ * everything that needs to change when the normal files themselves change.
*/
-const stateForUpdatedFiles = (
+const stateForUpdatedNormalFiles = (
state: GalleryState,
- files: GalleryState["files"],
-) => ({
+ normalFiles: GalleryState["normalFiles"],
+): GalleryState => ({
...state,
- files,
- archivedFileIDs: deriveArchivedFileIDs(state.archivedCollectionIDs, files),
+ normalFiles,
+ archivedFileIDs: deriveArchivedFileIDs(
+ state.archivedCollectionIDs,
+ normalFiles,
+ ),
favoriteFileIDs: deriveFavoriteFileIDs(
- state.collections,
- files,
+ state.normalCollections,
+ normalFiles,
state.unsyncedFavoriteUpdates,
),
- fileCollectionIDs: createFileCollectionIDs(files),
- collectionSummaries: deriveCollectionSummaries(
+ fileNormalCollectionIDs: createFileCollectionIDs(normalFiles),
+ normalCollectionSummaries: deriveNormalCollectionSummaries(
state.user!,
- state.collections,
- files,
+ state.normalCollections,
+ normalFiles,
state.trashedFiles,
state.archivedFileIDs,
),
@@ -1667,17 +1661,17 @@ const stateForUpdatedFiles = (
/**
* Return a new state from the given {@link state} by recomputing all properties
- * that depend on file using the provided {@link hiddenFiles}.
+ * that depend on hidden files, using the provided {@link hiddenFiles}.
*
* Usually, we update state by manually dependency tracking on a fine grained
* basis, but it results in a duplicate code when the hidden files themselves
* change, since they effect a few things. This is a convenience function for
- * updating everything that needs to change when the hiddenFiles change.
+ * updating everything that needs to change when the hidden files change.
*/
const stateForUpdatedHiddenFiles = (
state: GalleryState,
hiddenFiles: GalleryState["hiddenFiles"],
-) => ({
+): GalleryState => ({
...state,
hiddenFiles,
hiddenFileIDs: deriveHiddenFileIDs(hiddenFiles),
@@ -1704,7 +1698,7 @@ const stateByUpdatingFilteredFiles = (state: GalleryState) => {
return { ...state, filteredFiles };
} else if (state.view?.type == "albums") {
const filteredFiles = deriveAlbumsFilteredFiles(
- state.files,
+ state.normalFiles,
state.trashedFiles,
state.hiddenFileIDs,
state.archivedCollectionIDs,
@@ -1724,7 +1718,7 @@ const stateByUpdatingFilteredFiles = (state: GalleryState) => {
return { ...state, filteredFiles };
} else if (state.view?.type == "people") {
const filteredFiles = derivePeopleFilteredFiles(
- state.files,
+ state.normalFiles,
state.view,
);
return { ...state, filteredFiles };
@@ -1738,7 +1732,7 @@ const stateByUpdatingFilteredFiles = (state: GalleryState) => {
* the dependencies change.
*/
const deriveAlbumsFilteredFiles = (
- files: GalleryState["files"],
+ normalFiles: GalleryState["normalFiles"],
trashedFiles: GalleryState["trashedFiles"],
hiddenFileIDs: GalleryState["hiddenFileIDs"],
archivedCollectionIDs: GalleryState["archivedCollectionIDs"],
@@ -1753,11 +1747,11 @@ const deriveAlbumsFilteredFiles = (
if (activeCollectionSummaryID === TRASH_SECTION) {
return uniqueFilesByID([
...trashedFiles,
- ...files.filter((file) => tempDeletedFileIDs.has(file.id)),
+ ...normalFiles.filter((file) => tempDeletedFileIDs.has(file.id)),
]);
}
- const filteredFiles = files.filter((file) => {
+ const filteredFiles = normalFiles.filter((file) => {
if (tempDeletedFileIDs.has(file.id)) return false;
if (hiddenFileIDs.has(file.id)) return false;
if (tempHiddenFileIDs.has(file.id)) return false;
@@ -1851,12 +1845,12 @@ const sortAndUniqueFilteredFiles = (
* the dependencies change.
*/
const derivePeopleFilteredFiles = (
- files: GalleryState["files"],
+ normalFiles: GalleryState["normalFiles"],
view: Extract,
) => {
const pfSet = new Set(view.activePerson?.fileIDs ?? []);
return uniqueFilesByID(
- files.filter(({ id }) => {
+ normalFiles.filter(({ id }) => {
if (!pfSet.has(id)) return false;
return true;
}),
diff --git a/web/packages/new/photos/components/sidebar/TwoFactorSettings.tsx b/web/packages/new/photos/components/sidebar/TwoFactorSettings.tsx
index a1958d5460..9118b83b3b 100644
--- a/web/packages/new/photos/components/sidebar/TwoFactorSettings.tsx
+++ b/web/packages/new/photos/components/sidebar/TwoFactorSettings.tsx
@@ -12,8 +12,7 @@ import {
} from "@/base/components/mui/SidebarDrawer";
import { useBaseContext } from "@/base/context";
import { disable2FA, get2FAStatus } from "@/new/photos/services/user";
-import { PHOTOS_PAGES as PAGES } from "@ente/shared/constants/pages";
-import { LS_KEYS, getData, setLSUser } from "@ente/shared/storage/localStorage";
+import { getData, setLSUser } from "@ente/shared/storage/localStorage";
import LockIcon from "@mui/icons-material/Lock";
import { Stack, Typography } from "@mui/material";
import { t } from "i18next";
@@ -29,7 +28,7 @@ export const TwoFactorSettings: React.FC<
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const isTwoFactorEnabled =
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
- getData(LS_KEYS.USER).isTwoFactorEnabled ?? false;
+ getData("user").isTwoFactorEnabled ?? false;
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
setIsTwoFactorEnabled(isTwoFactorEnabled);
}, []);
@@ -41,7 +40,7 @@ export const TwoFactorSettings: React.FC<
setIsTwoFactorEnabled(isEnabled);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await setLSUser({
- ...getData(LS_KEYS.USER),
+ ...getData("user"),
isTwoFactorEnabled: isEnabled,
});
})();
@@ -83,7 +82,7 @@ const SetupDrawerContents: React.FC = ({ onRootClose }) => {
const configure = () => {
onRootClose();
- void router.push(PAGES.TWO_FACTOR_SETUP);
+ void router.push("/two-factor/setup");
};
return (
@@ -122,10 +121,7 @@ const ManageDrawerContents: React.FC = ({ onRootClose }) => {
const disable = async () => {
await disable2FA();
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
- await setLSUser({
- ...getData(LS_KEYS.USER),
- isTwoFactorEnabled: false,
- });
+ await setLSUser({ ...getData("user"), isTwoFactorEnabled: false });
onRootClose();
};
@@ -142,7 +138,7 @@ const ManageDrawerContents: React.FC = ({ onRootClose }) => {
const reconfigure = async () => {
onRootClose();
- await router.push(PAGES.TWO_FACTOR_SETUP);
+ await router.push("/two-factor/setup");
};
return (
diff --git a/web/packages/new/photos/services/collection.ts b/web/packages/new/photos/services/collection.ts
index 5e2a411e10..1a5a9fe54f 100644
--- a/web/packages/new/photos/services/collection.ts
+++ b/web/packages/new/photos/services/collection.ts
@@ -1,7 +1,7 @@
import { encryptBoxB64 } from "@/base/crypto";
import { authenticatedRequestHeaders, ensureOk } from "@/base/http";
import { apiURL } from "@/base/origins";
-import { SUB_TYPE, type Collection } from "@/media/collection";
+import { CollectionSubType, type Collection } from "@/media/collection";
import { type EnteFile } from "@/media/file";
import { ItemVisibility } from "@/media/file-metadata";
import { batch } from "@/utils/array";
@@ -32,7 +32,7 @@ export const ALL_SECTION = 0;
export const isDefaultHiddenCollection = (collection: Collection) =>
// TODO: Need to audit the types
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
- collection.magicMetadata?.data.subType === SUB_TYPE.DEFAULT_HIDDEN;
+ collection.magicMetadata?.data.subType == CollectionSubType.defaultHidden;
/**
* Extract the IDs of all the "default" hidden collections.
diff --git a/web/packages/new/photos/services/collection/ui.ts b/web/packages/new/photos/services/collection/ui.ts
index 6b9340def6..104fbe7352 100644
--- a/web/packages/new/photos/services/collection/ui.ts
+++ b/web/packages/new/photos/services/collection/ui.ts
@@ -1,12 +1,10 @@
+import type { CollectionType } from "@/media/collection";
import type { EnteFile } from "@/media/file";
export type CollectionSummaryType =
- | "folder"
- | "favorites"
- | "album"
+ | CollectionType
| "archive"
| "trash"
- | "uncategorized"
| "all"
| "outgoingShare"
| "incomingShareViewer"
diff --git a/web/packages/new/photos/services/collections.ts b/web/packages/new/photos/services/collections.ts
index 8dd08a6d58..13e8dba874 100644
--- a/web/packages/new/photos/services/collections.ts
+++ b/web/packages/new/photos/services/collections.ts
@@ -29,7 +29,7 @@ import {
} from "@/new/photos/services/files";
import HTTPService from "@ente/shared/network/HTTPService";
import localForage from "@ente/shared/storage/localForage";
-import { getData, LS_KEYS } from "@ente/shared/storage/localStorage";
+import { getData } from "@ente/shared/storage/localStorage";
import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { getActualKey } from "@ente/shared/user";
import { isHiddenCollection } from "./collection";
@@ -200,7 +200,7 @@ export const getCollectionWithSecrets = async (
masterKey: string,
): Promise => {
const cryptoWorker = await sharedCryptoWorker();
- const userID = getData(LS_KEYS.USER).id;
+ const userID = getData("user").id;
let collectionKey: string;
if (collection.owner.id === userID) {
collectionKey = await cryptoWorker.decryptB64(
@@ -209,7 +209,7 @@ export const getCollectionWithSecrets = async (
masterKey,
);
} else {
- const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
+ const keyAttributes = getData("keyAttributes");
const secretKey = await cryptoWorker.decryptB64(
keyAttributes.encryptedSecretKey,
keyAttributes.secretKeyDecryptionNonce,
diff --git a/web/packages/new/photos/services/files.ts b/web/packages/new/photos/services/files.ts
index 61c1e4e90b..d46fd10646 100644
--- a/web/packages/new/photos/services/files.ts
+++ b/web/packages/new/photos/services/files.ts
@@ -33,7 +33,7 @@ export const getAllLocalFiles = async () =>
* "hidden" to get it to instead return hidden files that we know about locally.
*/
export const getLocalFiles = async (type: "normal" | "hidden" = "normal") => {
- const tableName = type === "normal" ? FILES_TABLE : HIDDEN_FILES_TABLE;
+ const tableName = type == "normal" ? FILES_TABLE : HIDDEN_FILES_TABLE;
const files: EnteFile[] =
(await localForage.getItem(tableName)) ?? [];
return files;
@@ -48,7 +48,7 @@ export const setLocalFiles = async (
type: "normal" | "hidden",
files: EnteFile[],
) => {
- const tableName = type === "normal" ? FILES_TABLE : HIDDEN_FILES_TABLE;
+ const tableName = type == "normal" ? FILES_TABLE : HIDDEN_FILES_TABLE;
await localForage.setItem(tableName, files);
};
diff --git a/web/packages/new/photos/services/ml/ml-data.ts b/web/packages/new/photos/services/ml/ml-data.ts
index fc6313a25f..a152f12d1b 100644
--- a/web/packages/new/photos/services/ml/ml-data.ts
+++ b/web/packages/new/photos/services/ml/ml-data.ts
@@ -1,10 +1,10 @@
import { decryptBlob } from "@/base/crypto";
import log from "@/base/log";
+import { fetchFilesData, putFileData } from "@/gallery/services/file-data";
import type { EnteFile } from "@/media/file";
import { nullToUndefined } from "@/utils/transform";
import { z } from "zod";
import { gunzip, gzip } from "../../utils/gzip";
-import { fetchFileData, putFileData } from "../file-data";
import { type RemoteCLIPIndex } from "./clip";
import { type RemoteFaceIndex } from "./face";
@@ -153,7 +153,7 @@ const ParsedRemoteMLData = z.object({
export const fetchMLData = async (
filesByID: Map,
): Promise