Compare commits

...

441 Commits

Author SHA1 Message Date
ashilkn
87fae3e6d9 Resolve merge conflicts and merge main 2025-05-27 19:16:31 +05:30
Ashil
89cd360f93 [mob][photos] Bump up to v1.1.0 (#6065) 2025-05-27 19:15:03 +05:30
ashilkn
f1274afdd4 Bump up to v1.1.0 2025-05-27 19:09:55 +05:30
ashilkn
0a5005d064 Add scrollbar for album widget settings screen 2025-05-27 19:06:16 +05:30
ashilkn
b54fe20520 chore 2025-05-27 18:46:18 +05:30
ashilkn
204a046e0a Merge branch 'main' into widget-superpowered 2025-05-27 18:44:52 +05:30
Ashil
4f21f1e94e [mob][photos] All albums screen UI/UX and performance improvements (#6060)
<img
src="https://github.com/user-attachments/assets/c9ca2050-9e5c-48c5-b01e-7ed89885bc6b"
width="200" height="450" alt="Image 1">
<img
src="https://github.com/user-attachments/assets/39aeda32-9f68-4d2f-b156-7b9312578435"
width="200" height="450" alt="Image 2">

Plus some improvements from @ashilkn
2025-05-27 18:43:40 +05:30
ashilkn
039866cf3b Chore: fix lint warning 2025-05-27 18:42:39 +05:30
ashilkn
c4b860a8fe Use SliverPrototypeExtentList instead of just SliverList for improved (scrolling?) performance 2025-05-27 18:35:56 +05:30
ashilkn
1d1e01898f Add scrollbar to all on ente albums page 2025-05-27 18:19:04 +05:30
ashilkn
53f947b5f0 Update arrow icon size 2025-05-27 18:10:17 +05:30
Manav Rathi
1e3a112c35 [desktop] Tweak changelog entry (#6064) 2025-05-27 17:51:15 +05:30
Manav Rathi
3dc23092a4 tweak 2025-05-27 17:48:47 +05:30
Manav Rathi
fd65e81079 [desktop] Enable stream generation for non-internal users (#6063) 2025-05-27 17:40:12 +05:30
Manav Rathi
eec0480618 [web] New translations (#6062)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-27 17:35:48 +05:30
Manav Rathi
fac5ab5079 [desktop] Enable stream generation for non-internal users 2025-05-27 17:34:13 +05:30
Ashil
051ce42ae6 [mob][photos] Home widget improvements (#6059)
## Description

See commits
2025-05-27 17:32:17 +05:30
Crowdin Bot
297d4bdbf5 New Crowdin translations by GitHub Action 2025-05-27 11:39:57 +00:00
Manav Rathi
9f9ad19d4b [web] Show full uploader name (#6061) 2025-05-27 17:09:22 +05:30
ashilkn
4d26de8ffd Add safety check 2025-05-27 17:05:46 +05:30
Manav Rathi
f16846b82e Added by 2025-05-27 16:49:08 +05:30
ashilkn
b44ef9f68a Prevent infinite loops 2025-05-27 16:45:37 +05:30
AmanRajSinghMourya
cf28fddfb3 Fix popup sheet background color 2025-05-27 16:17:42 +05:30
ashilkn
6c3b2ee25e Randomize memories and files shown in memories widget 2025-05-27 15:58:04 +05:30
Manav Rathi
2d8310460b [web] Use path prefix as context when collating metadata and live photos (#6058)
Fixes: 
- https://github.com/ente-io/ente/discussions/5920
- https://github.com/ente-io/ente/discussions/5950
2025-05-27 15:52:44 +05:30
Manav Rathi
0d5363c7a1 Fix typo 2025-05-27 15:48:14 +05:30
Manav Rathi
2f277bbffc lf 2025-05-27 15:38:16 +05:30
Manav Rathi
cbf3340bf2 Handle lp retry 2025-05-27 15:19:16 +05:30
Manav Rathi
de918f42e6 Retain metadata 2025-05-27 15:05:37 +05:30
Manav Rathi
6bd1547e09 Impl 2025-05-27 15:05:37 +05:30
Manav Rathi
aa70b2a437 spl 2025-05-27 15:05:37 +05:30
Manav Rathi
13b74f387f reuse 2025-05-27 15:05:37 +05:30
Manav Rathi
d52e3894d8 Move 2025-05-27 15:05:37 +05:30
Manav Rathi
780c2c2493 Outline 2025-05-27 15:05:37 +05:30
Manav Rathi
405c4d1258 [web] New translations (#6057)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-27 15:05:15 +05:30
Crowdin Bot
5f498b01ee New Crowdin translations by GitHub Action 2025-05-27 09:33:56 +00:00
Manav Rathi
af5020e62c [web] General refactoring (#6056) 2025-05-27 15:03:10 +05:30
Manav Rathi
7ddf0f6fe1 lf 2025-05-27 14:54:15 +05:30
ashilkn
5fa951ad4b Refactor people widget settings screen 2025-05-27 14:51:23 +05:30
ashilkn
e9ceb705f6 Sort album widget settings screen's albums, showing selected ones on top. Note that sorting doesn't happen when selection is modified on the screen and only once when it's built 2025-05-27 14:38:08 +05:30
ashilkn
9dcd9d63b2 Avoid using shrinkWrap 2025-05-27 13:43:49 +05:30
ashilkn
129e9f8f49 Avoid adding empty albums in _getAlbumsWithFiles() 2025-05-27 12:32:39 +05:30
ashilkn
6f02df19c6 Improve UI of widget's empty state 2025-05-27 12:31:59 +05:30
ashilkn
c8efc1a590 Randomize albums and files shown in album widget 2025-05-27 12:02:07 +05:30
ashilkn
8b1a659d68 Avoid sorting on selecting albums in album widget settings 2025-05-27 11:47:39 +05:30
Manav Rathi
9114fbca27 Update 2025-05-27 10:55:01 +05:30
Manav Rathi
e25d71a7d4 cb 2025-05-27 10:25:18 +05:30
Manav Rathi
1018765f7c [web] General refactoring (#6054) 2025-05-27 10:00:26 +05:30
Manav Rathi
0fb984d031 missing dep 2025-05-27 09:53:16 +05:30
Manav Rathi
4ad3560387 Move 2025-05-27 08:49:00 +05:30
Manav Rathi
482b175324 Move 2025-05-27 08:40:10 +05:30
Manav Rathi
894d7382e8 inline 2025-05-27 08:29:11 +05:30
Manav Rathi
53cc78d3e3 Inline 2025-05-27 08:25:29 +05:30
Manav Rathi
a634500e55 Inline 2025-05-27 08:20:53 +05:30
Manav Rathi
ee8ecd456c [web] General refactoring (#6052) 2025-05-27 08:18:07 +05:30
Manav Rathi
d69a22a73e Fix 2025-05-27 08:08:44 +05:30
Manav Rathi
8b1af42cf0 Conv 2025-05-27 08:04:42 +05:30
Manav Rathi
41e7d0056b Swap 2025-05-27 07:48:30 +05:30
Manav Rathi
d170789446 Update 2025-05-27 07:42:33 +05:30
Manav Rathi
afbbde5f2b Update 2025-05-27 07:31:29 +05:30
Manav Rathi
4e3112a4f6 Conv 2025-05-27 07:25:31 +05:30
Manav Rathi
a4950ece53 Tweak vis 2025-05-27 07:21:36 +05:30
Manav Rathi
1a01d759b0 Fix ellipsis 2025-05-27 07:19:18 +05:30
Manav Rathi
175b51fdb3 Improve visual look 2025-05-27 07:01:18 +05:30
Manav Rathi
a4ba2edc54 Update 2025-05-27 06:31:44 +05:30
Manav Rathi
1a8a26e9e4 Update 2025-05-27 05:49:27 +05:30
Laurens Priem
a2ddcfd34f [mob][photos] Minor ML improvements (#6043)
## Description

- Expose flag for when ML and Memories is running
- UI fix for deleting all files in cluster 
- Log times ML models are loaded

## Tests

Tested in debug mode on my pixel 8.
2025-05-26 21:44:33 +05:30
Manav Rathi
95700f52f6 [web] General refactoring (#6047) 2025-05-26 20:15:45 +05:30
Manav Rathi
fc16638bfe Redo 2025-05-26 19:47:16 +05:30
Manav Rathi
5d375eb837 Move 2025-05-26 19:42:24 +05:30
Ashil
fe86d3bb34 [mob][photos] Make widget settings pages less confusing on their empty states (#6046) 2025-05-26 19:37:53 +05:30
Manav Rathi
77956d0f67 Rename 2025-05-26 19:37:04 +05:30
ashilkn
53a22a8d58 chore 2025-05-26 19:32:21 +05:30
ashilkn
a5b178d283 Extract strings 2025-05-26 19:30:54 +05:30
Manav Rathi
e651c1e328 inline 3 2025-05-26 19:24:36 +05:30
ashilkn
9069975bf0 Avoid confusion on empty widget settings pages 2025-05-26 19:22:51 +05:30
Manav Rathi
5938e755ae wip 2 2025-05-26 18:38:18 +05:30
Manav Rathi
6f7b3738b3 inline wip 1 2025-05-26 18:32:24 +05:30
Manav Rathi
4ee9f45b3a Inline 2025-05-26 18:15:45 +05:30
Manav Rathi
c835a3d009 Tweak 2025-05-26 18:11:06 +05:30
Manav Rathi
6d3e55a6d9 Inline 2025-05-26 18:08:11 +05:30
Ashil
08b7986d70 [mob][photos] Randomize people and file shown in people widget (#6044) 2025-05-26 18:06:17 +05:30
Manav Rathi
067c8b2a76 Tweak 2025-05-26 18:03:47 +05:30
Manav Rathi
d355d18acb Inline 2025-05-26 17:57:19 +05:30
ashilkn
0e2a0388ff Randomize people and thier files shown in people widget 2025-05-26 17:56:48 +05:30
Manav Rathi
2baf3a3dd7 Tweak 2025-05-26 17:54:56 +05:30
Manav Rathi
854610dd48 Inline 2025-05-26 17:53:11 +05:30
laurenspriem
61be57fef5 Log loading of ML models events 2025-05-26 17:39:04 +05:30
Manav Rathi
8d59d7e254 Update 2025-05-26 17:32:42 +05:30
Manav Rathi
1bcf728b3a Conv 2025-05-26 17:24:51 +05:30
Manav Rathi
5797be3460 Update 2025-05-26 17:17:27 +05:30
Manav Rathi
20f50e4816 Update 2025-05-26 17:11:18 +05:30
Manav Rathi
5064ebf4d3 Update 2025-05-26 17:01:15 +05:30
laurenspriem
eb783f0fff Remove redundant method 2025-05-26 16:44:06 +05:30
laurenspriem
ca8f310868 Fix duplicate notification issue 2025-05-26 16:43:15 +05:30
Neeraj
2e0a2802e7 [mob] Add change log (#6042)
## Description

## Tests
2025-05-26 16:33:47 +05:30
Neeraj Gupta
7868c2e16e Remove unused entries 2025-05-26 16:31:34 +05:30
Neeraj Gupta
ace5dc04e2 Add change log 2025-05-26 16:30:11 +05:30
laurenspriem
4249491730 More logging 2025-05-26 16:16:53 +05:30
laurenspriem
a958380a1d More logging 2025-05-26 15:56:23 +05:30
Manav Rathi
b0d940e65b [web] New translations (#6039)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-26 15:54:30 +05:30
Crowdin Bot
5b8472b5a9 New Crowdin translations by GitHub Action 2025-05-26 10:23:27 +00:00
Manav Rathi
6bb7627d47 [web] Minor loose ends (#6038) 2025-05-26 15:52:52 +05:30
laurenspriem
b00c406b09 Extract string 2025-05-26 15:52:45 +05:30
laurenspriem
ff9494d438 Setting to disable memories notifications 2025-05-26 15:51:59 +05:30
Neeraj
b24b5893ae [mob] Fix: Hide both shared and collect files (#6023) 2025-05-26 15:46:46 +05:30
Manav Rathi
9716ff80c4 tr 2025-05-26 15:34:37 +05:30
Manav Rathi
2808f72233 yes 2025-05-26 15:00:37 +05:30
Manav Rathi
5dd097ee09 ditto 2025-05-26 14:58:34 +05:30
Ashil
be9fddf1d4 [mob][photos] Avoid reordering selected faces (#6037) 2025-05-26 14:43:15 +05:30
ashilkn
f9b3f6e9eb Avoid reordering selected faces 2025-05-26 14:39:16 +05:30
laurenspriem
dcb73abdec Log time of scheduled notificaiton 2025-05-26 14:33:39 +05:30
ashilkn
a14c6f4d26 Merge branch 'main' into widget-superpowered 2025-05-26 14:24:35 +05:30
laurenspriem
7afdfe6ed9 Fix delete all files from person 2025-05-26 14:16:59 +05:30
Manav Rathi
8ff8981b76 Fix close button color on download failure notification 2025-05-26 13:54:02 +05:30
Manav Rathi
b89f247f42 Reduce unhandled exception logspam on transient network issues 2025-05-26 13:40:42 +05:30
Neeraj
c3e5a037c0 [auth] New translations (#6035)
New translations from
[Crowdin](https://crowdin.com/project/ente-authenticator-app)
2025-05-26 11:46:16 +05:30
Neeraj
70a1894071 [mob] Explicitly exclude app data during D2D backup/transfer (#6028)
As it breaks ente photos anyway because of KeyStore AFAICT 
Tries to fix #6027
2025-05-26 11:44:41 +05:30
Neeraj
42453675b2 [auth] Add new icons & change Mistral icon (#6014)
## Description

- Add [AR24](https://www.ar24.fr/) icon
- Add [Finary](https://finary.com/) icon
- Change [Mistral](https://mistral.ai/) icon
2025-05-26 11:40:48 +05:30
laurenspriem
bdd09e12d8 More logs 2025-05-26 10:27:46 +05:30
laurenspriem
407ad41520 Test clearing with payload 2025-05-26 10:09:52 +05:30
Manav Rathi
185759d234 [infra] Allowlist x-client-version (#6036) 2025-05-26 09:54:07 +05:30
Manav Rathi
860760784a Update doc 2025-05-26 09:33:54 +05:30
Manav Rathi
de10292a84 [infra] Allowlist x-client-version 2025-05-26 09:31:29 +05:30
Manav Rathi
95f10e5a45 [web] New translations (#6033)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-26 08:38:45 +05:30
Crowdin Bot
eabacf24ad New Crowdin translations by GitHub Action 2025-05-26 03:06:46 +00:00
Crowdin Bot
61ffcfdc93 New Crowdin translations by GitHub Action 2025-05-26 01:17:57 +00:00
LucasMZ
0ade0a2807 Try to not allow backup from the system in D2D
As it breaks ente photos anyway because of KeyStore AFAICT
Tries to fix #6027
2025-05-25 08:51:36 -03:00
Neeraj
1e2fb13908 [auth] Add Oracle Cloud icon (#6020)
- Added Oracle Cloud SVG icon.
- Updated custom-icons.json to include the new icon.
2025-05-24 09:02:11 +05:30
Neeraj Gupta
856e126bc8 Fix: Hide both shared and collect files 2025-05-24 08:04:19 +05:30
Burak
845d014945 [auth] add Oracle Cloud icon
- Added Oracle Cloud SVG icon.
- Updated custom-icons.json to include the new icon.
2025-05-23 19:46:44 +03:00
Ashil
d8b54f5211 [mob][photos] Add files to multiple collections at once (#6019) 2025-05-23 20:37:17 +05:30
Ashil
bc059c861f Merge branch 'widget-superpowered' into collection_sheet_batch_operation 2025-05-23 20:34:06 +05:30
ashilkn
b52ee5bbfb bump up build number to 1052 2025-05-23 20:33:11 +05:30
ashilkn
93c85a57e4 Do remote sync irrespective of error when adding files to multiple collections 2025-05-23 20:23:08 +05:30
ashilkn
e01826217d Refactor 2025-05-23 20:11:44 +05:30
Aman Raj Singh Mourya
b79b7ff3ef Refactor addToMultipleCollections to improve error handling 2025-05-23 19:40:49 +05:30
Manav Rathi
7d52e3d852 [desktop] HLS - Avoid upscaling (#6018)
https://trac.ffmpeg.org/wiki/Scaling#AvoidingUpscaling
2025-05-23 18:29:20 +05:30
Laurens Priem
9a647d6f78 [mob][photos] Fixed crashes on 200MP photos (#6017)
## Description

- Fixed crashes on 200MP photos by decoding them at lower resolution (at
trade-off of zoom)
- Fixed a text overflow issue

## Tests

Tested on a separate build with multiple 200MP photos on my pixel 8.
2025-05-23 17:59:47 +05:30
laurenspriem
6e99206523 Merge branch 'main' into some_fixes 2025-05-23 17:44:50 +05:30
laurenspriem
d7af21aa84 Fix crashes on 200MP photos 2025-05-23 17:37:22 +05:30
Manav Rathi
ced1f6e164 Avoid upscaling
https://trac.ffmpeg.org/wiki/Scaling#AvoidingUpscaling
2025-05-23 17:19:54 +05:30
Manav Rathi
4ea3989a33 [desktop][web] Dependency updates (#6016)
\+ Electron 36 workaround
2025-05-23 16:57:05 +05:30
Vishnu Mohandas
641a99b823 [docs] Update export.md 2025-05-23 16:55:04 +05:30
Manav Rathi
7b48dbc1ad Dep updates 2025-05-23 16:47:54 +05:30
Manav Rathi
54c69e7aa5 Add workaround 2025-05-23 16:44:11 +05:30
Manav Rathi
f8bd8c9955 Dep 2025-05-23 16:40:04 +05:30
Manav Rathi
60246be861 [desktop] Multipart HLS video uploads (#6015) 2025-05-23 15:47:49 +05:30
Manav Rathi
d71016500a Equal sized parts (except last) 2025-05-23 15:33:29 +05:30
Aman Raj Singh Mourya
f44c2d14c7 Enable drag functionality in pick cover photo, person avatar, and center point widget. 2025-05-23 15:31:56 +05:30
Neeraj
9c26f4040a [server] Add multipart upload support for preview data (#5992)
## Description

## Tests
2025-05-23 15:31:11 +05:30
Manav Rathi
79e048b4b7 logout 2025-05-23 15:07:12 +05:30
Tanguy
5c0ce038d1 Change Mistral AI icon 2025-05-23 11:36:59 +02:00
Aman Raj Singh Mourya
2903388c94 Refactor CollectionActionSheet and improve UX 2025-05-23 14:48:36 +05:30
Tanguy
331a65d2a0 Add AR24 and Finary icons 2025-05-23 11:14:33 +02:00
Vishnu Mohandas
6c6ab8f463 [mob] Minor UI patch (#6013)
## Description
Increase the width of the container to prevent text overflow

## Tests
- [x] Tested on emulator
2025-05-23 14:03:22 +05:30
vishnukvmd
441a884314 Increase the width of the text container 2025-05-23 14:01:30 +05:30
Manav Rathi
3372d83c5d impl 2025-05-23 12:52:44 +05:30
Manav Rathi
0cf50513cc get 1 2025-05-23 12:39:54 +05:30
Neeraj
7ccf473190 [mob] Trust the user trust store (Android) (#5999)
## Description

It's currently not possible to use a server that has a CA that is
trusted by the _user_ trust store in Android.
This is generally due to a missing configuration of the
`networkSecurityConfig` (by default only system-level CAs are accepted).
  
With this change, the app should be able to reach out to servers that do
not use a publicly trusted CA (but that are still trusted by the user).

## Tests

None

## Remarks

I wasn't able to test my changes as the Flutter build fails with:


```
warning: [options] source value 8 is obsolete and will be removed in a future release
warning: [options] target value 8 is obsolete and will be removed in a future release
warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
$HOME/.pub-cache/git/ffmpeg-kit-6d5d27a8c259eda6292f204a27fba53da70af20e/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java:157: error: cannot find symbol
    public static void registerWith(final io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
                                                                                 ^
  symbol:   class Registrar
  location: interface PluginRegistry
$HOME/.pub-cache/git/ffmpeg-kit-6d5d27a8c259eda6292f204a27fba53da70af20e/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java:651: error: cannot find symbol
    protected void init(final BinaryMessenger messenger, final Context context, final Activity activity, final io.flutter.plugin.common.PluginRegistry.Registrar registrar, final ActivityPluginBinding activityBinding) {
                                                                                                                ^
  symbol:   class Registrar
  location: interface PluginRegistry
2 errors
3 warnings

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':ffmpeg_kit_flutter:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

* Try:
> Run with --info option to get more log output.
> Run with --scan to get full insights.

BUILD FAILED in 59s
```
2025-05-23 12:36:40 +05:30
laurenspriem
c1f7a01ed2 Fix text overflow issue 2025-05-23 12:31:46 +05:30
Aman Raj Singh Mourya
256243e273 Enable drag functionality in collection action sheet 2025-05-23 12:30:27 +05:30
Aman Raj Singh Mourya
dc9dc5d8f9 Single tap selection to select albums 2025-05-23 12:28:24 +05:30
Manav Rathi
6969385089 sketch 2 2025-05-23 12:27:54 +05:30
Manav Rathi
87a1c9417e sketch 1 wip 2025-05-23 12:04:34 +05:30
Manav Rathi
6d13ff5151 ver 2025-05-23 11:31:29 +05:30
Manav Rathi
0b5317867f ue 2025-05-23 11:22:20 +05:30
Manav Rathi
a32c8116a2 Use 2025-05-23 11:16:10 +05:30
Manav Rathi
d8cd81c702 desktop zod
we'll need it for parsing responses for requests we'll make subsequently
2025-05-23 11:11:33 +05:30
laurenspriem
18e7bbd1ed Extract strings for i18n for existing notifications 2025-05-23 10:41:27 +05:30
laurenspriem
63850df06a Change copy and extract string 2025-05-23 10:33:58 +05:30
Manav Rathi
886ab6d106 Tweak 2025-05-23 10:07:27 +05:30
Manav Rathi
d17296216c retry enhancements 2025-05-23 09:17:37 +05:30
Manav Rathi
55ee8b90b9 more conservative to prevent unforeseen loops 2025-05-23 08:45:04 +05:30
Prateek Sunal
634561347f chore: bump version 2025-05-22 23:52:05 +05:30
Prateek Sunal
575abdb8eb Merge remote-tracking branch 'origin/widget-superpowered' into widget-superpowered 2025-05-22 23:50:22 +05:30
Prateek Sunal
e998502b53 fix: add a status key to check if partial sync was did but a full is required now
(like previously widget was not their so it was fine to sync only 5 images but now since widget is there a full sync is compulsory)
2025-05-22 23:50:07 +05:30
laurenspriem
2ada68e837 Merge remote-tracking branch 'origin/widget-superpowered' into widget-superpowered 2025-05-22 22:41:04 +05:30
laurenspriem
28822a8dc1 Swallow notification scheduling issues 2025-05-22 22:38:24 +05:30
laurenspriem
deaa9a703d Bump for internal release 2025-05-22 22:26:02 +05:30
laurenspriem
4510edf8bd Update notification dependency 2025-05-22 22:24:59 +05:30
laurenspriem
7af59a1ecf Schedule test notifications 2025-05-22 22:24:40 +05:30
Denys Vitali
e003c783f5 fix: use only system CA for ente.io 2025-05-22 18:54:12 +02:00
Denys Vitali
379d2487bd Merge branch 'main' into feature/user-trust-store-android 2025-05-22 18:53:08 +02:00
Manav Rathi
8cdbb737dc Fix 2025-05-22 21:05:39 +05:30
Prateek Sunal
d528d97a0f fix: add got all widget logic 2025-05-22 21:00:48 +05:30
Prateek Sunal
682e4a913f fix: ui stuff 2025-05-22 20:52:13 +05:30
Manav Rathi
a72041b8ba cpkg 2025-05-22 20:29:29 +05:30
Prateek Sunal
ab1a8aa592 fix: don't repeat 2025-05-22 20:21:48 +05:30
Prateek Sunal
c37a0339d2 fix: default state ui 2025-05-22 20:18:41 +05:30
Manav Rathi
3b60f4954b Impl 2025-05-22 20:05:56 +05:30
Manav Rathi
b2ea248a5c Sketch 2025-05-22 19:58:39 +05:30
Prateek Sunal
1bda14fb6f fix: redirect with correct context 2025-05-22 19:57:08 +05:30
Manav Rathi
54e8d6392d Scaffold 2025-05-22 19:46:00 +05:30
Manav Rathi
afa9e03743 ref 2025-05-22 19:39:13 +05:30
Manav Rathi
a4eaf04a33 Extract 2025-05-22 19:34:39 +05:30
Manav Rathi
d30f0fba04 pc estimate 2025-05-22 19:27:57 +05:30
Prateek Sunal
b2855cfd72 fix: rank selected first 2025-05-22 19:20:16 +05:30
Prateek Sunal
06d260f40a fix: only allow selection 2025-05-22 19:04:21 +05:30
Manav Rathi
fb16346b0d Forward 2025-05-22 18:31:05 +05:30
Manav Rathi
41b1638838 Outline 2025-05-22 18:31:05 +05:30
Manav Rathi
702b3a8868 [desktop] Split x-client-package and x-client-version to match mobile (#6008) 2025-05-22 17:49:20 +05:30
Manav Rathi
3572c4328d str 2025-05-22 17:46:08 +05:30
Manav Rathi
1c2b8061dc Include "X-Client-Version" where applicable 2025-05-22 17:41:51 +05:30
Manav Rathi
a9edcead06 [desktop] Don't add version to x-client-package 2025-05-22 17:26:28 +05:30
laurenspriem
5a574c69d3 log debug notification options 2025-05-22 16:48:01 +05:30
Manav Rathi
192905b21e [web] Multipart changes - Finish (#6007)
Finishes the set of changes from
https://github.com/ente-io/ente/pull/5997 and
https://github.com/ente-io/ente/pull/6002.
2025-05-22 16:23:38 +05:30
Manav Rathi
52a533a1e1 Fin 2025-05-22 16:08:07 +05:30
Manav Rathi
0314e94359 Up 2 2025-05-22 15:56:00 +05:30
Neeraj Gupta
cbef1a9145 ios build changes 2025-05-22 15:53:59 +05:30
Aman Raj Singh Mourya
822c33940e Skip single tap action when selection mode is enabled 2025-05-22 15:53:06 +05:30
Manav Rathi
eb29c48f0e Up 1 2025-05-22 15:50:55 +05:30
Aman Raj Singh Mourya
c77b4f176c Refactor AlbumColumnItemWidget to improve selection handling and UI layout 2025-05-22 15:49:49 +05:30
Aman Raj Singh Mourya
afcc7b1e46 Add selection functionality and action buttons to collection action sheet 2025-05-22 15:26:49 +05:30
Manav Rathi
84dda89e15 up 2025-05-22 15:26:26 +05:30
Aman Raj Singh Mourya
4bbc0d1f46 Implement addToMultipleCollections method for batch adding files to collections 2025-05-22 15:26:07 +05:30
laurenspriem
aa6d6f4e77 Bump for internal release 2025-05-22 15:04:50 +05:30
Manav Rathi
ff26dd5652 Simplify 2025-05-22 15:04:37 +05:30
Manav Rathi
b68d95d481 normal put 2025-05-22 14:50:00 +05:30
laurenspriem
ec1b54cbb1 Merge branch 'main' into widget-superpowered 2025-05-22 14:46:00 +05:30
laurenspriem
459540fe7a Flag for ML running 2025-05-22 14:38:17 +05:30
Neeraj
2255ea1b92 [meta] Update mobile-internal-release.yml (#6005)
Include branch name

## Description

## Tests
2025-05-22 14:04:25 +05:30
Neeraj
ac704f1082 Update mobile-internal-release.yml
Include branch name
2025-05-22 14:04:04 +05:30
Laurens Priem
4db2e42ee3 [mob][photos] On this day memories + notification + fix (#5998)
## Description

- Added 'On this day' memory similar to [user
request](https://github.com/ente-io/ente/discussions/5852)
- 'On this day' memory gives a notification in the morning
- Fixed [other memories
issue](https://github.com/ente-io/ente/issues/5965)


## Tests

Tested in debug mode on my pixel 8:
- No caching issues
- 'On this day' memories are computed correctly
- Scheduled notifications come at correct time
- Tapping on notification directs to the memory
2025-05-22 13:17:06 +05:30
Manav Rathi
f5949f5bd4 [web] Multipart upload tweaks (#6002)
Refactoring this now before starting on the work on porting some of it
to desktop side.
2025-05-22 12:18:53 +05:30
Manav Rathi
c4feb4b764 in body 2025-05-22 12:13:37 +05:30
Manav Rathi
29bab5705b Sep 2025-05-22 11:40:50 +05:30
Manav Rathi
2ebeed3b6f Unused 2025-05-22 11:35:44 +05:30
Manav Rathi
a0dbcd3dbe Prune 2025-05-22 11:31:12 +05:30
Neeraj
81137652d4 Fix: Return correct status code for maxPassKey err (#6001)
## Description

## Tests
2025-05-22 11:29:55 +05:30
Manav Rathi
4e1418b11a package 2025-05-22 11:29:22 +05:30
Neeraj Gupta
91268341be Fix: Return correct status code for maxPassKey err 2025-05-22 11:27:31 +05:30
Manav Rathi
fb8fc051a9 wrkr 2025-05-22 11:15:28 +05:30
Manav Rathi
d99914c4e9 off by 1 2025-05-22 11:03:30 +05:30
Manav Rathi
736b3fc613 Upload progress 2025-05-22 09:08:52 +05:30
Manav Rathi
ef7f45aa3d Alt 2025-05-22 08:56:09 +05:30
Denys Vitali
4dc741151b fix(mobile): trust the user trust store (Android) 2025-05-22 02:14:11 +02:00
Manav Rathi
e4471af4cb Pass 2025-05-21 21:04:43 +05:30
Manav Rathi
057df349b7 Move retry to service 2025-05-21 20:47:28 +05:30
Manav Rathi
24c7b49132 custom 2025-05-21 19:39:36 +05:30
Manav Rathi
5df009c7c7 Revert because of ERR_H2_OR_QUIC_REQUIRED
Chrome throws ERR_H2_OR_QUIC_REQUIRED when we try to use a stream body on a
non-TLS HTTP request. This will break both dev setups on localhost, and perhaps
some self hosting setups, so is not a feasible path forward for an essential
endpoint to the use of the app.
2025-05-21 19:29:12 +05:30
Manav Rathi
1d276c795c transform 1 2025-05-21 17:56:09 +05:30
Manav Rathi
bc762b972f take 1 2025-05-21 17:39:58 +05:30
laurenspriem
36e4c06dd6 Merge branch 'main' into on_this_day 2025-05-21 17:15:55 +05:30
laurenspriem
ceb3d3fe42 Fix hidden persons in memories 2025-05-21 16:59:50 +05:30
laurenspriem
1dc806d270 Don't await on page route 2025-05-21 16:58:22 +05:30
laurenspriem
8d03df5c36 Remove old debug options 2025-05-21 16:57:56 +05:30
laurenspriem
a1ef8d33d3 Simplify notification ID 2025-05-21 16:56:51 +05:30
Manav Rathi
4f347c1afd [web] Remove unnecessary sax dependency by reworking multipart uploads (#5997) 2025-05-21 16:39:35 +05:30
laurenspriem
8171d56168 Route notification to memory 2025-05-21 16:35:57 +05:30
Manav Rathi
7e7751b5be Nicer 2025-05-21 16:27:25 +05:30
Manav Rathi
d19a0fccda Remove dependency 2025-05-21 16:22:52 +05:30
Manav Rathi
5b38ef394b More debug info 2025-05-21 16:10:27 +05:30
Manav Rathi
ad87470c25 2 2025-05-21 16:10:26 +05:30
Manav Rathi
67140fe7f2 s2 2025-05-21 16:10:26 +05:30
Manav Rathi
b372ba47ba Swap 2025-05-21 16:10:26 +05:30
Manav Rathi
24c66a9b6b impl 2025-05-21 16:10:26 +05:30
Manav Rathi
201ef60f07 Outline 2025-05-21 16:10:26 +05:30
Manav Rathi
89294f2a76 Outline 2025-05-21 16:10:26 +05:30
Manav Rathi
4772557f7a Tweak 2025-05-21 16:10:26 +05:30
Manav Rathi
073d2c5684 2 2025-05-21 16:10:26 +05:30
Manav Rathi
e022e7ae5b 1 2025-05-21 16:10:26 +05:30
Manav Rathi
2cdeb88b4d Outline 2025-05-21 16:10:26 +05:30
Neeraj
ca319e501e [mob][auth] Update copy for change email dialog (#5996)
## Description

## Tests
2025-05-21 15:32:05 +05:30
Neeraj Gupta
05898dfbe2 Update copy for change email dialog 2025-05-21 15:28:01 +05:30
Neeraj
c129cc15b5 [server] Increase file size limit 5 -> 10 GiB (#5995)
## Description

## Tests
2025-05-21 15:26:31 +05:30
Neeraj Gupta
a683883733 Increase file size limit 5 -> 10 GiB 2025-05-21 15:20:12 +05:30
laurenspriem
69b575cc66 Log cache update due to caching issue 2025-05-21 14:39:12 +05:30
laurenspriem
63a4972839 Fix caching issue 2025-05-21 14:37:38 +05:30
Neeraj
6188578d18 [docs] Update example config (#5951)
## Description
In my testing web apps only worked with https:// in front of them.
## Tests
2025-05-21 13:38:56 +05:30
laurenspriem
5a4d8950af Integrate notifications to OnThisDay memories 2025-05-21 12:36:04 +05:30
Neeraj
5007204944 [server] Change file_data.obj_size column type (#5994)
## Description

## Tests
Tested locally
2025-05-21 11:24:52 +05:30
Neeraj Gupta
4a19fc077e Change file_data.obj_size column type 2025-05-21 11:13:05 +05:30
Ashil
2b29f55587 [mob][photos] Album UI Revamp (#5661)
## Description
This update introduces a redesigned user interface for album management,
featuring a new layout for albums. Improve user experience by providing
intuitive navigation and efficient batch operations.

## Tests
1. A new grid & list layout for the album screen. The first cell is
dedicated to quickly adding new albums.
2. App Bar Enhancements
    - Sort Options: Organize albums by name, latest, or time.
    - View Toggle: Switch between grid and list views with ease.
    - Search Functionality: Quickly find albums using the search icon.
3. Long-press to select albums for batch actions. A bottom sheet
provides options to delete, share, hide, or pin selected albums.
2025-05-21 11:01:48 +05:30
laurenspriem
4cc8ff2fb1 Notification scheduling working 2025-05-21 10:57:49 +05:30
Aman Raj Singh Mourya
de29246304 move the collection.type == CollectionType.favorites check before isEmptyCollection check to handle the case where favourite collection is empty 2025-05-21 10:47:01 +05:30
laurenspriem
8deb52301a Android permissions for notifications 2025-05-21 10:30:01 +05:30
Manav Rathi
16a20e8b0d [web] Hash functions - Document and namespace (#5993)
No functional changes.
2025-05-21 08:56:29 +05:30
Manav Rathi
3824bfbdd5 namespace 2025-05-21 08:51:22 +05:30
Prateek Sunal
c996c794fd fix: launch people page before launching the file previewer 2025-05-21 08:47:03 +05:30
Manav Rathi
ef245e5c02 outline 2025-05-21 08:36:34 +05:30
Neeraj Gupta
4dc6890afc Add multipart upload support for preview data 2025-05-21 08:14:53 +05:30
Prateek Sunal
87195f3801 chore: fix incorrect widget count 2025-05-21 04:15:57 +05:30
Prateek Sunal
8ce45a4fa8 chore: bump version 2025-05-21 04:06:02 +05:30
Prateek Sunal
520e5d4ae7 fix: update routing 2025-05-21 04:01:37 +05:30
Prateek Sunal
2a8e167e42 fix: don't listen to collection route 2025-05-21 03:51:20 +05:30
Prateek Sunal
2f7bde36bd chore: bump version to 1.0.17 2025-05-21 03:27:49 +05:30
Prateek Sunal
ace375b7f6 fix: get effective selected people code 2025-05-21 03:27:38 +05:30
Prateek Sunal
cde6ebfa39 fix: pass and parse mainKey correctly 2025-05-21 03:12:19 +05:30
Prateek Sunal
a1e56a457f fix: update people default illustration 2025-05-21 03:04:21 +05:30
Prateek Sunal
a4ebf972e1 fix: count home widget for android 2025-05-21 02:56:32 +05:30
Prateek Sunal
7d5bed0493 fix: iOS build 2025-05-21 02:20:43 +05:30
Prateek Sunal
d449bd0f90 chore: update version 2025-05-21 02:16:48 +05:30
Prateek Sunal
5d14ca8439 fix: handle PeopleChangedEvent, add better limit for files, better behavior on save 2025-05-21 02:15:23 +05:30
Prateek Sunal
619f6795e2 fix: don't show un-named person 2025-05-21 01:44:12 +05:30
Prateek Sunal
04cd1d3bb3 fix: update code to look clean 2025-05-21 01:28:14 +05:30
Prateek Sunal
0960f189ce Merge remote-tracking branch 'origin/main' into widget-superpowered 2025-05-21 01:11:56 +05:30
Prateek Sunal
734b836a7a chore: update locals 2025-05-21 01:11:48 +05:30
Prateek Sunal
91447cdc77 fix: widgets code 2025-05-21 01:11:40 +05:30
Manav Rathi
961501a6fb [desktop] HLS newlines - Take 2 (#5990) 2025-05-20 20:07:22 +05:30
Manav Rathi
914893eae6 Fix 2025-05-20 20:01:44 +05:30
Manav Rathi
7a10f4c145 Note results of tests and add extra checks 2025-05-20 19:58:10 +05:30
ashilkn
092f64c3ca Refactor CollectionsFlexiGridViewWidget 2025-05-20 17:44:27 +05:30
laurenspriem
bdecb04398 Add timezone package for finding OS timezone 2025-05-20 17:38:04 +05:30
Neeraj
e25418e5a6 [server] Fix err handling during stream upload (#5986)
## Description

## Tests
2025-05-20 16:37:29 +05:30
Neeraj Gupta
a062c1ccc3 Fix err handling 2025-05-20 16:35:22 +05:30
Aman Raj Singh Mourya
d1ae4d52dd refactor: update padding and width to make sure thumbnail is perfect square 2025-05-20 16:04:53 +05:30
Manav Rathi
3c532cd4f4 [desktop] Fix HLS regex for Windows (#5984)
`$` eol should match both `\r\n` (windows) and `\n` (rest)
2025-05-20 16:02:56 +05:30
Manav Rathi
013389c696 Fix regex for Windows 2025-05-20 15:57:41 +05:30
Aman Raj Singh Mourya
43cdd10e85 Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-05-20 14:25:30 +05:30
Aman Raj Singh Mourya
539145d38d refactor: simplify layout calculations in flex grid view 2025-05-20 14:25:16 +05:30
ashilkn
6e4a856ea4 Use better colors 2025-05-20 11:57:19 +05:30
ashilkn
40ff361af1 Add Todo comment 2025-05-20 11:28:59 +05:30
laurenspriem
63b0cee589 Add timezone dependency for scheduling notifications 2025-05-20 09:13:56 +05:30
Prateek Sunal
574eea58fc fix: add robust logic for album home widget service 2025-05-20 07:06:57 +05:30
Prateek Sunal
138310b8f8 fix: update get collection by id function 2025-05-19 19:54:24 +05:30
Prateek Sunal
3d63ded84d fix: blockers, getter function for albums hw service 2025-05-19 19:54:09 +05:30
Prateek Sunal
2ff69f661e Merge branch 'main' into widget-superpowered 2025-05-19 19:20:26 +05:30
Prateek Sunal
10c65f13c8 fix: update get total function for memory home widget 2025-05-19 19:19:30 +05:30
Prateek Sunal
761c976d7e Merge remote-tracking branch 'origin/on_this_day' into widget-superpowered 2025-05-19 19:13:47 +05:30
Prateek Sunal
423a7eec37 fix: show on this day to both ml & non-ml users 2025-05-19 19:10:29 +05:30
Prateek Sunal
c8b23f80e2 feat: add selection and save/get from db for people widget settings 2025-05-19 18:53:41 +05:30
Prateek Sunal
d127199ade feat: complete save and selection logic for memories and albums settings 2025-05-19 17:35:33 +05:30
Aman Raj Singh Mourya
f44e90801f refractor: revert back copy of sort options 2025-05-19 17:23:25 +05:30
Aman Raj Singh Mourya
ded497d421 fix: make album sqaure and show file count 2025-05-19 17:22:08 +05:30
Prateek Sunal
22bae0292d feat: add new widget services 2025-05-19 14:04:42 +05:30
Prateek Sunal
4c7121fd6c chore: update generated messages 2025-05-19 14:04:19 +05:30
Prateek Sunal
f53745bbb0 Merge remote-tracking branch 'origin/album_UI_revamp' into widget-superpowered 2025-05-19 14:00:13 +05:30
ashilkn
1c6e343994 Use StatelessWidget instead of helper method 2025-05-19 13:51:52 +05:30
laurenspriem
2144f57ee0 remove null check 2025-05-19 11:08:00 +05:30
laurenspriem
476fe1b624 Assign IDs to memories 2025-05-19 11:06:39 +05:30
laurenspriem
ff705280c7 Rename variable 2025-05-18 11:58:42 +05:30
laurenspriem
6ff6594a81 Include onThisDay in widget api 2025-05-18 11:40:23 +05:30
laurenspriem
69f12125ec Merge branch 'memories_widget_api' into on_this_day 2025-05-18 11:26:53 +05:30
laurenspriem
862b11c530 Calc onThisDay even when ML is off 2025-05-18 11:23:05 +05:30
laurenspriem
e40afac212 Rename for clarity 2025-05-18 11:09:48 +05:30
Ferdinand Saurenbach
a880726f16 Update museum.md 2025-05-17 16:43:36 +02:00
Prateek Sunal
bffd4d83a5 fix: update the deep link 2025-05-16 18:41:21 +05:30
Aman Raj Singh Mourya
59a534225c [mob][photos] Refactor add participant page (#5940) 2025-05-16 17:49:02 +05:30
ashilkn
810ee3d9fe Merge album_UI_revamp after resolving merge conflicts 2025-05-16 16:19:45 +05:30
ashilkn
9605637e50 Refactor add participants page 2025-05-16 16:15:53 +05:30
laurenspriem
9016394ccc Integrate on this day into gallery memories 2025-05-16 15:08:40 +05:30
Prateek Sunal
a518bbd608 fix(home-widget): update default image caption & rename totalMemories 2025-05-16 15:07:45 +05:30
Aman Raj Singh Mourya
1c4ebcccb1 fix: allow to leave favourite albums 2025-05-16 14:44:48 +05:30
Aman Raj Singh Mourya
793fd5ba39 fix: avoid poping of delete dialog to avoid poping of main screen 2025-05-16 14:39:56 +05:30
Prateek Sunal
9b1eacf736 fix: update the preview images 2025-05-16 14:37:33 +05:30
Aman Raj Singh Mourya
cae9988c9a fix: avoid poping of delete dialog as it pop the main screen 2025-05-16 14:37:02 +05:30
Prateek Sunal
538a5df32d feat: add preview images for both android & iOS 2025-05-16 14:30:13 +05:30
laurenspriem
853b916cf1 Exclude certain collections 2025-05-16 14:25:31 +05:30
Aman Raj Singh Mourya
93d6f58660 fix: code refractor 2025-05-16 14:22:53 +05:30
Neeraj Gupta
7b145f0898 Bump version code 2025-05-16 14:15:30 +05:30
Neeraj Gupta
add09a601d Merge branch 'main' into album_UI_revamp 2025-05-16 14:15:06 +05:30
laurenspriem
5dda596544 Max of 20 photos spread across years 2025-05-16 13:52:05 +05:30
Neeraj Gupta
8101bee2fd Update intl_pt.arb 2025-05-16 12:50:13 +05:30
Neeraj Gupta
c234bc7be8 Fix lint 2025-05-16 12:45:41 +05:30
Neeraj Gupta
27fd372d62 Bump version v1.0.14 2025-05-16 12:42:58 +05:30
laurenspriem
66f23283c1 Only memories spread across multiple years 2025-05-16 12:42:00 +05:30
Neeraj Gupta
8d7bc81c20 Merge branch 'main' into album_UI_revamp 2025-05-16 12:40:56 +05:30
Aman Raj Singh Mourya
41e870f7a0 [mob][photos] Contacts section performance improvements (#5923)
## Description

- Defer the initial load until the Shared Collection tab is in view to
avoid unnecessary work at app startup.
- Remove the computation previously done for the Search tab sections
that was intended for the Contacts section, as it is no longer present.
2025-05-16 11:59:14 +05:30
Aman Raj Singh Mourya
0342e1ef56 Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-05-16 11:57:33 +05:30
Aman Raj Singh Mourya
efed42ce4a refractor: used better code format 2025-05-16 11:56:55 +05:30
Aman Raj Singh Mourya
ef9d925686 fix: alignment of icons 2025-05-16 11:34:37 +05:30
laurenspriem
e84f46f435 correct translation use 2025-05-16 11:31:47 +05:30
laurenspriem
c1193be61c Extract strings 2025-05-16 11:31:23 +05:30
laurenspriem
9b460ca1dc Init onThisDay method 2025-05-16 11:30:44 +05:30
ashilkn
a101dba6cd Defer loading of contacts section in shared collections tab until the tab is in view for atleast 500ms. This is to avoid work at app start 2025-05-15 19:11:30 +05:30
Prateek Sunal
491de296ca feat: similar UI's for all the widgets 2025-05-15 18:18:42 +05:30
ashilkn
a614636789 Avoid computing data for contacts section for the search tab since it has been moved temporarily to the shared collections tab 2025-05-15 17:23:35 +05:30
Aman Raj Singh Mourya
07c640cf90 refractor: extract string + code refractor and improvements 2025-05-15 16:33:16 +05:30
Prateek Sunal
9fa13508b8 feat: add iOS widgets 2025-05-15 16:26:16 +05:30
Aman Raj Singh Mourya
1c099a60e8 refactor: use params to store resultCollections 2025-05-15 16:25:52 +05:30
laurenspriem
9170c80b26 Fix constructor 2025-05-15 14:18:46 +05:30
Neeraj Gupta
6ae8abb492 Bump version v1.0.13 2025-05-15 10:47:45 +05:30
Neeraj Gupta
f077213c62 Merge branch 'main' into album_UI_revamp 2025-05-15 10:46:26 +05:30
Aman Raj Singh Mourya
62c1f0c6ac fix: merge conflict 2025-05-15 10:17:53 +05:30
Aman Raj Singh Mourya
cc486983ab Merge branch 'main' into album_UI_revamp 2025-05-15 10:14:40 +05:30
Prateek Sunal
f22ad9611f feat: populate people as well 2025-05-14 15:14:11 +05:30
Prateek Sunal
9cafa72ae3 fix: add color scheme based icon 2025-05-14 14:01:25 +05:30
Prateek Sunal
0c9d7321eb fix: nominal display limit count & disable show create album 2025-05-14 13:52:13 +05:30
Prateek Sunal
5fc5d0ef48 feat: add initial album grid and save button 2025-05-14 13:48:08 +05:30
Prateek Sunal
84017c7397 Merge remote-tracking branch 'origin/memories_widget_api' into widget-superpowered 2025-05-14 12:13:06 +05:30
Prateek Sunal
e250759999 Merge remote-tracking branch 'origin/album_grid_UI' into widget-superpowered 2025-05-14 11:21:50 +05:30
Aman Raj Singh Mourya
f088c24abe refactor: remove debug print statements 2025-05-13 18:15:35 +05:30
Aman Raj Singh Mourya
e197423c1d fix: fixed album list opening scrolled down & increase bottom padding 2025-05-13 18:10:38 +05:30
laurenspriem
1785baf4af method for memories widget 2025-05-13 13:33:31 +05:30
Aman Raj Singh Mourya
51d55ee92b feat: Add new album row item widget and update collections grid view 2025-05-12 22:06:19 +05:30
Aman Raj Singh Mourya
7cd3f8e2ac [mob][photos] feat: show albums shared by contact in contact section 2025-05-12 20:12:45 +05:30
Prateek Sunal
91fefa7eb9 feat: memories leading icons 2025-05-12 19:12:46 +05:30
Prateek Sunal
63b9a09a2d feat: init widgets settings and default states
Next: Add Grid, make things dynamic, Add sync logic and native code
2025-05-12 19:07:58 +05:30
Aman Raj Singh Mourya
6627f77d92 [mob][photos] fix: increase bottom padding 2025-05-06 20:36:44 +05:30
Aman Raj Singh Mourya
14b70ce66e Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-05-01 10:15:12 +05:30
Aman Raj Singh Mourya
d9a5fbfe00 [mob][photos] implemented new sorting order for contact section 2025-05-01 10:14:54 +05:30
Neeraj Gupta
f816166743 Fix translation file 2025-04-28 09:26:57 +05:30
Neeraj Gupta
3aba4fad47 Bump version for droid internal release 2025-04-28 09:25:15 +05:30
Neeraj Gupta
60137585d1 Merge remote-tracking branch 'origin/main' into album_UI_revamp 2025-04-28 09:24:37 +05:30
Aman Raj Singh Mourya
59316c263f [mob][photos] fix: Reduce main axis spacing from 4px -> 2px 2025-04-25 22:39:20 +05:30
Aman Raj Singh Mourya
44682404ff Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-04-25 21:48:57 +05:30
Aman Raj Singh Mourya
83c864df2b [mob][photos] minor fix 2025-04-25 21:41:06 +05:30
Neeraj Gupta
184882fae2 Bump version for droid internal release 2025-04-25 16:16:10 +05:30
Neeraj Gupta
e59e600a35 Merge branch 'album_UI_revamp' of https://github.com/ente-io/auth into album_UI_revamp 2025-04-25 16:14:57 +05:30
Neeraj Gupta
6f5c5a0b06 Merge branch 'main' into album_UI_revamp 2025-04-25 16:14:32 +05:30
Aman Raj Singh Mourya
3d4ff93e65 [mob][photos] Move Contacts section from search tab to shared tab 2025-04-25 16:11:02 +05:30
Aman Raj Singh Mourya
d88621ab5a [mob][photos] feat: implement ascending/descending sort direction 2025-04-25 15:52:09 +05:30
Aman Raj Singh Mourya
95e6a86b10 [mob][photos] feat: update sharing functionality improve UI flow 2025-04-25 15:45:38 +05:30
Aman Raj Singh Mourya
e5d63fe9e7 [mob][photos] feat: enable selection on album screen itself 2025-04-25 12:57:27 +05:30
Aman Raj Singh Mourya
1265002d5a Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-04-24 02:32:20 +05:30
Aman Raj Singh Mourya
c7aecc9b30 [mob][photos] minor fix 2025-04-24 02:31:24 +05:30
Aman Raj Singh Mourya
dba837c62c [mob][photos] refactor: allow favourite album selection for better UX 2025-04-24 02:31:10 +05:30
Aman Raj Singh Mourya
e5bdd74fa9 [mob][photos] refractor: update icon colors to use blurStrokePressed 2025-04-24 01:14:33 +05:30
Aman Raj Singh Mourya
0f31278965 [mob][photos] refactor: remove create album option and update item limit count 2025-04-23 22:24:49 +05:30
Neeraj Gupta
be3e434bec Bump version 2025-04-23 14:46:54 +05:30
Aman Raj Singh Mourya
9d9a7b548d [mob][photos] minor fix 2025-04-23 13:53:54 +05:30
Aman Raj Singh Mourya
3708819e6b Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-04-23 13:32:30 +05:30
Aman Raj Singh Mourya
389220357e [mob][photos] feat: enable album selection actions for incoming collections 2025-04-23 13:31:56 +05:30
Neeraj Gupta
d9925f29d8 Merge branch 'main' into album_UI_revamp 2025-04-23 13:14:58 +05:30
Aman Raj Singh Mourya
0dab15b703 [mpb][photos] feat: collections and optimize grid/list item rendering 2025-04-22 13:02:04 +05:30
Aman Raj Singh Mourya
2449dbe0cd [mob][photos] feat: update selection logic to exclude favorite collections from actions 2025-04-22 12:42:40 +05:30
Aman Raj Singh Mourya
7f96a11e07 [mob][photos] refactor: remove debug print statements and update parameter naming 2025-04-21 10:18:44 +05:30
Aman Raj Singh Mourya
d7cb5c29cf [mob][photos] feat: reflect SelectAll action change on UI 2025-04-21 10:18:05 +05:30
Aman Raj Singh Mourya
399ecdfd7d [mob][photos] feat: support for multiple selected albums and add SelectAllAlbumsButton 2025-04-21 10:17:12 +05:30
Aman Raj Singh Mourya
f4580c8fdf [mob][photos] feat: add support for sharing and deleting multiple collections with action sheets 2025-04-19 21:45:49 +05:30
Aman Raj Singh Mourya
13f78ecc19 [mob][photos] feat: enhance AddParticipantPage to support multiple collections and update album selection actions 2025-04-19 21:43:01 +05:30
Aman Raj Singh Mourya
9267c4012b feat: integrate album selection management into collection list and flex grid views 2025-04-19 00:14:54 +05:30
Aman Raj Singh Mourya
a8e80717aa [mob][photos] fix: use selected albums for showing selected/unselected state 2025-04-19 00:14:34 +05:30
Aman Raj Singh Mourya
8e552c57bb [mob][photos] feat: implement album selection management and action overlay components 2025-04-19 00:13:10 +05:30
Aman Raj Singh Mourya
28f03d3514 [mob][photos] feat: add searchable app bar and enhance collection filtering 2025-04-16 00:27:10 +05:30
Aman Raj Singh Mourya
c7047ab964 [mob][photos] feat: support album sorting by name and newest photo for shared albums 2025-04-15 22:40:25 +05:30
Aman Raj Singh Mourya
daa3fcd354 [mob][photos] fix: hide "add new album" options when any album is selected 2025-04-15 19:17:02 +05:30
Aman Raj Singh Mourya
0057e71e02 [mob][photos] fix: use "strokeFaint" instead of "strokeFainter" for better visibility 2025-04-15 19:16:01 +05:30
Aman Raj Singh Mourya
50fabee1e0 [mob][photos] feat: enhance AlbumRowItemWidget with selection handling 2025-04-09 00:13:19 +05:30
Aman Raj Singh Mourya
227d76db29 [mob][photos] feat: enhance CollectionsFlexiGridViewWidget with selection mode and album creation options 2025-04-09 00:12:50 +05:30
Aman Raj Singh Mourya
9207b0c7b8 [mob][photos] feat: add album view type settings 2025-04-09 00:12:08 +05:30
Aman Raj Singh Mourya
9b8c48ca6e [mob][photos] feat: implement AlbumListItemWidget for displaying album in vertical layout 2025-04-09 00:10:30 +05:30
Aman Raj Singh Mourya
dc05e254cb [mob][photos] feat: add NewAlbumRowItemWidget for creating new albums in grid view 2025-04-09 00:09:44 +05:30
Aman Raj Singh Mourya
f047757c63 [mob][photos] changes: make SectionOptions tappable for incoming, outgoing, and quick links 2025-04-05 21:23:13 +05:30
Aman Raj Singh Mourya
f9711e09a1 [mob][photos] fix: show "Add new" album for "On ente" section only 2025-04-05 21:04:56 +05:30
Aman Raj Singh Mourya
a5644f292e [mob][photos] changes: add new album icon to flex grid view 2025-04-05 20:27:09 +05:30
Aman Raj Singh Mourya
f3a88dc3fa [mob][photos] changes: adjust thumbnail size and gap for 3x3 layout 2025-04-05 19:57:14 +05:30
Aman Raj Singh Mourya
9ef2a5fc62 [mob][photos] changes: move sort option into full screen view of "On ente" section & remove "View all" section 2025-04-05 00:37:01 +05:30
Aman Raj Singh Mourya
36ab2f05df [mob][photos] changes: make the complete SectionOptions tappable 2025-04-05 00:34:34 +05:30
Aman Raj Singh Mourya
723511540c [mob][photos] Show 3 albums in a row and max 3 rows i.e _kOnEnteItemLimitCount = 9 (3*3) 2025-04-04 20:40:01 +05:30
405 changed files with 19226 additions and 9838 deletions

View File

@@ -63,6 +63,6 @@ jobs:
with:
webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }}
nodetail: true
title: "🏆 Internal release available for Photos"
title: "🏆 Internal release Photos (Branch: ${{ github.ref_name }})"
description: "[Download](https://play.google.com/store/apps/details?id=io.ente.photos)"
color: 0x00ff00

View File

@@ -43,6 +43,12 @@
"title": "Anycoin Direct",
"slug": "anycoindirect"
},
{
"title": "AR24",
"altNames": [
"Docaposte AR24"
]
},
{
"title": "Aruba",
"slug": "aruba",
@@ -441,6 +447,9 @@
"title": "Finanzfluss",
"slug": "finanzfluss"
},
{
"title": "Finary"
},
{
"title": "Firefox",
"slug": "mozilla"
@@ -743,6 +752,7 @@
{
"title": "Mistral",
"altNames": [
"Le Chat",
"Mistral AI",
"MistralAI"
]
@@ -892,6 +902,10 @@
"slug": "onshape",
"hex": "7abb5e"
},
{
"title": "Oracle Cloud",
"slug": "oracle_cloud"
},
{
"title": "Parqet",
"slug": "parqet"

View File

@@ -0,0 +1,6 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="#0000FF" xmlns="http://www.w3.org/2000/svg">
<path d="M139.63 306.55H125.64C123.41 306.55 121.53 306.5 119.99 306.39C118.45 306.28 117.13 305.99 116.01 305.51C114.9 305.04 113.92 304.32 113.08 303.36C112.22 302.41 111.38 301.09 110.53 299.39L103.85 286.35H35.47L25.29 306.55H0L58.37 194.11H81.26L139.63 306.55ZM93.2 265.36L69.66 218.6L46.12 265.36H93.2Z"/>
<path d="M265.23 306.55H245.67C241.96 306.55 238.93 306.07 236.6 305.12C234.27 304.16 232.31 302.68 230.72 300.67L206.17 270.76H177.48V306.55H153.95V195.23C156.92 195.12 160.16 195.04 163.66 194.99C167.17 194.93 170.77 194.86 174.5 194.75C178.21 194.64 181.92 194.57 185.64 194.51C189.36 194.46 192.86 194.43 196.15 194.43C209.74 194.43 220.97 195.41 229.84 197.37C238.71 199.34 246 202.91 251.74 208.1C258.11 214.04 261.3 222.1 261.3 232.28C261.3 237.37 260.61 241.85 259.23 245.72C257.84 249.59 255.88 252.96 253.33 255.81C250.78 258.68 247.7 261.09 244.09 263.05C240.49 265.02 236.45 266.63 231.99 267.9L265.23 306.55ZM196.25 250.25C199.75 250.25 203.27 250.22 206.82 250.17C210.38 250.12 213.74 249.88 216.93 249.45C220.1 249.03 223.02 248.36 225.67 247.46C228.32 246.55 230.5 245.24 232.19 243.54C233.67 241.94 234.82 240.29 235.61 238.59C236.4 236.89 236.81 234.7 236.81 232.03C236.81 230.23 236.45 228.47 235.77 226.77C235.08 225.06 234.15 223.62 232.99 222.45C231.4 220.85 229.44 219.6 227.11 218.7C224.77 217.79 222.1 217.12 219.07 216.7C216.05 216.27 212.63 216.03 208.81 215.98C205 215.93 200.81 215.9 196.25 215.9H187.18C183.58 215.9 180.34 215.95 177.48 216.06V250.1C180.34 250.2 183.58 250.25 187.18 250.25H196.25Z"/>
<path d="M324.59 213.35C318.34 213.35 312.61 215.03 307.41 218.37C302.22 221.7 297.93 225.65 294.54 230.22L276.09 217.97C282.13 210.65 289.36 204.66 297.79 200C306.22 195.33 315.47 193 325.55 193C332.33 193 338.53 193.87 344.15 195.62C349.77 197.37 354.59 199.84 358.63 203.02C362.65 206.2 365.78 210.07 368.01 214.63C370.23 219.19 371.35 224.27 371.35 229.89C371.35 235.2 370.36 239.86 368.4 243.89C366.44 247.92 363.85 251.6 360.61 254.94C357.38 258.28 353.69 261.38 349.56 264.25C345.42 267.11 341.18 269.97 336.84 272.84L317.27 285.72H370.87V306.55H279.42V286.04L318.39 260.27C322.2 257.73 325.86 255.32 329.36 253.03C332.86 250.76 335.93 248.42 338.58 246.04C341.24 243.65 343.35 241.13 344.95 238.48C346.54 235.83 347.33 232.91 347.33 229.74C347.33 227.41 346.72 225.23 345.5 223.22C344.28 221.2 342.64 219.45 340.57 217.97C338.51 216.49 336.09 215.35 333.34 214.55C330.58 213.75 327.66 213.35 324.59 213.35Z"/>
<path d="M457.22 306.55V283.49H388.84V259.95L455.47 195.23H480.12V263.77H500V283.49H480.12V306.55L457.22 306.55ZM413.17 263.77H457.22V220.35L413.17 263.77Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,3 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="#F1C086" xmlns="http://www.w3.org/2000/svg">
<path d="M166.67 62C74.62 62 0 136.62 0 228.67H333.33C425.38 228.67 500 154.05 500 62H166.67ZM166.67 270.33C74.62 270.33 0 344.95 0 437H154.76C246.81 437 321.43 362.38 321.43 270.33H166.67Z"/>
</svg>

After

Width:  |  Height:  |  Size: 302 B

View File

@@ -1,15 +1,7 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<g style="mix-blend-mode:difference">
<path fill-rule="evenodd" clip-rule="evenodd" d="M363.636 23H409.091V477.545H363.636V23ZM0 23H45.4545V477.545H0V23ZM227.273 295.727H181.818V386.636H227.273V295.727ZM272.727 113.909H318.182V204.818H272.727V113.909Z" fill="white"/>
</g>
<path d="M136.364 386.636H45.4545V477.545H136.364V386.636Z" fill="#EA3326"/>
<path d="M500 386.636H409.091V477.545H500V386.636Z" fill="#EA3326"/>
<path d="M136.364 295.727H45.4545V386.636H136.364V295.727Z" fill="#EB5829"/>
<path d="M318.182 295.727H227.273V386.636H318.182V295.727Z" fill="#EB5829"/>
<path d="M500 295.727H409.091V386.636H500V295.727Z" fill="#EB5829"/>
<path d="M136.364 23H45.4545V113.909H136.364V23Z" fill="#F7D046"/>
<path d="M500 23H409.091V113.909H500V23Z" fill="#F7D046"/>
<path d="M227.273 113.909H45.4545V204.818H227.273V113.909Z" fill="#F2A73B"/>
<path d="M500 113.909H318.182V204.818H500V113.909Z" fill="#F2A73B"/>
<path d="M500 204.818H45.4545V295.727H500V204.818Z" fill="#EE792F"/>
</svg>
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<path d="M71.41 73H142.83V143.75H71.41V73ZM357.12 73H428.54V143.75H357.12V73Z" fill="#FFD800"/>
<path d="M71.41 143.75H214.25V214.5H71.41V143.75ZM285.7 143.75H428.54V214.5H285.7V143.75Z" fill="#FFAF00"/>
<path d="M71.41 214.5H428.54V285.25H71.41V214.5Z" fill="#FF8205"/>
<path d="M71.41 285.27H142.83V356.02H71.41V285.27ZM214.27 285.27H285.69V356.02H214.27V285.27ZM357.12 285.27H428.54V356.02H357.12V285.27Z" fill="#FA500F"/>
<path d="M0 356.06H214.3V426.82H0V356.06ZM285.7 356.06H500V426.82H285.7V356.06Z" fill="#E10500"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 628 B

View File

@@ -0,0 +1 @@
<svg height="2100" viewBox="0 0 32 21" width="3200" xmlns="http://www.w3.org/2000/svg"><path d="m9.9 20.1c-5.5 0-9.9-4.4-9.9-9.9s4.4-9.9 9.9-9.9h11.6c5.5 0 9.9 4.4 9.9 9.9s-4.4 9.9-9.9 9.9zm11.3-3.5c3.6 0 6.4-2.9 6.4-6.4 0-3.6-2.9-6.4-6.4-6.4h-11c-3.6 0-6.4 2.9-6.4 6.4s2.9 6.4 6.4 6.4z" fill="#c74634"/></svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@@ -47,7 +47,7 @@
"saveAction": "حفظ",
"nextTotpTitle": "التالي",
"deleteCodeTitle": "حذف الرمز؟",
"deleteCodeMessage": "هل أنت متأكد من أنك تريد حذف هذه الشيفرة؟ هذا الإجراء لا رجعة فيه.",
"deleteCodeMessage": "هل أنت متيقِّن من أنك تريد حذف هذه الشيفرة؟ هذا الإجراء لا رجعة فيه.",
"trashCode": "حذف الكود؟",
"trashCodeMessage": "هل أنت متيقِّن أنك تريد حذف الكود الخاص بـ {account}؟",
"trash": "سلة المهملات",
@@ -513,5 +513,10 @@
"free5GB": "5GB مجانًا على <bold-green>ente</bold-green> صور",
"loginWithAuthAccount": "سجّل الدخول باستخدام حساب المُصادقة",
"freeStorageOffer": "خَصْم 10٪ على صور <bold-green>ente</bold-green>",
"freeStorageOfferDescription": "استخدم الكود \"AUTH\" وأحصل على 10٪ خَصْم في السنة الأولى"
"freeStorageOfferDescription": "استخدم الكود \"AUTH\" وأحصل على 10٪ خَصْم في السنة الأولى",
"advanced": "متقدم",
"algorithm": "الخوارزمية",
"type": "النوع",
"period": "المدّة",
"digits": "الأرقام"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Ungültiger QR-Code",
"noRecoveryKeyTitle": "Kein Wiederherstellungsschlüssel?",
"enterEmailHint": "Geben Sie Ihre E-Mail-Adresse ein",
"enterNewEmailHint": "Gib deine neue E-Mail-Adresse ein",
"invalidEmailTitle": "Ungültige E-Mail-Adresse",
"invalidEmailMessage": "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
"deleteAccount": "Konto löschen",
@@ -517,5 +518,6 @@
"advanced": "Erweitert",
"algorithm": "Algorithmus",
"type": "Typ",
"period": "Periode",
"digits": "Ziffern"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Invalid QR code",
"noRecoveryKeyTitle": "No recovery key?",
"enterEmailHint": "Enter your email address",
"enterNewEmailHint": "Enter your new email address",
"invalidEmailTitle": "Invalid email address",
"invalidEmailMessage": "Please enter a valid email address.",
"deleteAccount": "Delete account",

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "QR code non valide",
"noRecoveryKeyTitle": "Pas de clé de récupération ?",
"enterEmailHint": "Entrez votre adresse e-mail",
"enterNewEmailHint": "Saisissez votre nouvelle adresse email",
"invalidEmailTitle": "Adresse e-mail invalide",
"invalidEmailMessage": "Veuillez saisir une adresse e-mail valide.",
"deleteAccount": "Supprimer le compte",
@@ -514,5 +515,9 @@
"loginWithAuthAccount": "Connectez-vous avec votre compte Auth",
"freeStorageOffer": "10% de réduction sur <bold-green>Ente</bold-green> Photos",
"freeStorageOfferDescription": "Utilisez le code coupon \"AUTH\" pour obtenir 10% de réduction la première année",
"period": "Période"
"advanced": "Avancé",
"algorithm": "Algorithme",
"type": "Type",
"period": "Période",
"digits": "Chiffres"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Érvénytelen QR-kód",
"noRecoveryKeyTitle": "Nincs helyreállítási kulcs?",
"enterEmailHint": "Adja meg az e-mail címét",
"enterNewEmailHint": "Add meg az új e-mail címed",
"invalidEmailTitle": "Érvénytelen e-mail cím",
"invalidEmailMessage": "Kérjük, adjon meg egy érvényes e-mail címet.",
"deleteAccount": "Fiók törlése",
@@ -513,5 +514,6 @@
"free5GB": "5GB ingyen <bold-green>ente <bold-green> Photos",
"loginWithAuthAccount": "Jelentkezzen be Auth fiókjával",
"freeStorageOffer": "10% kedvezmény on <bold-green>ente<bold-green> photos",
"freeStorageOfferDescription": "Használja az \"AUTH\" kódot, hogy 10% kedvezményt kapjon az első évben"
"freeStorageOfferDescription": "Használja az \"AUTH\" kódot, hogy 10% kedvezményt kapjon az első évben",
"type": "Típus"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Codice QR non valido",
"noRecoveryKeyTitle": "Nessuna chiave di recupero?",
"enterEmailHint": "Inserisci il tuo indirizzo email",
"enterNewEmailHint": "Inserisci il tuo nuovo indirizzo email",
"invalidEmailTitle": "Indirizzo email non valido",
"invalidEmailMessage": "Inserisci un indirizzo email valido.",
"deleteAccount": "Elimina account",

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Ongeldige QR-code",
"noRecoveryKeyTitle": "Geen herstelsleutel?",
"enterEmailHint": "Voer je e-mailadres in",
"enterNewEmailHint": "Voer uw nieuwe e-mailadres in",
"invalidEmailTitle": "Ongeldig e-mailadres",
"invalidEmailMessage": "Voer een geldig e-mailadres in.",
"deleteAccount": "Account verwijderen",
@@ -513,5 +514,10 @@
"free5GB": "5GB gratis op <bold-green>ente</bold-green> Photos",
"loginWithAuthAccount": "Log in met je Auth account",
"freeStorageOffer": "10% korting op <bold-green>ente</bold-green> photos",
"freeStorageOfferDescription": "Gebruik de code \"AUTH\" voor 10% korting op je eerste jaar"
"freeStorageOfferDescription": "Gebruik de code \"AUTH\" voor 10% korting op je eerste jaar",
"advanced": "Geavanceerd",
"algorithm": "Algoritme",
"type": "Type",
"period": "Periode",
"digits": "Cijfers"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Nieprawidłowy kod QR",
"noRecoveryKeyTitle": "Brak klucza odzyskiwania?",
"enterEmailHint": "Wprowadź adres e-mail",
"enterNewEmailHint": "Wprowadź nowy adres e-mail",
"invalidEmailTitle": "Nieprawidłowy adres e-mail",
"invalidEmailMessage": "Prosimy podać prawidłowy adres e-mail.",
"deleteAccount": "Usuń konto",

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "QR Code inválido",
"noRecoveryKeyTitle": "Sem chave de recuperação?",
"enterEmailHint": "Insira o endereço de e-mail",
"enterNewEmailHint": "Insira seu novo e-mail",
"invalidEmailTitle": "Endereço de e-mail inválido",
"invalidEmailMessage": "Insira um endereço de e-mail válido.",
"deleteAccount": "Excluir conta",

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "二维码无效",
"noRecoveryKeyTitle": "没有恢复密钥吗?",
"enterEmailHint": "请输入您的电子邮件地址",
"enterNewEmailHint": "请输入您的新电子邮件地址",
"invalidEmailTitle": "无效的电子邮件地址",
"invalidEmailMessage": "请输入一个有效的电子邮件地址。",
"deleteAccount": "删除账户",

View File

@@ -18,7 +18,7 @@ class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
Widget build(BuildContext context) {
final l10n = context.l10n;
return AlertDialog(
title: Text(l10n.enterEmailHint),
title: Text(l10n.enterNewEmailHint),
content: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,

View File

@@ -2,6 +2,11 @@
## v1.7.13 (Unreleased)
- Generate streams for videos (beta)
> Streamable videos can be enabled in Preferences. For more details, see the
> [video streaming FAQ](https://help.ente.io/photos/faq/video-streaming).
- Support Turkish translations.
- .

View File

@@ -38,22 +38,23 @@
"lru-cache": "^11.1.0",
"next-electron-server": "^1.0.0",
"node-stream-zip": "^1.15.0",
"onnxruntime-node": "^1.20.1"
"onnxruntime-node": "^1.20.1",
"zod": "^3.25.23"
},
"devDependencies": {
"@eslint/js": "^9.25.1",
"@tsconfig/node22": "^22.0.1",
"@eslint/js": "^9.27.0",
"@tsconfig/node22": "^22.0.2",
"@types/auto-launch": "^5.0.5",
"@types/ffmpeg-static": "^3.0.3",
"ajv": "^8.17.1",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"electron": "^36.2.1",
"electron": "^36.3.1",
"electron-builder": "^26.0.14",
"eslint": "^9",
"prettier": "3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-packagejson": "^2.5.13",
"prettier-plugin-packagejson": "^2.5.14",
"shx": "^0.4.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.1"

View File

@@ -78,6 +78,14 @@ export const allowWindowClose = (): void => {
* We call this at the end of this file.
*/
const main = () => {
// Workaround for Electron 36 not launching on some Linux distros. Remove
// once fixed or otherwise mitigated upstream.
//
// https://github.com/electron/electron/issues/46538#issuecomment-2808806722
if (process.platform == "linux") {
app.commandLine.appendSwitch("gtk-version", "3");
}
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();

View File

@@ -12,11 +12,16 @@ import fs_ from "node:fs";
import fs from "node:fs/promises";
import path from "node:path";
import { Readable } from "node:stream";
import { z } from "zod";
import type { FFmpegCommand } from "../../types/ipc";
import log from "../log-worker";
import { messagePortMainEndpoint } from "../utils/comlink";
import { wait } from "../utils/common";
import { nullToUndefined, wait } from "../utils/common";
import { execAsyncWorker } from "../utils/exec-worker";
import {
authenticatedRequestHeaders,
publicRequestHeaders,
} from "../utils/http";
/* Ditto in the web app's code (used by the Wasm FFmpeg invocation). */
const ffmpegPathPlaceholder = "FFMPEG";
@@ -44,7 +49,9 @@ export interface FFmpegUtilityProcess {
ffmpegGenerateHLSPlaylistAndSegments: (
inputFilePath: string,
outputPathPrefix: string,
outputUploadURL: string,
fileID: number,
fetchURL: string,
authToken: string,
) => Promise<FFmpegGenerateHLSPlaylistAndSegmentsResult | undefined>;
ffmpegDetermineVideoDuration: (inputFilePath: string) => Promise<number>;
@@ -52,7 +59,11 @@ export interface FFmpegUtilityProcess {
log.debugString("Started ffmpeg utility process");
process.on("uncaughtException", (e, origin) => log.error(origin, e));
process.parentPort.once("message", (e) => {
// Initialize ourselves with the data we got from our parent.
parseInitData(e.data);
// Expose an instance of `FFmpegUtilityProcess` on the port we got from our
// parent.
expose(
@@ -64,9 +75,26 @@ process.parentPort.once("message", (e) => {
} satisfies FFmpegUtilityProcess,
messagePortMainEndpoint(e.ports[0]!),
);
// Let the main process know we're ready.
mainProcess("ack", undefined);
});
/**
* We cannot access Electron's {@link app} object within a utility process, so
* we pass the value of `app.getVersion()` during initialization, and it can be
* subsequently retrieved from here.
*/
let _desktopAppVersion: string | undefined;
/** Equivalent to `app.getVersion()` */
const desktopAppVersion = () => _desktopAppVersion!;
const FFmpegWorkerInitData = z.object({ appVersion: z.string() });
const parseInitData = (data: unknown) => {
_desktopAppVersion = FFmpegWorkerInitData.parse(data).appVersion;
};
/**
* Send a message to the main process using a barebones RPC protocol.
*/
@@ -184,6 +212,7 @@ export interface FFmpegGenerateHLSPlaylistAndSegmentsResult {
playlistPath: string;
dimensions: { width: number; height: number };
videoSize: number;
videoObjectID: string;
}
/**
@@ -199,7 +228,7 @@ export interface FFmpegGenerateHLSPlaylistAndSegmentsResult {
*
* Example invocation:
*
* ffmpeg -i in.mov -vf 'scale=-2:720,fps=30,zscale=transfer=linear,tonemap=tonemap=hable:desat=0,zscale=primaries=709:transfer=709:matrix=709,format=yuv420p' -c:v libx264 -c:a aac -f hls -hls_key_info_file out.m3u8.info -hls_list_size 0 -hls_flags single_file out.m3u8
* ffmpeg -i in.mov -vf "scale=-2:'min(720,ih)',fps=30,zscale=transfer=linear,tonemap=tonemap=hable:desat=0,zscale=primaries=709:transfer=709:matrix=709,format=yuv420p" -c:v libx264 -c:a aac -f hls -hls_key_info_file out.m3u8.info -hls_list_size 0 -hls_flags single_file out.m3u8
*
* See: [Note: Preview variant of videos]
*
@@ -210,9 +239,17 @@ export interface FFmpegGenerateHLSPlaylistAndSegmentsResult {
* the user's local file system. This function will write the generated HLS
* playlist and video segments under this prefix.
*
* @returns The paths to two files on the user's local file system - one
* containing the generated HLS playlist, and the other containing the
* transcoded and encrypted video segments that the HLS playlist refers to.
* @param fileID The ID of the {@link EnteFile} whose HLS playlist we are
* generating.
*
* @param fetchURL The fully resolved API URL for obtaining pre-signed S3 URLs
* for uploading the generated video segment file.
*
* @param authToken A token that can be used to make API request to
* {@link fetchURL}.
*
* @returns The path to the file on the user's file system containing the
* generated HLS playlist, and other metadata about the generated video stream.
*
* If the video is such that it doesn't require stream generation, then this
* function returns `undefined`.
@@ -220,7 +257,9 @@ export interface FFmpegGenerateHLSPlaylistAndSegmentsResult {
const ffmpegGenerateHLSPlaylistAndSegments = async (
inputFilePath: string,
outputPathPrefix: string,
outputUploadURL: string,
fileID: number,
fetchURL: string,
authToken: string,
): Promise<FFmpegGenerateHLSPlaylistAndSegmentsResult | undefined> => {
const { isH264, isHDR, bitrate } =
await detectVideoCharacteristics(inputFilePath);
@@ -357,11 +396,23 @@ const ffmpegGenerateHLSPlaylistAndSegments = async (
// - the first line specifies the key URI that is written into the playlist.
// - the second line specifies the path to the local file system file from
// where ffmpeg should read the key.
//
// [Note: ffmpeg newlines]
//
// Tested on Windows that ffmpeg recognizes these lines correctly. In
// general, ffmpeg tends to expect input and write output the Unix way (\n),
// even when we're running on Windows.
//
// - The ffmetadata and the HLS playlist file generated by ffmpeg uses \n
// separators, even on Windows.
// - The HLS key info file, expected as an input by ffmpeg, works fine when
// \n separated even on Windows.
//
const keyInfo = [keyURI, keyPath].join("\n");
// Overview:
//
// - Video H.264 HD 720p 30fps.
// - Video H.264 HD 720p (max) 30fps.
// - Audio AAC 128kbps.
// - Encrypted HLS playlist with a single file containing all the chunks.
//
@@ -399,7 +450,7 @@ const ffmpegGenerateHLSPlaylistAndSegments = async (
// keeping aspect ratio and the calculated
// dimension divisible by 2 (some of the other
// operations require an even pixel count).
"scale=-2:720",
"scale=-2:'min(720,ih)'",
// Convert the video to a constant 30 fps,
// duplicating or dropping frames as necessary.
"fps=30",
@@ -475,6 +526,7 @@ const ffmpegGenerateHLSPlaylistAndSegments = async (
let dimensions: { width: number; height: number };
let videoSize: number;
let videoObjectID: string;
try {
// Write the key and the keyInfo to their desired paths.
@@ -491,6 +543,15 @@ const ffmpegGenerateHLSPlaylistAndSegments = async (
// Note: Depending on the size of the input file, this may take long!
await execAsyncWorker(commandWithRedirection);
// While ffmpeg uses \n as the line separator in the generated playlist
// file on Windows too, add an extra safety check that should fail the
// HLS generation if this doesn't hold. See: [Note: ffmpeg newlines].
if (process.platform == "win32") {
const playlistText = await fs.readFile(playlistPath, "utf-8");
if (playlistText.includes("\r\n"))
throw new Error("Unexpected Windows newlines in playlist");
}
// Determine the dimensions of the generated video from the stderr
// output produced by ffmpeg during the conversion.
dimensions = await detectVideoDimensions(stderrPath);
@@ -499,7 +560,13 @@ const ffmpegGenerateHLSPlaylistAndSegments = async (
// the generated .ts file.
videoSize = await fs.stat(videoPath).then((st) => st.size);
await uploadVideoSegments(videoPath, videoSize, outputUploadURL);
videoObjectID = await uploadVideoSegments(
videoPath,
videoSize,
fileID,
fetchURL,
authToken,
);
} catch (e) {
log.error("HLS generation failed", e);
await Promise.all([deletePathIgnoringErrors(playlistPath)]);
@@ -515,7 +582,7 @@ const ffmpegGenerateHLSPlaylistAndSegments = async (
]);
}
return { playlistPath, dimensions, videoSize };
return { playlistPath, dimensions, videoSize, videoObjectID };
};
/**
@@ -544,10 +611,10 @@ const deletePathIgnoringErrors = async (tempFilePath: string) => {
*
* Stream #0:1[0x2](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 480x270 [SAR 1:1 DAR 16:9], 539 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)
*/
const videoStreamLineRegex = /Stream #.+: Video:(.+)\n/;
const videoStreamLineRegex = /Stream #.+: Video:(.+)\r?\n/;
/** {@link videoStreamLineRegex}, but global. */
const videoStreamLinesRegex = /Stream #.+: Video:(.+)\n/g;
const videoStreamLinesRegex = /Stream #.+: Video:(.+)\r?\n/g;
/**
* A regex that matches "<digits> kb/s" preceded by a space. See
@@ -762,10 +829,10 @@ const pseudoFFProbeVideo = async (inputFilePath: string) => {
};
/**
* Upload the file at the given {@link videoFilePath} to the provided presigned
* {@link objectUploadURL} using a HTTP PUT request.
* Upload the file at the given {@link videoFilePath} to the provided pre-signed
* URL(s) using a HTTP PUT request.
*
* In case on non-HTTP-4xx errors, retry up to 3 times with exponential backoff.
* All HTTP requests are retried up to 3 times with exponential backoff.
*
* See: [Note: Upload HLS video segment from node side].
*
@@ -774,11 +841,146 @@ const pseudoFFProbeVideo = async (inputFilePath: string) => {
*
* @param videoSize The size in bytes of the file at {@link videoFilePath}.
*
* @param objectUploadURL A pre-signed URL to upload the file.
* @param fileID The ID of the {@link EnteFile} whose video segment this is.
*
* ---
* @param fetchURL The API URL for fetching pre-signed upload URLs.
*
* This is an inlined but bespoke reimplementation of `retryEnsuringHTTPOkOr4xx`
* @param authToken The user's auth token for use with {@link fetchURL}.
*
* @return The object ID of the uploaded file on remote storage.
*/
const uploadVideoSegments = async (
videoFilePath: string,
videoSize: number,
fileID: number,
fetchURL: string,
authToken: string,
) => {
// Self hosters might be using Cloudflare's free plan which (currently) has
// a maximum request size of 100 MB. Keeping a bit of margin for headers,
const partSize = 96 * 1024 * 1024; /* 96 MB */
const partCount = Math.ceil(videoSize / partSize);
const { objectID, url, partURLs, completeURL } =
await getFilePreviewDataUploadURL(
partCount,
fileID,
fetchURL,
authToken,
);
if (url) {
await uploadVideoSegmentsSingle(videoFilePath, videoSize, url);
} else if (partURLs && completeURL) {
await uploadVideoSegmentsMultipart(
videoFilePath,
videoSize,
partSize,
partURLs,
completeURL,
);
} else {
throw new Error("Malformed upload URLs");
}
return objectID;
};
const FilePreviewDataUploadURLResponse = z.object({
/**
* The objectID with which this uploaded data can be referred to post upload
* (e.g. when invoking {@link putVideoData}).
*/
objectID: z.string(),
/**
* A pre-signed URL that can be used to upload the file.
*
* This will be present only if we requested a singular object upload URL.
*/
url: z.string().nullish().transform(nullToUndefined),
/**
* A list of pre-signed URLs that can be used to upload parts of a multipart
* upload of the uploaded data.
*
* This will be present only if we requested a multipart upload URLs for the
* object by setting `isMultiPart` true in the request.
*/
partURLs: z.string().array().nullish().transform(nullToUndefined),
/**
* A pre-signed URL that can be used to finalize the multipart upload.
*
* This will be present only if we requested a multipart upload URLs for the
* object by setting `isMultiPart` true in the request.
*/
completeURL: z.string().nullish().transform(nullToUndefined),
});
/**
* Obtain a pre-signed URL(s) that can be used to upload the "file preview data"
* of type "vid_preview".
*
* This will be the file containing the encrypted video segments which the
* "vid_preview" HLS playlist for the file would refer to.
*
* @param partCount If greater than 1, then we request for a multipart upload.
*/
export const getFilePreviewDataUploadURL = async (
partCount: number,
fileID: number,
fetchURL: string,
authToken: string,
) => {
const params = new URLSearchParams({
fileID: fileID.toString(),
type: "vid_preview",
});
if (partCount > 1) {
params.set("isMultiPart", "true");
params.set("count", partCount.toString());
}
const res = await retryEnsuringHTTPOk(() =>
fetch(`${fetchURL}?${params.toString()}`, {
headers: authenticatedRequestHeaders(
desktopAppVersion(),
authToken,
),
}),
);
return FilePreviewDataUploadURLResponse.parse(await res.json());
};
const uploadVideoSegmentsSingle = (
videoFilePath: string,
videoSize: number,
objectUploadURL: string,
) =>
retryEnsuringHTTPOk(() =>
// net.fetch is 40-50x slower than the native fetch for this particular
// PUT request. This is easily reproducible - replace `fetch` with
// `net.fetch`, then even on localhost the PUT requests start taking a
// minute or so, while they take second(s) with node's native fetch.
fetch(objectUploadURL, {
method: "PUT",
// net.fetch deduces and inserts a content-length for us, when we
// use the node native fetch then we need to provide it explicitly.
headers: {
...publicRequestHeaders(desktopAppVersion()),
"Content-Length": `${videoSize}`,
},
// See: [Note: duplex param required for stream body]
// @ts-expect-error ^see note above
duplex: "half",
body: Readable.toWeb(fs_.createReadStream(videoFilePath)),
}),
);
/**
* Retry a async operation on failure up to 3 times (1 original + 2 retries)
* with exponential backoff.
*
* This is an inlined but bespoke reimplementation of `retryEnsuringHTTPOk`
* from `web/packages/base/http.ts`
*
* - We don't have the rest of the scaffolding used by that function, which is
@@ -795,65 +997,84 @@ const pseudoFFProbeVideo = async (inputFilePath: string) => {
* - This also moved to a utility process, where we also have a more restricted
* ability to import electron API.
*/
const uploadVideoSegments = async (
videoFilePath: string,
videoSize: number,
objectUploadURL: string,
) => {
const waitTimeBeforeNextTry = [5000, 20000];
const retryEnsuringHTTPOk = async (request: () => Promise<Response>) => {
const waitTimeBeforeNextTry = [10000, 30000];
while (true) {
let abort = false;
try {
const nodeStream = fs_.createReadStream(videoFilePath);
const webStream = Readable.toWeb(nodeStream);
// net.fetch is 40-50x slower than the native fetch for this
// particular PUT request. This is easily reproducible - replace
// `fetch` with `net.fetch`, then even on localhost the PUT requests
// start taking a minute or so, while they take second(s) with
// node's native fetch.
const res = await fetch(objectUploadURL, {
method: "PUT",
// net.fetch apparently deduces and inserts a content-length,
// because when we use the node native fetch then we need to
// provide it explicitly.
headers: { "Content-Length": `${videoSize}` },
// The duplex option is required since we're passing a stream.
//
// @ts-expect-error TypeScript's libdom.d.ts does not include
// the "duplex" parameter, e.g. see
// https://github.com/node-fetch/node-fetch/issues/1769.
duplex: "half",
body: webStream,
});
if (res.ok) {
// Success.
return;
}
if (res.status >= 400 && res.status < 500 && res.status != 429) {
// HTTP 4xx, except potentially transient 429 rate limits.
abort = true;
}
const res = await request();
if (res.ok) /* Success. */ return res;
throw new Error(
`Failed to upload generated HLS video: HTTP ${res.status} ${res.statusText}`,
`Request failed: HTTP ${res.status} ${res.statusText}`,
);
} catch (e) {
if (abort) {
throw e;
}
const t = waitTimeBeforeNextTry.shift();
if (!t) {
throw e;
} else {
log.warn("Will retry potentially transient request failure", e);
await wait(t);
}
await wait(t);
}
}
};
const uploadVideoSegmentsMultipart = async (
videoFilePath: string,
videoSize: number,
partSize: number,
partUploadURLs: string[],
completionURL: string,
) => {
// The part we're currently uploading.
let partNumber = 0;
// A rolling offset into the file.
let start = 0;
// See `createMultipartUploadRequestBody` in the web code for a more
// expansive and documented version of this XML body construction.
const completionXML = ["<CompleteMultipartUpload>"];
for (const partUploadURL of partUploadURLs) {
partNumber += 1;
const size = Math.min(start + partSize, videoSize) - start;
const end = start + size - 1;
const res = await retryEnsuringHTTPOk(() =>
fetch(partUploadURL, {
method: "PUT",
headers: {
...publicRequestHeaders(desktopAppVersion()),
"Content-Length": `${size}`,
},
// See: [Note: duplex param required for stream body]
// @ts-expect-error ^see note above
duplex: "half",
body: Readable.toWeb(
// start and end are inclusive 0-indexed range of bytes to
// read from the file.
fs_.createReadStream(videoFilePath, { start, end }),
),
}),
);
const eTag = res.headers.get("etag");
if (!eTag) throw new Error("Response did not have an ETag");
start += size;
completionXML.push(
`<Part><PartNumber>${partNumber}</PartNumber><ETag>${eTag}</ETag></Part>`,
);
}
completionXML.push("</CompleteMultipartUpload>");
const completionBody = completionXML.join("");
return await retryEnsuringHTTPOk(() =>
fetch(completionURL, {
method: "POST",
headers: {
...publicRequestHeaders(desktopAppVersion()),
"Content-Type": "text/xml",
},
body: completionBody,
}),
);
};
/**
* A regex that matches the first line of the form
*

View File

@@ -3,6 +3,7 @@ import log from "../log";
import { clearPendingVideoResults } from "../stream";
import { clearStores } from "./store";
import { watchReset } from "./watch";
import { terminateUtilityProcesses } from "./workers";
import { clearOpenZipCache } from "./zip";
/**
@@ -36,4 +37,9 @@ export const logout = (watcher: FSWatcher) => {
} catch (e) {
ignoreError("zip cache", e);
}
try {
terminateUtilityProcesses();
} catch (e) {
ignoreError("utility processes", e);
}
};

View File

@@ -15,6 +15,7 @@ import { existsSync } from "fs";
import fs from "node:fs/promises";
import path from "node:path";
import * as ort from "onnxruntime-node";
import { z } from "zod";
import log from "../log-worker";
import { messagePortMainEndpoint } from "../utils/comlink";
import { wait } from "../utils/common";
@@ -23,6 +24,8 @@ import { fsStatMtime } from "./fs";
log.debugString("Started ML utility process");
process.on("uncaughtException", (e, origin) => log.error(origin, e));
process.parentPort.once("message", (e) => {
// Initialize ourselves with the data we got from our parent.
parseInitData(e.data);
@@ -50,17 +53,10 @@ let _userDataPath: string | undefined;
/** Equivalent to app.getPath("userData") */
const userDataPath = () => _userDataPath!;
const MLWorkerInitData = z.object({ userDataPath: z.string() });
const parseInitData = (data: unknown) => {
if (
data &&
typeof data == "object" &&
"userDataPath" in data &&
typeof data.userDataPath == "string"
) {
_userDataPath = data.userDataPath;
} else {
log.error("Unparseable initialization data");
}
_userDataPath = MLWorkerInitData.parse(data).userDataPath;
};
/**

View File

@@ -15,9 +15,22 @@ import type { UtilityProcessType } from "../../types/ipc";
import log, { processUtilityProcessLogMessage } from "../log";
import { messagePortMainEndpoint } from "../utils/comlink";
/**
* Terminate any existing utility processes if they're running.
*
* This function is called during the logout sequence.
*/
export const terminateUtilityProcesses = () => {
terminateMLProcessIfRunning();
terminateFFmpegProcessIfRunning();
};
/** The active ML utility process, if any. */
let _utilityProcessML: UtilityProcess | undefined;
/** The active FFmpeg utility process, if any. */
let _utilityProcessFFmpeg: UtilityProcess | undefined;
/**
* A promise to a comlink {@link Endpoint} that can be used to communicate with
* the active ffmpeg utility process (if any).
@@ -92,18 +105,22 @@ export const triggerCreateUtilityProcess = (
window: BrowserWindow,
) => triggerCreateMLUtilityProcess(window);
export const triggerCreateMLUtilityProcess = (window: BrowserWindow) => {
const terminateMLProcessIfRunning = () => {
if (_utilityProcessML) {
log.debug(() => "Terminating previous ML utility process");
log.debug(() => "Terminating running ML utility process");
_utilityProcessML.kill();
_utilityProcessML = undefined;
}
};
export const triggerCreateMLUtilityProcess = (window: BrowserWindow) => {
terminateMLProcessIfRunning();
const { port1, port2 } = new MessageChannelMain();
const child = utilityProcess.fork(path.join(__dirname, "ml-worker.js"));
const userDataPath = app.getPath("userData");
child.postMessage({ userDataPath }, [port1]);
child.postMessage(/* MLWorkerInitData */ { userDataPath }, [port1]);
window.webContents.postMessage("utilityProcessPort/ml", undefined, [port2]);
@@ -173,7 +190,20 @@ const handleMessagesFromMLUtilityProcess = (child: UtilityProcess) => {
export const ffmpegUtilityProcessEndpoint = () =>
(_utilityProcessFFmpegEndpoint ??= createFFmpegUtilityProcessEndpoint());
const terminateFFmpegProcessIfRunning = () => {
if (_utilityProcessFFmpeg) {
log.debug(() => "Terminating running FFmpeg utility process");
_utilityProcessFFmpeg.kill();
_utilityProcessFFmpeg = undefined;
_utilityProcessFFmpegEndpoint = undefined;
}
};
const createFFmpegUtilityProcessEndpoint = () => {
if (_utilityProcessFFmpeg) {
throw new Error("FFmpeg utility process is already running");
}
// Promise.withResolvers is currently in the node available to us.
let resolve: ((endpoint: Endpoint) => void) | undefined;
const promise = new Promise<Endpoint>((r) => (resolve = r));
@@ -182,8 +212,10 @@ const createFFmpegUtilityProcessEndpoint = () => {
const child = utilityProcess.fork(path.join(__dirname, "ffmpeg-worker.js"));
// Send a handle to the port (one end of the message channel) to the utility
// process. The utility process will reply with an "ack" when it get it.
child.postMessage({}, [port1]);
// process (alongwith any other init data). The utility process will reply
// with an "ack" when it get it.
const appVersion = app.getVersion();
child.postMessage(/* FFmpegWorkerInitData */ { appVersion }, [port1]);
child.on("message", (m: unknown) => {
if (m && typeof m == "object" && "method" in m) {
@@ -201,6 +233,8 @@ const createFFmpegUtilityProcessEndpoint = () => {
log.info("Ignoring unknown message from ffmpeg utility process", m);
});
_utilityProcessFFmpeg = child;
// Resolve with the other end of the message channel (once we get an "ack"
// from the utility process).
return promise;

View File

@@ -277,9 +277,9 @@ const handleVideoDone = async (token: string) => {
*
* The difference here is that we the conversion generates two streams^ - one
* for the HLS playlist itself, and one for the file containing the encrypted
* and transcoded video chunks. The video stream we write to the objectUploadURL
* (provided via {@link params}), and then we return a JSON object containing
* the token for the playlist, and other metadata for use by the renderer.
* and transcoded video chunks. The video stream we write to the pre-signed
* object upload URL(s), and then we return a JSON object containing the token
* for the playlist, and other metadata for use by the renderer.
*
* ^ if the video doesn't require a stream to be generated (e.g. it is very
* small and already uses a compatible codec) then a HTT 204 is returned and
@@ -289,8 +289,10 @@ const handleGenerateHLSWrite = async (
request: Request,
params: URLSearchParams,
) => {
const objectUploadURL = params.get("objectUploadURL");
if (!objectUploadURL) throw new Error("Missing objectUploadURL");
const fileID = parseInt(params.get("fileID") ?? "", 10);
const fetchURL = params.get("fetchURL");
const authToken = params.get("authToken");
if (!fileID || !fetchURL || !authToken) throw new Error("Missing params");
let inputItem: Parameters<typeof makeFileForStreamOrPathOrZipItem>[0];
const path = params.get("path");
@@ -324,7 +326,9 @@ const handleGenerateHLSWrite = async (
result = await worker.ffmpegGenerateHLSPlaylistAndSegments(
inputFilePath,
outputFilePathPrefix,
objectUploadURL,
fileID,
fetchURL,
authToken,
);
if (!result) {
@@ -332,13 +336,18 @@ const handleGenerateHLSWrite = async (
return new Response(null, { status: 204 });
}
const { playlistPath, videoSize, dimensions } = result;
const { playlistPath, dimensions, videoSize, videoObjectID } = result;
const playlistToken = randomUUID();
pendingVideoResults.set(playlistToken, playlistPath);
return new Response(
JSON.stringify({ playlistToken, videoSize, dimensions }),
JSON.stringify({
playlistToken,
dimensions,
videoSize,
videoObjectID,
}),
{ status: 200 },
);
} finally {

View File

@@ -15,3 +15,11 @@
*/
export const wait = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
/**
* Convert `null` to `undefined`, passthrough everything else unchanged.
*
* Duplicated from `web/packages/utils/transform.ts`.
*/
export const nullToUndefined = <T>(v: T | null | undefined): T | undefined =>
v === null ? undefined : v;

View File

@@ -0,0 +1,31 @@
export const clientPackageName = "io.ente.photos.desktop";
/**
* Reimplementation of {@link publicRequestHeaders} from the web source.
*
* @param desktopAppVersion The desktop app's version. This will get passed on
* as the "X-Client-Version" header.
*
* We cannot directly use `app.getVersion()` to obtain this value since the
* {@link app} module is not accessible to Electron utility processes which also
* calls this function.
*/
export const publicRequestHeaders = (desktopAppVersion: string) => ({
"X-Client-Package": clientPackageName,
"X-Client-Version": desktopAppVersion,
});
/**
* Reimplementation of {@link authenticatedRequestHeaders} from the web source.
*
* This builds on top of {@link publicRequestHeaders} and takes the same
* parameters, and additionally also requires the {@link authToken} that will be
* passed as the "X-Auth-Token" header.
*/
export const authenticatedRequestHeaders = (
desktopAppVersion: string,
authToken: string,
) => ({
...publicRequestHeaders(desktopAppVersion),
"X-Auth-Token": authToken,
});

View File

@@ -184,10 +184,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.1.tgz#4a97e85e982099d6c7ee8410aacb55adaa576f06"
integrity sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==
"@eslint/js@^9.25.1":
version "9.25.1"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.25.1.tgz#25f5c930c2b68b5ebe7ac857f754cbd61ef6d117"
integrity sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==
"@eslint/js@^9.27.0":
version "9.27.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.27.0.tgz#181a23460877c484f6dd03890f4e3fa2fdeb8ff0"
integrity sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==
"@eslint/object-schema@^2.1.4":
version "2.1.4"
@@ -297,10 +297,10 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@tsconfig/node22@^22.0.1":
version "22.0.1"
resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.1.tgz#27e3ee9b359e31e5b94690bf2bad5a923c1d57d0"
integrity sha512-VkgOa3n6jvs1p+r3DiwBqeEwGAwEvnVCg/hIjiANl5IEcqP3G0u5m8cBJspe1t9qjZRlZ7WFgqq5bJrGdgAKMg==
"@tsconfig/node22@^22.0.2":
version "22.0.2"
resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.2.tgz#1e04e2c5cc946dac787d69bb502462a851ae51b6"
integrity sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==
"@types/auto-launch@^5.0.5":
version "5.0.5"
@@ -1234,10 +1234,10 @@ electron-updater@^6.6.3:
semver "^7.6.3"
tiny-typed-emitter "^2.1.0"
electron@^36.2.1:
version "36.2.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-36.2.1.tgz#7c9d7c6c7076a3ddb7b1c326a851cb92c775b0b1"
integrity sha512-mm1Y+Ms46xcOTA69h8hpqfX392HfV4lga9aEkYkd/Syx1JBStvcACOIouCgGrnZpxNZPVS1jM8NTcMkNjuK6BQ==
electron@^36.3.1:
version "36.3.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-36.3.1.tgz#12a8c1b1cd9163a4bd0cb60f89816243b26ab788"
integrity sha512-LeOZ+tVahmctHaAssLCGRRUa2SAO09GXua3pKdG+WzkbSDMh+3iOPONNVPTqGp8HlWnzGj4r6mhsIbM2RgH+eQ==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^22.7.7"
@@ -2664,13 +2664,13 @@ prettier-plugin-organize-imports@^4.1.0:
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz#f3d3764046a8e7ba6491431158b9be6ffd83b90f"
integrity sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==
prettier-plugin-packagejson@^2.5.13:
version "2.5.13"
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.13.tgz#4e908d25b97a8f8f1cb69fd611caa677653787d5"
integrity sha512-94B/Xy25HwiwSkGUGnwQw3cBw9jg9L5LfKCHpuRMjC8ETPq4oCMa2S4EblV628E0XER9n6v5rH0TQY9cUd10pg==
prettier-plugin-packagejson@^2.5.14:
version "2.5.14"
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.14.tgz#8ada09114ff60c7f42c3f8755ffb2f8152f3624f"
integrity sha512-h+3tSpr2nVpp+YOK1MDIYtYhHVXr8/0V59UUbJpIJFaqi3w4fvUokJo6eV8W+vELrUXIZzJ+DKm5G7lYzrMcKQ==
dependencies:
sort-package-json "3.2.1"
synckit "0.11.5"
synckit "0.11.6"
prettier@3.5.3:
version "3.5.3"
@@ -3108,13 +3108,12 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
synckit@0.11.5:
version "0.11.5"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.5.tgz#258b3185736512f7ef11a42d67c4f3ad49da1744"
integrity sha512-frqvfWyDA5VPVdrWfH24uM6SI/O8NLpVbIIJxb8t/a3YGsp4AW9CYgSKC0OaSEfexnp7Y1pVh2Y6IHO8ggGDmA==
synckit@0.11.6:
version "0.11.6"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.6.tgz#e742a0c27bbc1fbc96f2010770521015cca7ed5c"
integrity sha512-2pR2ubZSV64f/vqm9eLPz/KOvR9Dm+Co/5ChLgeHl0yEDRc6h5hXHoxEQH8Y5Ljycozd3p1k5TTSVdzYGkPvLw==
dependencies:
"@pkgr/core" "^0.2.4"
tslib "^2.8.1"
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.2.1:
version "6.2.1"
@@ -3214,11 +3213,6 @@ tslib@^2.1.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
tslib@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -3410,3 +3404,8 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod@^3.25.23:
version "3.25.23"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.23.tgz#128fb02f3619a8bca6bbbf6b07b457236cf33391"
integrity sha512-Od2bdMosahjSrSgJtakrwjMDb1zM1A3VIHCPGveZt/3/wlrTWBya2lmEh2OYe4OIu8mPTmmr0gnLHIWQXdtWBg==

View File

@@ -21,7 +21,7 @@ always available on your machine.
background without you needing to run any other cron jobs. See
[migration/export](/photos/migration/export/) for more details.
## Does the exported data preserve folder structure?
## Does the exported data preserve album structure?
Yes. When you export your data for local backup, it will maintain the exact
album structure how you have set up within Ente.

View File

@@ -8,22 +8,43 @@ description:
> [!NOTE]
>
> Video streaming is available in beta on mobile apps starting v0.9.98.
> Video streaming is available in beta on mobile apps starting v0.9.98 and on
> desktop starting v1.7.13.
### How to enable video streaming?
#### On mobile
- Open Settings -> General -> Advanced
- Switch on the toggle for `Video streaming`
#### On desktop
- Open Settings -> Preferences
- Enable the toggle for `Streamable videos`
### What happens when I enable video streaming?
#### On mobile
Enabling video streaming will start processing videos captured in the last 30
days, generating streams for each. Both local and remote videos will be
processed, so this may consume bandwidth for downloading of remote files and
uploading of the generated streams.
#### On desktop
When enabled, the desktop app will generate streams both for new uploads, and
also for all existing videos that were previously uploaded.
Stream generation is CPU intensive and can take time so the app will continue
processing them in the background. Clicking on search bar will show "Processing
videos..." when stream generation is happening.
### How can I view video streams?
### On mobile
Settings -> Backup > Backup status will show details regarding the processing
status for videos. Processed videos will have a green play button next to them.
You can open these videos by tapping on them.
@@ -34,6 +55,12 @@ play the stream.
Clicking on the `Info` icon within the original video will show details about
the generated stream.
### On desktop and web
Desktop and web app will automatically play the streaming version of a video if
it has been already generated. The quality selector will show "Auto" when
playing the stream.
### What is a stream?
Stream is an encrypted HLS file with an `.m3u8` playlist that helps play a video

View File

@@ -49,10 +49,10 @@ For example,
```yaml
apps:
public-albums: albums.myente.xyz
cast: cast.myente.xyz
accounts: accounts.myente.xyz
family: family.myente.xyz
public-albums: https://albums.myente.xyz
cast: https://cast.myente.xyz
accounts: https://accounts.myente.xyz
family: https://family.myente.xyz
```
>[!IMPORTANT]
@@ -74,4 +74,4 @@ functionalities like SMTP, Discord notifications, Hardcoded-OTTs, etc.
## References
- [Environment variables and ports](/self-hosting/faq/environment)
- [Environment variables and ports](/self-hosting/faq/environment)

View File

@@ -3,14 +3,14 @@ title: Uploads
description: Fixing upload errors when trying to self host Ente
---
# Troubleshooting upload failures
# Troubleshooting upload failures
Here are some errors our community members frequently encountered with the
context and potential fixes.
Fundamentally in most situations, the problem is because of minor mistakes or
misconfiguration. Please make sure to reverse proxy museum and MinIO API
endpoint to a domain and check your S3 credentials and whole configuration
misconfiguration. Please make sure to reverse proxy museum and MinIO API
endpoint to a domain and check your S3 credentials and whole configuration
file for any minor misconfigurations.
It is also suggested that the user setups bucket CORS on MinIO or any external
@@ -21,10 +21,10 @@ this](/self-hosting/troubleshooting/bucket-cors).
S3 is an cloud storage protocol made by Amazon (specifically AWS). S3 is designed to store
files and data as objects inside Buckets and it is mostly used for Online
Backups and storing different types of files.
Backups and storing different types of files.
Ente's Docker setup is shipped with [MinIO](https://min.io/) as its default S3 provider.
MinIO supports the Amazon S3 protocol and leverages your disk storage to
Ente's Docker setup is shipped with [MinIO](https://min.io/) as its default S3 provider.
MinIO supports the Amazon S3 protocol and leverages your disk storage to
dump all the uploaded files as encrypted object blobs.
## 403 Forbidden
@@ -40,15 +40,15 @@ This could be because
1. The bucket CORS rules do not allow museum to access these objects. For
uploading files from the browser, you will need to set `allowedOrigins` to
`*`, and allow the `X-Auth-Token`, `X-Client-Package` headers configuration
too. [Here is an example of a working
`*`, and allow the `X-Auth-Token`, `X-Client-Package`, `X-Client-Version`
headers configuration too. [Here is an example of a working
configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204).
2. The credentials are not being picked up (you might be setting the correct
credentials, but not in the place where museum reads them from).
## Mismatch in file size
## Mismatch in file size
The "Mismatch in file size" error mostly occurs in a situation where the client is re-uploading a file which is already in the bucket with a different
file size. The reason for re-upload could be anything including network issue,
sudden killing of app before the upload is complete and etc.
sudden killing of app before the upload is complete and etc.

View File

@@ -21,7 +21,7 @@ const handleOPTIONS = (request: Request) => {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
"Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package, X-Client-Version",
"Access-Control-Max-Age": "86400",
},
});

View File

@@ -22,7 +22,7 @@ const handleOPTIONS = (request: Request) => {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers":
"X-Auth-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package",
"X-Auth-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package, X-Client-Version",
"Access-Control-Max-Age": "86400",
},
});

View File

@@ -21,7 +21,7 @@ const handleOPTIONS = (request: Request) => {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
"Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package, X-Client-Version",
"Access-Control-Max-Age": "86400",
},
});

View File

@@ -28,7 +28,7 @@ const handleOPTIONS = (request: Request) => {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, PUT, OPTIONS",
"Access-Control-Allow-Headers":
"Content-Type, UPLOAD-URL, X-Client-Package",
"Content-Type, UPLOAD-URL, X-Client-Package, X-Client-Version",
"Access-Control-Expose-Headers": "X-Request-Id, CF-Ray",
"Access-Control-Max-Age": "86400",
},

View File

@@ -53,7 +53,7 @@ analyzer:
sort_child_properties_last: warning
sort_pub_dependencies: warning
library_private_types_in_public_api: warning
constant_identifier_names: warning
constant_identifier_names: ignore
prefer_const_constructors: warning
prefer_const_declarations: warning
prefer_const_constructors_in_immutables: warning

View File

@@ -8,7 +8,10 @@
android:requestLegacyExternalStorage="true"
android:allowBackup="false"
android:fullBackupContent="false"
android:largeHeap="true">
android:dataExtractionRules="@xml/data_extraction_rules"
android:largeHeap="true"
android:networkSecurityConfig="@xml/network_security_config"
>
<activity android:name=".MainActivity" android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
@@ -150,6 +153,29 @@
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/memory_widget" />
</receiver>
<receiver android:name="EnteAlbumsWidgetProvider" android:label="Albums" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/albums_widget" />
</receiver>
<receiver android:name="EntePeopleWidgetProvider" android:label="People" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/people_widget" />
</receiver>
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" /> <!-- Needed for scheduling notifications -->
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver"> <!-- Needed for scheduling notifications -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
</application>
<!-- Android 11: https://developer.android.com/preview/privacy/package-visibility -->
@@ -177,4 +203,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <!-- Needed for scheduling notifications -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <!-- Needed for scheduling notifications -->
</manifest>

View File

@@ -0,0 +1,195 @@
package io.ente.photos
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetProvider
import java.io.File
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
@Serializable
data class AlbumsFileData(
val title: String?,
val subText: String?,
val generatedId: Int?,
val mainKey: String?
)
class EnteAlbumsWidgetProvider : HomeWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
widgetData: SharedPreferences
) {
appWidgetIds.forEach { widgetId ->
val views =
RemoteViews(context.packageName, R.layout.albums_widget_layout)
.apply {
val totalAlbums =
widgetData.getInt("totalAlbums", 0)
var randomNumber = -1
var imagePath: String? = null
if (totalAlbums > 0) {
randomNumber =
(0 until totalAlbums!!).random()
imagePath =
widgetData.getString(
"albums_widget_" +
randomNumber,
null
)
}
var imageExists: Boolean = false
if (imagePath != null) {
val imageFile = File(imagePath)
imageExists = imageFile.exists()
}
if (imageExists) {
val data =
widgetData.getString(
"albums_widget_${randomNumber}_data",
null
)
val decoded: AlbumsFileData? =
data?.let {
Json.decodeFromString<
AlbumsFileData>(it)
}
val title = decoded?.title
val subText = decoded?.subText
val generatedId = decoded?.generatedId
val mainKey = decoded?.mainKey
val deepLinkUri =
Uri.parse(
"albumwidget://message?generatedId=${generatedId}&mainKey=${mainKey}&homeWidget"
)
val pendingIntent =
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
deepLinkUri
)
setOnClickPendingIntent(
R.id.widget_container,
pendingIntent
)
Log.d(
"EnteAlbumsWidgetProvider",
"Image exists: $imagePath"
)
setViewVisibility(
R.id.widget_img,
View.VISIBLE
)
setViewVisibility(
R.id.widget_subtitle,
View.VISIBLE
)
setViewVisibility(
R.id.widget_title,
View.VISIBLE
)
setViewVisibility(
R.id.widget_overlay,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder_text,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder_container,
View.GONE
)
val bitmap: Bitmap =
BitmapFactory.decodeFile(imagePath)
setImageViewBitmap(R.id.widget_img, bitmap)
setTextViewText(R.id.widget_title, title)
setTextViewText(
R.id.widget_subtitle,
subText
)
} else {
// Open App on Widget Click
val pendingIntent =
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java
)
setOnClickPendingIntent(
R.id.widget_container,
pendingIntent
)
Log.d(
"EnteAlbumsWidgetProvider",
"Image doesn't exists"
)
setViewVisibility(
R.id.widget_img,
View.GONE
)
setViewVisibility(
R.id.widget_subtitle,
View.GONE
)
setViewVisibility(
R.id.widget_title,
View.GONE
)
setViewVisibility(
R.id.widget_overlay,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder_text,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder_container,
View.VISIBLE
)
val drawable =
ContextCompat.getDrawable(
context,
R.drawable.ic_albums_widget
)
val bitmap =
(drawable as BitmapDrawable).bitmap
setImageViewBitmap(
R.id.widget_placeholder,
bitmap
)
}
}
appWidgetManager.updateAppWidget(widgetId, views)
}
}
}

View File

@@ -91,10 +91,6 @@ class EnteMemoryWidgetProvider : HomeWidgetProvider() {
R.id.widget_img,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder_container,
View.VISIBLE
)
setViewVisibility(
R.id.widget_subtitle,
View.VISIBLE
@@ -148,10 +144,6 @@ class EnteMemoryWidgetProvider : HomeWidgetProvider() {
R.id.widget_img,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder_container,
View.GONE
)
setViewVisibility(
R.id.widget_subtitle,
View.GONE
@@ -181,7 +173,7 @@ class EnteMemoryWidgetProvider : HomeWidgetProvider() {
ContextCompat.getDrawable(
context,
R.drawable
.ic_home_widget_default
.ic_memories_widget
)
val bitmap =
(drawable as BitmapDrawable).bitmap

View File

@@ -0,0 +1,195 @@
package io.ente.photos
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetProvider
import java.io.File
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
@Serializable
data class PeopleFileData(
val title: String?,
val subText: String?,
val generatedId: Int?,
val mainKey: String?
)
class EntePeopleWidgetProvider : HomeWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
widgetData: SharedPreferences
) {
appWidgetIds.forEach { widgetId ->
val views =
RemoteViews(context.packageName, R.layout.people_widget_layout)
.apply {
val totalPeople =
widgetData.getInt("totalPeople", 0)
var randomNumber = -1
var imagePath: String? = null
if (totalPeople > 0) {
randomNumber =
(0 until totalPeople!!).random()
imagePath =
widgetData.getString(
"people_widget_" +
randomNumber,
null
)
}
var imageExists: Boolean = false
if (imagePath != null) {
val imageFile = File(imagePath)
imageExists = imageFile.exists()
}
if (imageExists) {
val data =
widgetData.getString(
"people_widget_${randomNumber}_data",
null
)
val decoded: PeopleFileData? =
data?.let {
Json.decodeFromString<
PeopleFileData>(it)
}
val title = decoded?.title
val subText = decoded?.subText
val generatedId = decoded?.generatedId
val mainKey = decoded?.mainKey
val deepLinkUri =
Uri.parse(
"peoplewidget://message?generatedId=${generatedId}&mainKey=${mainKey}&homeWidget"
)
val pendingIntent =
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
deepLinkUri
)
setOnClickPendingIntent(
R.id.widget_container,
pendingIntent
)
Log.d(
"EntePeopleWidgetProvider",
"Image exists: $imagePath"
)
setViewVisibility(
R.id.widget_img,
View.VISIBLE
)
setViewVisibility(
R.id.widget_subtitle,
View.VISIBLE
)
setViewVisibility(
R.id.widget_title,
View.VISIBLE
)
setViewVisibility(
R.id.widget_overlay,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder_text,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder_container,
View.GONE
)
val bitmap: Bitmap =
BitmapFactory.decodeFile(imagePath)
setImageViewBitmap(R.id.widget_img, bitmap)
setTextViewText(R.id.widget_title, title)
setTextViewText(
R.id.widget_subtitle,
subText
)
} else {
// Open App on Widget Click
val pendingIntent =
HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java
)
setOnClickPendingIntent(
R.id.widget_container,
pendingIntent
)
Log.d(
"EntePeopleWidgetProvider",
"Image doesn't exists"
)
setViewVisibility(
R.id.widget_img,
View.GONE
)
setViewVisibility(
R.id.widget_subtitle,
View.GONE
)
setViewVisibility(
R.id.widget_title,
View.GONE
)
setViewVisibility(
R.id.widget_overlay,
View.GONE
)
setViewVisibility(
R.id.widget_placeholder,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder_text,
View.VISIBLE
)
setViewVisibility(
R.id.widget_placeholder_container,
View.VISIBLE
)
val drawable =
ContextCompat.getDrawable(
context,
R.drawable.ic_people_widget
)
val bitmap =
(drawable as BitmapDrawable).bitmap
setImageViewBitmap(
R.id.widget_placeholder,
bitmap
)
}
}
appWidgetManager.updateAppWidget(widgetId, views)
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/widget_container">
<!-- Main Image (if available) -->
<ImageView
android:id="@+id/widget_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:visibility="gone" /> <!-- Initially hidden -->
<!-- Gradient Overlay for Text Readability -->
<LinearLayout
android:id="@+id/widget_overlay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp"
android:paddingTop="4dp"
android:background="@layout/gradient_overlay"
android:visibility="gone"> <!-- Initially hidden, shown when image is available -->
<!-- Title -->
<TextView
android:id="@+id/widget_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/white"
android:textSize="14sp"
android:textStyle="bold"
android:maxLines="1"
android:ellipsize="end"
android:visibility="gone"/>
<!-- Subtitle -->
<TextView
android:id="@+id/widget_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/white"
android:textSize="12sp"
android:maxLines="1"
android:ellipsize="end"
android:visibility="gone"/>
</LinearLayout>
<!-- Placeholder View (when no image available) -->
<LinearLayout
android:id="@+id/widget_placeholder_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:background="@color/widget_placeholder_bg">
<ImageView
android:id="@+id/widget_placeholder"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/ic_albums_widget"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/widget_placeholder_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to Settings -> General to customise the widget"
android:textSize="12sp"
android:gravity="center_horizontal"
android:textColor="@color/widget_text_color"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:layout_marginTop="12dp"/>
</LinearLayout>
</FrameLayout>

View File

@@ -65,15 +65,15 @@
android:id="@+id/widget_placeholder"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/ic_home_widget_default"
android:src="@drawable/ic_memories_widget"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/widget_placeholder_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your memories will appear here"
android:textSize="14sp"
android:text="Go to Settings -> General to customise the widget"
android:textSize="12sp"
android:gravity="center_horizontal"
android:textColor="@color/widget_text_color"
android:paddingStart="8dp"

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/widget_container">
<!-- Main Image (if available) -->
<ImageView
android:id="@+id/widget_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:visibility="gone" /> <!-- Initially hidden -->
<!-- Gradient Overlay for Text Readability -->
<LinearLayout
android:id="@+id/widget_overlay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp"
android:paddingTop="4dp"
android:background="@layout/gradient_overlay"
android:visibility="gone"> <!-- Initially hidden, shown when image is available -->
<!-- Title -->
<TextView
android:id="@+id/widget_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/white"
android:textSize="14sp"
android:textStyle="bold"
android:maxLines="1"
android:ellipsize="end"
android:visibility="gone"/>
<!-- Subtitle -->
<TextView
android:id="@+id/widget_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/white"
android:textSize="12sp"
android:maxLines="1"
android:ellipsize="end"
android:visibility="gone"/>
</LinearLayout>
<!-- Placeholder View (when no image available) -->
<LinearLayout
android:id="@+id/widget_placeholder_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:background="@color/widget_placeholder_bg">
<ImageView
android:id="@+id/widget_placeholder"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/ic_people_widget"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/widget_placeholder_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to Settings -> General to customise the widget"
android:textSize="12sp"
android:gravity="center_horizontal"
android:textColor="@color/widget_text_color"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:layout_marginTop="12dp"/>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="100dp"
android:minHeight="100dp"
android:updatePeriodMillis="900000"
android:initialLayout="@layout/albums_widget_layout"
android:previewImage="@drawable/albums_widget_preview"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen">
</appwidget-provider>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
<cloud-backup>
<exclude domain="root" path="."/>
<exclude domain="file" path="."/>
<exclude domain="database" path="."/>
<exclude domain="sharedpref" path="."/>
<exclude domain="external" path="."/>
</cloud-backup>
<device-transfer>
<exclude domain="root" path="."/>
<exclude domain="file" path="."/>
<exclude domain="database" path="."/>
<exclude domain="sharedpref" path="."/>
<exclude domain="external" path="."/>
</device-transfer>
</data-extraction-rules>

View File

@@ -0,0 +1,14 @@
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">ente.io</domain>
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</domain-config>
</network-security-config>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="100dp"
android:minHeight="100dp"
android:updatePeriodMillis="900000"
android:initialLayout="@layout/people_widget_layout"
android:previewImage="@drawable/people_widget_preview"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen">
</appwidget-provider>

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.668 3.33073V13.3307H6.66797V3.33073H16.668ZM16.668 1.66406H6.66797C5.7513 1.66406 5.0013 2.41406 5.0013 3.33073V13.3307C5.0013 14.2474 5.7513 14.9974 6.66797 14.9974H16.668C17.5846 14.9974 18.3346 14.2474 18.3346 13.3307V3.33073C18.3346 2.41406 17.5846 1.66406 16.668 1.66406ZM9.58464 9.7224L10.993 11.6057L13.0596 9.0224L15.8346 12.4974H7.5013L9.58464 9.7224ZM1.66797 4.9974V16.6641C1.66797 17.5807 2.41797 18.3307 3.33464 18.3307H15.0013V16.6641H3.33464V4.9974H1.66797Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 604 B

View File

@@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="1" width="15" height="18" rx="1.4" stroke="black" stroke-width="1.4"/>
<path d="M11.773 16.5745C11.5071 16.8091 11.0978 16.8091 10.8319 16.5711L10.7934 16.5371C8.95659 14.9221 7.75655 13.8646 7.80203 12.5454C7.82302 11.9674 8.12741 11.4132 8.62072 11.0868C9.54436 10.4748 10.6849 10.7604 11.3007 11.4608C11.9164 10.7604 13.057 10.4714 13.9807 11.0868C14.474 11.4132 14.7783 11.9674 14.7993 12.5454C14.8483 13.8646 13.6448 14.9221 11.808 16.5439L11.773 16.5745Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 595 B

View File

@@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.3333 3.33073H15.5V1.66406H13.8333V3.33073H7.16667V1.66406H5.5V3.33073H4.66667C3.74167 3.33073 3 4.08073 3 4.9974V16.6641C3 17.5807 3.74167 18.3307 4.66667 18.3307H16.3333C17.25 18.3307 18 17.5807 18 16.6641V4.9974C18 4.08073 17.25 3.33073 16.3333 3.33073ZM16.3333 16.6641H4.66667V8.33073H16.3333V16.6641ZM16.3333 6.66406H4.66667V4.9974H16.3333V6.66406ZM6.33333 9.9974H10.5V14.1641H6.33333V9.9974Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 529 B

View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.9987 5.0026C10.9154 5.0026 11.6654 5.7526 11.6654 6.66927C11.6654 7.58594 10.9154 8.33594 9.9987 8.33594C9.08203 8.33594 8.33203 7.58594 8.33203 6.66927C8.33203 5.7526 9.08203 5.0026 9.9987 5.0026ZM9.9987 13.3359C12.2487 13.3359 14.832 14.4109 14.9987 15.0026H4.9987C5.19036 14.4026 7.75703 13.3359 9.9987 13.3359ZM9.9987 3.33594C8.15703 3.33594 6.66536 4.8276 6.66536 6.66927C6.66536 8.51094 8.15703 10.0026 9.9987 10.0026C11.8404 10.0026 13.332 8.51094 13.332 6.66927C13.332 4.8276 11.8404 3.33594 9.9987 3.33594ZM9.9987 11.6693C7.7737 11.6693 3.33203 12.7859 3.33203 15.0026V16.6693H16.6654V15.0026C16.6654 12.7859 12.2237 11.6693 9.9987 11.6693Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 781 B

View File

@@ -0,0 +1,11 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_38630_146929)">
<path d="M11.1613 17.0685C10.5815 17.5949 9.68898 17.5949 9.10919 17.0609L9.02528 16.9846C5.0202 13.3609 2.40355 10.9884 2.50272 8.02846C2.5485 6.73158 3.2122 5.4881 4.28784 4.75574C6.30183 3.38257 8.78879 4.02339 10.1314 5.5949C11.4741 4.02339 13.9611 3.37494 15.975 4.75574C17.0507 5.4881 17.7144 6.73158 17.7602 8.02846C17.867 10.9884 15.2427 13.3609 11.2376 16.9998L11.1613 17.0685Z" stroke="black" stroke-width="1.5"/>
<path d="M14.5938 0.34668C14.9459 -0.282495 15.8744 -0.282502 16.2266 0.34668L16.293 0.491211L16.9727 2.34277L18.8252 3.02344L18.9697 3.08984C19.5989 3.44199 19.5989 4.37051 18.9697 4.72266L18.8252 4.78906L16.9727 5.46875L16.293 7.32129C16.01 8.09135 14.971 8.13983 14.5938 7.46582L14.5273 7.32129L13.8467 5.46875L11.9951 4.78906C11.1738 4.4873 11.1738 3.3252 11.9951 3.02344L13.8467 2.34277L14.5273 0.491211L14.5938 0.34668Z" fill="black" stroke="#F5F5F5" stroke-width="1.25366"/>
</g>
<defs>
<clipPath id="clip0_38630_146929">
<rect width="20" height="20" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
//
// EnteAlbumWidgetBundle.swift
// EnteAlbumWidget
//
// Created by Prateek Sunal on 5/15/25.
// Copyright © 2025 The Chromium Authors. All rights reserved.
//
import WidgetKit
import SwiftUI
@main
struct EnteAlbumWidgetBundle: WidgetBundle {
var body: some Widget {
EnteAlbumWidget()
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.io.ente.frame.EnteMemoryWidget</string>
</array>
</dict>
</plist>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
//
// EntePeopleWidgetBundle.swift
// EntePeopleWidget
//
// Created by Prateek Sunal on 5/15/25.
// Copyright © 2025 The Chromium Authors. All rights reserved.
//
import WidgetKit
import SwiftUI
@main
struct EntePeopleWidgetBundle: WidgetBundle {
var body: some Widget {
EntePeopleWidget()
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More