Compare commits

...

723 Commits

Author SHA1 Message Date
Neeraj Gupta
38503e8673 Merge remote-tracking branch 'origin/main' into remote_db 2025-09-02 10:34:47 +05:30
Aman Raj Singh Mourya
91785d8c90 Add Parallels custom icon (#7026)
## Description
This PR adds a custom icon for Parallels.

- Added `parallels.svg` under
`mobile/apps/auth/assets/custom-icons/icons/`
- Updated `custom-icons.json` with:
  - title: "Parallels"
  - slug: "parallels"
  - hex: #E61E25
  - altNames: ["Parallels Desktop", "Parallels VM"]

The icon is optimized (well under 50KB) and uses the official Parallels
red (#E61E25).
2025-09-02 00:19:46 +05:30
Ashil
210c18d244 Update internal changes (#7030) 2025-09-01 17:32:12 +05:30
Ashil
6636849838 update internal changes 2025-09-01 17:26:20 +05:30
Neeraj
5500315351 [mob][photos] fix unsupported locales in language selector (#7029) 2025-09-01 17:24:32 +05:30
Prateek Sunal
562292e642 fix: remove unsupported languages from language picker
Remove languages from _getLanguageName that don't have >90% translation
coverage and aren't in appSupportedLocales (Finnish, Korean, Arabic).
Also improve Chinese locale display.

- Removed fi, ko, ar cases that don't meet translation threshold
- Fixed Chinese locale handling to properly show "中文 (简体)" for zh_CN
- Ensures only properly translated languages appear in the picker

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-01 17:13:58 +05:30
Prateek Sunal
4aa80edbcf fix: resolve unsupported locales appearing in language selector
Replace AppLocalizations.supportedLocales with a curated list of properly
translated locales in the Photos app. This fixes the issue where unsupported
language codes (Bg, Be, Ca, Cs, etc.) were appearing in the language selector
without proper language name formatting.

- Add custom appSupportedLocales list with only >90% translated languages
- Update all references throughout Photos app to use the custom locale list
- Ensures only properly supported languages appear in the language picker

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-01 17:02:15 +05:30
Neeraj
9524a639cd [server] Fix collection link for locker (#6961)
## Description

## Tests
2025-09-01 16:28:19 +05:30
Neeraj
b8eb793c16 [mobile/photos] New translations (#7022)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-09-01 16:26:51 +05:30
Ashil
4b514f1e1a [mob][photos] Revert "Revert diskLoadDeferDuration to 500ms" (#7028)
This reverts commit a295f223b6.
2025-09-01 16:25:59 +05:30
ashilkn
772121c22e Revert "Revert diskLoadDeferDuration to 500ms"
This reverts commit a295f223b6.
2025-09-01 16:07:40 +05:30
Onurcan
f2e51893ad Update Parallels custom-icons.json 2025-09-01 11:59:32 +03:00
Onurcan
c08b78c775 dd Parallels custom icon 2025-09-01 11:58:26 +03:00
Laurens Priem
73ab50f113 [mob][photos] Run vectorDB migration is memory safe way (#7024)
## Description

- Add ability to block computeController temporarily
- Block computeController when vectorDB migration is running
2025-09-01 11:44:39 +05:30
laurenspriem
4a2346fe93 Block compute when vectorDB migration is happening 2025-09-01 11:11:10 +05:30
laurenspriem
68b5cce158 Add option to block compute tasks (ml, streaming) 2025-09-01 11:09:51 +05:30
laurenspriem
e907a9e8cb comment 2025-09-01 10:59:02 +05:30
Manav Rathi
92a40afca2 [web] New translations (#7021)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-09-01 10:22:50 +05:30
Aman Raj Singh Mourya
0c2b38c059 Fixing dev build on macos (#7012)
This should fix this error
https://github.com/ente-io/ente/pull/6768#discussion_r2310164866
2025-09-01 09:26:51 +05:30
Crowdin Bot
19650bcd57 New Crowdin translations by GitHub Action 2025-09-01 01:05:33 +00:00
Crowdin Bot
2b9ca073ce New Crowdin translations by GitHub Action 2025-09-01 00:45:39 +00:00
Aman Raj Singh Mourya
cf4b87dad9 [locker] Refactor theme handling in Locker to fix DynamicFAB style (#7016)
## Description
DynamicFAB theme was not getting applied from the commons package. This
PR fix that issue.

## Tests

**Before**

<img width="300" height="750" alt="Simulator Screenshot - iPhone 16 Plus
- 2025-08-30 at 15 53 26"
src="https://github.com/user-attachments/assets/17dfc778-b652-4e10-ad8f-3c8aed2656f6"
/>


**After**

<img width="300" height="750" alt="Simulator Screenshot - iPhone 16 Plus
- 2025-08-30 at 15 52 58"
src="https://github.com/user-attachments/assets/9e0c2feb-8204-4875-9bad-f9d4eaab8f36"
/>
2025-08-30 16:01:01 +05:30
AmanRajSinghMourya
3fd0db6a90 Refactor theme handling in locker to fix DynamicFAB 2025-08-30 15:52:34 +05:30
Laurens Priem
ce1701d211 [mob][photos] Similar small fixes (#7008)
## Description

Small design changes and fixes.

## Tests

Tested in debug mode on my pixel phone.
2025-08-30 07:29:27 +05:30
Laurens Priem
aaed336991 [infra] Release action changes (#7010)
## Description

- Disk space cleanup
- Generate rust bindings
2025-08-29 20:05:31 +05:30
eYdr1en
0b85dfe7e4 fixing dev build on macos 2025-08-29 15:53:56 +02:00
Prateek Sunal
68422b172f [mob][photos] fix manual video streaming when ML is enabled (#7009) 2025-08-29 18:53:53 +05:30
laurenspriem
db99dae3e1 log line 2025-08-29 18:48:00 +05:30
laurenspriem
3717a156d3 Logging unexpected embeddings 2025-08-29 18:47:01 +05:30
Prateek Sunal
ca9930e01b style: fix import directive ordering in thumbnail_widget 2025-08-29 12:50:13 +00:00
laurenspriem
eb23a4e770 rust bindings 2025-08-29 18:19:50 +05:30
laurenspriem
e03303e5b3 release workflow disk cleanup 2025-08-29 18:18:45 +05:30
laurenspriem
2ad27f1c6e Clear similar images json cache 2025-08-29 18:03:27 +05:30
Prateek Sunal
202e6a9f7c fix: trigger processing for already-queued manual stream files
When users click "Create Stream" on files already in queue from
previous sessions, ensure processing actually starts even if the
file was previously stalled due to ML blocking.

Add forceProcess parameter to queueFiles() to bypass the existing
queue check and trigger processing of stalled manual queue items.
2025-08-29 12:28:48 +00:00
laurenspriem
ceaedad327 debug option to delete vectorDB index 2025-08-29 17:57:21 +05:30
Prateek Sunal
fd963a1c8e fix: allow manual video stream creation when ML is waiting
When ML is enabled but not running, the compute controller blocks
all stream requests due to _waitingToRunML flag. This prevents
users from manually creating video streams even though ML isn't
actively using resources.

Add bypassMLWaiting parameter to allow manual stream creation
to proceed regardless of ML waiting state, improving UX.
2025-08-29 12:22:08 +00:00
laurenspriem
b40b5bb1ae delete progress 2025-08-29 17:07:44 +05:30
laurenspriem
91827626b2 dot dot dot 2025-08-29 17:04:33 +05:30
laurenspriem
42318335ae Fix issue with deleting favorites 2025-08-29 16:16:51 +05:30
laurenspriem
858db62385 Left align large files 2025-08-29 16:09:10 +05:30
laurenspriem
46e36612d3 Scroll to top after delete 2025-08-29 15:49:09 +05:30
laurenspriem
62cf236e3b Cycle through loading screen texts 2025-08-29 15:27:11 +05:30
Ashil
c2b1ab86f2 [mob][photos] Fix incorrect file deletion from db when widget unmounts during thumbnail loading (#7007)
## Description

Previously, when _loadWithRetry returned null due to widget unmounting,
the code incorrectly assumed the local file was deleted and would remove
database reference of the file and which would trigger re-upload of the
file.
2025-08-29 15:17:55 +05:30
laurenspriem
43adf42281 Don't auto select favorites for deletions 2025-08-29 15:00:42 +05:30
laurenspriem
1e2a65281c Fix delete button bug 2025-08-29 14:32:12 +05:30
ashilkn
70eb68b13c Fix incorrect file deletion when widget unmounts during thumbnail loading
Previously, when _loadWithRetry returned null due to widget unmounting,
the code incorrectly assumed the local file was deleted and would remove
database references or delete the file. This could lead to data loss.

Changes:
- Add new WidgetUnmountedException to centralized exceptions.dart for reuse
- Throw WidgetUnmountedException instead of returning null when widget unmounts
- Handle WidgetUnmountedException separately in error handler with appropriate logging
- Still set _errorLoadingLocalThumbnail flag to prevent retry attempts

Using Exception instead of Error follows Dart conventions:
- Exceptions are for recoverable runtime conditions (like widget unmounting)
- Errors are for programming mistakes that shouldn't be caught

This ensures that widget unmounting is properly distinguished from actual
file access failures.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 14:17:49 +05:30
Ashil
fa86b19307 [mob][photos] Update internal change log (#7006) 2025-08-29 14:10:19 +05:30
Ashil
e632dc7771 Merge branch 'main' into update_int_change_log 2025-08-29 14:08:58 +05:30
ashilkn
7fa9adb636 update internal change log 2025-08-29 14:08:00 +05:30
Ashil
83f885f158 [mob][photos] Revert diskLoadDeferDuration to 500ms (#7005)
## Description
2025-08-29 13:58:58 +05:30
ashilkn
a295f223b6 Revert diskLoadDeferDuration to 500ms
Reverts the change from commit 1f1cad181f
which reduced galleryThumbnailDiskLoadDeferDuration from 500ms to 80ms.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 12:57:42 +05:30
Laurens Priem
cc64ef8035 [infra] Create more space for internal release action (#7004)
## Description

- Removed redundant SDKs
- Removed redundant rust install (already pre-installed)
- Delete old other action
2025-08-29 12:41:28 +05:30
Ashil
69dd7b6233 [mob][photos] Spacing (#7002)
## Description

Add spacing in similar images page.
2025-08-29 12:41:11 +05:30
Ashil
bcc9f1be73 [mob][photos] Revert cache extent changes (#7000)
## Description

The reverted changes were intended to solve the issue #6957 fixed. So
these changes are no longer needed and there are doubts if they are
causing regressions related to thumbnail loading.

## Tests
2025-08-29 12:26:29 +05:30
Ashil
296b2a2a6c Merge branch 'main' into revert-cache-extent-changes 2025-08-29 12:24:03 +05:30
laurenspriem
6b48c9bc34 Remove ineffective cleanup steps 2025-08-29 12:23:47 +05:30
ashilkn
6a951bcc72 Update internal change log 2025-08-29 12:23:28 +05:30
laurenspriem
38914981a1 Fix disk space calculation in cleanup step 2025-08-29 11:52:36 +05:30
laurenspriem
66f4d5b1a6 Add disk cleanup step to free space in GitHub Actions
Removes unused pre-installed software to free ~30-45GB:
- .NET SDK (~20-25GB)
- Haskell compiler (~5-8GB)
- Boost libraries (~1-2GB)
- Cached tool versions (~5-10GB)

Includes timing and space metrics for each removal

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 11:43:07 +05:30
laurenspriem
9ee3781320 spacing 2025-08-29 10:30:05 +05:30
laurenspriem
907d1d2bb8 delete rust install (already on runner env by default) 2025-08-29 10:27:46 +05:30
laurenspriem
8218283463 delete old action 2025-08-29 10:26:32 +05:30
Laurens Priem
bd43385949 [mob][photos] Similar index clear (#6997)
## Description

- Clear vectorDB index on logout
- Revert to using `view` on index
- Use `.usearch` for index file
- Minor design changes

## Tests

Tested in debug mode on my pixel phone.
2025-08-28 18:57:28 +05:30
Laurens Priem
2e6a9acaf9 Merge branch 'main' into similar_index_clear 2025-08-28 18:57:11 +05:30
Ashil
a02dcace7d [mob][photos] New Ducky launcher icons (#6999) 2025-08-28 18:56:34 +05:30
Laurens Priem
cf4285de6d Merge branch 'main' into similar_index_clear 2025-08-28 18:50:12 +05:30
laurenspriem
f831491e4a log changes 2025-08-28 18:30:29 +05:30
laurenspriem
af154d82de ducky analyzing riv animation 2025-08-28 18:17:11 +05:30
Prateek Sunal
ff2f75ea74 [mob][photos] bypass size/duration limits for manual video stream requests (#6998)
## Summary
- Modified `_checkFileForPreviewCreation` method to accept `isManual`
parameter
- Bypass 500MB file size and 60 second duration limits when user
manually triggers video stream processing
- Maintains size/duration restrictions for automatic streaming to
preserve device performance

## Test plan
- [x] Manual Create/Recreate Stream button bypasses 500MB and 60 second
limits
- [x] Automatic streaming still respects size and duration restrictions
- [x] Files larger than 500MB or longer than 60 seconds can be manually
processed
2025-08-28 17:51:26 +05:30
laurenspriem
97e3ef819a Change migration key because index file was changed (internal only) 2025-08-28 17:43:18 +05:30
Prateek Sunal
3685cd2154 fix: don't show create stream if file size is null 2025-08-28 17:34:29 +05:30
laurenspriem
c64fff8ca4 empty tab state ducky 2025-08-28 17:25:54 +05:30
ashilkn
23dc809589 Remove hardcoded cacheExtent to use Flutter's default value 2025-08-28 17:07:46 +05:30
laurenspriem
33d1242c6d strings 2025-08-28 17:03:53 +05:30
laurenspriem
b8ee9fafd1 Better confirmation dialog 2025-08-28 17:03:24 +05:30
ashilkn
f72c9fa068 Revert "Different cache extents for different photoGridSizes"
This reverts commit 769adb75c5.
2025-08-28 16:55:39 +05:30
Ashil
1a7275a101 Merge branch 'main' into ducky_icon 2025-08-28 16:17:58 +05:30
Prateek Sunal
fa7ccbd180 fix: if fileSize is null for manual way then skip 10MB check 2025-08-28 16:16:15 +05:30
ashilkn
79e26d6993 Update internal change log 2025-08-28 16:16:04 +05:30
ashilkn
023135afb5 Remove green background from ducky icon display
Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-28 16:07:32 +05:30
Prateek Sunal
04aaa3a5e4 fix: bypass size/duration limits for manual video stream requests
Allow manual stream requests to bypass the 500MB file size and 60-second
duration limits by passing isManual parameter to _checkFileForPreviewCreation.
This ensures users can manually process large files even if they exceed the
automatic streaming limits.
2025-08-28 10:25:45 +00:00
laurenspriem
848857f409 same close related 2025-08-28 15:27:33 +05:30
ashilkn
137033be67 Update Android ducky launcher icon
Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-28 15:23:51 +05:30
laurenspriem
04b6f4a765 right threshold 2025-08-28 15:05:58 +05:30
laurenspriem
2645ba0949 Change index file name to use usearch 2025-08-28 13:13:16 +05:30
laurenspriem
5958647fa8 Delete vectorDB index file on logout 2025-08-28 13:11:05 +05:30
laurenspriem
b7b91631f6 revert back to view on index 2025-08-28 13:01:26 +05:30
Prateek Sunal
67d7f586b2 [mob][photos] bypass interaction check for manual stream requests (#6993)
## Summary
- Manual Create/Recreate Stream button presses now bypass user
interaction timer for immediate processing
- Fixed multiple concurrent streaming processes bug in ComputeController
- Fixed video streaming description text display spacing in advanced
settings
- Maintains device health and ML priority checks for all streaming
requests

## Tests
- [x] Manual Create/Recreate Stream button bypasses interaction timer  
- [x] Automatic streaming still respects interaction timer
- [x] Only one streaming process allowed at a time
2025-08-27 21:15:55 +05:30
Prateek Sunal
7c22a8bb25 chore: lint fix 2025-08-27 21:10:18 +05:30
Prateek Sunal
ff3864a09a fix: check only if permission granted before chunking 2025-08-27 21:09:10 +05:30
Prateek Sunal
4484b9e4ad update: add video streaming improvements to change logs
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-27 13:21:59 +00:00
Prateek Sunal
e9554ffbcb fix: prevent multiple concurrent streaming processes
Remove condition allowing additional stream requests when already streaming to ensure only one stream process runs at a time.

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-27 13:15:10 +00:00
Prateek Sunal
ad3901d484 fix: remove conditional clearQueue for manual processing
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-27 13:08:12 +00:00
Prateek Sunal
ecca4c3dc8 feat: bypass interaction check for manual stream requests
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-27 13:00:21 +00:00
Prateek Sunal
d05521f884 [mob][photos] video streaming description spacing and alignment (#6992)
## Summary
- Split videoStreamingDescription into separate line1/line2 localization
keys
- Remove TextAlign.justify from enabled state to fix awkward word
spacing
- Standardize text rendering between enabled and disabled states
- Both states now display description consistently without spacing
issues

## Test plan
- [x] Verify enabled state displays as single line without spacing
issues
- [x] Verify disabled state shows proper line breaks in onboarding
- [x] Confirm localization keys generate correctly
- [x] Run dart format and dart analyze (no issues)

Fixes video streaming settings page text display inconsistencies.
2025-08-27 18:08:28 +05:30
Prateek Sunal
ff37c4bf81 fix: video streaming description spacing and alignment
- Split videoStreamingDescription into separate line1/line2 localization keys
- Remove TextAlign.justify from enabled state to fix awkward word spacing
- Standardize text rendering between enabled and disabled states
- Both states now display description consistently without spacing issues

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-27 12:03:31 +00:00
ashilkn
446df755fa Add ducky icon for iOS
Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-27 17:23:31 +05:30
ashilkn
a7805784b7 Add ducky icon for Android
Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-27 17:01:09 +05:30
Neeraj
84a5ad0b86 [mob][photos] More minor design changes for similar images (#6986)
## Description

- Change tab order
- Make tabs distinct
- Change default ordering to size

## Tests

Tested in debug mode on my pixel phone.
2025-08-27 13:25:40 +05:30
laurenspriem
44ad11343a Better empty state prompt for emtpy tab 2025-08-27 13:17:41 +05:30
laurenspriem
07e50e3cfe Change default sort to size 2025-08-27 13:03:30 +05:30
laurenspriem
df8bbdb788 Make identical and similar distinct 2025-08-27 13:01:56 +05:30
laurenspriem
1ed381fe52 Change order of tabs 2025-08-27 12:52:45 +05:30
ashilkn
55090436ce Add new ducky-icon assets 2025-08-27 11:21:36 +05:30
Laurens Priem
ddd1d5ac86 [mob][photos] Similar images UX changes (#6981)
## Description

Similar images UX changes

## Tests

Tested in debug mode on my pixel phone.
2025-08-26 23:50:33 +05:30
Laurens Priem
26845a502e [mob][photos] Use load instead of view on index (#6980)
## Description

Use load instead of index
2025-08-26 23:48:59 +05:30
laurenspriem
21aac29020 format count properly 2025-08-26 23:48:31 +05:30
laurenspriem
c1ff02df14 Always select all on tab change 2025-08-26 23:39:21 +05:30
laurenspriem
e4927c4022 Merge branch 'main' into similar_ux_changes 2025-08-26 23:30:32 +05:30
laurenspriem
4fd797338b Empty state 2025-08-26 23:26:51 +05:30
laurenspriem
eca0e5943d tab button look 2025-08-26 23:24:37 +05:30
laurenspriem
56cc7309a5 Show progress only for multiple albums symlinking 2025-08-26 23:05:04 +05:30
laurenspriem
b740d1af05 Show modal on 100+ deleted files only 2025-08-26 23:01:30 +05:30
laurenspriem
6d21b73367 faster select 2025-08-26 22:59:30 +05:30
laurenspriem
a5704eef25 Use load instead of view on index 2025-08-26 22:46:33 +05:30
laurenspriem
7e83682686 tiny margin in threshold 2025-08-26 22:42:04 +05:30
laurenspriem
18d5aa61b0 Extract string 2025-08-26 22:34:59 +05:30
laurenspriem
7c2a719ba8 (un)select all 2025-08-26 22:32:11 +05:30
laurenspriem
47313a74ff Tab bar filter 2025-08-26 21:28:21 +05:30
Prateek Sunal
65a7a16298 [mob][photos] fixes (#6979)
## Description

- [x] Fix Spacing in Video streaming settings
- [x] Update copy in Video Streaming settings
- [x] Disable debug notifications for work manager in iOS

## Tests
2025-08-26 20:57:02 +05:30
Prateek Sunal
9251e4f5b6 fix: update spacing and remove cross icon from top right 2025-08-26 19:07:44 +05:30
Prateek Sunal
c4bc6abf83 fix: remove debug mode notification flag 2025-08-26 19:07:27 +05:30
laurenspriem
3165289483 Remove header 2025-08-26 17:48:39 +05:30
laurenspriem
01aab41c25 Select all by default 2025-08-26 17:46:53 +05:30
laurenspriem
1826258161 Copy 2025-08-26 17:43:58 +05:30
laurenspriem
df5917060b Copy change 2025-08-26 17:40:20 +05:30
Prateek Sunal
b5aa05cc1b [mob][photos] merge migration scripts (#6974)
## Description

Fixes #6923

## Tests
2025-08-26 17:16:10 +05:30
Prateek Sunal
cd865992f2 chore: directly use database 2025-08-26 17:02:21 +05:30
Prateek Sunal
370c0ab54a fix: merge migration scripts 2025-08-26 16:02:15 +05:30
Neeraj
923f2484fb [auth] Fix missing token (#6971)
## Description
When using Auth without backup, it was giving a error `Offline key is
missing`

**Reason**: During the `init` of `BaseConfiguration` if the `tokenKey`
is not set, we clear all the keys in the secure storage, and in this
process the `offlineAuthSecretKey` was also getting cleared

**Fix** Fixed by skipping the deletion of `offlineAuthSecretKey`  

## Tests
[Test Video](https://wormhole.app/qz3mol#Dlhr0NRpVQVQsrid2X-quA)
2025-08-26 13:02:43 +05:30
AmanRajSinghMourya
37928cd2c6 Code refractoring 2025-08-26 12:40:03 +05:30
AmanRajSinghMourya
fc32ba97c1 Refactor BaseConfiguration to ensure preserved keys are not deleted 2025-08-26 12:26:01 +05:30
AmanRajSinghMourya
e49084867e Revert "Refactor BaseConfiguration to preserve offlineAuthSecretKey during logout"
This reverts commit 5b5f563d47.
2025-08-26 12:21:00 +05:30
Laurens Priem
a046748ded [mob][photos] Minor fixes and changes (#6969)
## Description

Minor fixes and changes based on testing.

## Tests

Tested in debug mode on my pixel phone.
2025-08-26 10:08:42 +05:30
laurenspriem
047d708ef1 Merge branch 'main' into fix_modal 2025-08-26 10:08:18 +05:30
AmanRajSinghMourya
5b5f563d47 Refactor BaseConfiguration to preserve offlineAuthSecretKey during logout 2025-08-26 10:02:19 +05:30
Ashil
2b60ad3748 [mob][packages] Organize imports (#6968) 2025-08-26 10:01:40 +05:30
Neeraj
1f70043c83 [mob][photos] video streaming settings & create/recreate stream (#6923) 2025-08-26 10:00:08 +05:30
laurenspriem
7ce6f6a346 Check symlink permissions 2025-08-26 09:55:17 +05:30
ashilkn
03814bff0c Organize imports 2025-08-26 09:34:00 +05:30
laurenspriem
4c63a0ff13 Copy changes 2025-08-26 09:21:59 +05:30
laurenspriem
93552fb872 vectorDB flag check ML enabled 2025-08-26 09:05:06 +05:30
laurenspriem
1b61becdcf Fix modal on group-level delete 2025-08-26 08:37:16 +05:30
Prateek Sunal
0499cad3c9 chore: ignore generated mocks file 2025-08-26 04:48:32 +05:30
Prateek Sunal
79752ef4b8 chore: update file name 2025-08-26 04:35:51 +05:30
Prateek Sunal
c1bd6d3fdb Merge branch 'taking-streaming-oob' of https://github.com/ente-io/ente into taking-streaming-oob 2025-08-26 04:35:30 +05:30
Prateek Sunal
621423d9a4 fix: refactor code 2025-08-26 04:35:27 +05:30
Prateek Sunal
edb11c89ba fix: update mobile/apps/photos/lib/ui/settings/streaming/video_streaming_settings_page.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-26 04:31:44 +05:30
Prateek Sunal
adb71fe09c fix: update mobile/apps/photos/lib/services/video_preview_service.dart
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-26 04:31:12 +05:30
Prateek Sunal
c20cee2406 feat: state update event, tests, total logic 2025-08-26 04:27:38 +05:30
Prateek Sunal
dcfad86c47 fix: ensure preview ids are present 2025-08-25 23:32:57 +05:30
Prateek Sunal
0a2bff67bf fix: delete file from upload locks db if not found 2025-08-25 23:31:51 +05:30
Prateek Sunal
7aaa689cfb fix: simplify logic 2025-08-25 23:26:34 +05:30
Prateek Sunal
ad2a0ce897 refactor: simplify StreamingStatus handling in VideoPreviewService 2025-08-25 23:22:39 +05:30
Prateek Sunal
d99615b24f fix: remove skipped 2025-08-25 22:16:22 +05:30
Prateek Sunal
09cc48ae55 fix: add comments 2025-08-25 21:50:07 +05:30
Prateek Sunal
6ab2223a80 fix: mostly all review comments 2025-08-25 21:42:40 +05:30
Prateek Sunal
6fd86162e0 Merge remote-tracking branch 'origin/main' into taking-streaming-oob 2025-08-25 20:58:09 +05:30
Prateek Sunal
707e8dbfcf fix: show processing status, fix when to not show popup buttons, update getFiles logic 2025-08-25 20:57:18 +05:30
Prateek Sunal
5869bec781 feat: create and recreate stream buttons 2025-08-25 20:11:08 +05:30
Laurens Priem
e311a8bb32 [mob][photos] Similar images UI (#6963)
## Description

Minor fixes and UI changes.

## Tests

Tested in debug mode on my pixel phone.
2025-08-25 16:55:29 +05:30
laurenspriem
547ccfceca Use shared preferences for tracking migration 2025-08-25 16:53:33 +05:30
Keerthana
3a1917949b [mobile/photos] New translations (#6955)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-08-25 13:30:03 +05:30
Keerthana
3a1ce3258e [auth] New translations (#6956)
New translations from
[Crowdin](https://crowdin.com/project/ente-authenticator-app)
2025-08-25 13:10:39 +05:30
Prateek Sunal
13b2542bea fix: update logic 2025-08-25 12:02:56 +05:30
Prateek Sunal
6db3741a3b Merge remote-tracking branch 'origin/main' into taking-streaming-oob 2025-08-25 11:48:49 +05:30
laurenspriem
ce17eccd68 Fix delete issue 2025-08-25 11:11:57 +05:30
Ashil
95dc683088 Update internal change log (#6959) 2025-08-25 11:11:28 +05:30
Neeraj
cf9d5f72f7 [mob] Fix query for duplicate cleanup (#6962)
## Description
Only consider owned files
## Tests
2025-08-25 11:10:36 +05:30
Neeraj Gupta
3096e1550a Merge remote-tracking branch 'origin/main' into fixQuery 2025-08-25 11:03:45 +05:30
Neeraj Gupta
1b39435735 Fix query 2025-08-25 11:02:25 +05:30
laurenspriem
8f3d8505bb Better UI when selection is not possible 2025-08-25 11:02:03 +05:30
Manav Rathi
47e8aafe25 [desktop] Update changelog (#6960) 2025-08-25 10:50:10 +05:30
Neeraj Gupta
bc6506cb10 Fix link for locker 2025-08-25 10:50:05 +05:30
Manav Rathi
edf32d065e [desktop] Update changelog 2025-08-25 10:47:43 +05:30
ashilkn
1fa6a0c3b9 Update internal change log 2025-08-25 10:41:16 +05:30
Neeraj Gupta
f2a26ba391 Minor refactor 2025-08-25 10:35:47 +05:30
Manav Rathi
2388989dd0 [web] Enable Czech (#6958) 2025-08-25 10:35:06 +05:30
laurenspriem
9e392277b1 Fix initState issue 2025-08-25 10:31:41 +05:30
Neeraj
4609c375db Revert "[auth] Add smaller Activision icon" (#6953)
Reverts ente-io/ente#6950

I rushed a bit, sorry. The PR wasn't meant to be merged yet (if ever)
and it won't work right now anyway. It was meant to create conversation
on the topic and then possibly merged and there may be concerns to this
as a company may not want their logo/wordmark altered but I'm not well
versed in this topic (idk maybe I'm overthinking this).

Discussion: #6951
2025-08-25 10:31:20 +05:30
Manav Rathi
839c62ea72 [web] Enable Czech 2025-08-25 10:28:23 +05:30
Neeraj
dceef49f33 [mob][photos] Pre-cache thumbnails fetched from LRU cache to Flutter's ImageCache for faster rendering (#6957)
## Description

In Gallery, even if thumbnails are stored in LRU cache, there was a
delay in rendering thumbnails when scrolling fast enough. Pre-caching
these thumbnails to flutter's `ImageCache` right before they're rendered
has made the rendering fast enough for seamless UX.

#### Before:


https://github.com/user-attachments/assets/c47958fb-fbda-4e1f-9ce7-26b51ca87938

#### After:


https://github.com/user-attachments/assets/cbaf4427-f52f-4544-a0c2-820eb2b43953
2025-08-25 10:18:05 +05:30
laurenspriem
acbdc3111a Remove use of withOpacity 2025-08-25 10:15:49 +05:30
laurenspriem
98b91a6935 Remove duplicate string 2025-08-25 10:11:07 +05:30
laurenspriem
e1640e67d4 Extract strings 2025-08-25 10:09:03 +05:30
laurenspriem
e875758419 Simplify sort options 2025-08-25 09:48:33 +05:30
Manav Rathi
214b120472 [web] New translations (#6954)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-08-25 09:43:37 +05:30
ashilkn
f139e0a098 Fix flickering of GalleryFileWidget on hero animation after closing it's open full view 2025-08-25 09:21:57 +05:30
laurenspriem
e3c9a61887 Align 2025-08-25 09:20:19 +05:30
ashilkn
0da3dc5084 Skip clearing flutter image cache since default (current) limit is 100MB and the threshold to clear is 250MB 2025-08-25 09:20:08 +05:30
ashilkn
a856a82249 Refactor 2025-08-25 09:18:29 +05:30
ashilkn
fbdec00a62 Improve lru cache thumbnail rendering speed when scrolling gallery by precaching it it flutter's image cache 2025-08-25 09:16:59 +05:30
Crowdin Bot
6a7f980a0d New Crowdin translations by GitHub Action 2025-08-25 01:18:00 +00:00
Crowdin Bot
10a855fe27 New Crowdin translations by GitHub Action 2025-08-25 01:05:02 +00:00
Crowdin Bot
b4f8a2b27c New Crowdin translations by GitHub Action 2025-08-25 00:39:57 +00:00
dnred
89489b4d7c Revert "[auth] Add smaller Activision icon" 2025-08-24 23:48:21 +02:00
Aman Raj Singh Mourya
50296f8dfa [auth] Add smaller Activision icon (#6950)
## Description

The current Activision icon is too wide and small to be nicely displayed
in Auth so this PR adds a smaller one, just like the favicon on
Activision's [website](https://activision.com).

I know the Activision icon is pulled from simple-icons and I don't want
to get rid of that, just add an option for a smaller one, but I see that
the smaller Allegro icon is also added but it isn't displayed in the
icon picker and the icon from simple-icons takes precedence so you'd
have to figure this out.

## Tests

I haven't tested this.
2025-08-24 23:15:44 +05:30
dnred
f69cec864b Rename activision2.svg to activision.svg 2025-08-24 16:42:49 +02:00
dnred
73d5d33fc5 Update custom-icons.json 2025-08-24 16:25:47 +02:00
dnred
4d8ea12ddd Add logo 2025-08-24 16:17:25 +02:00
Prateek Sunal
7beb267ba7 chore: remove unused import 2025-08-24 02:15:09 +05:30
Prateek Sunal
7e13ef3537 chore: remove formatting for files_db 2025-08-24 02:10:06 +05:30
Prateek Sunal
47edca5bf5 chore: fix formatting 2025-08-24 02:08:00 +05:30
Prateek Sunal
925ba10b15 chore: revert remote_sync formatting 2025-08-24 02:06:28 +05:30
Prateek Sunal
db2d0bb7e9 fix: remove formatting from ml_service 2025-08-24 02:04:09 +05:30
Prateek Sunal
f3a2b2af0c fix: include it in if loop 2025-08-24 02:02:47 +05:30
Prateek Sunal
967e88f88d Merge remote-tracking branch 'origin/main' into taking-streaming-oob 2025-08-24 02:00:33 +05:30
Prateek Sunal
b44734a493 fix: add streaming static image 2025-08-24 01:59:23 +05:30
Manav Rathi
6478b08a19 [docs] Minor improvements to self-hosted docs (#6936)
## Description
- Small correction on the self-hosted docker exec command.
- Added tip on how to install Ente CLI.

In spirit of starting with a small PR :p
2025-08-23 21:54:47 +05:30
Laurens Priem
314e81565b Fix linter issues (#6939)
## Description

Linter was failing because it didn't first run
`flutter_rust_bridge_codegen generate` to generate the dart bindings to
rust code.
2025-08-23 20:34:02 +05:30
laurenspriem
f95e20d00f Consistent tap behaviour 2025-08-23 17:35:12 +05:30
laurenspriem
35a04d6e7e Don't unnecessarily sort 2025-08-23 17:34:53 +05:30
laurenspriem
403264d2c9 Fix linter issues 2025-08-23 17:20:22 +05:30
Toby
6b06a4c388 Add instructions on how to install Ente CLI 2025-08-23 13:13:08 +02:00
Toby
678bce89b2 Add small corrections to docker commands 2025-08-23 13:06:34 +02:00
Laurens Priem
2f1d4b9f1a Update rust to solve bindings generation issue (#6935)
## Description

Update rust to potentially solve bindings generation issue
2025-08-23 10:44:27 +05:30
laurenspriem
af20eadff0 Update rust to solve bindings generation issue 2025-08-23 10:39:54 +05:30
Prateek Sunal
3264ea046c [mob][photos] add named params for translations (#6932)
## Description

Parameters were sorted based on name by intl plugin which is a breaking
change.

We now have shifted to named params for translations so position won't
change.

## Tests
2025-08-22 22:50:07 +05:30
Laurens Priem
d81a73c833 [mob][photos] Similar images various improvements (#6931)
## Description

- Put the rust generated bindings in gitignore
- Use `view` instead of `load` on VectorDB index to use less RAM
- Various UI changes

## Tests

Tested in debug mode on my pixel phone.
2025-08-22 21:12:00 +05:30
laurenspriem
ac9c63fe29 Log updates 2025-08-22 21:11:25 +05:30
laurenspriem
53cb217dbc Fix MediaQuery in initState issue (for large files view) 2025-08-22 21:06:59 +05:30
Prateek Sunal
fca9a42e0a fix: add named params for translations to fix position 2025-08-22 19:41:45 +05:30
Prateek Sunal
8b708228be fix: add different ui for enabling it 2025-08-22 19:04:16 +05:30
laurenspriem
d379262f56 Small animation 2025-08-22 18:57:37 +05:30
laurenspriem
9282632af1 Exclude dart linter checks for rust 2025-08-22 18:14:13 +05:30
laurenspriem
6a43d6a567 Generate rust bindings on internal release 2025-08-22 18:11:53 +05:30
laurenspriem
1cdbef1a01 More fancy loading 2025-08-22 15:12:12 +05:30
laurenspriem
fa84bb0845 Delete progress indicator 2025-08-22 14:33:19 +05:30
laurenspriem
cbb6f07d0d Improve empty state 2025-08-22 12:38:37 +05:30
laurenspriem
fad9cf8559 Add rust bindings generation to readme 2025-08-22 11:57:45 +05:30
laurenspriem
371ba9c552 Put generated rust bindings in gitignore 2025-08-22 11:54:59 +05:30
laurenspriem
19086e43cc Remove generated rust bindings 2025-08-22 11:54:24 +05:30
laurenspriem
964c837c40 Remove scrollbar 2025-08-22 11:36:48 +05:30
laurenspriem
d85121862d Use view of index instead of loading in memory 2025-08-22 11:34:40 +05:30
Prateek Sunal
42d31a73a3 fix: update localization & fix lint 2025-08-21 23:32:45 +05:30
Prateek Sunal
946d2ae522 fix: remove unnecessary blank line in analysis_options.yaml + circular button 2025-08-21 22:51:01 +05:30
Prateek Sunal
8e9eb50783 fix: downgrade Dart SDK version to 3.7.2 2025-08-21 22:50:24 +05:30
Prateek Sunal
af3bc7757f fix: downgrade dart sdk again 2025-08-21 22:50:04 +05:30
Prateek Sunal
eda1d05216 fix: revert dart sdk 2025-08-21 22:49:49 +05:30
Prateek Sunal
b58e0f8331 fix: remove analysis options for now 2025-08-21 22:49:37 +05:30
Prateek Sunal
6dcf53650d fix: re-add captioned text 2025-08-21 22:48:42 +05:30
Prateek Sunal
bff53d9081 chore: add back space 2025-08-21 22:47:42 +05:30
Prateek Sunal
f3306e14c7 fix: revert 2025-08-21 22:47:30 +05:30
Prateek Sunal
b5c075bac4 fix: add space at end 2025-08-21 22:45:38 +05:30
Prateek Sunal
241d21c2aa fix: revert things 2025-08-21 22:44:34 +05:30
Prateek Sunal
789d77747c fix: update other contact page 2025-08-21 22:35:24 +05:30
Prateek Sunal
35050aa32f fix: delete generated intl_utils locale 2025-08-21 22:33:23 +05:30
Prateek Sunal
40e6bd9fae Merge remote-tracking branch 'origin/main' into taking-streaming-oob 2025-08-21 22:32:41 +05:30
Prateek Sunal
9fe15d7ff0 [mob][photos] remove generated locals (#6925)
## Description

We depended on intl_utils but that had problems + it was not
auto-generating things when running `flutter pub get`

Now we are using pure intl implementation of l10n, by which generated
code would be less.

- [x] Removes generated locals

## Tests
2025-08-21 22:27:09 +05:30
Prateek Sunal
28a2afe275 Merge remote-tracking branch 'origin/main' into remove-intl_utils 2025-08-21 22:26:54 +05:30
Aman Raj Singh Mourya
c072097c11 Add custom icons (#6924)
## Description
Adds custom SVG icons for "CoinTracing", "VHV Versicherungen (German
Insurance Company)" and "HR Document Box".
SVG sourced from official CoinTracking press assets.
SVG sourced from Wikipedia for VHV Versicherungen.
For HR Document Box was no svg available, so i used a png to svg
converter.

## Tests
2025-08-21 19:27:57 +05:30
Prateek Sunal
b317df2000 Merge branch 'main' into taking-streaming-oob 2025-08-21 18:11:42 +05:30
Prateek Sunal
dd420a80a4 Merge remote-tracking branch 'origin/main' into remove-intl_utils 2025-08-21 18:08:31 +05:30
Prateek Sunal
3dc0620e18 chore: update flutter again for auth 2025-08-21 18:04:29 +05:30
Prateek Sunal
173d075f8b feat: remove generated locals 2025-08-21 18:04:20 +05:30
Daniel
48283282e5 Merge branch 'ente-io:main' into main 2025-08-21 14:30:49 +02:00
Laurens Priem
fa555c448f [mob][photos] Various similar images improvements (#6922)
## Description

Various improvements for similar images, mainly caching and UI changes.

## Tests

Tested in debug mode on my pixel phone.
2025-08-21 17:59:13 +05:30
laurenspriem
6f6770d677 Selection options 2025-08-21 17:58:43 +05:30
Daniel
0b894e9724 Update custom-icons.json 2025-08-21 14:21:02 +02:00
Daniel
0670550cb1 Add files via upload 2025-08-21 14:18:48 +02:00
Daniel
45783cf527 Update custom-icons.json 2025-08-21 14:07:32 +02:00
Daniel
1615779eb8 Add files via upload 2025-08-21 14:05:48 +02:00
Daniel
02e4c9d8fd Add files via upload 2025-08-21 14:00:23 +02:00
Prateek Sunal
2e706228ee feat: separate settings page improvements 2025-08-21 17:22:57 +05:30
Neeraj Gupta
c5319f2ba8 Merge remote-tracking branch 'origin/main' into remote_db 2025-08-21 17:19:42 +05:30
Daniel
6eab6457ee Update custom-icons.json 2025-08-21 13:34:14 +02:00
Daniel
25490a7238 Add files via upload 2025-08-21 13:30:49 +02:00
Neeraj
f519ff8a51 [auth] Option to scan image using native plugin (#6920)
## Description

## Tests
Tested on physical device (android and ios)
2025-08-21 16:20:45 +05:30
Neeraj Gupta
afebe1ade1 Clean up 2025-08-21 16:15:44 +05:30
laurenspriem
3862644dd5 Show info at top 2025-08-21 16:07:52 +05:30
Neeraj Gupta
274a7d207d Improve scanning 2025-08-21 15:59:53 +05:30
laurenspriem
add2f0c8de Debug option for full refresh 2025-08-21 15:34:05 +05:30
Neeraj Gupta
8e807616e0 Bump version 2025-08-21 15:29:08 +05:30
laurenspriem
70f4325c71 Refresh for small size 2025-08-21 15:18:05 +05:30
Neeraj Gupta
38ea2248b8 Show option on mobile only 2025-08-21 15:16:21 +05:30
laurenspriem
9600b26359 More stable sort 2025-08-21 15:10:40 +05:30
Neeraj Gupta
5b3e996aaa Option to scan image using native plugin 2025-08-21 15:08:11 +05:30
laurenspriem
4d4cce091f Fix json decoding issue 2025-08-21 14:13:49 +05:30
Neeraj
aaca140d1b [mobile] Use same lint rule file (#6917)
## Description
Had verified that hash for these rules were same.
## Tests
2025-08-21 14:06:37 +05:30
Neeraj Gupta
596ffcd4c4 [mobile] Use same lint rule file 2025-08-21 14:04:04 +05:30
laurenspriem
41ef85a294 Add scroll bars 2025-08-21 13:08:51 +05:30
Neeraj
f722d82835 [server]: add one click verify button for verification email (#5654)
OG (ott.html):

<img width="701" height="590" alt="image"
src="https://github.com/user-attachments/assets/80b926d1-c65f-44a8-9de4-7b591258bf3c"
/>



New (ott_mobile.html):

<img width="642" height="811" alt="image"
src="https://github.com/user-attachments/assets/aa18a778-1161-4b4e-ad82-cf472da06ff7"
/>
2025-08-21 12:44:24 +05:30
Neeraj Gupta
cbb3096534 use mobile ott template for only photos 2025-08-21 12:41:56 +05:30
laurenspriem
f635e1e856 Merge branch 'main' into smart_dedupe 2025-08-21 12:22:29 +05:30
laurenspriem
c6734a5cb7 More logging 2025-08-21 12:15:37 +05:30
laurenspriem
e26b4796d3 Match to closest group 2025-08-21 12:04:31 +05:30
laurenspriem
99c0194c0f Check cache parameters 2025-08-21 11:54:10 +05:30
laurenspriem
e824c02d7f Fix bug 2025-08-21 11:45:08 +05:30
laurenspriem
a11f66b51d Caching and partial compute logic for similar files calculation 2025-08-21 11:35:42 +05:30
laurenspriem
f202fef266 JSON caching of similar files 2025-08-21 11:35:12 +05:30
Neeraj
ff8cfd3e87 [auth] Additional import option (#6916)
## Description

## Tests
2025-08-21 11:22:04 +05:30
Neeraj Gupta
431ab7fcc7 [auth] Additional import option 2025-08-21 11:11:48 +05:30
Ashil
2ac1d58dac [mob][photos] Fix jank when scrolling gallery when lot of selected items are in view (#6913)
## Description

Using `ColorFiltered` with `Blendmode.darken` introduces a performance
[issue](https://github.com/flutter/flutter/issues/174118) with flutter's
new rendering engine Impeller.

The fix uses an alternative method to that maintains the same UI
appearance as before.
2025-08-20 19:09:46 +05:30
ashilkn
5533e6a71d Fix performance issue (jank) when scrolling gallery when lot of selected items in view
This was only bad enough to be noticed on one device (Samsung A54) out of few
2025-08-20 18:46:32 +05:30
laurenspriem
a8ae0727a8 Fix potential duplicates 2025-08-20 18:24:21 +05:30
Aman Raj Singh Mourya
6955788724 Add custom icon for Mobile01 (#6908)
Custom icon for [Mobile01](https://www.mobile01.com/)

- Add optimised SVG file
- Add entry to custom-icons.json
2025-08-20 15:49:42 +05:30
Neeraj Gupta
f6dd35f5e7 Update templates 2025-08-20 15:11:28 +05:30
Neeraj Gupta
9148916d88 Merge remote-tracking branch 'origin/main' into ott_email_one_click 2025-08-20 15:02:57 +05:30
Neeraj
68545f8947 [auth] add import from gallery using zxing2 (#6909)
This pr implements the feature to add a 2FA account by importing a QR
code image from the device gallery..
Adds a new "Import from gallery" button to the Floating Action Button
menu.

The button's text is localized, and its styling is consistent with the
app's theme.

How to Test:

    Open the FAB menu and tap "Import from gallery".
    
1) Test with a valid 2FA QR code image. Expected: The account gets added
successfully.
2) Test with an image that has no QR code. Expected: A "No QR code
found" toast message appears.
3) Test with a QR code of plain text (like "hello "). Expected: An
"Invalid QR Code" dialog appears.
2025-08-20 14:44:02 +05:30
Prateek Sunal
fe40185889 fix: redirect video streaming to setting page 2025-08-20 14:43:54 +05:30
Prateek Sunal
6bb4428a8a chore: update generated translations 2025-08-20 14:41:57 +05:30
Neeraj
76c5c12c53 [mobile] Setup melos (#6907)
## Description

```
dart pub global activate melos
```
Run following command to get all dependencies for projects
```
melos bootstrap
```


## Tests
2025-08-20 14:36:10 +05:30
Prateek Sunal
0881685915 feat: add video streaming settings page 2025-08-20 14:34:16 +05:30
Prateek Sunal
3e13932d03 chore: format files and update analysis file 2025-08-20 14:33:35 +05:30
Dxball ☕
8d749a2dc8 Add custom icon fo Mobile01 2025-08-20 09:01:14 +00:00
a5xwin
56af818482 add qr code scanning from gallery using zxing2 2025-08-20 14:28:41 +05:30
Neeraj Gupta
88260a05e3 Setup melos 2025-08-20 14:14:35 +05:30
laurenspriem
28a842b006 Show size 2025-08-20 09:51:27 +05:30
laurenspriem
19eb342f59 Move internal things to debug mode only 2025-08-20 09:47:36 +05:30
laurenspriem
2b82c79be9 Merge branch 'main' into smart_dedupe 2025-08-20 09:13:43 +05:30
laurenspriem
58182cc8ab Remove slider interface in release 2025-08-19 17:11:12 +05:30
laurenspriem
bb177bc3f6 Merge branch 'main' into smart_dedupe 2025-08-19 11:47:19 +05:30
laurenspriem
65f7e3f6c6 Exclude rust_builder in linter 2025-08-19 11:39:03 +05:30
laurenspriem
37c1d0f6a8 Unify UI 2025-08-18 18:23:14 +05:30
laurenspriem
be1bf28cd8 Add cacheExtend for smoother scroll 2025-08-18 17:25:44 +05:30
laurenspriem
cad8613e81 Remove "select extra" button 2025-08-18 10:28:57 +05:30
laurenspriem
b46e51f64d Prefer smaller names 2025-08-18 10:25:06 +05:30
laurenspriem
e6bf64548c Use cached files 2025-08-18 10:21:28 +05:30
laurenspriem
5729e0cf3e no shared or hidden files 2025-08-18 10:11:04 +05:30
laurenspriem
b353539328 Sort by highest size first 2025-08-18 09:54:31 +05:30
laurenspriem
ad39694026 report changes at correct place 2025-08-14 19:06:03 +05:30
Neeraj Gupta
5d851d8f90 Add model for localAsset 2025-08-08 16:11:52 +05:30
Neeraj Gupta
dd76317bb0 Clean up EnteFile 2025-08-07 15:45:55 +05:30
Neeraj Gupta
5519981f9c Stop reading redundant data 2025-08-07 15:43:55 +05:30
Neeraj Gupta
1c249560c0 Clean up EnteFile 2025-08-07 15:10:56 +05:30
Neeraj Gupta
130cc9137c File:Duration Switch to get only prop 2025-08-07 13:53:29 +05:30
Neeraj Gupta
95f2d282b5 Clean up EnteFile 2025-08-07 13:51:04 +05:30
Neeraj Gupta
e6668606db Minimize data read 2025-08-07 13:37:43 +05:30
Neeraj Gupta
316c767ffa Merge branch 'reduceLog' into remote_db 2025-08-07 11:32:25 +05:30
Neeraj Gupta
c08b0f7aa4 Build changes 2025-08-07 11:08:15 +05:30
Neeraj Gupta
b5a4bcf98f Clean up EnteFile 2025-08-07 11:08:03 +05:30
Neeraj Gupta
dc06a2e193 Use getter for title 2025-08-07 10:41:20 +05:30
Neeraj Gupta
c29446e00a Add index 2025-08-06 14:51:41 +05:30
Neeraj Gupta
5aa36921d8 Use remoteDB 2025-08-06 12:38:06 +05:30
Neeraj Gupta
3b3af65d74 Rewrite reload and cache clear check 2025-08-06 11:35:12 +05:30
Neeraj Gupta
9ad88d3908 Filter out files for which we don't need to create streams 2025-08-06 10:50:34 +05:30
Neeraj Gupta
012e9091f0 Use remote DB 2025-08-06 10:34:43 +05:30
Neeraj Gupta
8ff0f237e7 Use remote DB 2025-08-06 10:17:27 +05:30
Neeraj Gupta
c80e4a65b8 Set state context early 2025-08-06 09:14:08 +05:30
Neeraj Gupta
c317f2494f Fix parsing 2025-08-06 09:13:42 +05:30
Neeraj Gupta
264b0b151a Merge remote-tracking branch 'origin/main' into remote_db 2025-08-05 14:41:02 +05:30
Neeraj Gupta
e5cb3e7005 Hide uploaded local files from homescreen 2025-08-05 14:31:38 +05:30
Neeraj Gupta
adc1939638 Use existing method 2025-08-05 13:15:12 +05:30
Neeraj Gupta
2cc1c36b7b Flatten all remote asset fields 2025-08-05 13:12:34 +05:30
Neeraj Gupta
b99450615e Remove unused field 2025-08-05 09:35:02 +05:30
Neeraj Gupta
5de1f0c93b Switch to remoteDB 2025-07-31 16:24:23 +05:30
Neeraj Gupta
ee902a5ccb ML typecast fixes 2025-07-31 15:39:53 +05:30
Neeraj Gupta
9e56afaa73 Fixed query 2025-07-31 15:35:48 +05:30
Neeraj Gupta
77f8c3f712 Fix: Specify type 2025-07-31 15:04:43 +05:30
Neeraj Gupta
f7a0a414db Fix: Use new db to get fileKey 2025-07-31 15:02:25 +05:30
Neeraj Gupta
bd49b8464b Minor db query fix 2025-07-31 14:20:55 +05:30
Neeraj Gupta
0cbfa319ba Use remote db for dedupe 2025-07-31 14:15:25 +05:30
Neeraj Gupta
95e05f167c Merge remote-tracking branch 'origin/main' into remote_db 2025-07-31 12:07:04 +05:30
Neeraj Gupta
84ef4c2d0b Clean up 2025-07-31 11:22:24 +05:30
Neeraj Gupta
53c14dff01 Refactor 2025-07-31 10:34:42 +05:30
Neeraj Gupta
02ef29fd8f Consolidate shared assets deletion logic 2025-07-31 10:29:00 +05:30
Neeraj Gupta
1848f1a94b Use remoteDB 2025-07-29 15:14:36 +05:30
Neeraj Gupta
276c38236f Use new db to identify backed up files 2025-07-29 14:53:26 +05:30
Neeraj Gupta
5e3e3b4427 Clean up 2025-07-28 16:53:57 +05:30
Neeraj Gupta
b8dab3ea1c Use new db for archive file count 2025-07-28 14:57:36 +05:30
Neeraj Gupta
2dc32f5339 Strip out exif from metadata 2025-07-28 14:54:40 +05:30
Neeraj Gupta
9fd6bc4974 Fix query 2025-07-28 14:54:24 +05:30
Neeraj Gupta
3740e9e29d Gracefully handle partial cleanup 2025-07-28 14:33:34 +05:30
Neeraj Gupta
118dde38a2 Refactor 2025-07-28 11:48:01 +05:30
Neeraj Gupta
cd15fe86c6 Fix delete 2025-07-28 11:47:55 +05:30
Neeraj Gupta
693a40cc24 Refactor save asset for edits 2025-07-26 12:17:53 +05:30
Neeraj Gupta
2cfa8497da Merge remote-tracking branch 'origin/main' into remote_db 2025-07-26 11:53:48 +05:30
Neeraj Gupta
3f6b9d7ae6 Refactor 2025-07-26 11:13:54 +05:30
Neeraj Gupta
e71b6dbb63 Remove unused method 2025-07-26 11:04:49 +05:30
Neeraj Gupta
44722c40c2 Merge branch 'main' into remote_db 2025-07-24 16:22:57 +05:30
Neeraj Gupta
bfd13b99d2 Fix compile error 2025-07-21 11:36:59 +05:30
Neeraj Gupta
e82d878fa8 Merge branch 'main' into remote_db 2025-07-21 10:46:57 +05:30
Neeraj Gupta
0587813c70 Rename 2025-07-14 14:43:08 +05:30
Neeraj Gupta
b7712a7c51 Clean up 2025-07-14 14:42:16 +05:30
Neeraj Gupta
213f3cd122 Clean up 2025-07-14 11:44:13 +05:30
Neeraj Gupta
d103274da5 Add file matching logic before upload 2025-07-14 11:04:44 +05:30
Neeraj Gupta
28b244ebc5 Use fk to keep updated mapping info 2025-07-14 09:53:59 +05:30
Neeraj Gupta
7d24dea7bc Merge branch 'main' into remote_db 2025-07-11 16:56:34 +05:30
Neeraj Gupta
4a358a7793 Refactor 2025-07-11 11:09:00 +05:30
Neeraj Gupta
699249cd26 Upload [1/x] 2025-07-11 10:15:35 +05:30
Neeraj Gupta
7125ac7419 Simplify 2025-07-10 10:34:50 +05:30
Neeraj Gupta
de67b6e9fc Rename column and minor fixes 2025-07-09 15:20:49 +05:30
Neeraj Gupta
39868de5d9 Update schema for shared assets 2025-07-09 14:22:33 +05:30
Neeraj Gupta
751550d469 Refactor 2025-07-09 12:01:46 +05:30
Neeraj Gupta
6f0034dd9d Merge remote-tracking branch 'origin/main' into remote_db 2025-07-09 10:07:55 +05:30
Neeraj Gupta
7bd6180ebf Reflect backup status for device folder 2025-07-09 10:06:25 +05:30
Neeraj Gupta
5a3ae5f97c Log stack trace 2025-07-09 10:05:45 +05:30
Neeraj Gupta
e447058573 Simplify 2025-07-09 09:08:21 +05:30
Neeraj Gupta
8a7e8b8237 Fix queue clean up on backup folder update 2025-07-08 17:57:38 +05:30
Neeraj Gupta
ed7b1be591 Re-organize 2025-07-08 15:08:56 +05:30
Neeraj Gupta
9a5ef8b634 Clean up 2025-07-08 11:29:37 +05:30
Neeraj Gupta
c2668387b5 Refactor to use new upload media and metadata 2025-07-08 11:01:37 +05:30
Neeraj Gupta
d265cf62c7 Separate model to get upload media 2025-07-08 09:18:57 +05:30
Neeraj Gupta
a67c3b0624 Clean up fields 2025-07-07 16:57:06 +05:30
Neeraj Gupta
306c78fbb0 Refactor 2025-07-07 16:09:40 +05:30
Neeraj Gupta
e4f9dd6b33 Simplify new files notification + avoid redundant compute 2025-07-07 15:57:47 +05:30
Neeraj Gupta
5fec59f0fe Clean up 2025-07-07 15:20:32 +05:30
Neeraj Gupta
53050ca25e Map remote files to local during diff sync 2025-07-07 14:31:37 +05:30
Neeraj Gupta
926aa42168 Merge branch 'main' into remote_db 2025-07-07 09:52:59 +05:30
Neeraj Gupta
f4f8141b99 Move mobile -> mobile/apps/photos 2025-07-04 16:52:07 +05:30
Neeraj Gupta
3d044dd3d4 Refactor metadata computation 2025-07-04 14:06:11 +05:30
Neeraj Gupta
8699ad2f01 New upload media data model 2025-07-04 11:52:27 +05:30
Neeraj Gupta
01aad531f1 Generated changes 2025-07-04 10:05:42 +05:30
Neeraj Gupta
6340d9f646 Simplify 2025-07-04 09:37:17 +05:30
Neeraj Gupta
0f944b1796 Simplify 2025-07-04 09:33:02 +05:30
Neeraj Gupta
1d8533168f Mark fields non-nullable 2025-07-03 17:32:58 +05:30
Neeraj Gupta
2fca1ba534 Add location in shared assets 2025-07-03 16:29:38 +05:30
Neeraj Gupta
2d386c769b Simplify 2025-07-03 11:41:14 +05:30
Neeraj Gupta
1b41d81839 Refactor 2025-07-02 20:08:49 +05:30
Neeraj Gupta
487156c7df Use computer for parsing XMP 2025-07-02 19:32:19 +05:30
Neeraj Gupta
35c54111e7 Remove unused import 2025-07-02 17:24:55 +05:30
Neeraj Gupta
d71340fbdd Refactor 2025-07-02 17:19:35 +05:30
Neeraj Gupta
f32ea85ee2 Refactor 2025-07-02 16:37:06 +05:30
Neeraj Gupta
6397ab888a Merge branch 'main' into remote_db 2025-07-02 14:48:53 +05:30
Neeraj Gupta
5a73043b63 Measure time 2025-07-02 14:13:39 +05:30
Neeraj Gupta
f258c40e98 Measure time 2025-07-02 14:13:20 +05:30
Neeraj Gupta
36b6476049 Use remote DB 2025-07-02 11:32:47 +05:30
Neeraj Gupta
c4c5ea150f Merge branch 'main' into remote_db 2025-07-02 09:30:08 +05:30
Neeraj Gupta
1956b3788b Rename 2025-07-01 15:52:11 +05:30
Neeraj Gupta
72cbddff6d Use upload queue for pending uploads 2025-07-01 15:42:48 +05:30
Neeraj Gupta
17670d5538 Use asset queue db for queueing pending upload 2025-07-01 15:25:52 +05:30
Neeraj Gupta
8cfd80663e Merge branch 'main' into remote_db 2025-07-01 14:55:11 +05:30
Neeraj Gupta
f285e2d706 Use lAsset for video type 2025-06-30 17:49:15 +05:30
Neeraj Gupta
f60e074dd5 Use tag instead of generatedID 2025-06-30 17:00:45 +05:30
Neeraj Gupta
140eae6859 Use tag instead of genID 2025-06-30 16:52:23 +05:30
Neeraj Gupta
23ee022472 Refactor 2025-06-30 16:46:08 +05:30
Neeraj Gupta
b1cf3f9fb0 Refactor live photo 2025-06-30 15:50:46 +05:30
Neeraj Gupta
dbbb80a817 Merge remote-tracking branch 'origin/main' into remote_db 2025-06-30 14:35:46 +05:30
Neeraj Gupta
91a10634cc Remove redundant import 2025-06-30 13:01:53 +05:30
Neeraj Gupta
0a2c230254 Merge remote-tracking branch 'origin/main' into remote_db 2025-06-30 12:24:18 +05:30
Neeraj Gupta
6745b110df Refactor shared assets 2025-06-30 12:23:01 +05:30
Neeraj Gupta
7061161181 Rename 2025-06-30 11:54:41 +05:30
Neeraj Gupta
f0026f0a81 Refactor 2025-06-30 11:52:36 +05:30
Neeraj Gupta
acec985bcb Add shared asset service 2025-06-30 11:31:42 +05:30
Neeraj Gupta
c8103a9e06 Refactor 2025-06-28 13:54:16 +05:30
Neeraj Gupta
02f64ad45f Refactor 2025-06-27 15:32:19 +05:30
Neeraj Gupta
d0931d1d0e Refactor 2025-06-27 15:17:08 +05:30
Neeraj Gupta
5c78de5355 Refactor 2025-06-27 14:08:47 +05:30
Neeraj Gupta
1aa9f61419 Rename 2025-06-27 12:49:00 +05:30
Neeraj Gupta
0f2b51d1a5 Remove redundant method 2025-06-27 12:46:29 +05:30
Neeraj Gupta
9fef560d15 Refactor 2025-06-27 12:02:01 +05:30
Neeraj Gupta
09c7bfd717 refactor 2025-06-26 14:44:44 +05:30
Neeraj Gupta
2ff059a701 Remove unused file 2025-06-26 14:25:05 +05:30
Neeraj Gupta
70b043d34a Migrate restore to new store 2025-06-26 14:19:15 +05:30
Neeraj Gupta
15a00379b5 Use remoteDB for linking 2025-06-26 10:01:25 +05:30
Neeraj Gupta
7246ade2ae Rename 2025-06-26 09:50:42 +05:30
Neeraj Gupta
7cad0a83d2 Clean up 2025-06-26 00:04:00 +05:30
Neeraj Gupta
e6703aef65 Simplify 2025-06-25 23:38:03 +05:30
Neeraj Gupta
662dfad7ca Remove unused method 2025-06-25 23:20:18 +05:30
Neeraj Gupta
466ab30f8b Improve handling of empty collection for cover 2025-06-25 22:55:04 +05:30
Neeraj Gupta
12c1845a5f Clean up 2025-06-25 22:43:44 +05:30
Neeraj Gupta
2d0202df36 Refactor magic metadata 2025-06-25 22:24:17 +05:30
Neeraj Gupta
2ec4f5a7e5 Use rAsset for metadata 2025-06-25 21:55:14 +05:30
Neeraj Gupta
6723bed1b0 Refactor filemagic service to use rAsset 2025-06-25 17:22:09 +05:30
Neeraj Gupta
84e8ce519e Fix error parsing for internal dialog 2025-06-25 16:43:05 +05:30
Neeraj Gupta
1b50528181 Remove unused filed 2025-06-25 14:58:23 +05:30
Neeraj Gupta
08dff77ad4 Refactor 2025-06-25 14:58:11 +05:30
Neeraj Gupta
713abce89a Refactor: get size from remoteAsset 2025-06-25 13:34:17 +05:30
Neeraj Gupta
da15593a47 Remove unused method 2025-06-25 12:44:40 +05:30
Neeraj Gupta
fc31cc61d1 Avoid redundant async 2025-06-25 12:44:34 +05:30
Neeraj Gupta
9c6259b713 Use remote db for favroite cache 2025-06-25 12:29:50 +05:30
Neeraj Gupta
ed603232a5 Merge branch 'main' into remote_db 2025-06-25 12:29:27 +05:30
Neeraj Gupta
ccd89d3451 Remove unused method 2025-06-25 11:28:28 +05:30
Neeraj Gupta
647b2ef4a7 Cache remoteAssets entry 2025-06-25 11:07:50 +05:30
Neeraj Gupta
f54c79462e Clear remote db on logout 2025-06-25 11:06:10 +05:30
Neeraj Gupta
eb81d96ddf Fix incorrect request key 2025-06-25 11:05:44 +05:30
Neeraj Gupta
57363a24ef Fix minor bugs 2025-06-25 09:23:34 +05:30
Neeraj Gupta
9431995e8c Clean up 2025-06-24 14:35:06 +05:30
Neeraj Gupta
64b86376f6 Cleanup 2025-06-24 13:31:58 +05:30
Neeraj Gupta
a825367c49 Merge remote-tracking branch 'origin/main' into remote_db 2025-06-24 12:42:22 +05:30
Neeraj Gupta
1ffbb27ac5 Fix schema 2025-06-24 12:42:07 +05:30
Neeraj Gupta
d4add9f7ef Fix 2025-06-24 12:41:54 +05:30
Neeraj Gupta
541494613f Use CF for file key derivation 2025-06-24 12:19:55 +05:30
Neeraj Gupta
2b3427e40b Track shared assets separately 2025-06-24 11:55:28 +05:30
Neeraj Gupta
a57c9e881d Use remote db 2025-06-24 09:49:51 +05:30
Neeraj Gupta
d15f1e15ce Use remote db for file copy 2025-06-23 16:30:26 +05:30
Neeraj Gupta
0411f8ad40 Clean up 2025-06-23 15:04:42 +05:30
Neeraj Gupta
2981816c90 Use remotedb for trash 2025-06-23 14:54:48 +05:30
Neeraj Gupta
a6de98ef68 Add trash time 2025-06-23 14:35:13 +05:30
Neeraj Gupta
18156ce8bc Add trash group type 2025-06-23 14:24:56 +05:30
Neeraj Gupta
458c1cf86d Remove log 2025-06-21 11:28:05 +05:30
Neeraj Gupta
90c0874608 Merge branch 'main' into remote_db 2025-06-21 10:13:22 +05:30
Neeraj Gupta
928ffba4d7 rename 2025-06-21 09:14:01 +05:30
Neeraj Gupta
0701212540 Clean up 2025-06-21 08:46:49 +05:30
Neeraj Gupta
347bf4d2e0 Move 2025-06-21 07:57:41 +05:30
Neeraj Gupta
2729edfded rename 2025-06-21 07:57:26 +05:30
Neeraj Gupta
4e8d2c5cea Use local or remote id for selection 2025-06-21 07:56:55 +05:30
Neeraj Gupta
84e9336672 Use new abstraction to fetch public files 2025-06-20 14:22:02 +05:30
Neeraj Gupta
cecdea3f93 Rename 2025-06-20 13:21:14 +05:30
Neeraj Gupta
37674deba0 Implement move 2025-06-20 13:02:42 +05:30
Neeraj Gupta
733be57df8 Merge remote-tracking branch 'origin/main' into remote_db 2025-06-19 22:49:29 +05:30
Neeraj Gupta
74df52baf1 rename 2025-06-19 16:28:35 +05:30
Neeraj Gupta
b817c4475e Refactor 2025-06-19 16:09:22 +05:30
Neeraj Gupta
f95dac31d2 Merge remote-tracking branch 'origin/main' into remote_db 2025-06-19 11:44:20 +05:30
Neeraj Gupta
151289b24a Use remoteDB during add to collection 2025-06-17 17:24:16 +05:30
Neeraj Gupta
5dac9d4dd6 Rename 2025-06-17 16:44:13 +05:30
Neeraj Gupta
43b9dbdc54 Refactor 2025-06-17 16:14:56 +05:30
Neeraj Gupta
9d3caaa5d5 Use remoteDB to get files within duration 2025-06-17 15:45:13 +05:30
Neeraj Gupta
7eda2ed24e remove unused import 2025-06-17 14:24:23 +05:30
Neeraj Gupta
30df5271b4 Fix query 2025-06-17 14:24:12 +05:30
Neeraj Gupta
4b1f7612a3 Rename 2025-06-17 14:15:40 +05:30
Neeraj Gupta
bf6521e8d5 Use new remoteDB 2025-06-17 14:00:50 +05:30
Neeraj Gupta
4bac1bcb1d Merge remote-tracking branch 'origin/main' into remote_db 2025-06-17 13:34:12 +05:30
Neeraj Gupta
b123635584 Merge remote-tracking branch 'origin/main' into remote_db 2025-06-17 12:33:29 +05:30
Neeraj Gupta
d815143bb4 Rewrite upload queue logic 1/x 2025-06-16 14:02:12 +05:30
Neeraj Gupta
ff6228497f Add tables to support shared media & upload tracking 2025-06-11 17:02:03 +05:30
Neeraj Gupta
7469578e77 Merge branch 'main' into remote_db 2025-06-11 12:38:31 +05:30
Neeraj Gupta
76afef6149 Support for persiting path backup config 2025-06-10 15:58:18 +05:30
Neeraj Gupta
2b3178495a Fix build 2025-06-09 21:54:46 +05:30
anandbaburajan
1752192688 [email]: different ott templates for with and without verify btn 2025-06-09 19:21:49 +05:30
Neeraj Gupta
d6f3ff8db3 Merge branch 'main' into remote_db 2025-06-09 13:15:33 +05:30
Neeraj Gupta
7b0ef2b0c0 Add table to store path backup config 2025-06-03 15:52:36 +05:30
Neeraj Gupta
35f95010ea Merge branch 'main' into remote_db 2025-06-03 12:46:53 +05:30
Neeraj Gupta
233f0ec1e1 Fix shared collections decryption 2025-05-28 16:36:46 +05:30
Neeraj Gupta
64820ff5fa Merge branch 'main' into remote_db 2025-05-28 16:36:30 +05:30
Neeraj Gupta
86ffd4e1e6 Merge branch 'main' into remote_db 2025-05-26 16:27:39 +05:30
Neeraj Gupta
436a02d352 Merge branch 'main' into remote_db 2025-05-19 15:34:32 +05:30
Neeraj Gupta
0f3b8bae48 Add models for upload mapping 2025-05-09 15:12:25 +05:30
Neeraj Gupta
0f270a379f Rename 2025-05-08 16:57:10 +05:30
Neeraj Gupta
609f6b8e18 Merge branch 'main' into remote_db 2025-05-08 15:28:06 +05:30
Neeraj Gupta
7896b397c2 Merge branch 'main' into remote_db 2025-05-08 13:08:08 +05:30
Neeraj Gupta
097078bd24 Switch to remoteDB 2025-05-02 16:34:11 +05:30
Neeraj Gupta
e43e3c4230 Switch to remoteDB 2025-05-02 16:26:18 +05:30
Neeraj Gupta
439f1ff0fb keep reference to collectionFileEntry 2025-05-02 16:09:44 +05:30
Neeraj Gupta
e5d78cfd99 Remove unused method 2025-05-02 16:09:26 +05:30
Neeraj Gupta
bd76e66abf perf refactor 2025-05-02 15:41:58 +05:30
Neeraj Gupta
9e6d7908a9 Refactor 2025-05-02 15:14:58 +05:30
Neeraj Gupta
281735e172 Show hidden files from latestDB 2025-05-02 12:28:18 +05:30
Neeraj Gupta
bc93aca110 Merge remote-tracking branch 'origin/main' into remote_db 2025-05-02 11:00:02 +05:30
Neeraj Gupta
df6e409ca1 Remove debugCaption 2025-04-30 15:52:35 +05:30
Neeraj Gupta
7489821434 Refactor 2025-04-30 15:50:31 +05:30
Neeraj Gupta
52e0f04ec2 Merge remote-tracking branch 'origin/main' into remote_db 2025-04-30 15:06:51 +05:30
Neeraj Gupta
ad88ce632c Remove unused method 2025-04-30 14:32:22 +05:30
Neeraj Gupta
26222ec836 Use remoteDB 2025-04-30 14:10:04 +05:30
Neeraj Gupta
beeaee4fd9 Switch to remote db 1/51 2025-04-30 13:18:17 +05:30
Neeraj Gupta
dc98c7bcf5 Remove unused method 2025-04-30 13:11:19 +05:30
Neeraj Gupta
82497563c2 Switch to remoteDB 2025-04-30 13:03:58 +05:30
Neeraj Gupta
4a9b4520d2 Rename 2025-04-30 12:25:52 +05:30
Neeraj Gupta
756c8e5b7d rename 2025-04-30 12:14:53 +05:30
Neeraj Gupta
dffb920cab Switch to remoteDB 2025-04-30 12:12:34 +05:30
Neeraj Gupta
fa7ddbba0c Merge branch 'main' into remote_db 2025-04-30 11:20:44 +05:30
Neeraj Gupta
13a068969c Catch uncaught exception to avoid splash screen issue 2025-04-30 11:10:18 +05:30
Neeraj Gupta
717e8c8b7e Disable iOS battery check in debugmode 2025-04-30 11:09:59 +05:30
Neeraj Gupta
015adb595c Support for DB filters on home screen 2025-04-30 10:37:53 +05:30
Neeraj Gupta
91635d2e7d Schema update 2025-04-30 10:32:10 +05:30
Neeraj Gupta
cd3499a004 Merge branch 'main' into remote_db 2025-04-30 09:27:09 +05:30
Neeraj Gupta
92a964cda6 Remove unused method 2025-04-28 15:47:00 +05:30
Neeraj Gupta
a9ba615962 Switch to new remotedb 2025-04-28 15:36:43 +05:30
Neeraj Gupta
f2b0c11622 Merge remote-tracking branch 'origin/main' into remote_db 2025-04-28 13:55:46 +05:30
Neeraj Gupta
83b89b6bbf Merge branch 'main' into remote_db 2025-04-28 13:55:26 +05:30
Neeraj Gupta
ee0a858302 Merge branch 'main' into remote_db 2025-04-28 09:52:10 +05:30
Neeraj Gupta
b34c923a66 merge files for home screen 2025-04-25 13:04:30 +05:30
Neeraj Gupta
fd927d038b Fix minor bugs 2025-04-25 12:36:57 +05:30
Neeraj Gupta
64e9902f57 Model & schema for local mapping 2025-04-25 12:36:33 +05:30
Neeraj Gupta
c3af79d113 Merge branch 'main' into remote_db 2025-04-24 08:50:49 +05:30
Neeraj Gupta
d87e679650 use remoteDB for collection cover 2025-04-23 12:00:21 +05:30
Neeraj Gupta
7e2242dc69 Show collection files 2025-04-22 16:34:47 +05:30
Neeraj Gupta
9adc207b02 Gradually load on device files 2025-04-22 15:10:09 +05:30
Neeraj Gupta
36049f6633 Treat default 0.0,0.0 as missing location 2025-04-22 14:14:32 +05:30
Neeraj Gupta
9341bc95ee Clean up 2025-04-22 13:57:38 +05:30
Neeraj Gupta
252dca1a01 Clean up 2025-04-22 13:07:53 +05:30
Neeraj Gupta
70501054d2 use remoteDb 2025-04-22 12:50:14 +05:30
Neeraj Gupta
be012e0a28 use remoteDb 2025-04-22 12:18:13 +05:30
Neeraj Gupta
340a0c097f Remove unused method 2025-04-22 12:11:20 +05:30
Neeraj Gupta
7fc8649455 use remoteDb 2025-04-22 11:58:56 +05:30
Neeraj Gupta
c97a313edb use remoteDb 2025-04-22 11:52:34 +05:30
Neeraj Gupta
480fdc84dc Merge remote-tracking branch 'origin/main' into remote_db 2025-04-22 11:52:10 +05:30
Neeraj Gupta
c92ef45c9a Refactor 2025-04-21 16:31:39 +05:30
Neeraj Gupta
ca62012a6f Store local mapping & creation time for remote files 2025-04-21 15:04:42 +05:30
anandbaburajan
873ee3ac14 [email]: different views for mobile and desktop 2025-04-18 16:54:21 +05:30
Neeraj Gupta
151a0d13a4 Sync remote assets to local 2025-04-18 14:00:14 +05:30
Neeraj Gupta
747b1b84c6 Upsert instead of replace 2025-04-18 13:59:15 +05:30
anandbaburajan
cfce2d00f5 [email]: add one click verify button for verification email 2025-04-18 13:45:04 +05:30
Neeraj Gupta
e060fb9823 Disable metadata and ml indexing 2025-04-18 12:14:39 +05:30
Neeraj Gupta
cd377149bc Fix parsing 2025-04-18 11:48:23 +05:30
Neeraj Gupta
d9e22a489b Fix count query 2025-04-18 11:47:34 +05:30
Neeraj Gupta
524db74bf5 Read collection file count 2025-04-17 16:45:36 +05:30
Neeraj Gupta
e1222d51a9 Merge branch 'main' into remote_db 2025-04-17 16:17:36 +05:30
Neeraj Gupta
1c68f0bb60 Refactor 2025-04-17 15:30:40 +05:30
Neeraj Gupta
f6419caf5c Disable metadata scan on ios 2025-04-17 13:50:48 +05:30
Neeraj Gupta
441bcbd187 todo 2025-04-17 13:35:07 +05:30
Neeraj Gupta
4ad3927348 Add trigger to clean up stale collection entries 2025-04-17 13:34:51 +05:30
Neeraj Gupta
4ae15e5966 Remove unused import 2025-04-17 12:17:33 +05:30
Neeraj Gupta
d67d1d3df8 Index local files 2025-04-16 15:57:08 +05:30
Neeraj Gupta
07e1d33ca8 Merge branch 'main' into remote_db 2025-04-16 10:45:51 +05:30
Neeraj Gupta
50e15fa56c offline indexing 1/x 2025-04-15 16:03:39 +05:30
Neeraj Gupta
3f262c5ba2 Add db for offline ml data 2025-04-15 15:40:27 +05:30
Neeraj Gupta
7f34870e3a Remove unused code 2025-04-15 15:39:56 +05:30
Neeraj Gupta
8ba5013926 Merge branch 'main' into remote_db 2025-04-15 11:12:12 +05:30
Neeraj Gupta
e9a24efecb Make ml related classes generic 2025-04-14 16:23:26 +05:30
Neeraj Gupta
eaf74e4059 Merge branch 'main' into remote_db 2025-04-14 10:44:22 +05:30
Neeraj Gupta
e9e1c3ca27 Add wrapper for local metadata 2025-04-12 12:51:45 +05:30
Neeraj Gupta
eb34533aed Add enum for processing state 2025-03-29 13:42:57 +05:30
Neeraj Gupta
cd042e741e Merge branch 'main' into remote_db 2025-03-27 16:43:32 +05:30
Neeraj Gupta
6e944b0b55 Process latest assets first 2025-03-27 13:56:47 +05:30
Neeraj Gupta
18b6b499dd Store time in microseconds 2025-03-27 13:51:34 +05:30
Neeraj Gupta
9205ef8219 Fix: droid metadata parsing 2025-03-27 13:50:59 +05:30
Neeraj Gupta
1ecdbdb88e Fix: get device album assets in desc order 2025-03-27 13:42:18 +05:30
Neeraj Gupta
e2bb4d723e Perform local medatascan for droid 2025-03-27 10:46:33 +05:30
Neeraj Gupta
cfe32c47f0 Merge branch 'main' into remote_db 2025-03-27 06:34:35 +05:30
Neeraj Gupta
a7f6b6589d Service for parsing local metadata 2025-03-26 22:11:59 +05:30
Neeraj Gupta
715e305e09 Add local metadata models 2025-03-26 22:08:43 +05:30
Neeraj Gupta
f7330be52c Reduce queue size 2025-03-26 16:44:08 +05:30
Neeraj Gupta
4cce54a0c6 Use local files for search 2025-03-26 16:42:15 +05:30
Neeraj Gupta
1850e9a2a6 Refactor 2025-03-26 16:24:51 +05:30
Neeraj Gupta
21e2b589cc Minor refactor 2025-03-26 16:23:34 +05:30
Neeraj Gupta
b7f8deb452 Disable smart memories in debug mode 2025-03-26 16:22:59 +05:30
Neeraj Gupta
b6ffb3ca22 Simplify schema 2025-03-26 14:39:29 +05:30
Neeraj Gupta
9351a52800 Clean up imports 2025-03-26 12:46:03 +05:30
Neeraj Gupta
c7510024c0 Use db query to get files on on device albums 2025-03-26 12:43:53 +05:30
Neeraj Gupta
63d3b1c94b Show files within on device albums 2025-03-25 16:10:50 +05:30
Neeraj Gupta
cec27b40a4 Show local device albums 2025-03-25 15:41:16 +05:30
Neeraj Gupta
2f8d0d1957 Delete old local sync 2025-03-25 15:10:49 +05:30
Neeraj Gupta
7f0a36f110 Merge branch 'main' into remote_db 2025-03-25 14:29:12 +05:30
Neeraj Gupta
355367a601 Stop photoManager callback for old local sync 2025-03-25 13:19:09 +05:30
Neeraj Gupta
c66da422cd Update local asset cache 2025-03-25 12:31:15 +05:30
Neeraj Gupta
6f90fad4a2 Fix: Store localSync time in ms 2025-03-25 12:30:52 +05:30
Neeraj Gupta
bcd6f55376 Fix: Use parameterized query params 2025-03-25 12:27:26 +05:30
Neeraj Gupta
b2766a0d4f Use thumbnail widget in the backfolder screen 2025-03-25 11:38:35 +05:30
Neeraj Gupta
ec1b95b0cd Merge branch 'main' into remote_db 2025-03-25 11:35:03 +05:30
Neeraj Gupta
4369317a4d Use lock for full sync 2025-03-25 05:47:47 +05:30
Neeraj Gupta
b18298dc62 Merge remote-tracking branch 'origin/main' into remote_db 2025-03-25 05:43:36 +05:30
Neeraj Gupta
b3e467a1a4 Return early 2025-03-25 05:43:21 +05:30
Neeraj Gupta
f8cd3d9fb4 Add retry on task cancelation 2025-03-24 17:15:18 +05:30
Neeraj Gupta
6d4756ca4b Undo cancellation 2025-03-24 16:16:44 +05:30
Neeraj Gupta
676bbb4d88 Add thumb queue 2025-03-24 16:14:43 +05:30
Neeraj Gupta
da8edfd34e Use new cache for inMem thumbnails 2025-03-24 15:43:42 +05:30
Neeraj Gupta
bf453cfaac Fix selection 2025-03-24 15:10:22 +05:30
Neeraj Gupta
35f41f044e Load thumbnail from cache 2025-03-24 15:09:36 +05:30
Neeraj Gupta
acff269695 Add global cache for image thumbnail 2025-03-24 14:58:24 +05:30
Neeraj Gupta
2b4f96dbb7 Remove task queue from existing thumb fetch 2025-03-24 14:01:50 +05:30
Neeraj Gupta
d5796e2abb Use local thumb provider for thumbnails 2025-03-24 14:00:59 +05:30
Neeraj Gupta
afe9690891 Keep reference for assetEntity 2025-03-24 11:39:20 +05:30
Neeraj Gupta
fc619bbd03 Use task queue to throttle local thumbnail fetch 2025-03-22 21:53:31 +05:30
Neeraj Gupta
a198331ffd Skip reading on disk cache for local thumbnails 2025-03-22 16:26:35 +05:30
Neeraj Gupta
c58fe5358d Add task queue 2025-03-22 16:13:17 +05:30
Neeraj Gupta
defc5164b9 Merge remote-tracking branch 'origin/main' into remote_db 2025-03-22 15:17:42 +05:30
Neeraj Gupta
97d4fb0693 Generated changes 2025-03-22 15:17:30 +05:30
Neeraj Gupta
e708564cb9 Show local assets on home screen 2025-03-22 15:13:19 +05:30
Neeraj Gupta
92068e026b Fix mapping 2025-03-22 14:16:07 +05:30
Neeraj Gupta
8a079ab4f4 Disable existing local & remote sync 2025-03-22 13:27:44 +05:30
Neeraj Gupta
b41c57cb8d Speed up backup folder selection page 2025-03-22 13:26:20 +05:30
Neeraj Gupta
87167e49fc Remove deadlock 2025-03-21 16:59:20 +05:30
Neeraj Gupta
089d1dcd10 Copy ios proj from main 2025-03-21 14:26:03 +05:30
Neeraj Gupta
db02e66124 Merge branch 'main' into remote_db 2025-03-21 14:18:05 +05:30
Neeraj Gupta
964066bf31 Merge remote-tracking branch 'origin/main' into remote_db 2025-03-21 11:09:22 +05:30
Neeraj Gupta
643220e595 Merge branch 'main' into remote_db 2025-03-20 16:47:55 +05:30
Neeraj Gupta
e871498161 Disable remote sync 2025-03-20 15:06:06 +05:30
Neeraj Gupta
31a88b74df Merge branch 'main' into remote_db 2025-03-20 14:05:00 +05:30
Neeraj Gupta
1801258fea Show thumbnail on backup folder 2025-03-19 22:33:22 +05:30
Neeraj Gupta
27acc2125b Fix log 2025-03-19 21:45:48 +05:30
Neeraj Gupta
60b7a91756 Add support for caching local db 2025-03-19 21:45:31 +05:30
Neeraj Gupta
b38a01820d Avoid redundant db txn 2025-03-19 16:25:18 +05:30
Neeraj Gupta
347d5a7a72 Add local image provider for thumbnail 2025-03-19 16:03:47 +05:30
Neeraj Gupta
82979ac729 Fix bug in computing fullDiff 2025-03-19 14:09:22 +05:30
Neeraj Gupta
5768eeb1fe Use trigger instead of fk to avoid redundant deletion 2025-03-19 14:07:58 +05:30
Neeraj Gupta
7a9ff9877a Add new screen for backup 2025-03-19 14:00:51 +05:30
Neeraj Gupta
3565540a61 get assetPath from local 2025-03-19 11:34:41 +05:30
Neeraj Gupta
06d78e5d6a Merge remote-tracking branch 'origin/main' into remote_db 2025-03-19 10:29:54 +05:30
Neeraj Gupta
6c11b76c11 [mob] Refactor 2025-03-17 17:16:43 +05:30
Neeraj Gupta
749cfde7d8 [mob] Support for enabling foreign key 2025-03-17 16:28:49 +05:30
Neeraj Gupta
6bcaa8ae26 [mob] Refactor 2025-03-17 16:27:12 +05:30
Neeraj Gupta
99c6318b0e Merge branch 'db_refactor' into remote_db 2025-03-17 15:35:02 +05:30
Neeraj Gupta
abf789a4aa rename 2025-03-17 14:12:39 +05:30
Neeraj Gupta
f5d3712cbb [mob] Remove unused code + update debouncer 2025-03-17 13:58:01 +05:30
Neeraj Gupta
45dd540abc [mob] move 2025-03-17 13:40:29 +05:30
Neeraj Gupta
865a736bdd [mob] Switch to leading debouncer 2025-03-17 13:29:35 +05:30
Neeraj Gupta
75bd1bfef6 [mob] Avoid running two fullSync 2025-03-17 13:27:57 +05:30
Neeraj Gupta
4cf67fe171 [mob] Fix delete from local db 2025-03-17 12:32:11 +05:30
Neeraj Gupta
65895328dc [mob] Fix full diff computation 2025-03-17 11:46:03 +05:30
Neeraj Gupta
a1c20b9c8a Merge remote-tracking branch 'origin/main' into remote_db 2025-03-17 11:25:45 +05:30
Neeraj Gupta
de9def5370 [mob] Rename 2025-03-17 11:25:24 +05:30
Neeraj Gupta
9cc723a280 [mob] Local local device assets info in db 2025-03-17 11:03:04 +05:30
Neeraj Gupta
16beae2a82 [mob] Rename 2025-03-15 21:56:10 +05:30
Neeraj Gupta
2e25c38324 [mob] Store local assets state in db 2025-03-15 21:53:47 +05:30
Neeraj Gupta
7e691f84e4 Merge remote-tracking branch 'origin/main' into remote_db 2025-03-15 16:24:42 +05:30
Neeraj Gupta
d99593fc85 [mob] Fix impl diff compute & simplify 2025-03-14 18:30:11 +05:30
Neeraj Gupta
d4877ea446 [mob] Write in parallel 2025-03-14 17:05:16 +05:30
Neeraj Gupta
5f4c748886 [mob] Refactor & improve logs 2025-03-14 16:17:59 +05:30
Neeraj Gupta
eaab58c62a [mob] refactor 2025-03-14 13:48:34 +05:30
Neeraj Gupta
c1c020402e [mob] Simplify local import 2025-03-14 13:10:44 +05:30
Neeraj Gupta
028f4e61d2 [mob] Add initial db schema for local files 2025-03-13 17:19:47 +05:30
Neeraj Gupta
abc6f56247 [mob] Fix: Handle null nonce for shared collections 2025-03-13 17:12:26 +05:30
Neeraj Gupta
822eb59761 Merge branch 'main' into remote_db 2025-03-13 15:07:20 +05:30
Neeraj Gupta
fade7859ab Refactor 2025-03-13 11:34:33 +05:30
Neeraj Gupta
f85047fb28 [mob] Refactor 2025-03-13 11:21:50 +05:30
Neeraj Gupta
3f81c9beae [mob] Add helpers for local assets import 2025-03-13 09:55:53 +05:30
Neeraj Gupta
b7fa8d7c89 Merge branch 'main' into remote_db 2025-03-12 13:59:12 +05:30
Neeraj Gupta
5f75c5fc3f [mob] Add sql scripts for local db 2025-03-11 14:06:13 +05:30
Neeraj Gupta
98eaee3b9e Merge branch 'main' into remote_db 2025-03-11 13:35:36 +05:30
Neeraj Gupta
59bd039bed Add db schema for local files 2025-03-10 11:07:17 +05:30
Neeraj Gupta
3e90126a55 Merge branch 'main' into remote_db 2025-03-07 13:47:42 +05:30
Neeraj Gupta
dabcc0aeb5 Merge remote-tracking branch 'origin/main' into remote_db 2025-03-05 13:35:37 +05:30
Neeraj Gupta
c4b99af0e2 Merge branch 'main' into remote_db 2025-03-03 19:07:38 +05:30
Neeraj Gupta
679c12bb90 Remove recursion 2025-03-03 11:21:11 +05:30
Neeraj Gupta
3ef8ece8c0 Refactor 2025-03-03 11:16:43 +05:30
Neeraj Gupta
24f8cf188a Refactor 2025-03-03 10:34:38 +05:30
Neeraj Gupta
233838da3e Merge branch 'main' into remote_db 2025-03-01 12:37:42 +05:30
Neeraj Gupta
06c4866c75 [mob] Refactor 2025-02-28 14:07:01 +05:30
Neeraj Gupta
fa71acf91a Merge branch 'main' into remote_db 2025-02-28 13:51:53 +05:30
Neeraj Gupta
81d40826b3 Merge remote-tracking branch 'origin/main' into remote_db 2025-02-28 12:59:40 +05:30
Neeraj Gupta
2a14b5e5a3 clean up 2025-02-28 12:59:26 +05:30
Neeraj Gupta
63bbca09f3 [mob] clean up 2025-02-28 11:39:20 +05:30
Neeraj Gupta
cbff68bc42 [server] Persist remote pull response 2025-02-28 10:56:15 +05:30
Neeraj Gupta
070ab80be9 [mob] Enable foreign_keys on remote db 2025-02-27 14:12:26 +05:30
Neeraj Gupta
0efbf407d3 [mob] table for collection_files and files 2025-02-27 14:11:52 +05:30
Neeraj Gupta
ab22b28695 Merge branch 'main' into remote_db 2025-02-26 16:13:26 +05:30
Neeraj Gupta
d3466d7efe [mob] Insert collection_files 2025-02-25 05:30:46 +05:30
Neeraj Gupta
5945f2aaad Merge branch 'main' into remote_db 2025-02-24 15:11:30 +05:30
Neeraj Gupta
4c79b9cb92 [mob] Pull remote diff using new diff models 2025-02-20 11:57:36 +05:30
Neeraj Gupta
4676c363d2 [mob] Refactor 2025-02-20 11:55:46 +05:30
Neeraj Gupta
f75807d8f0 [mob] New diff model 2025-02-20 11:24:02 +05:30
Neeraj Gupta
578541308a [mob] Refactor 2025-02-19 15:51:41 +05:30
Neeraj Gupta
30cded4d3d [mob][crypto] Sync stream decryption 2025-02-19 15:51:13 +05:30
Neeraj Gupta
be2aee6baa Merge branch 'main' into remote_db 2025-02-18 15:21:25 +05:30
Neeraj Gupta
fae23df6eb [mob] refactor 2025-02-17 14:37:09 +05:30
Neeraj Gupta
2a1f2aded1 [mob] Use remote db for collections 2025-02-14 21:23:01 +05:30
Neeraj Gupta
6e85d24286 [mob] Add db row mappers for collection 2025-02-14 21:23:01 +05:30
Neeraj Gupta
0bcc676e44 [mob] Add new collection model for remote 2025-02-14 21:23:01 +05:30
Neeraj Gupta
b5a9bab5c6 refactor 2025-02-14 21:23:01 +05:30
Neeraj Gupta
5849d14cd9 refactor 2025-02-14 21:23:01 +05:30
Neeraj Gupta
77cde87927 [mob] Create db for collections & collection_files 2025-02-14 21:23:01 +05:30
Neeraj Gupta
670d6e8470 [mob] Scaffold remote db 2025-02-14 21:23:01 +05:30
659 changed files with 23825 additions and 80590 deletions

View File

@@ -8,7 +8,7 @@ on:
env:
FLUTTER_VERSION: "3.32.8"
RUST_VERSION: "1.85.1"
RUST_VERSION: "1.86.0"
permissions:
contents: read
@@ -27,6 +27,38 @@ jobs:
with:
submodules: recursive
- name: Free up disk space
run: |
echo "Initial disk usage:"
df -h /
# Get available space in KB
INITIAL=$(df / | awk 'NR==2 {print $4}')
echo -e "\n=== Removing .NET SDK (~20-25GB) ==="
BEFORE=$(df / | awk 'NR==2 {print $4}')
START=$(date +%s)
sudo rm -rf /usr/share/dotnet
END=$(date +%s)
AFTER=$(df / | awk 'NR==2 {print $4}')
FREED=$(( (AFTER - BEFORE) / 1048576 )) # Convert KB to GB
echo "Time: $((END-START))s | Freed: ${FREED}GB"
echo -e "\n=== Removing cached tools (~5-10GB) ==="
BEFORE=$(df / | awk 'NR==2 {print $4}')
START=$(date +%s)
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
END=$(date +%s)
AFTER=$(df / | awk 'NR==2 {print $4}')
FREED=$(( (AFTER - BEFORE) / 1048576 ))
echo "Time: $((END-START))s | Freed: ${FREED}GB"
echo -e "\n=== Final Summary ==="
FINAL=$(df / | awk 'NR==2 {print $4}')
TOTAL_FREED=$(( (FINAL - INITIAL) / 1048576 ))
echo "Total space freed: ${TOTAL_FREED}GB"
echo "Final disk usage:"
df -h /
- name: Setup JDK 17
uses: actions/setup-java@v1
with:
@@ -39,14 +71,12 @@ jobs:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust ${{ env.RUST_VERSION }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install Flutter Rust Bridge
run: cargo install flutter_rust_bridge_codegen
- name: Generate Rust bindings
run: flutter_rust_bridge_codegen generate
- name: Increment version code for build
run: |
CURRENT_VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //')

View File

@@ -1,77 +0,0 @@
name: "Old Internal release (photos)"
on:
workflow_dispatch: # Allow manually running the action
env:
FLUTTER_VERSION: "3.32.8"
RUST_VERSION: "1.85.1"
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: mobile/apps/photos
steps:
- name: Checkout code and submodules
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup JDK 17
uses: actions/setup-java@v1
with:
java-version: 17
- name: Install Flutter ${{ env.FLUTTER_VERSION }}
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust ${{ env.RUST_VERSION }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install Flutter Rust Bridge
run: cargo install flutter_rust_bridge_codegen
- name: Setup keys
uses: timheuer/base64-to-file@v1
with:
fileName: "keystore/ente_photos_key.jks"
encodedString: ${{ secrets.SIGNING_KEY_PHOTOS }}
- name: Build PlayStore AAB
run: |
flutter build appbundle --dart-define=cronetHttpNoPlay=true --release --flavor playstore
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_photos_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_PHOTOS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD_PHOTOS }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD_PHOTOS }}
- name: Upload AAB to PlayStore
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: io.ente.photos
releaseFiles: mobile/apps/photos/build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab
track: internal
- name: Notify Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }}
nodetail: true
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

@@ -9,6 +9,7 @@ on:
env:
FLUTTER_VERSION: "3.32.8"
RUST_VERSION: "1.86.0"
permissions:
contents: read
@@ -31,7 +32,18 @@ jobs:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- run: flutter pub get
- name: Install Rust ${{ env.RUST_VERSION }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install Flutter Rust Bridge
run: cargo install flutter_rust_bridge_codegen
- name: Generate Rust bindings
run: flutter_rust_bridge_codegen generate
- run: flutter analyze --no-fatal-infos

View File

@@ -28,6 +28,38 @@ jobs:
with:
submodules: recursive
- name: Free up disk space
run: |
echo "Initial disk usage:"
df -h /
# Get available space in KB
INITIAL=$(df / | awk 'NR==2 {print $4}')
echo -e "\n=== Removing .NET SDK (~20-25GB) ==="
BEFORE=$(df / | awk 'NR==2 {print $4}')
START=$(date +%s)
sudo rm -rf /usr/share/dotnet
END=$(date +%s)
AFTER=$(df / | awk 'NR==2 {print $4}')
FREED=$(( (AFTER - BEFORE) / 1048576 )) # Convert KB to GB
echo "Time: $((END-START))s | Freed: ${FREED}GB"
echo -e "\n=== Removing cached tools (~5-10GB) ==="
BEFORE=$(df / | awk 'NR==2 {print $4}')
START=$(date +%s)
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
END=$(date +%s)
AFTER=$(df / | awk 'NR==2 {print $4}')
FREED=$(( (AFTER - BEFORE) / 1048576 ))
echo "Time: $((END-START))s | Freed: ${FREED}GB"
echo -e "\n=== Final Summary ==="
FINAL=$(df / | awk 'NR==2 {print $4}')
TOTAL_FREED=$(( (FINAL - INITIAL) / 1048576 ))
echo "Total space freed: ${TOTAL_FREED}GB"
echo "Final disk usage:"
df -h /
- name: Setup JDK 17
uses: actions/setup-java@v1
with:
@@ -40,6 +72,12 @@ jobs:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Flutter Rust Bridge
run: cargo install flutter_rust_bridge_codegen
- name: Generate Rust bindings
run: flutter_rust_bridge_codegen generate
- name: Setup keys
uses: timheuer/base64-to-file@v1
with:

View File

@@ -2,6 +2,8 @@
## v1.7.15 (Unreleased)
- Custom domains.
- Support Czech translations.
- .
## v1.7.14

View File

@@ -8,6 +8,12 @@ description: Guide to configuring Ente CLI for Self Hosted Instance
If you are self-hosting, you can configure Ente CLI to export data & perform
basic administrative actions.
::: tip Installing Ente CLI
For instructions on installing the Ente CLI, see the [README available on Github](https://github.com/ente-io/ente/tree/main/cli/README.md).
:::
## Step 1: Configure endpoint
To do this, first configure the CLI to use your server's endpoint.

View File

@@ -22,8 +22,7 @@ can achieve this the following steps:
# Change the DB name and DB user name if you use different
# values.
# If using Docker
docker exec -it <postgres-ente-container-name>
docker exec -it <postgres-ente-container-name> sh
psql -U pguser -d ente_db
# Or when using psql directly

View File

@@ -46,7 +46,7 @@ If running Museum without Docker, the code should be visible in the terminal
# Change the DB name and DB user name if you use different
# values.
# If using Docker docker exec -it <postgres-ente-container-name>
# If using Docker docker exec -it <postgres-ente-container-name> sh
psql -U pguser -d ente_db
# Or when using psql directly

45
mobile/.gitignore vendored Normal file
View File

@@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
melos_*.iml
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

View File

@@ -0,0 +1,72 @@
# For more linters, we can check https://dart-lang.github.io/linter/lints/index.html
# or https://pub.dev/packages/lint (Effective dart)
# use "flutter analyze ." or "dart analyze ." for running lint checks
include: package:flutter_lints/flutter.yaml
linter:
rules:
# Ref https://github.com/flutter/packages/blob/master/packages/flutter_lints/lib/flutter.yaml
# Ref https://dart-lang.github.io/linter/lints/
- avoid_print
- avoid_unnecessary_containers
- avoid_web_libraries_in_flutter
- no_logic_in_create_state
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_final_locals
- require_trailing_commas
- sized_box_for_whitespace
- use_full_hex_values_for_flutter_colors
- use_key_in_widget_constructors
- cancel_subscriptions
- avoid_empty_else
- exhaustive_cases
# just style suggestions
- sort_pub_dependencies
- use_rethrow_when_possible
- prefer_double_quotes
- directives_ordering
- always_use_package_imports
- sort_child_properties_last
- unawaited_futures
analyzer:
errors:
avoid_empty_else: error
exhaustive_cases: error
curly_braces_in_flow_control_structures: error
directives_ordering: error
require_trailing_commas: error
always_use_package_imports: warning
prefer_final_fields: error
unused_import: error
camel_case_types: error
prefer_is_empty: warning
use_rethrow_when_possible: info
unused_field: warning
use_key_in_widget_constructors: warning
sort_child_properties_last: warning
sort_pub_dependencies: warning
library_private_types_in_public_api: warning
constant_identifier_names: ignore
prefer_const_constructors: warning
prefer_const_declarations: warning
prefer_const_constructors_in_immutables: warning
prefer_final_locals: warning
unnecessary_const: error
cancel_subscriptions: error
unrelated_type_equality_checks: error
unnecessary_cast: info
unawaited_futures: warning # convert to warning after fixing existing issues
invalid_dependency: info
use_build_context_synchronously: ignore # experimental lint, requires many changes
prefer_interpolation_to_compose_strings: ignore # later too many warnings
prefer_double_quotes: ignore # too many warnings
avoid_renaming_method_parameters: ignore # incorrect warnings for `equals` overrides

View File

@@ -382,6 +382,11 @@
{
"title": "CoinDCX"
},
{
"title": "CoinTracking",
"slug": "cointracking",
"altNames": ["cointracking.info", "Coin Tracking"]
},
{
"title": "colorado",
"altNames": [
@@ -735,6 +740,11 @@
{
"title": "Hivelocity"
},
{
"title": "HRDocumentBox",
"slug": "hrdocumentbox",
"altNames": ["HRDocumentBox", "HR Document Box"]
},
{
"title": "HSA Bank",
"slug": "hsa_bank",
@@ -1040,6 +1050,13 @@
"MistralAI"
]
},
{
"title": "Mobile01",
"slug": "mobile01",
"altNames": [
"M01"
]
},
{
"title": "Mozilla"
},
@@ -1219,6 +1236,12 @@
"title": "Parqet",
"slug": "parqet"
},
{
"title": "Parallels",
"slug": "parallels",
"hex": "#E61E25",
"altNames": ["Parallels Desktop", "Parallels VM"]
},
{
"title": "Parsec"
},
@@ -1773,6 +1796,11 @@
"uollet.com.br"
]
},
{
"title": "VHV",
"slug": "vhv",
"altNames": ["VHV", "VHV Versicherung"]
},
{
"title": "Vikunja"
},

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1220.8 227.9" style="enable-background:new 0 0 1220.8 227.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:#0D253E;}
.st1{fill:#008AFB;}
</style>
<title>CoinTracking light</title>
<g id="Layer_2_1_">
<g id="Layer_1-2">
<path class="st0" d="M198.1,167c-30.2,0-54.7-24.5-54.7-54.7s24.5-54.7,54.7-54.7s54.7,24.5,54.7,54.7l0,0 C252.8,142.5,228.3,167,198.1,167z M198.1,81.6c-17,0-30.7,13.7-30.7,30.7s13.7,30.7,30.7,30.7s30.7-13.7,30.7-30.7l0,0 C228.8,95.4,215,81.6,198.1,81.6z"/>
<path class="st0" d="M292.2,59.5h-23.6v107.9h23.6V59.5z"/>
<path class="st0" d="M339.5,167.4h-23.8V59.5h23.8v16.2c6.2-12.5,21-18.5,33-18.5c26.1,0,41.1,16.9,41.1,47.3v62.8h-23.8v-60.1 c0-17.1-8.8-26.8-22.6-26.8c-14.1,0-27.7,7.6-27.7,28.9V167.4z"/>
<path class="st1" d="M390.6,8.2h151.7v22.9h-65.9v136.3h-25V31.1h-60.9V8.2H390.6z"/>
<path class="st1" d="M540.3,167.4h-23.8V59.5h23.8V79c7.4-13.5,15.4-19.5,29.6-21.8c7.5-1.2,15.7,1.8,19.2,4.2l-3.9,22 c-4.9-2.5-10.4-3.8-15.9-3.7c-20.3,0-28.9,20.3-28.9,49L540.3,167.4L540.3,167.4z"/>
<path class="st1" d="M680.7,151.9c-7.2,11.8-22.9,17.8-36.3,17.8c-29.1,0-54.8-21.9-54.8-56.4s25.6-56.1,54.8-56.1 c12.9,0,28.9,5.3,36.3,17.5V59.5h23.6v107.9h-23.6V151.9z M647.2,146.6c17.6,0,33.3-12.2,33.3-33.5s-17.1-32.8-33.3-32.8 c-18,0-33,12.9-33,32.8S629.2,146.6,647.2,146.6L647.2,146.6z"/>
<path class="st1" d="M778.4,57.2c17.1,0,32.6,6.7,42.7,18.7l-18.5,14.8c-5.8-6.7-14.8-10.4-24.3-10.4c-18,0-34,12.7-34,32.8 s15.9,33.7,34,33.7c9.5,0,18.5-3.9,24.3-10.6l18.7,14.6c-10.2,12-25.6,18.9-43,18.9c-31,0-57.5-22.4-57.5-56.6 S747.4,57.2,778.4,57.2z"/>
<path class="st1" d="M860.3,117.2v50.1h-23.6V0.8h23.6V95l34.2-35.6h31.9l-46,46.9l56.4,61h-30.5L860.3,117.2z"/>
<path class="st1" d="M967.4,59.5h-23.6v107.9h23.6V59.5z"/>
<path class="st1" d="M1014.7,167.4h-23.8V59.5h23.8v16.2c6.2-12.5,21-18.5,33-18.5c26.1,0,41.1,16.9,41.1,47.3v62.8H1065v-60.1 c0-17.1-8.8-26.8-22.6-26.8c-14.1,0-27.7,7.6-27.7,28.9V167.4z"/>
<path class="st1" d="M1220.2,111.5c0-12.3-4.5-24.2-12.5-33.6l13-17.1l-19.6-13l-11.9,15.7c-8.3-4.1-17.5-6.2-26.8-6.2 c-31.9,0-57.8,24.4-57.8,54.3s25.9,54.3,57.8,54.3c20.2,0,34.2,10.2,34.2,19.3s-14.1,19.3-34.2,19.3s-34.2-10.2-34.2-19.3h-23.6 c0,24,25.4,42.9,57.8,42.9s57.8-18.8,57.8-42.9c0-13.2-7.7-24.8-19.9-32.6C1212.5,142.5,1220.2,127.8,1220.2,111.5z M1128.2,111.5 c0-16.9,15.4-30.7,34.2-30.7s34.2,13.8,34.2,30.7s-15.4,30.7-34.2,30.7S1128.2,128.4,1128.2,111.5L1128.2,111.5z"/>
<path class="st0" d="M81.4,170.5C36.4,170.5,0,134,0,89c0-21.6,8.6-42.3,23.9-57.6c31.8-31.8,83.4-31.8,115.2,0l0,0l-17.7,17.7 C99.3,27,63.6,27,41.5,49.1s-22.1,57.8,0,79.9s57.8,22.1,79.9,0l17.7,17.7C123.8,162,103.1,170.6,81.4,170.5z"/>
<circle class="st0" cx="280.7" cy="15.5" r="15.5"/>
<circle class="st1" cx="954.7" cy="15.5" r="15.5"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<svg width="320" height="280" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
<g class="layer">
<title>Layer 1</title>
<g id="Layer1000">
<g id="Layer1002">
<g id="Layer1003">
<path d="m123.08,34.29c-66.43,0 -120.27,53.85 -120.27,120.27c0,66.43 53.85,120.27 120.27,120.27c66.47,0 120.32,-53.85 120.32,-120.27c0,-66.43 -53.85,-120.27 -120.32,-120.27zm0,215.67c-52.67,0 -95.36,-42.73 -95.36,-95.4c0,-52.67 42.68,-95.4 95.36,-95.4c52.72,0 95.4,42.73 95.4,95.4c0,52.67 -42.68,95.4 -95.4,95.4z" fill="#2a5e00" fill-rule="evenodd" id="path7"/>
<g id="Layer1004">
<g id="Layer1005">
<path d="m138.72,146.29l59.61,-41.47l7.78,33.7l-67.39,7.78z" fill="#2a5e00" fill-rule="evenodd" id="path8"/>
<path d="m110.88,146.29l-59.61,-41.47l-7.78,33.7l67.39,7.78z" fill="#2a5e00" fill-rule="evenodd" id="path9"/>
</g>
<path d="m43.95,192.02l74.62,49.75l87.12,-78.8l-161.75,29.05z" fill="#2a5e00" fill-rule="evenodd" id="path10"/>
</g>
<path d="m94.24,59.29l-30.48,-55.1l54.26,33.24l-23.79,21.86z" fill="#2a5e00" fill-rule="evenodd" id="path11"/>
<path d="m202.64,78.1l30.43,-55.1l-54.22,33.24l23.79,21.86z" fill="#2a5e00" fill-rule="evenodd" id="path12"/>
</g>
<path d="m275.63,274.67l29.35,0l0,-240.76l-29.35,0l0,240.76z" fill="#2a5e00" fill-rule="evenodd" id="path13"/>
<path d="m317.94,125.93c0,15.3 -12.33,27.63 -27.63,27.63c-15.26,0 -27.63,-12.33 -27.63,-27.63c0,-15.26 12.37,-27.63 27.63,-27.63c15.3,0 27.63,12.37 27.63,27.63z" fill="#2a5e00" fill-rule="evenodd" id="path14"/>
<path d="m288.84,33.91l-41.76,0l16.76,45.99l23.58,0l1.42,-45.99z" fill="#2a5e00" fill-rule="evenodd" id="path15"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect x="20" y="10" width="10" height="80" rx="5" fill="#E61E25"/>
<rect x="50" y="10" width="10" height="80" rx="5" fill="#E61E25"/>
</svg>

After

Width:  |  Height:  |  Size: 207 B

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Inkscape (http://www.inkscape.org/) by Marsupilami -->
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="1024" height="357" viewBox="-1.98252 -1.98252 201.02104 70.04904" id="svg3349">
<defs id="defs3351"/>
<path d="m 0,0 11.76,0 4.455,31.962 0.12,0 L 20.789,0 32.55,0 23.402,42.417 9.147,42.417 0,0" id="path3131" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 34.039,0 11.05,0 0,15.567 6.771,0 0,-15.567 11.05,0 0,42.417 -11.05,0 0,-17.465 -6.771,0 0,17.465 -11.05,0 0,-42.417" id="path3133" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 64.395,0 11.757,0 4.457,31.962 0.121,0 L 85.185,0 96.944,0 87.797,42.417 73.54,42.417 64.395,0" id="path3135" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 97.576,42.414 8.907,0 9.222,-42.41 -8.912,0 -9.217,42.41" id="path3137" style="fill:#f0ab00;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 111.026,42.424 8.908,-0.01 9.218,-42.41 -8.913,0 -9.213,42.42" id="path3139" style="fill:#f0ab00;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 124.564,42.414 8.906,0 9.217,-42.41 -8.906,0 -9.217,42.41" id="path3141" style="fill:#f0ab00;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 4.169,46.784 5.251,0 1.985,14.261 0.05,0 1.99,-14.261 5.247,0 -4.082,18.928 -6.363,0 -4.082,-18.928" id="path3143" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 19.356,46.784 11.216,0 0,4.031 -6.282,0 0,3.234 5.882,0 0,3.87 -5.882,0 0,3.763 6.517,0 0,4.03 -11.451,0 0,-18.928" id="path3145" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 54.93,52.247 0,-0.45 c 0,-1.117 -0.449,-2.043 -1.405,-2.043 -1.06,0 -1.538,0.823 -1.538,1.67 0,3.739 8.059,1.91 8.059,8.828 0,4.027 -2.357,5.832 -6.705,5.832 -4.082,0 -6.362,-1.404 -6.362,-5.331 l 0,-0.663 4.772,0 0,0.453 c 0,1.615 0.663,2.202 1.614,2.202 1.007,0 1.594,-0.798 1.594,-1.831 0,-3.739 -7.743,-1.88 -7.743,-8.586 0,-3.819 2.043,-5.913 6.205,-5.913 4.294,0 6.12,1.775 6.12,5.832 l -4.611,0" id="path3147" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 61.476,65.712 4.932,0 0,-18.928 -4.932,0 0,18.928 z" id="path3149" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 32.477,46.784 7.714,0 c 3.766,0 5.195,2.124 5.195,5.039 0,2.516 -0.979,4.16 -3.232,4.506 2.385,0.265 3.103,1.776 3.103,4.294 l 0,1.616 c 0,0.981 0,2.251 0.237,2.626 0.132,0.209 0.237,0.422 0.558,0.582 l 0,0.265 -5.25,0 C 40.325,64.705 40.325,62.9 40.325,62.109 l 0,-1.275 c 0,-2.147 -0.423,-2.704 -1.619,-2.704 l -1.296,0 0,7.582 -4.933,0 0,-18.928 z m 4.933,8.008 0.98,0 c 1.405,0 2.066,-0.9 2.066,-2.252 0,-1.541 -0.609,-2.202 -2.094,-2.202 l -0.952,0 0,4.454" id="path3151" style="fill:#1e1e1e;fill-opacity:1;fill-rule:evenodd;stroke:none"/>
<path d="m 75.975,52.54 c 0,-2.147 -0.396,-2.786 -1.35,-2.786 -1.513,0 -1.67,1.381 -1.67,6.494 0,5.117 0.157,6.497 1.67,6.497 1.22,0 1.485,-1.063 1.485,-4.64 l 4.771,0 0,1.405 c 0,5.3 -3.101,6.574 -6.256,6.574 -5.54,0 -6.76,-2.784 -6.76,-9.836 0,-7.236 1.642,-9.833 6.76,-9.833 4.451,0 6.12,2.334 6.12,5.992 l 0,1.19 -4.77,0 0,-1.057" id="path3153" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 82.524,46.784 4.928,0 0,6.948 3.02,0 0,-6.948 4.932,0 0,18.928 -4.932,0 0,-7.793 -3.02,0 0,7.793 -4.928,0 0,-18.928" id="path3155" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 97.606,46.784 11.21,0 0,4.031 -6.282,0 0,3.234 5.886,0 0,3.87 -5.886,0 0,3.763 6.522,0 0,4.03 -11.45,0 0,-18.928" id="path3157" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 130.526,46.784 0,13.655 c 0,1.824 0.559,2.306 1.485,2.306 0.928,0 1.485,-0.482 1.485,-2.306 l 0,-13.655 4.929,0 0,12.408 c 0,5.298 -2.28,6.892 -6.414,6.892 -4.135,0 -6.412,-1.594 -6.412,-6.892 l 0,-12.408 4.927,0" id="path3159" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 140.415,46.784 5.51,0 3.185,11.665 0.05,0 0,-11.665 4.614,0 0,18.928 -5.407,0 -3.288,-11.689 -0.05,0 0,11.689 -4.613,0 0,-18.928" id="path3161" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 110.726,46.784 7.716,0 c 3.76,0 5.192,2.124 5.192,5.039 0,2.516 -0.979,4.16 -3.234,4.506 2.383,0.265 3.101,1.776 3.101,4.294 l 0,1.616 c 0,0.981 0,2.251 0.238,2.626 0.131,0.209 0.24,0.422 0.558,0.582 l 0,0.265 -5.251,0 c -0.477,-1.007 -0.477,-2.812 -0.477,-3.603 l 0,-1.275 c 0,-2.147 -0.422,-2.704 -1.612,-2.704 l -1.301,0 0,7.582 -4.93,0 0,-18.928 z m 4.93,8.008 0.979,0 c 1.404,0 2.07,-0.9 2.07,-2.252 0,-1.541 -0.61,-2.202 -2.095,-2.202 l -0.954,0 0,4.454" id="path3163" style="fill:#1e1e1e;fill-opacity:1;fill-rule:evenodd;stroke:none"/>
<path d="m 162.334,55.428 6.361,0 0,10.284 -3.34,0 -0.113,-1.669 -0.05,0 c -0.662,1.617 -2.412,2.041 -4.082,2.041 -5.01,0 -5.459,-3.58 -5.459,-9.836 0,-6.336 1.22,-9.833 7.047,-9.833 3.502,0 5.993,1.775 5.993,6.36 l -4.771,0 c 0,-0.952 -0.07,-1.695 -0.266,-2.198 -0.185,-0.53 -0.554,-0.823 -1.139,-0.823 -1.612,0 -1.774,1.381 -1.774,6.494 0,5.117 0.161,6.497 1.67,6.497 1.034,0 1.639,-0.666 1.669,-3.978 l -1.75,0 0,-3.339" id="path3165" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 170.577,46.784 11.213,0 0,4.031 -6.28,0 0,3.234 5.885,0 0,3.87 -5.885,0 0,3.763 6.519,0 0,4.03 -11.452,0 0,-18.928" id="path3167" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<path d="m 183.697,46.784 5.514,0 3.18,11.665 0.05,0 0,-11.665 4.615,0 0,18.928 -5.408,0 -3.284,-11.689 -0.05,0 0,11.689 -4.614,0 0,-18.928" id="path3169" style="fill:#1e1e1e;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
</svg>
<!-- version: 20110311, original size: 197.056 66.084, border: 3% -->

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -39,6 +39,8 @@ PODS:
- DKPhotoGallery/Resource (0.0.19):
- SDWebImage
- SwiftyGif
- ente_qr (0.0.1):
- Flutter
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
@@ -126,6 +128,8 @@ PODS:
- sqlite3/perf-threadsafe
- sqlite3/rtree
- SwiftyGif (5.4.5)
- ua_client_hints (1.4.1):
- Flutter
- url_launcher_ios (0.0.1):
- Flutter
@@ -134,6 +138,7 @@ DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- cupertino_http (from `.symlinks/plugins/cupertino_http/darwin`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- ente_qr (from `.symlinks/plugins/ente_qr/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- file_saver (from `.symlinks/plugins/file_saver/ios`)
- fk_user_agent (from `.symlinks/plugins/fk_user_agent/ios`)
@@ -158,6 +163,7 @@ DEPENDENCIES:
- sodium_libs (from `.symlinks/plugins/sodium_libs/ios`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
@@ -180,6 +186,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/cupertino_http/darwin"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
ente_qr:
:path: ".symlinks/plugins/ente_qr/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
file_saver:
@@ -228,6 +236,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
sqlite3_flutter_libs:
:path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
ua_client_hints:
:path: ".symlinks/plugins/ua_client_hints/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
@@ -238,6 +248,7 @@ SPEC CHECKSUMS:
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
ente_qr: f39434aa69ea0e71047b49316365b2737f8a20aa
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
@@ -268,6 +279,7 @@ SPEC CHECKSUMS:
sqlite3: 3e82a2daae39ba3b41ae6ee84a130494585460fc
sqlite3_flutter_libs: 2c48c4ee7217fd653251975e43412250d5bcbbe2
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: 78f002751f1a8f65042b8da97902ba4124271c5a

View File

@@ -111,6 +111,7 @@
"importAegisGuide": "Použijte možnost \"Export the vault\" v nastavení aplikace Aegis.",
"import2FasGuide": "Použijte možnost \"Settings->Backup -Export\" v 2FA.\n\nPokud je Vaše záloha šifrovaná, budete muset zadat heslo pro její odemčení",
"importLastpassGuide": "V nastavení aplikace Lastpass Authenticator vyberte možnost \"Transfer accounts\" a poté \"Export accounts to file\". Vygenerovaný soubor JSON následně nahrajte sem.",
"importProtonAuthGuide": "K exportu kódů použijte možnost „Exportovat“ v nastavení aplikace Proton Authenticator.",
"exportCodes": "Exportovat kódy",
"importLabel": "Importovat",
"importInstruction": "Vyberte, prosím, soubor obsahující seznam Vašich kódů v následujícím formátu",
@@ -124,6 +125,7 @@
"authToChangeYourEmail": "Pro změnu svého e-mailu se, prosím, ověřte",
"authToChangeYourPassword": "Pro změnu svého hesla se, prosím, ověřte",
"authToViewSecrets": "Pro zobrazení svých tajných údajů se musíte ověřit",
"authToInitiateSignIn": "Proveďte ověření a přihlaste se k zálohování.",
"ok": "Ok",
"cancel": "Zrušit",
"yes": "Ano",
@@ -171,6 +173,7 @@
"invalidQRCode": "Neplatný QR kód",
"noRecoveryKeyTitle": "Nemáte obnovovací klíč?",
"enterEmailHint": "Zadejte svou e-mailovou adresu",
"enterNewEmailHint": "Zadejte svou novou e-mailovou adresu",
"invalidEmailTitle": "Neplatná e-mailová adresa",
"invalidEmailMessage": "Prosím, zadejte platnou e-mailovou adresu.",
"deleteAccount": "Odstranit účet",
@@ -509,6 +512,19 @@
"supportEnte": "Podpořte <bold-green>ente</bold-green>",
"giveUsAStarOnGithub": "Dejte nám hvězdu na Githubu",
"free5GB": "5GB zdarma na <bold-green>ente</bold-green> Fotky",
"loginWithAuthAccount": "Přihlaste se pomocí svého účtu Auth",
"freeStorageOffer": "10% sleva na <bold-green>ente</bold-green> fotky",
"freeStorageOfferDescription": "Použijte kód \"AUTH\" pro získání 10% slevy na první rok"
"freeStorageOfferDescription": "Použijte kód \"AUTH\" pro získání 10% slevy na první rok",
"advanced": "Pokročilé",
"algorithm": "Algoritmus",
"type": "Typ",
"period": "Období",
"digits": "Digitální",
"importFromGallery": "Importovat z galerie",
"errorCouldNotReadImage": "Nelze přečíst vybraný obrazový soubor.",
"errorInvalidQRCode": "Neplatný QR kód",
"errorInvalidQRCodeBody": "Naskenovaný QR kód není platným účtem 2FA.",
"errorNoQRCode": "Nenalezen žádný QR kód",
"errorGenericTitle": "Došlo k chybě",
"errorGenericBody": "Při importu došlo k neočekávané chybě."
}

View File

@@ -111,6 +111,7 @@
"importAegisGuide": "Verwenden Sie die Option \"Tresor exportieren\" in den Einstellungen von Aegis.\n\nFalls Ihr Tresor verschlüsselt ist, müssen Sie das Passwort für den Tresor eingeben, um ihn zu entschlüsseln.",
"import2FasGuide": "Verwenden Sie unter \"Einstellungen → Backup\" die Option \"Exportieren\" in 2FAS.\n\nFalls Ihr Backup verschlüsselt ist, müssen Sie das Passwort eingeben, um das Backup zu entschlüsseln.",
"importLastpassGuide": "Verwenden Sie die Option \"Konten übertragen → Konten in Datei exportieren\" in den Lastpass Authenticator Einstellungen. \nImportieren Sie anschließend die heruntergeladene JSON-Datei.",
"importProtonAuthGuide": "Verwenden Sie die Option \"Exportieren\" in den Proton Authenticator Settings um Ihre Codes zu exportieren.",
"exportCodes": "Codes exportieren",
"importLabel": "Importieren",
"importInstruction": "Bitte wählen Sie eine Datei die Codes in folgendem Format beinhaltet",
@@ -519,5 +520,12 @@
"algorithm": "Algorithmus",
"type": "Typ",
"period": "Periode",
"digits": "Ziffern"
"digits": "Ziffern",
"importFromGallery": "Aus Galerie importieren",
"errorCouldNotReadImage": "Die ausgewählte Bild-Datei konnte nicht verarbeitet werden.",
"errorInvalidQRCode": "Ungültiger QR-Code",
"errorInvalidQRCodeBody": "Der gescannte QR-Code ist kein gültiges 2FA-Konto.",
"errorNoQRCode": "Kein QR-Code gefunden",
"errorGenericTitle": "Ein Fehler ist aufgetreten",
"errorGenericBody": "Beim Importieren ist ein unerwarteter Fehler aufgetreten."
}

View File

@@ -111,6 +111,7 @@
"importAegisGuide": "Use the \"Export the vault\" option in Aegis's Settings.\n\nIf your vault is encrypted, you will need to enter vault password to decrypt the vault.",
"import2FasGuide": "Use the \"Settings->Backup -Export\" option in 2FAS.\n\nIf your backup is encrypted, you will need to enter the password to decrypt the backup",
"importLastpassGuide": "Use the \"Transfer accounts\" option within Lastpass Authenticator Settings and press \"Export accounts to file\". Import the JSON downloaded.",
"importProtonAuthGuide": "Use the \"Export\" option in Proton Authenticator Settings to export your codes.",
"exportCodes": "Export codes",
"importLabel": "Import",
"importInstruction": "Please select a file that contains a list of your codes in the following format",
@@ -519,5 +520,12 @@
"algorithm": "Algorithm",
"type": "Type",
"period": "Period",
"digits": "Digits"
"digits": "Digits",
"importFromGallery": "Import from gallery",
"errorCouldNotReadImage": "Could not read the selected image file.",
"errorInvalidQRCode": "Invalid QR Code",
"errorInvalidQRCodeBody": "The scanned QR code is not a valid 2FA account.",
"errorNoQRCode": "No QR code found",
"errorGenericTitle": "An Error Occurred",
"errorGenericBody": "An unexpected error occurred while importing."
}

View File

@@ -111,6 +111,7 @@
"importAegisGuide": "Utilisez l'option \"Exporter le coffre-fort\" dans les paramètres d'Aegis.\n\nSi votre coffre-fort est crypté, vous devrez saisir le mot de passe du coffre-fort pour déchiffrer le coffre-fort.",
"import2FasGuide": "Utilisez l'option \"Paramètres->Sauvegarde -Export\" dans 2FAS.\n\nSi votre sauvegarde est chiffrée, vous devrez entrer le mot de passe pour déchiffrer la sauvegarde",
"importLastpassGuide": "Utilisez l'option \"Transférer des comptes\" dans les paramètres de l'authentificateur Lastpass et appuyez sur \"Exporter des comptes vers un fichier\". Importez le JSON téléchargé.",
"importProtonAuthGuide": "Utilisez l'option \"Export\" dans les paramètres de Proton Authenticator pour exporter vos codes.",
"exportCodes": "Exporter les codes",
"importLabel": "Importer",
"importInstruction": "Veuillez sélectionner un fichier qui contient une liste de vos codes dans le format suivant",
@@ -519,5 +520,12 @@
"algorithm": "Algorithme",
"type": "Type",
"period": "Période",
"digits": "Chiffres"
"digits": "Chiffres",
"importFromGallery": "Importer depuis la galerie",
"errorCouldNotReadImage": "Impossible de lire le fichier sélectionné.",
"errorInvalidQRCode": "QR Code invalide",
"errorInvalidQRCodeBody": "Le code QR scanné n'est pas un compte 2FA valide.",
"errorNoQRCode": "Aucun code QR trouvé",
"errorGenericTitle": "Une erreur s'est produite",
"errorGenericBody": "Une erreur inattendue est survenue lors de l'importation."
}

View File

@@ -111,6 +111,7 @@
"importAegisGuide": "Naudokite „Aegis“ nustatymuose esančią parinktį Eksportuoti slėptuvę.\n\nJei jūsų saugykla užšifruota, turėsite įvesti saugyklos slaptažodį, kad iššifruotumėte saugyklą.",
"import2FasGuide": "Naudokite programoje 2FAS esančią parinktį „Settings->2FAS Backup->Export to file“.\n\nJei atsarginė kopija užšifruota, turėsite įvesti slaptažodį, kad iššifruotumėte atsarginę kopiją.",
"importLastpassGuide": "Naudokite „Lastpass Authenticator“ nustatymuose esančią parinktį „Transfer accounts“ (perkelti paskyras) ir paspauskite „Export accounts to file“ (eksportuoti paskyras į failą). Importuokite atsisiųstą JSON failą.",
"importProtonAuthGuide": "Naudokite „Proton Authenticator“ nustatymuose esančią parinktį „Export“ (eksportuoti), kad eksportuotumėte savo kodus.",
"exportCodes": "Eksportuoti kodus",
"importLabel": "Importuoti",
"importInstruction": "Pasirinkite failą, kuriame yra tokio formato jūsų kodų sąrašas",
@@ -519,5 +520,12 @@
"algorithm": "Algoritmas",
"type": "Tipas",
"period": "Laikotarpis",
"digits": "Skaitmenys"
"digits": "Skaitmenys",
"importFromGallery": "Importuoti iš galerijos",
"errorCouldNotReadImage": "Nepavyko perskaityti pasirinkto vaizdo failo.",
"errorInvalidQRCode": "Netinkamas QR kodas",
"errorInvalidQRCodeBody": "Nuskenuotas QR kodas nėra tinkama 2FA paskyra.",
"errorNoQRCode": "QR kodas nerastas.",
"errorGenericTitle": "Įvyko klaida",
"errorGenericBody": "Importuojant įvyko netikėta klaida."
}

View File

@@ -111,6 +111,7 @@
"importAegisGuide": "Użyj opcji \"Eksportuj sejf\" w ustawieniach Aegis.\n\nJeśli twój sejf jest zaszyfrowany, musisz wprowadzić hasło sejfu, aby odszyfrować sejf.",
"import2FasGuide": "Użyj opcji \"Ustawienia->Kopia Zapasowa-Eksport\" w 2FAS.\n\nJeśli twoja kopia zapasowa jest zaszyfrowana, musisz wprowadzić hasło, aby odszyfrować kopię zapasową",
"importLastpassGuide": "Użyj opcji \"Przenieś konta\" w Ustawieniach Lastpass Authenticator i naciśnij \"Eksportuj konta do pliku\". Zaimportuj pobrany plik JSON.",
"importProtonAuthGuide": "Użyj opcji „Eksportuj” w ustawieniach Proton Authenticator, aby wyeksportować kody.",
"exportCodes": "Eksportuj kody",
"importLabel": "Importuj",
"importInstruction": "Wybierz plik, który zawiera listę twoich kodów w następującym formacie",
@@ -519,5 +520,12 @@
"algorithm": "Algorytm",
"type": "Rodzaj",
"period": "Okres",
"digits": "Cyfry"
"digits": "Cyfry",
"importFromGallery": "Importuj z galerii",
"errorCouldNotReadImage": "Nie można odczytać wybranego pliku obrazu.",
"errorInvalidQRCode": "Nieprawidłowy kod QR",
"errorInvalidQRCodeBody": "Zeskanowany kod QR nie wskazuje na prawidłowe konto 2FA.",
"errorNoQRCode": "Nie znaleziono kodu QR",
"errorGenericTitle": "Wystąpił błąd",
"errorGenericBody": "Podczas importowania wystąpił nieoczekiwany błąd."
}

View File

@@ -18,7 +18,7 @@
"incorrectDetails": "Felaktiga uppgifter",
"pleaseVerifyDetails": "Kontrollera dina detaljer och försök igen",
"codeIssuerHint": "Utfärdare",
"codeSecretKeyHint": "Secret Key",
"codeSecretKeyHint": "Hemlig nyckel",
"secret": "Säkerhetsnyckel",
"all": "Alla",
"notes": "Anteckningar",
@@ -33,7 +33,7 @@
}
}
},
"codeAccountHint": "Konto (du@domän.com)",
"codeAccountHint": "Konto (du@domain.com)",
"codeTagHint": "Tagg",
"accountKeyType": "Typ av nyckel",
"sessionExpired": "Sessionen har gått ut",
@@ -68,7 +68,7 @@
"reportABug": "Rapportera en bugg",
"crashAndErrorReporting": "Krasch och felrapportering",
"reportBug": "Rapportera bugg",
"emailUsMessage": "Skicka e-mail till {email}",
"emailUsMessage": "Skicka e-post till {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
@@ -79,7 +79,7 @@
"contactSupport": "Kontakta support",
"rateUsOnStore": "Betygsätt på {storeName}",
"blog": "Blogg",
"merchandise": "Merchandise",
"merchandise": "Produkter",
"verifyPassword": "Bekräfta lösenord",
"pleaseWait": "Vänligen vänta...",
"generatingEncryptionKeysTitle": "Skapar krypteringsnycklar...",
@@ -104,13 +104,14 @@
"importFromApp": "Importera koder från {appName}",
"importGoogleAuthGuide": "Exportera dina konton från Google Authenticator till en QR-kod med alternativet \"Överföra konton\". Använd sedan en annan enhet och skanna QR-koden.\n\nTips: Du kan använda din bärbara dators webbkamera för att ta en bild av QR-koden.",
"importSelectJsonFile": "Välj JSON-fil",
"importSelectAppExport": "Välj {appName} exportfil",
"importSelectAppExport": "Välj {appName} exporteringsfil",
"importEnteEncGuide": "Välj den krypterade JSON-filen som exporteras från Ente",
"importRaivoGuide": "Använd alternativet \"Exportera OTPs till zip-arkiv\" i Raivos inställningar.\n\nExtrahera zip-filen och importera JSON-filen.",
"importBitwardenGuide": "Använd alternativet \"Exportera valv\" inom Bitwarden Tools och importera den okrypterade JSON-filen.",
"importAegisGuide": "Använd alternativet \"Exportera valvet\" i Aegis inställningar.\n\nOm ditt valv är krypterat måste du ange valvlösenordet för att dekryptera valvet.",
"import2FasGuide": "Använd alternativet \"Inställningar->Säkerhetskopiera -Exportera\" i 2FAS.\n\nOm din säkerhetskopia är krypterad måste du ange lösenordet för att dekryptera säkerhetskopian.",
"importLastpassGuide": "Använd alternativet \"Överför konton\" i LastPass Authenticators inställningar och tryck på \"Exportera konton till fil\". Importera JSON-filen som laddas ner.",
"importProtonAuthGuide": "Använd alternativet \"Exportera\" i Proton Authenticator-inställningarna för att exportera koder.",
"exportCodes": "Exportera koder",
"importLabel": "Importera",
"importInstruction": "Vänligen välj en fil som innehåller en lista över dina koder i följande format",
@@ -119,11 +120,11 @@
"emailVerificationToggle": "E-postverifiering",
"emailVerificationEnableWarning": "För att undvika att bli låst från ditt konto, se till att spara en kopia av din e-post 2FA utanför Ente Auth innan du aktiverar e-postverifiering.",
"authToChangeEmailVerificationSetting": "Autentisera för att ändra din e-postadress",
"authenticateGeneric": "Var god autentisera",
"authenticateGeneric": "Vänligen autentisera",
"authToViewYourRecoveryKey": "Autentisera för att visa din återställningsnyckel",
"authToChangeYourEmail": "Autentisera för att ändra din e-postadress",
"authToChangeYourPassword": "Autentisera för att ändra ditt lösenord",
"authToViewSecrets": "Autentisera för att visa din återställningsnyckel",
"authToViewSecrets": "Vänligen autentisera för att visa din återställningsnyckel",
"authToInitiateSignIn": "Vänligen autentisera för att initiera inloggning för säkerhetskopiering.",
"ok": "OK",
"cancel": "Avbryt",
@@ -147,7 +148,7 @@
"leaveFamily": "Lämna familjen",
"leaveFamilyMessage": "Är du säker på att du vill lämna familjeplanen?",
"inFamilyPlanMessage": "Du är på en familjeplan!",
"hintForMobile": "Håll i på en kod för att redigera eller ta bort.",
"hintForMobile": "Tryck länge på en kod för att redigera eller ta bort.",
"hintForDesktop": "Högerklicka på en kod för att redigera eller ta bort.",
"scan": "Skanna",
"scanACode": "Skanna kod",
@@ -191,7 +192,7 @@
"oopsSomethingWentWrong": "Hoppsan! Något gick fel.",
"selectLanguage": "Välj språk",
"language": "Språk",
"social": "Social",
"social": "Socialt",
"security": "Säkerhet",
"lockscreen": "Låsskärm",
"authToChangeLockscreenSetting": "Vänligen autentisera för att ändra låsskärms inställningar",
@@ -200,7 +201,7 @@
"authToViewYourActiveSessions": "Autentisera för att visa dina aktiva sessioner",
"searchHint": "Sök...",
"search": "Sök",
"sorryUnableToGenCode": "Tyvärr, det gick inte att generera en kod för {issuerName}",
"sorryUnableToGenCode": "Tyvärr, kunde inte generera en kod för {issuerName}",
"noResult": "Inga resultat",
"addCode": "Lägg till kod",
"scanAQrCode": "Skanna en QR-kod",
@@ -215,7 +216,7 @@
"error": "Fel",
"recoveryKeyCopiedToClipboard": "Återställningsnyckel kopierad till urklipp",
"recoveryKeyOnForgotPassword": "Om du glömmer ditt lösenord är det enda sättet du kan återställa dina data med denna nyckel.",
"recoveryKeySaveDescription": "Vi lagrar inte och har därför inte åtkomst till denna nyckel, vänligen spara denna 24 ords nyckel på en säker plats.",
"recoveryKeySaveDescription": "Vi lagrar inte och har därför inte åtkomst till denna nyckel, vänligen spara denna 24 ordsnyckeln på en säker plats.",
"doThisLater": "Gör detta senare",
"saveKey": "Spara nyckel",
"save": "Spara",
@@ -254,7 +255,7 @@
"insecureDevice": "Osäker enhet",
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Tyvärr, kunde vi inte generera säkra nycklar på den här enheten.\n\nvänligen registrera dig från en annan enhet.",
"howItWorks": "Så här fungerar det",
"ackPasswordLostWarning": "Jag förstår att om jag förlorar mitt lösenord kan jag förlora mina data eftersom min data är <underline>end-to-end-krypterad</underline>.",
"ackPasswordLostWarning": "Jag förstår att om jag förlorar mitt lösenord kan jag förlora mina data eftersom min data är <underline>totalsträckskrypterad</underline>.",
"loginTerms": "Jag samtycker till <u-terms>användarvillkoren</u-terms> och <u-policy>integritetspolicyn</u-policy>",
"logInLabel": "Logga in",
"logout": "Logga ut",
@@ -278,7 +279,7 @@
"recoveryKeyVerifyReason": "Din återställningsnyckel är det enda sättet att återställa dina foton om du glömmer ditt lösenord. Du hittar din återställningsnyckel i Inställningar > Säkerhet.\n\nAnge din återställningsnyckel här för att verifiera att du har sparat den ordentligt.",
"confirmYourRecoveryKey": "Bekräfta din återställningsnyckel",
"confirm": "Bekräfta",
"emailYourLogs": "Maila dina loggar",
"emailYourLogs": "E-posta dina loggar",
"pleaseSendTheLogsTo": "Vänligen skicka loggarna till \n{toEmail}",
"copyEmailAddress": "Kopiera e-postadress",
"exportLogs": "Exportera loggar",
@@ -297,7 +298,7 @@
"criticalUpdateAvailable": "Kritisk uppdatering tillgänglig",
"updateAvailable": "Uppdatering tillgänglig",
"update": "Uppdatera",
"checking": "Kontrollerar ...",
"checking": "Kontrollerar...",
"youAreOnTheLatestVersion": "Du är på den senaste versionen",
"warning": "Varning",
"exportWarningDesc": "Den exporterade filen innehåller känslig information. Förvara den på ett säkert sätt.",
@@ -306,7 +307,7 @@
"description": "Text for the button to confirm the user understands the warning"
},
"authToExportCodes": "Autentisera för att exportera dina koder",
"importSuccessTitle": "Jippi!",
"importSuccessTitle": "Hurra!",
"importSuccessDesc": "Du har importerat {count} koder!",
"@importSuccessDesc": {
"placeholders": {
@@ -324,7 +325,7 @@
"checkInboxAndSpamFolder": "Vänligen kontrollera din inkorg (och skräppost) för att slutföra verifieringen",
"tapToEnterCode": "Tryck för att ange kod",
"resendEmail": "Skicka e-post igen",
"weHaveSendEmailTo": "Vi har skickat ett mail till <green>{email}</green>",
"weHaveSendEmailTo": "Vi har skickat ett e-postmeddelande till <green>{email}</green>",
"@weHaveSendEmailTo": {
"description": "Text to indicate that we have sent a mail to the user",
"placeholders": {
@@ -362,7 +363,7 @@
"selectExportFormat": "Välj exportformat",
"exportDialogDesc": "Krypterad export skyddas av ett lösenord som du väljer.",
"encrypted": "Krypterad",
"plainText": "Enkel text",
"plainText": "Oformaterad text",
"passwordToEncryptExport": "Lösenord för att kryptera export",
"export": "Exportera",
"useOffline": "Använd utan säkerhetskopior",
@@ -374,14 +375,14 @@
"compactMode": "Kompakt läge",
"shouldHideCode": "Dölj koder",
"doubleTapToViewHiddenCode": "Du kan dubbeltrycka på en post för att visa koden",
"focusOnSearchBar": "Fokusera på sök vid appstart",
"focusOnSearchBar": "Fokusera på sök vid uppstart av app",
"confirmUpdatingkey": "Är du säker på att du vill uppdatera den hemliga nyckeln?",
"minimizeAppOnCopy": "Minimera appen vid kopiering",
"editCodeAuthMessage": "Autentisera för att redigera kod",
"deleteCodeAuthMessage": "Autentisera för att radera kod",
"showQRAuthMessage": "Autentisera för att visa QR-kod",
"confirmAccountDeleteTitle": "Bekräfta radering av kontot",
"confirmAccountDeleteMessage": "Detta konto är kopplat till andra Ente apps, om du använder någon.\n\nDina uppladdade data, över alla Ente appar, kommer att schemaläggas för radering och ditt konto kommer att raderas permanent.",
"confirmAccountDeleteMessage": "Detta konto är kopplat till andra Ente applikationer, om du använder någon.\n\nDina uppladdade data, över alla Ente applikationer, kommer att schemaläggas för radering och ditt konto kommer att raderas permanent.",
"androidBiometricHint": "Verifiera identitet",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
@@ -390,7 +391,7 @@
"@androidBiometricNotRecognized": {
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
},
"androidBiometricSuccess": "Slutförd",
"androidBiometricSuccess": "Lyckades",
"@androidBiometricSuccess": {
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
},
@@ -441,7 +442,7 @@
"signOutOtherDevices": "Logga ut andra enheter",
"doNotSignOut": "Logga inte ut",
"hearUsWhereTitle": "Hur hörde du talas om Ente? (valfritt)",
"hearUsExplanation": "Vi spårar inte appinstallationer, Det skulle hjälpa oss om du berättade var du hittade oss!",
"hearUsExplanation": "Vi spårar inte installationer. Det skulle hjälpa oss om du berättade hur du hittade oss!",
"recoveryKeySaved": "Återställningsnyckel sparad i nedladdningsmappen!",
"waitingForBrowserRequest": "Väntar på webbläsarbegäran...",
"waitingForVerification": "Väntar på verifiering...",
@@ -488,6 +489,8 @@
"hideContent": "Dölj innehåll",
"hideContentDescriptionAndroid": "Döljer appinnehåll i app-växlaren och inaktiverar skärmdumpar",
"hideContentDescriptioniOS": "Döljer appinnehåll i app-växlaren",
"autoLockFeatureDescription": "Tid efter vilken appen låses efter att ha satts i bakgrunden",
"appLockDescription": "Välj mellan enhetens förvalda låsskärm och en anpassad låsskärm med en PIN-kod eller lösenord.",
"pinLock": "Pinkodslås",
"enterPin": "Ange PIN-kod",
"setNewPin": "Ställ in ny PIN-kod",
@@ -498,9 +501,31 @@
"appLockOfflineModeWarning": "Du har valt att fortsätta utan säkerhetskopior. Om du glömmer ditt applås, kommer du att bli utelåst från att komma åt dina data.",
"duplicateCodes": "Dubblettkoder",
"noDuplicates": "✨ Inga dubbletter",
"youveNoDuplicateCodesThatCanBeCleared": "Du har inga dubbla koder som kan rensas",
"deduplicateCodes": "Deduplicera koder",
"deselectAll": "Avmarkera alla",
"selectAll": "Markera alla",
"deleteDuplicates": "Radera dubbletter",
"plainHTML": "Ren HTML"
"plainHTML": "Ren HTML",
"tellUsWhatYouThink": "Berätta vad du tycker",
"dropReviewiOS": "Skriv en recension på App Store",
"dropReviewAndroid": "Skriv en recension på Play Store",
"supportEnte": "Stöd <bold-green>ente</bold-green>",
"giveUsAStarOnGithub": "Ge oss en stjärna på Github",
"free5GB": "5 GB gratis på <bold-green>ente</bold-green> Foton",
"loginWithAuthAccount": "Logga in med ditt Auth-konto",
"freeStorageOffer": "10% rabatt på <bold-green>ente</bold-green> foton",
"freeStorageOfferDescription": "Använd koden \"AUTH\" för att få 10% rabatt första året",
"advanced": "Avancerad",
"algorithm": "Algoritm",
"type": "Typ",
"period": "Tidsperiod",
"digits": "Siffror",
"importFromGallery": "Importera från galleri",
"errorCouldNotReadImage": "Kunde inte läsa den valda bildfilen.",
"errorInvalidQRCode": "Ogiltig QR-kod",
"errorInvalidQRCodeBody": "Den skannade QR-koden är inte ett giltigt 2FA konto.",
"errorNoQRCode": "Ingen QR-kod hittades",
"errorGenericTitle": "Ett fel inträffade",
"errorGenericBody": "Ett oväntat fel inträffade vid import."
}

View File

@@ -6,7 +6,7 @@
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "妥善保管您的两步验证码",
"onBoardingBody": "妥善保管您的双重认证代码",
"onBoardingGetStarted": "开始",
"setupFirstAccount": "设置您的第一个账户",
"importScanQrCode": "扫描二维码",
@@ -111,13 +111,14 @@
"importAegisGuide": "使用 Aegis 设置中的“导出密码库”选项。\n\n如果您的密码库已加密则需要输入密码库密码才能解密密码库。",
"import2FasGuide": "使用 2FAS 中的“设置 -> 备份 -> 导出”选项。\n\n如果您的备份已加密则需要输入密码来解密备份",
"importLastpassGuide": "使用 Lastpass Authenticator 设置中的“转移账户”选项,然后按“将账户导出到文件”。导入下载的 JSON。",
"importProtonAuthGuide": "使用 Proton Authenticator 设置中的“导出”选项导出您的代码。",
"exportCodes": "导出代码",
"importLabel": "导入",
"importInstruction": "请选择一个包含以下格式的代码列表的文件",
"importCodeDelimiterInfo": "代码可以用逗号或换行符分隔",
"selectFile": "选择文件",
"emailVerificationToggle": "电子邮件验证",
"emailVerificationEnableWarning": "为避免被锁在您的账户之外,请在启用电子邮件验证之前确保在 Ente Auth 之外存储电子邮件两步验证的副本。",
"emailVerificationEnableWarning": "为避免被锁在您的账户之外,请在启用电子邮件验证之前确保在 Ente Auth 之外存储电子邮件双重认证的副本。",
"authToChangeEmailVerificationSetting": "请进行身份验证以更改电子邮件验证",
"authenticateGeneric": "请验证",
"authToViewYourRecoveryKey": "请验证以查看您的恢复密钥",
@@ -155,7 +156,7 @@
"verifyEmail": "验证电子邮件",
"enterCodeHint": "从你的身份验证器应用中\n输入6位数字代码",
"lostDeviceTitle": "丢失了设备吗?",
"twoFactorAuthTitle": "两步验证",
"twoFactorAuthTitle": "双重认证",
"passkeyAuthTitle": "通行密钥验证",
"verifyPasskey": "验证通行密钥",
"loginWithTOTP": "使用 TOTP 登录",
@@ -519,5 +520,12 @@
"algorithm": "算法",
"type": "类型",
"period": "周期",
"digits": "数字"
"digits": "数字",
"importFromGallery": "从图库导入",
"errorCouldNotReadImage": "无法读取所选图片文件。",
"errorInvalidQRCode": "二维码无效",
"errorInvalidQRCodeBody": "扫描的二维码不是有效的双重认证账户。",
"errorNoQRCode": "未找到二维码",
"errorGenericTitle": "出错了",
"errorGenericBody": "导入时发生意外错误。"
}

View File

@@ -39,7 +39,9 @@ import 'package:ente_auth/utils/totp_util.dart';
import 'package:ente_events/event_bus.dart';
import 'package:ente_lock_screen/lock_screen_settings.dart';
import 'package:ente_lock_screen/ui/app_lock.dart';
import 'package:ente_qr/ente_qr.dart';
import 'package:ente_ui/pages/base_home_page.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -48,7 +50,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:logging/logging.dart';
import 'package:move_to_background/move_to_background.dart';
class HomePage extends BaseHomePage {
class HomePage extends BaseHomePage {
const HomePage({super.key});
@override
@@ -62,6 +64,7 @@ class _HomePageState extends State<HomePage> {
);
bool _hasLoaded = false;
bool _isSettingsOpen = false;
bool _isImportingFromGallery = false;
final Logger _logger = Logger("HomePage");
final scaffoldKey = GlobalKey<ScaffoldState>();
@@ -288,6 +291,63 @@ class _HomePageState extends State<HomePage> {
}
}
Future<void> _importFromGalleryNative() async {
final l10n = AppLocalizations.of(context);
if (_isImportingFromGallery) {
return;
}
_isImportingFromGallery = true;
try {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.image,
);
if (result == null || result.files.single.path == null) {
return;
}
final String imagePath = result.files.single.path!;
final enteQr = EnteQr();
final QrScanResult qrResult = await enteQr.scanQrFromImage(imagePath);
if (qrResult.success && qrResult.content != null) {
try {
final newCode = Code.fromOTPAuthUrl(qrResult.content!);
await CodeStore.instance.addCode(newCode, shouldSync: false);
// Focus the new code by searching
if ((_allCodes?.where((e) => !e.hasError).length ?? 0) > 2) {
_focusNewCode(newCode);
}
} catch (e) {
_logger.severe('Error adding code from QR scan', e);
await showErrorDialog(
context,
l10n.errorInvalidQRCode,
l10n.errorInvalidQRCodeBody,
);
}
} else {
_logger.warning('QR scan failed: ${qrResult.error}');
await showErrorDialog(
context,
l10n.errorNoQRCode,
qrResult.error ?? l10n.errorNoQRCode,
);
}
} catch (e) {
await showErrorDialog(
context,
l10n.errorGenericTitle,
l10n.errorGenericBody,
);
} finally {
_isImportingFromGallery = false;
}
}
Future<void> _redirectToScannerPage() async {
final Code? code = await Navigator.of(context).push(
MaterialPageRoute(
@@ -745,6 +805,14 @@ class _HomePageState extends State<HomePage> {
labelWidget: SpeedDialLabelWidget(context.l10n.enterDetailsManually),
onTap: _redirectToManualEntryPage,
),
if (PlatformUtil.isMobile())
SpeedDialChild(
child: const Icon(Icons.image),
backgroundColor: Theme.of(context).colorScheme.fabBackgroundColor,
foregroundColor: Theme.of(context).colorScheme.fabForegroundColor,
labelWidget: SpeedDialLabelWidget(context.l10n.importFromGallery),
onTap: _importFromGalleryNative,
),
],
);
}

View File

@@ -4,6 +4,7 @@ import 'package:ente_auth/ui/settings/data/import/encrypted_ente_import.dart';
import 'package:ente_auth/ui/settings/data/import/google_auth_import.dart';
import 'package:ente_auth/ui/settings/data/import/lastpass_import.dart';
import 'package:ente_auth/ui/settings/data/import/plain_text_import.dart';
import 'package:ente_auth/ui/settings/data/import/proton_import.dart';
import 'package:ente_auth/ui/settings/data/import/raivo_plain_text_import.dart';
import 'package:ente_auth/ui/settings/data/import/two_fas_import.dart';
import 'package:ente_auth/ui/settings/data/import_page.dart';
@@ -43,6 +44,9 @@ class ImportService {
case ImportType.lastpass:
await showLastpassImportInstruction(context);
break;
case ImportType.proton:
await showProtonImportInstruction(context);
break;
}
}
}

View File

@@ -0,0 +1,171 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/services/authenticator_service.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/ui/common/progress_dialog.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
import 'package:ente_auth/ui/components/dialog_widget.dart';
import 'package:ente_auth/ui/components/models/button_type.dart';
import 'package:ente_auth/ui/settings/data/import/import_success.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
Future<void> showProtonImportInstruction(BuildContext context) async {
final l10n = context.l10n;
final result = await showDialogWidget(
context: context,
title: l10n.importFromApp("Proton Authenticator"),
body: l10n.importProtonAuthGuide,
buttons: [
ButtonWidget(
buttonType: ButtonType.primary,
labelText: l10n.importSelectJsonFile,
isInAlert: true,
buttonSize: ButtonSize.large,
buttonAction: ButtonAction.first,
),
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: context.l10n.cancel,
buttonSize: ButtonSize.large,
isInAlert: true,
buttonAction: ButtonAction.second,
),
],
);
if (result?.action != null && result!.action != ButtonAction.cancel) {
if (result.action == ButtonAction.first) {
await _pickProtonJsonFile(context);
}
}
}
Future<void> _pickProtonJsonFile(BuildContext context) async {
final l10n = context.l10n;
FilePickerResult? result = await FilePicker.platform
.pickFiles(dialogTitle: l10n.importSelectJsonFile);
if (result == null) {
return;
}
final ProgressDialog progressDialog =
createProgressDialog(context, l10n.pleaseWait);
await progressDialog.show();
try {
String path = result.files.single.path!;
int? count = await _processProtonExportFile(context, path, progressDialog);
await progressDialog.hide();
if (count != null) {
await importSuccessDialog(context, count);
}
} catch (e, s) {
Logger('ProtonImport')
.severe('exception while processing proton import', e, s);
await progressDialog.hide();
await showErrorDialog(
context,
context.l10n.sorry,
"${context.l10n.importFailureDescNew}\n Error: ${e.toString()}",
);
}
}
Future<int?> _processProtonExportFile(
BuildContext context,
String path,
final ProgressDialog dialog,
) async {
File file = File(path);
final jsonString = await file.readAsString();
final decodedJson = jsonDecode(jsonString);
// Validate that this is a Proton export
if (decodedJson['version'] == null || decodedJson['entries'] == null) {
await dialog.hide();
await showErrorDialog(
context,
'Invalid Proton export',
'The selected file is not a valid Proton Authenticator export.',
);
return null;
}
final parsedCodes = <Code>[];
final entries = decodedJson['entries'] as List;
for (var entry in entries) {
try {
final content = entry['content'];
if (content == null) {
continue; // Skip entries without content
}
final entryType = content['entry_type'] as String?;
if (entryType != 'Totp' && entryType != 'Steam') {
// log warning
Logger('ProtonImport').warning('Unsupported entry type: $entryType');
continue; // Skip non-TOTP and non-Steam entries
}
Code code;
if (entryType == 'Steam') {
// Handle Steam entries with steam:// format
final steamUri = content['uri'] as String?;
if (steamUri == null || !steamUri.startsWith('steam://')) {
continue; // Skip invalid Steam URIs
}
final secret = steamUri.split('steam://')[1];
final name = content['name'] as String? ?? '';
code = Code.fromAccountAndSecret(
Type.steam,
'', // Steam doesn't typically have separate account
name, // Use name as issuer
secret,
null,
Code.steamDigits,
);
} else {
// Handle TOTP entries with otpauth:// format
final otpUri = content['uri'] as String?;
if (otpUri == null || !otpUri.startsWith('otpauth://')) {
continue; // Skip invalid OTP URIs
}
// Create code from OTP auth URL
code = Code.fromOTPAuthUrl(otpUri);
}
// Add note if present
final note = entry['note'] as String?;
if (note != null && note.isNotEmpty) {
code = code.copyWith(
display: code.display.copyWith(note: note),
);
}
parsedCodes.add(code);
} catch (e, s) {
Logger('ProtonImport').warning('Failed to parse entry', e, s);
// Continue processing other entries
}
}
// Add all parsed codes to the store
for (final code in parsedCodes) {
await CodeStore.instance.addCode(code, shouldSync: false);
}
// Trigger sync
unawaited(AuthenticatorService.instance.onlineSync());
return parsedCodes.length;
}

View File

@@ -17,6 +17,7 @@ enum ImportType {
twoFas,
bitwarden,
lastpass,
proton,
}
class ImportCodePage extends StatelessWidget {
@@ -29,6 +30,7 @@ class ImportCodePage extends StatelessWidget {
ImportType.aegis,
ImportType.bitwarden,
ImportType.googleAuthenticator,
ImportType.proton,
ImportType.ravio,
ImportType.lastpass,
];
@@ -51,6 +53,8 @@ class ImportCodePage extends StatelessWidget {
return 'Bitwarden';
case ImportType.lastpass:
return 'LastPass Authenticator';
case ImportType.proton:
return 'Proton Authenticator';
}
}

View File

@@ -0,0 +1,33 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49"
channel: "stable"
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
- platform: android
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
- platform: ios
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View File

@@ -0,0 +1,8 @@
## 0.0.1
* Initial release of ente_qr plugin
* Support for scanning QR codes from image files
* Android implementation using ZXing library
* iOS implementation using Core Image framework
* Comprehensive error handling
* Example app demonstrating usage with file picker

View File

@@ -0,0 +1,170 @@
# ente_qr
A Flutter plugin for scanning QR codes from image files. This plugin provides a simple interface to scan QR codes from images on both Android and iOS platforms.
## Features
- Scan QR codes from image files
- Support for Android (using ZXing library)
- Support for iOS (using AVFoundation/Core Image)
- Returns structured results with error handling
- Works with images from file picker or camera
## Platform Support
| Platform | Support |
|----------|---------|
| Android | ✅ |
| iOS | ✅ |
| Web | ❌ |
| macOS | ❌ |
| Windows | ❌ |
| Linux | ❌ |
## Installation
Add this to your package's `pubspec.yaml` file:
```yaml
dependencies:
ente_qr:
path: path/to/ente_qr
```
## Usage
### Basic Usage
```dart
import 'package:ente_qr/ente_qr.dart';
final qr = EnteQr();
// Scan QR code from an image file
final result = await qr.scanQrFromImage('/path/to/image.jpg');
if (result.success) {
print('QR Code content: ${result.content}');
} else {
print('Error: ${result.error}');
}
```
### Complete Example with File Picker
```dart
import 'package:flutter/material.dart';
import 'package:ente_qr/ente_qr.dart';
import 'package:file_picker/file_picker.dart';
class QrScannerPage extends StatefulWidget {
@override
_QrScannerPageState createState() => _QrScannerPageState();
}
class _QrScannerPageState extends State<QrScannerPage> {
final _enteQr = EnteQr();
String _result = 'No QR code scanned';
Future<void> _scanQrFromImage() async {
// Pick an image file
FilePickerResult? fileResult = await FilePicker.platform.pickFiles(
type: FileType.image,
allowMultiple: false,
);
if (fileResult != null && fileResult.files.single.path != null) {
final imagePath = fileResult.files.single.path!;
// Scan QR code from the selected image
final qrResult = await _enteQr.scanQrFromImage(imagePath);
setState(() {
if (qrResult.success) {
_result = 'QR Code: ${qrResult.content}';
} else {
_result = 'Error: ${qrResult.error}';
}
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('QR Scanner')),
body: Column(
children: [
ElevatedButton(
onPressed: _scanQrFromImage,
child: Text('Pick Image and Scan QR'),
),
Text(_result),
],
),
);
}
}
```
## API Reference
### EnteQr
The main class for QR code scanning operations.
#### Methods
##### `scanQrFromImage(String imagePath)`
Scans a QR code from an image file.
**Parameters:**
- `imagePath` (String): The file path to the image containing the QR code
**Returns:**
- `Future<QrScanResult>`: A result object containing either the QR code content or an error
### QrScanResult
The result object returned by QR scanning operations.
**Properties:**
- `content` (String?): The QR code content if successful, null otherwise
- `error` (String?): Error message if scanning failed, null otherwise
- `success` (bool): Whether the scanning operation was successful
**Factory Constructors:**
- `QrScanResult.success(String content)`: Creates a successful result
- `QrScanResult.error(String error)`: Creates an error result
## Implementation Details
### Android
The Android implementation uses the ZXing library (com.google.zxing) for QR code detection:
- `com.journeyapps:zxing-android-embedded:4.3.0`
- `com.google.zxing:core:3.5.1`
### iOS
The iOS implementation uses Core Image framework's built-in QR code detection capabilities via `CIDetector`.
## Error Handling
The plugin provides comprehensive error handling for common scenarios:
- File not found
- Invalid image format
- No QR code found in image
- Platform-specific errors
- Unexpected errors
All errors are returned as part of the `QrScanResult` object with descriptive error messages.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the same license as the Ente project.

View File

@@ -0,0 +1 @@
include: ../../analysis_options.yaml

View File

@@ -0,0 +1,65 @@
group 'io.ente.auth.ente_qr'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 33
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
test.java.srcDirs += 'src/test/kotlin'
}
defaultConfig {
minSdkVersion 16
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
implementation 'com.google.zxing:core:3.5.1'
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}

View File

@@ -0,0 +1 @@
rootProject.name = 'ente_qr'

View File

@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.ente.auth.ente_qr">
</manifest>

View File

@@ -0,0 +1,138 @@
package io.ente.auth.ente_qr
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.annotation.NonNull
import com.google.zxing.BarcodeFormat
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType
import com.google.zxing.MultiFormatReader
import com.google.zxing.NotFoundException
import com.google.zxing.RGBLuminanceSource
import com.google.zxing.Result as ZXingResult
import com.google.zxing.common.HybridBinarizer
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import java.io.File
import java.util.*
/** EnteQrPlugin */
class EnteQrPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "ente_qr")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"getPlatformVersion" -> {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
}
"scanQrFromImage" -> {
val imagePath = call.argument<String>("imagePath")
if (imagePath == null) {
result.success(mapOf(
"success" to false,
"error" to "Image path is required"
))
return
}
try {
val qrResult = scanQrCode(imagePath)
result.success(qrResult)
} catch (e: Exception) {
result.success(mapOf(
"success" to false,
"error" to "Error scanning QR code: ${e.message}"
))
}
}
else -> {
result.notImplemented()
}
}
}
private fun scanQrCode(imagePath: String): Map<String, Any> {
try {
val file = File(imagePath)
if (!file.exists()) {
return mapOf(
"success" to false,
"error" to "Image file not found: $imagePath"
)
}
var bitmap = BitmapFactory.decodeFile(imagePath)
if (bitmap == null) {
return mapOf(
"success" to false,
"error" to "Unable to decode image file"
)
}
// Try multiple times with different image sizes like Aegis does
for (i in 0..2) {
if (i != 0) {
// Resize bitmap for subsequent attempts
val newWidth = bitmap.width / (i * 2)
val newHeight = bitmap.height / (i * 2)
if (newWidth > 0 && newHeight > 0) {
bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
}
}
try {
val width = bitmap.width
val height = bitmap.height
val pixels = IntArray(width * height)
bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
val source = RGBLuminanceSource(width, height, pixels)
val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
val reader = MultiFormatReader()
val hints = HashMap<DecodeHintType, Any>()
hints[DecodeHintType.POSSIBLE_FORMATS] = listOf(BarcodeFormat.QR_CODE)
hints[DecodeHintType.TRY_HARDER] = true
hints[DecodeHintType.ALSO_INVERTED] = true
reader.setHints(hints)
val qrResult: ZXingResult = reader.decode(binaryBitmap)
return mapOf(
"success" to true,
"content" to qrResult.text
)
} catch (e: NotFoundException) {
// Continue to next iteration
continue
}
}
return mapOf(
"success" to false,
"error" to "No QR code found in image"
)
} catch (e: Exception) {
return mapOf(
"success" to false,
"error" to "Error scanning QR code: ${e.message}"
)
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}

View File

@@ -0,0 +1,77 @@
import Flutter
import UIKit
import AVFoundation
public class EnteQrPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "ente_qr", binaryMessenger: registrar.messenger())
let instance = EnteQrPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion)
case "scanQrFromImage":
guard let args = call.arguments as? [String: Any],
let imagePath = args["imagePath"] as? String else {
result([
"success": false,
"error": "Image path is required"
])
return
}
scanQrCode(from: imagePath, result: result)
default:
result(FlutterMethodNotImplemented)
}
}
private func scanQrCode(from imagePath: String, result: @escaping FlutterResult) {
guard let image = UIImage(contentsOfFile: imagePath) else {
result([
"success": false,
"error": "Unable to load image from path: \(imagePath)"
])
return
}
guard let cgImage = image.cgImage else {
result([
"success": false,
"error": "Unable to get CGImage from UIImage"
])
return
}
let detector = CIDetector(ofType: CIDetectorTypeQRCode,
context: nil,
options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
guard let qrDetector = detector else {
result([
"success": false,
"error": "Unable to create QR code detector"
])
return
}
let ciImage = CIImage(cgImage: cgImage)
let features = qrDetector.features(in: ciImage)
if let qrFeature = features.first as? CIQRCodeFeature,
let messageString = qrFeature.messageString {
result([
"success": true,
"content": messageString
])
} else {
result([
"success": false,
"error": "No QR code found in image"
])
}
}
}

View File

@@ -0,0 +1,23 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint ente_qr.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'ente_qr'
s.version = '0.0.1'
s.summary = 'A QR code reader plugin for Ente.'
s.description = <<-DESC
A QR code reader plugin for Ente.
DESC
s.homepage = 'https://ente.io'
s.license = { :file => '../LICENSE' }
s.author = { 'Ente' => 'team@ente.io' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.platform = :ios, '9.0'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.0'
end

View File

@@ -0,0 +1,30 @@
import 'package:ente_qr/ente_qr_platform_interface.dart';
export 'ente_qr_platform_interface.dart' show QrScanResult;
class EnteQr {
Future<String?> getPlatformVersion() {
return EnteQrPlatform.instance.getPlatformVersion();
}
/// Scans a QR code from an image file at the given path.
///
/// [imagePath] - The file path to the image containing the QR code
///
/// Returns a [QrScanResult] containing either the QR code content on success
/// or an error message on failure.
///
/// Example:
/// ```dart
/// final qr = EnteQr();
/// final result = await qr.scanQrFromImage('/path/to/image.jpg');
/// if (result.success) {
/// print('QR Code content: ${result.content}');
/// } else {
/// print('Error: ${result.error}');
/// }
/// ```
Future<QrScanResult> scanQrFromImage(String imagePath) {
return EnteQrPlatform.instance.scanQrFromImage(imagePath);
}
}

View File

@@ -0,0 +1,52 @@
import 'package:ente_qr/ente_qr_platform_interface.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
/// An implementation of [EnteQrPlatform] that uses method channels.
class MethodChannelEnteQr extends EnteQrPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('ente_qr');
@override
Future<String?> getPlatformVersion() async {
final version =
await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
@override
Future<QrScanResult> scanQrFromImage(String imagePath) async {
try {
final dynamic result = await methodChannel.invokeMethod(
'scanQrFromImage',
{'imagePath': imagePath},
);
if (result == null) {
return QrScanResult.error('Failed to scan QR code');
}
// Convert to Map<String, dynamic> safely
final Map<String, dynamic> resultMap =
Map<String, dynamic>.from(result as Map);
final bool success = resultMap['success'] as bool? ?? false;
if (success) {
final String? content = resultMap['content'] as String?;
if (content != null && content.isNotEmpty) {
return QrScanResult.success(content);
} else {
return QrScanResult.error('No QR code found in image');
}
} else {
final String? error = resultMap['error'] as String?;
return QrScanResult.error(error ?? 'Unknown error occurred');
}
} on PlatformException catch (e) {
return QrScanResult.error('Platform error: ${e.message}');
} catch (e) {
return QrScanResult.error('Unexpected error: $e');
}
}
}

View File

@@ -0,0 +1,61 @@
import 'package:ente_qr/ente_qr_method_channel.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
/// The result of QR code scanning
class QrScanResult {
final String? content;
final String? error;
final bool success;
const QrScanResult({
this.content,
this.error,
required this.success,
});
factory QrScanResult.success(String content) {
return QrScanResult(
content: content,
success: true,
);
}
factory QrScanResult.error(String error) {
return QrScanResult(
error: error,
success: false,
);
}
}
abstract class EnteQrPlatform extends PlatformInterface {
/// Constructs a EnteQrPlatform.
EnteQrPlatform() : super(token: _token);
static final Object _token = Object();
static EnteQrPlatform _instance = MethodChannelEnteQr();
/// The default instance of [EnteQrPlatform] to use.
///
/// Defaults to [MethodChannelEnteQr].
static EnteQrPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [EnteQrPlatform] when
/// they register themselves.
static set instance(EnteQrPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
/// Scans a QR code from an image file at the given path.
/// Returns the QR code content as a string if successful, null otherwise.
Future<QrScanResult> scanQrFromImage(String imagePath) {
throw UnimplementedError('scanQrFromImage() has not been implemented.');
}
}

View File

@@ -0,0 +1,213 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
characters:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.0"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev"
source: hosted
version: "10.0.9"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "3.0.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.16.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
plugin_platform_interface:
dependency: "direct main"
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.4"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev"
source: hosted
version: "15.0.0"
sdks:
dart: ">=3.7.0-0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View File

@@ -0,0 +1,29 @@
name: ente_qr
description: "A QR code reader plugin for Ente."
version: 0.0.1
homepage: https://ente.io
environment:
sdk: '>=3.4.3 <4.0.0'
flutter: '>=3.3.0'
dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.0.2
dev_dependencies:
flutter_lints: ^3.0.0
flutter_test:
sdk: flutter
# The following section is specific to Flutter packages.
flutter:
# This section identifies this Flutter project as a plugin project.
plugin:
platforms:
android:
package: io.ente.auth.ente_qr
pluginClass: EnteQrPlugin
ios:
pluginClass: EnteQrPlugin

View File

@@ -0,0 +1,32 @@
import 'package:ente_qr/ente_qr.dart';
import 'package:ente_qr/ente_qr_method_channel.dart';
import 'package:ente_qr/ente_qr_platform_interface.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
class MockEnteQrPlatform
with MockPlatformInterfaceMixin
implements EnteQrPlatform {
@override
Future<String?> getPlatformVersion() => Future.value('42');
@override
Future<QrScanResult> scanQrFromImage(String imagePath) =>
Future.value(QrScanResult.error('Mock implementation'));
}
void main() {
final EnteQrPlatform initialPlatform = EnteQrPlatform.instance;
test('$MethodChannelEnteQr is the default instance', () {
expect(initialPlatform, isInstanceOf<MethodChannelEnteQr>());
});
test('getPlatformVersion', () async {
final EnteQr enteQrPlugin = EnteQr();
final MockEnteQrPlatform fakePlatform = MockEnteQrPlatform();
EnteQrPlatform.instance = fakePlatform;
expect(await enteQrPlugin.getPlatformVersion(), '42');
});
}

View File

@@ -451,6 +451,13 @@ packages:
relative: true
source: path
version: "1.0.0"
ente_qr:
dependency: "direct main"
description:
path: "plugins/qr"
relative: true
source: path
version: "0.0.1"
ente_strings:
dependency: "direct main"
description:
@@ -466,7 +473,7 @@ packages:
source: path
version: "1.0.0"
ente_utils:
dependency: transitive
dependency: "direct overridden"
description:
path: "../../packages/utils"
relative: true
@@ -532,10 +539,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a
sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22
url: "https://pub.dev"
source: hosted
version: "10.2.0"
version: "10.3.2"
file_saver:
dependency: "direct main"
description:
@@ -951,7 +958,7 @@ packages:
source: hosted
version: "0.1.0"
image:
dependency: transitive
dependency: "direct main"
description:
name: image
sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"

View File

@@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
version: 4.4.6+446
version: 4.4.7+447
publish_to: none
environment:
@@ -41,6 +41,8 @@ dependencies:
path: ../../packages/logging
ente_network:
path: ../../packages/network
ente_qr:
path: plugins/qr
ente_strings:
path: ../../packages/strings
ente_ui:
@@ -50,7 +52,7 @@ dependencies:
expansion_tile_card: ^3.0.0
ffi: ^2.1.0
figma_squircle: ^0.6.3
file_picker: ^10.2.0
file_picker: ^10.3.2
file_saver: ^0.3.1
fixnum: ^1.1.0
fk_user_agent: # no package updates on pub.dev
@@ -84,6 +86,7 @@ dependencies:
google_nav_bar: ^5.0.5 #supported
gradient_borders: ^1.0.0
http: ^1.1.0
image: ^4.5.4
intl: ^0.20.2
io: ^1.0.4
json_annotation: ^4.5.0

View File

@@ -0,0 +1,22 @@
# melos_managed_dependency_overrides: ente_accounts,ente_base,ente_configuration,ente_events,ente_lock_screen,ente_logging,ente_network,ente_strings,ente_ui,ente_utils
dependency_overrides:
ente_accounts:
path: ../../packages/accounts
ente_base:
path: ../../packages/base
ente_configuration:
path: ../../packages/configuration
ente_events:
path: ../../packages/events
ente_lock_screen:
path: ../../packages/lock_screen
ente_logging:
path: ../../packages/logging
ente_network:
path: ../../packages/network
ente_strings:
path: ../../packages/strings
ente_ui:
path: ../../packages/ui
ente_utils:
path: ../../packages/utils

View File

@@ -1,72 +1 @@
# For more linters, we can check https://dart-lang.github.io/linter/lints/index.html
# or https://pub.dev/packages/lint (Effective dart)
# use "flutter analyze ." or "dart analyze ." for running lint checks
include: package:flutter_lints/flutter.yaml
linter:
rules:
# Ref https://github.com/flutter/packages/blob/master/packages/flutter_lints/lib/flutter.yaml
# Ref https://dart-lang.github.io/linter/lints/
- avoid_print
- avoid_unnecessary_containers
- avoid_web_libraries_in_flutter
- no_logic_in_create_state
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_final_locals
- require_trailing_commas
- sized_box_for_whitespace
- use_full_hex_values_for_flutter_colors
- use_key_in_widget_constructors
- cancel_subscriptions
- avoid_empty_else
- exhaustive_cases
# just style suggestions
- sort_pub_dependencies
- use_rethrow_when_possible
- prefer_double_quotes
- directives_ordering
- always_use_package_imports
- sort_child_properties_last
- unawaited_futures
analyzer:
errors:
avoid_empty_else: error
exhaustive_cases: error
curly_braces_in_flow_control_structures: error
directives_ordering: error
require_trailing_commas: error
always_use_package_imports: warning
prefer_final_fields: error
unused_import: error
camel_case_types: error
prefer_is_empty: warning
use_rethrow_when_possible: info
unused_field: warning
use_key_in_widget_constructors: warning
sort_child_properties_last: warning
sort_pub_dependencies: warning
library_private_types_in_public_api: warning
constant_identifier_names: ignore
prefer_const_constructors: warning
prefer_const_declarations: warning
prefer_const_constructors_in_immutables: warning
prefer_final_locals: warning
unnecessary_const: error
cancel_subscriptions: error
unrelated_type_equality_checks: error
unnecessary_cast: info
unawaited_futures: warning # convert to warning after fixing existing issues
invalid_dependency: info
use_build_context_synchronously: ignore # experimental lint, requires many changes
prefer_interpolation_to_compose_strings: ignore # later too many warnings
prefer_double_quotes: ignore # too many warnings
avoid_renaming_method_parameters: ignore # incorrect warnings for `equals` overrides
include: ../../analysis_options.yaml

View File

@@ -7,8 +7,7 @@ import 'package:ente_events/event_bus.dart';
import 'package:ente_events/models/signed_in_event.dart';
import 'package:ente_events/models/signed_out_event.dart';
import 'package:ente_strings/l10n/strings_localizations.dart';
import 'package:ente_ui/theme/colors.dart';
import 'package:ente_ui/theme/ente_theme_data.dart';
import "package:ente_ui/theme/ente_theme_data.dart";
import 'package:ente_ui/utils/window_listener_service.dart';
import 'package:flutter/foundation.dart';
import "package:flutter/material.dart";
@@ -87,37 +86,14 @@ class _AppState extends State<App>
@override
Widget build(BuildContext context) {
final schemes = ColorSchemeBuilder.fromCustomColors(
primary700: const Color(0xFF1565C0), // Dark blue
primary500: const Color(0xFF2196F3), // Material blue
primary400: const Color(0xFF42A5F5), // Light blue
primary300: const Color(0xFF90CAF9), // Very light blue
iconButtonColor: const Color(0xFF1976D2), // Custom icon color
gradientButtonBgColors: const [
Color(0xFF1565C0),
Color(0xFF2196F3),
Color(0xFF42A5F5),
],
);
final lightTheme = createAppThemeData(
brightness: Brightness.light,
colorScheme: schemes.light,
);
final darkTheme = createAppThemeData(
brightness: Brightness.dark,
colorScheme: schemes.dark,
);
Widget buildApp() {
if (Platform.isAndroid ||
Platform.isWindows ||
Platform.isLinux ||
kDebugMode) {
return AdaptiveTheme(
light: lightTheme,
dark: darkTheme,
light: lightThemeData,
dark: darkThemeData,
initial: AdaptiveThemeMode.system,
builder: (lightTheme, dartTheme) => MaterialApp(
title: "ente",
@@ -142,8 +118,8 @@ class _AppState extends State<App>
return MaterialApp(
title: "ente",
themeMode: ThemeMode.system,
theme: lightTheme,
darkTheme: darkTheme,
theme: lightThemeData,
darkTheme: darkThemeData,
debugShowCheckedModeBanner: false,
locale: locale,
supportedLocales: appSupportedLocales,

View File

@@ -10,6 +10,7 @@ import 'package:ente_lock_screen/ui/lock_screen.dart';
import 'package:ente_logging/logging.dart';
import 'package:ente_network/network.dart';
import "package:ente_strings/l10n/strings_localizations.dart";
import "package:ente_ui/theme/ente_theme_data.dart";
import "package:ente_ui/theme/theme_config.dart";
import 'package:ente_ui/utils/window_listener_service.dart';
import 'package:ente_utils/platform_util.dart';
@@ -103,6 +104,8 @@ Future<void> _runInForeground() async {
lockScreen: LockScreen(Configuration.instance),
enabled: await LockScreenSettings.instance.shouldShowLockScreen(),
locale: locale,
lightTheme: lightThemeData,
darkTheme: darkThemeData,
savedThemeMode: savedThemeMode,
supportedLocales: appSupportedLocales,
localizationsDelegates: const [

View File

@@ -0,0 +1,22 @@
# melos_managed_dependency_overrides: ente_accounts,ente_base,ente_configuration,ente_events,ente_lock_screen,ente_logging,ente_network,ente_strings,ente_ui,ente_utils
dependency_overrides:
ente_accounts:
path: ../../packages/accounts
ente_base:
path: ../../packages/base
ente_configuration:
path: ../../packages/configuration
ente_events:
path: ../../packages/events
ente_lock_screen:
path: ../../packages/lock_screen
ente_logging:
path: ../../packages/logging
ente_network:
path: ../../packages/network
ente_strings:
path: ../../packages/strings
ente_ui:
path: ../../packages/ui
ente_utils:
path: ../../packages/utils

View File

@@ -45,4 +45,11 @@ fastlane/report.xml
android/app/build/
# FVM Version Cache
.fvm/
.fvm/
lib/generated/intl/app_localizations*.dart
# Generated rust bindings
lib/src/rust/*
rust/src/frb_generated*
test/**/*.mocks.dart

View File

@@ -48,7 +48,7 @@ You can alternatively install the build from PlayStore or F-Droid.
1. Install [Flutter v3.32.8](https://flutter.dev/docs/get-started/install) and [Rust](https://www.rust-lang.org/tools/install).
2. Install [Flutter Rust Bridge](https://cjycode.com/flutter_rust_bridge/) with `cargo install flutter_rust_bridge_codegen`
2. Install [Flutter Rust Bridge](https://cjycode.com/flutter_rust_bridge/) with `cargo install flutter_rust_bridge_codegen` and run `flutter_rust_bridge_codegen generate` to generate the Rust bindings.
3. Pull in all submodules with `git submodule update --init --recursive`

View File

@@ -73,3 +73,6 @@ analyzer:
- thirdparty/**
- lib/generated/**
- rust_builder/**
- lib/src/rust/**
- rust/src/**
- test/**

View File

@@ -135,6 +135,17 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name="${applicationId}.IconDuckyHuggingE"
android:icon="@mipmap/icon_ducky_hugging_e"
android:enabled="false"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_ducky_hugging_e_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

View File

@@ -0,0 +1,52 @@
<svg width="198" height="150" viewBox="0 0 198 150" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.2" d="M103.208 1.51891C70.0589 1.51891 17.0832 -6.28475 9.02179 30.1961C0.957739 66.6797 0.325369 122.498 30.8944 124.356C61.4634 126.213 136.678 126.856 160.318 124.356C183.957 121.855 185.312 83.2462 185.312 57.3881C185.312 31.53 174.179 -0.973365 123.125 0.817466C107.034 1.38341 103.21 1.51891 103.21 1.51891H103.208Z" fill="white"/>
<path d="M141.928 142.014C168.856 142.014 190.684 139.1 190.684 135.504C190.684 131.909 168.856 128.995 141.928 128.995C115.001 128.995 93.1719 131.909 93.1719 135.504C93.1719 139.1 115.001 142.014 141.928 142.014Z" fill="#343434"/>
<path d="M67.2538 149.392C104.397 149.392 134.508 145.779 134.508 141.321C134.508 136.864 104.397 133.251 67.2538 133.251C30.1105 133.251 0 136.864 0 141.321C0 145.779 30.1105 149.392 67.2538 149.392Z" fill="#343434"/>
<path d="M111.039 120.086C101.394 128.801 101.925 135.497 113.988 136.559C126.051 137.622 134.713 135.151 131.923 127.605C129.159 120.086 111.039 120.086 111.039 120.086Z" fill="#FF814A"/>
<path d="M118.989 137.665C117.408 137.665 115.71 137.585 113.909 137.428C108.141 136.921 104.71 135.165 103.722 132.21C102.595 128.852 104.923 124.436 110.452 119.438C110.612 119.294 110.822 119.212 111.037 119.212C111.802 119.212 129.801 119.305 132.739 127.303C133.675 129.829 133.483 131.982 132.173 133.698C130.186 136.299 125.584 137.662 118.989 137.662V137.665ZM111.369 120.963C106.642 125.299 104.514 129.088 105.375 131.657C106.113 133.86 109.118 135.258 114.063 135.691C122.635 136.445 128.733 135.335 130.789 132.643C131.727 131.416 131.828 129.869 131.105 127.908C128.778 121.574 113.803 121.011 111.372 120.963H111.369Z" fill="#1C1C1C"/>
<path d="M157.878 120.086C167.523 128.801 166.992 135.497 154.929 136.559C142.866 137.622 134.204 135.151 136.994 127.605C139.757 120.086 157.878 120.086 157.878 120.086Z" fill="#FF814A"/>
<path d="M149.927 137.665C143.332 137.665 138.73 136.302 136.743 133.701C135.433 131.984 135.241 129.832 136.177 127.303C139.115 119.305 157.114 119.215 157.879 119.215C158.094 119.215 158.304 119.295 158.464 119.441C163.993 124.436 166.321 128.852 165.194 132.213C164.203 135.168 160.775 136.921 155.007 137.431C153.205 137.591 151.508 137.668 149.927 137.668V137.665ZM157.547 120.963C155.116 121.011 140.141 121.574 137.813 127.906C137.088 129.867 137.192 131.416 138.13 132.641C140.186 135.332 146.281 136.446 154.855 135.688C159.8 135.253 162.803 133.858 163.544 131.655C164.405 129.088 162.277 125.297 157.55 120.961L157.547 120.963Z" fill="#1C1C1C"/>
<path d="M100.616 46.8054C80.2899 35.6035 65.3176 38.7095 71.7396 52.8316L100.616 46.8054Z" fill="#F4D93B"/>
<path d="M71.743 53.7029C71.4108 53.7029 71.0946 53.5142 70.9485 53.1927C68.0231 46.7628 69.6599 43.3299 71.5463 41.5842C76.3981 37.0912 87.9747 38.8422 101.039 46.0427C101.462 46.2739 101.616 46.8053 101.382 47.2277C101.148 47.6502 100.619 47.8016 100.197 47.5705C86.1015 39.8014 76.2466 39.6101 72.7314 42.8649C70.077 45.3227 71.1611 49.4463 72.5374 52.4727C72.7367 52.9111 72.5427 53.4292 72.1043 53.6285C71.9874 53.6816 71.8652 53.7082 71.743 53.7082V53.7029Z" fill="#232323"/>
<path d="M174.283 115.362C168.265 123.375 156.484 129.659 133.976 129.659C131.848 129.659 129.815 129.604 127.876 129.495C123.46 129.247 119.517 128.729 116.001 127.985C101.956 125.015 94.7002 118.444 91.084 111.161C86.2907 101.506 87.8929 90.6011 88.5518 85.1861C89.6146 76.4552 90.7253 70.2882 91.7456 64.4747C92.0059 62.9814 92.261 61.5147 92.5081 60.0321C93.1299 56.3043 93.903 52.8635 94.8117 49.6883C101.154 27.4916 114.091 18.3488 127.926 16.3932C129.93 16.1089 131.952 15.9761 133.976 15.9761C138.254 15.9761 142.59 16.5022 146.775 17.7696C160.206 21.8375 172.086 33.5469 175.444 60.0321C176.372 67.3389 178.069 74.2153 179.403 85.1861C180.161 91.4062 182.161 104.867 174.283 115.362Z" fill="#F4D93B"/>
<path d="M129.171 17.7694C129.171 17.7694 107.25 19.5257 97.8895 49.7174L95.2936 51.1947L94.8047 49.6882C101.147 27.4914 114.084 18.3486 127.919 16.3931L129.171 17.7694Z" fill="white"/>
<path d="M174.284 115.362C175.424 110.515 177.432 104.298 176.872 97.9079C174.932 75.8546 175.277 30.1539 144.047 18.8191L146.776 17.7695C160.207 21.8374 172.086 33.5469 175.445 60.0321C176.372 67.3389 178.07 74.2152 179.404 85.1861C180.161 91.4062 182.162 104.867 174.284 115.362Z" fill="white"/>
<path d="M121.074 101.628C120.253 107.898 118.297 117.926 116.001 127.986C101.956 125.015 94.7002 118.444 91.084 111.161C86.2907 101.506 87.8929 90.6013 88.5518 85.1863C89.6146 76.4553 90.7253 70.2884 91.7456 64.4748L94.368 54.9733C137.813 54.333 124.794 73.1978 121.074 101.628Z" fill="#E2B639"/>
<path d="M133.974 130.53C115.279 130.53 101.954 126.178 94.3657 117.596C84.9758 106.973 86.7453 92.6493 87.5956 85.7676L87.6806 85.0795C88.685 76.8215 89.7132 70.9734 90.707 65.3166C91.0338 63.454 91.342 61.6951 91.6449 59.8883C94.2674 44.1561 99.7674 32.343 107.996 24.7784C114.979 18.3564 123.72 15.1016 133.974 15.1016C144.227 15.1016 153.445 18.205 160.382 24.3214C168.906 31.8381 174.265 43.816 176.306 59.9228C176.707 63.0953 177.267 66.2518 177.863 69.5944C178.636 73.9492 179.513 78.8833 180.264 85.0795L180.349 85.7676C181.2 92.652 182.972 106.973 173.579 117.596C165.994 126.178 152.666 130.53 133.971 130.53H133.974ZM133.974 16.8472C124.172 16.8472 115.829 19.948 109.176 26.0644C101.242 33.3606 95.9227 44.8363 93.364 60.1779C93.0611 61.9926 92.7529 63.7542 92.4234 65.6195C91.4323 71.2523 90.4094 77.0792 89.4103 85.292L89.3253 85.9855C88.5069 92.6148 86.8011 106.41 95.6703 116.446C102.911 124.637 115.797 128.79 133.971 128.79C152.145 128.79 165.032 124.637 172.272 116.446C181.141 106.41 179.438 92.6148 178.617 85.9855L178.532 85.2947C177.785 79.1437 176.914 74.2335 176.143 69.9026C175.546 66.5388 174.982 63.361 174.573 60.146C170.035 24.3613 149.988 16.8499 133.971 16.8499L133.974 16.8472Z" fill="#1C1C1C"/>
<path d="M135.676 20.3044L126.961 19.5631C127.338 17.4136 127.864 15.5564 128.483 13.994C131.411 6.59157 136.401 5.82901 137.307 12.1208C137.307 12.1208 140.036 6.16113 147.21 7.88022C149.187 8.35583 150.143 9.60198 150.228 11.1324C150.454 15.1312 144.726 21.0776 135.676 20.3044Z" fill="#F4D93B"/>
<path d="M150.229 11.1324C147.761 9.91816 140.659 9.25922 138.754 11.2706C136.508 13.6406 137.282 12.0863 136.928 11.244C136.575 10.3991 130.108 11.0235 127.969 18.3914L128.484 13.994C131.412 6.59157 136.402 5.82901 137.308 12.1208C137.308 12.1208 140.037 6.16113 147.211 7.88022C149.188 8.35583 150.144 9.60198 150.229 11.1324Z" fill="white"/>
<path d="M126.453 19.475C126.299 15.4656 128.345 9.79818 131.853 7.54768C133.524 6.48222 135.604 6.64961 136.824 8.29697C137.621 9.36243 137.95 10.768 138.043 12.0115L136.619 11.8069C136.725 11.581 136.816 11.4216 136.922 11.2409C138.968 7.76025 142.871 6.13681 146.796 6.95251C152.516 7.97281 151.823 13.4516 148.488 16.7782C146.277 19.0287 143.31 20.4236 140.225 20.8966C138.692 21.1251 137.129 21.1011 135.623 20.8514C135.32 20.8009 135.115 20.5166 135.166 20.2137C135.211 19.9427 135.445 19.7514 135.71 19.7487C137.156 19.7434 138.58 19.6371 139.967 19.3714C142.704 18.8586 145.371 17.6523 147.308 15.641C148.873 14.0547 150.592 10.8185 148.26 9.20301C147.771 8.86557 147.075 8.67958 146.487 8.56533C145.812 8.43779 145.13 8.37136 144.457 8.38996C141.747 8.40591 139.242 10.0665 137.982 12.4286C137.663 13.0769 136.678 12.9255 136.558 12.224C136.21 10.6936 135.341 8.16146 133.375 9.0861C129.985 11.0231 128.956 16.2149 127.45 19.6478C127.253 20.1606 126.461 20.025 126.451 19.4724L126.453 19.475Z" fill="#1C1C1C"/>
<path d="M121.04 44.7142C127.356 40.8907 130.499 40.6516 136.932 44.8629C138.415 45.8407 137.939 47.3233 136.634 47.8574C133.52 49.1036 124.715 49.1912 121.216 48.0062C119.614 47.4429 119.319 45.7823 121.038 44.7142H121.04Z" fill="#FF814A"/>
<path d="M120.694 44.1455C122.944 42.8516 125.41 41.5815 128.054 41.2759C130.761 40.9624 133.434 42.0545 135.708 43.3405C136.096 43.545 136.466 43.7762 136.838 43.9994C137.263 44.2545 137.698 44.4989 138.031 44.9054C139.064 46.048 138.522 47.7644 137.22 48.4313C136.078 48.984 134.784 49.2045 133.546 49.3905C129.626 49.8581 125.622 49.9166 121.764 48.976C121.345 48.8352 120.744 48.6917 120.367 48.4286C118.541 47.2941 118.956 45.11 120.694 44.1455ZM121.39 45.2827C120.51 45.8274 120.205 46.8052 121.334 47.233C123.162 47.7963 125.115 47.8574 127.068 47.9504C129.967 48.0035 132.908 47.9902 135.738 47.3286C135.868 47.2808 136.378 47.1453 136.495 47.0736C137.446 46.5714 137.202 45.7982 136.365 45.3173C135.929 45.033 135.491 44.7248 135.044 44.4644C132.937 43.1731 130.636 42.1288 128.16 42.3706C125.67 42.6576 123.502 43.9675 121.387 45.2827H121.39Z" fill="#232323"/>
<path d="M111.373 54.4653L109.935 65.7577L100.806 137.407C100.806 142.152 83.2321 146 61.5535 146C60.5518 146 59.5607 145.992 58.5776 145.976C44.0969 145.737 31.8108 143.781 25.9601 141.036C23.6112 139.934 22.3013 138.703 22.3013 137.407L11.7344 54.4653H111.373Z" fill="#9F9DA8"/>
<path d="M109.936 65.7583L100.806 137.408C100.806 142.153 83.2326 146 61.554 146C60.5523 146 59.5612 145.992 58.5781 145.976C58.703 88.4253 69.0175 62.1793 109.936 65.7583Z" fill="#8A8899"/>
<path d="M25.9601 141.036C23.6112 139.934 22.3013 138.703 22.3013 137.407L11.7344 54.4653H12.5766L15.5126 57.4545L25.9601 141.036Z" fill="white"/>
<path d="M61.5596 146.871C51.0139 146.871 41.0899 145.97 33.6183 144.334C25.5915 142.577 21.4944 140.266 21.4359 137.468L10.8743 54.5742C10.8424 54.3244 10.9194 54.0747 11.0842 53.8887C11.2489 53.7027 11.488 53.5938 11.7378 53.5938H111.376C111.626 53.5938 111.865 53.7027 112.03 53.8887C112.194 54.0747 112.271 54.3271 112.24 54.5742L101.678 137.468C101.619 140.268 97.5223 142.577 89.4955 144.334C82.0213 145.97 72.1 146.871 61.5542 146.871H61.5596ZM12.7315 55.3368L23.1736 137.298C23.1789 137.335 23.1816 137.372 23.1816 137.407C23.1816 137.885 23.7023 140.377 33.993 142.63C41.3476 144.241 51.1387 145.125 61.5622 145.125C71.9857 145.125 81.7768 144.238 89.1314 142.63C99.4221 140.377 99.9429 137.885 99.9429 137.407C99.9429 137.37 99.9429 137.332 99.9508 137.298L110.393 55.3368H12.7342H12.7315Z" fill="#1C1C1C"/>
<path d="M111.373 54.4654C111.373 57.6273 101.868 60.3986 87.6135 61.9396C80.0331 62.7606 71.1081 63.2336 61.5535 63.2336C47.0169 63.2336 33.9364 62.1389 24.8282 60.3906C16.6977 58.8283 11.7344 56.7505 11.7344 54.4654C11.7344 51.2451 21.5919 48.4313 36.2826 46.9062C43.6903 46.1383 52.3283 45.6973 61.5535 45.6973C69.3014 45.6973 76.6374 46.0081 83.1763 46.5634C99.8597 47.9796 111.373 50.9847 111.373 54.4654Z" fill="#232323"/>
<path d="M61.5578 64.1055C47.5792 64.1055 34.1321 63.064 24.6677 61.2466C15.509 59.4876 10.8672 57.2052 10.8672 54.4658C10.8672 52.4306 13.2824 50.7141 18.2511 49.2156C22.5979 47.9057 28.8021 46.8057 36.1966 46.0404C43.8567 45.246 52.6249 44.8262 61.5578 44.8262C69.1622 44.8262 76.461 45.1184 83.255 45.695C91.6273 46.4071 98.7215 47.5151 103.767 48.8994C109.475 50.467 112.251 52.2871 112.251 54.4658C112.251 56.4692 109.913 58.1618 105.101 59.6444C100.903 60.9383 94.8901 62.0304 87.7135 62.8062C79.8673 63.6565 70.8228 64.1055 61.5605 64.1055H61.5578ZM61.5578 46.5692C52.686 46.5692 43.979 46.9863 36.3772 47.7728C17.5788 49.7257 12.6102 53.0045 12.6102 54.4658C12.6102 55.7067 15.8544 57.7791 24.9972 59.5354C34.3579 61.3316 47.6829 62.3625 61.5578 62.3625C70.7591 62.3625 79.7371 61.9161 87.5249 61.0738C105.704 59.1077 110.505 55.8927 110.505 54.4658C110.505 52.574 103.209 49.1385 83.1062 47.4327C76.3627 46.8588 69.1117 46.5692 61.5578 46.5692Z" fill="#232323"/>
<path d="M65.278 73.9174C50.4545 73.9174 32.1025 71.7679 12.7567 64.3973C12.483 64.2937 12.3449 63.9855 12.4485 63.7118C12.5521 63.4381 12.8603 63.3 13.134 63.4036C39.8503 73.5826 64.6696 73.7288 80.7844 72.0575C98.257 70.2454 109.555 65.9676 109.666 65.9251C109.94 65.8188 110.248 65.957 110.352 66.2306C110.458 66.5043 110.32 66.8125 110.046 66.9162C109.932 66.9587 98.5333 71.279 80.9305 73.1097C76.3578 73.5853 71.0836 73.9147 65.2727 73.9147L65.278 73.9174Z" fill="#1C1C1C"/>
<path d="M59.9036 138.648C48.4173 138.648 34.9515 137.13 21.3981 132.231C21.1217 132.13 20.9782 131.827 21.0792 131.551C21.1802 131.274 21.4831 131.131 21.7594 131.232C42.2317 138.632 62.5234 138.241 75.9413 136.61C90.4965 134.84 100.33 131.269 100.428 131.232C100.705 131.131 101.01 131.272 101.111 131.548C101.212 131.824 101.071 132.13 100.795 132.231C100.697 132.268 90.7702 135.874 76.1008 137.662C71.4351 138.23 65.943 138.65 59.9036 138.65V138.648Z" fill="#1C1C1C"/>
<path d="M28.3625 125.363C27.1482 125.363 26.1093 124.443 25.9844 123.208L21.34 76.6222C21.2098 75.3069 22.1689 74.1352 23.4815 74.005C24.7941 73.8748 25.9658 74.834 26.0987 76.1466L30.7432 122.732C30.8733 124.047 29.9142 125.219 28.6016 125.349C28.5219 125.357 28.4422 125.363 28.3625 125.363Z" fill="#232323"/>
<path d="M43.4128 127.828C42.1215 127.828 41.056 126.797 41.0242 125.498L39.8524 80.3419C39.8179 79.0214 40.8594 77.924 42.1799 77.8895C43.4952 77.855 44.5978 78.8965 44.6324 80.2171L45.8041 125.373C45.8387 126.694 44.7971 127.791 43.4766 127.826C43.4553 127.826 43.4341 127.826 43.4128 127.826V127.828Z" fill="#232323"/>
<path d="M60.6807 128.995C60.6807 128.995 60.6568 128.995 60.6435 128.995C59.323 128.976 58.2681 127.89 58.2894 126.569L58.9643 81.4077C58.9829 80.0872 60.0749 79.0297 61.3901 79.0536C62.7107 79.0722 63.7655 80.1589 63.7442 81.4795L63.0694 126.641C63.0508 127.948 61.9826 128.998 60.678 128.998L60.6807 128.995Z" fill="#232323"/>
<path d="M93.2992 125.362C93.2195 125.362 93.1398 125.36 93.0601 125.349C91.7449 125.219 90.7857 124.047 90.9185 122.732L95.563 76.1465C95.6932 74.8313 96.8676 73.8721 98.1802 74.005C99.4954 74.1352 100.455 75.3069 100.322 76.6221L95.6773 123.208C95.5551 124.441 94.5135 125.362 93.2992 125.362Z" fill="#232323"/>
<path d="M78.2515 127.828C78.2303 127.828 78.209 127.828 78.1877 127.828C76.8672 127.794 75.8257 126.696 75.8602 125.376L77.0319 80.2199C77.0665 78.9206 78.1293 77.8896 79.4206 77.8896C79.4419 77.8896 79.4631 77.8896 79.4844 77.8896C80.8049 77.9242 81.8465 79.0215 81.8119 80.3421L80.6402 125.498C80.6056 126.797 79.5428 127.828 78.2515 127.828Z" fill="#232323"/>
<path d="M92.3543 60.3824L87.6115 61.9394C80.031 62.7605 71.1061 63.2334 61.5514 63.2334C49.0342 63.2334 37.5984 62.423 28.8462 61.0786C27.4353 60.8633 26.0908 60.6322 24.8261 60.3904L24.7969 60.3824C24.7969 60.3824 24.7995 60.3718 24.7995 60.3665C25.7587 55.1507 30.815 50.5116 36.2805 46.906C40.9622 43.8186 45.9414 41.4963 48.8987 40.2316C50.5381 39.5301 51.5584 39.1528 51.5584 39.1528L74.5708 41.313C78.0409 42.7265 80.8733 44.5731 83.1743 46.5633C90.3801 52.7833 92.3543 60.3824 92.3543 60.3824Z" fill="#20D34F"/>
<path d="M50.7588 41.2815C50.7588 41.2815 31.785 53.0202 28.8411 61.0789C28.6816 61.52 28.5674 61.9478 28.5089 62.3623L24.6562 61.2463L24.821 60.3907L24.7944 60.3668C25.7536 55.1511 30.8099 50.5119 36.2754 46.9064C40.9571 43.8189 45.9363 41.4967 48.8936 40.2319L50.7588 41.2815Z" fill="white"/>
<path d="M61.5571 64.1048C47.5785 64.1048 34.1313 63.0633 24.667 61.2459C24.6457 61.2406 24.6245 61.2379 24.6032 61.2326L24.574 61.2246C24.1356 61.1077 23.8619 60.672 23.9443 60.2256C24.7999 55.5306 28.7907 50.8038 35.8052 46.1779C43.0828 41.3794 51.1814 38.3636 51.2611 38.3344C51.3833 38.2892 51.5135 38.2733 51.6437 38.2839L74.6562 40.4441C74.7412 40.4521 74.8236 40.4733 74.9033 40.5052C78.1687 41.8364 81.1446 43.6511 83.7485 45.9043C91.0765 52.228 93.1198 59.843 93.2022 60.1645C93.3191 60.6109 93.0667 61.0679 92.6309 61.2113L87.8881 62.7684C87.8297 62.787 87.7712 62.8002 87.7101 62.8056C79.8639 63.6558 70.8194 64.1048 61.5571 64.1048ZM25.8547 59.6942C35.1622 61.392 48.1019 62.3618 61.5597 62.3618C70.7264 62.3618 79.67 61.9208 87.4338 61.0838L91.2705 59.8244C90.5584 57.7705 88.191 52.0393 82.6113 47.2248C80.1828 45.1231 77.4088 43.4253 74.3665 42.1711L51.6836 40.0429C50.456 40.5132 43.2715 43.3482 36.7671 47.6366C30.6054 51.7019 26.9388 55.7538 25.8547 59.6968V59.6942Z" fill="#232323"/>
<path d="M73.0661 37.8245L52.6549 36.9291C52.2006 36.201 51.8684 35.5527 51.6399 34.9762C49.8704 30.4938 54.2491 30.2865 54.2491 30.2865C55.676 24.7387 60.1185 25.8094 63.469 27.5764C65.7354 28.772 67.5023 30.2865 67.5023 30.2865C79.2251 24.4411 73.0661 37.8245 73.0661 37.8245Z" fill="#20D34F"/>
<path d="M65.7886 29.5904C65.5229 29.5319 56.7547 27.5631 55.5272 31.9764C55.5272 31.9764 53.0535 32.545 53.9834 36.6209L51.6399 34.9762C49.8704 30.4938 54.2491 30.2865 54.2491 30.2865C55.676 24.7387 60.1185 25.8094 63.469 27.5764L65.7886 29.5904Z" fill="white"/>
<path d="M73.0599 38.696C73.0599 38.696 73.0334 38.696 73.0227 38.696L52.6115 37.8006C52.3245 37.7873 52.0615 37.6358 51.91 37.3914C50.353 34.8991 49.9545 32.8877 50.725 31.4158C51.3972 30.1298 52.755 29.6701 53.5601 29.5054C54.227 27.3904 55.4093 26.0539 57.0833 25.5251C60.9253 24.3135 66.0746 28.0413 67.6183 29.2583C70.9768 27.672 73.2459 27.5152 74.5479 28.7747C75.6479 29.8428 75.8418 31.7957 75.1218 34.5829C74.6302 36.4907 73.8836 38.1194 73.8517 38.1885C73.7082 38.4994 73.4 38.696 73.0599 38.696ZM53.1535 36.0788L72.5019 36.9264C73.5249 34.4899 74.3751 31.0358 73.3336 30.0261C72.6082 29.322 70.6234 29.702 67.8867 31.065C67.5732 31.2218 67.1959 31.174 66.9302 30.9481C65.336 29.5851 60.5533 26.2558 57.604 27.1884C56.3845 27.5737 55.5608 28.6578 55.0852 30.5044C54.9895 30.8737 54.6654 31.1394 54.2828 31.158C54.2721 31.158 52.7683 31.2563 52.2634 32.2315C51.8489 33.0312 52.1651 34.389 53.1509 36.0788H53.1535Z" fill="#232323"/>
<path d="M74.6803 37.9618L51.0823 36.4317C49.9841 36.3605 49.036 37.1931 48.9648 38.2913C48.8936 39.3896 49.7262 40.3376 50.8244 40.4089L74.4224 41.939C75.5206 42.0102 76.4687 41.1776 76.5399 40.0794C76.6111 38.9811 75.7785 38.033 74.6803 37.9618Z" fill="#9F9DA8"/>
<path d="M74.5503 42.8173C74.4866 42.8173 74.4254 42.8173 74.3617 42.812L50.7647 41.2816C50.0021 41.2311 49.3033 40.8883 48.7985 40.3144C48.2937 39.7405 48.0439 39.0019 48.0917 38.2393C48.1422 37.4767 48.485 36.7779 49.0589 36.2731C49.6355 35.7683 50.3715 35.5185 51.134 35.5663L74.731 37.0968C75.4936 37.1473 76.1924 37.49 76.6972 38.0639C77.202 38.6378 77.4518 39.3765 77.404 40.1391C77.3535 40.9016 77.0107 41.6004 76.4368 42.1053C75.9107 42.5676 75.2465 42.8173 74.5503 42.8173ZM74.4733 41.0717C74.7735 41.0903 75.0605 40.992 75.2863 40.7953C75.5122 40.5987 75.645 40.3251 75.6663 40.0248C75.6849 39.7246 75.5866 39.4376 75.3899 39.2118C75.1933 38.9859 74.9197 38.8531 74.6194 38.8318L51.0224 37.3014C50.7222 37.2828 50.4352 37.3811 50.2094 37.5777C49.9835 37.7743 49.8507 38.048 49.8294 38.3482C49.8108 38.6485 49.9091 38.9354 50.1057 39.1613C50.3024 39.3871 50.576 39.52 50.8763 39.5412L74.4733 41.0717Z" fill="#232323"/>
<path d="M111.235 40.3833C111.062 40.3833 110.889 40.3541 110.719 40.2877C109.964 40.0034 109.582 39.1584 109.869 38.4038C111.349 34.4874 114.266 33.3449 116.506 33.5813C119.158 33.863 121.299 35.9673 121.714 38.7014C121.836 39.4985 121.286 40.2452 120.489 40.3647C119.692 40.4843 118.945 39.9369 118.826 39.1398C118.61 37.7183 117.532 36.6289 116.201 36.4881C114.705 36.3287 113.36 37.4314 112.606 39.4374C112.385 40.022 111.83 40.3833 111.237 40.3833H111.235Z" fill="#1C1C1C"/>
<path d="M147.634 40.3833C147.044 40.3833 146.489 40.022 146.266 39.4374C145.509 37.434 144.164 36.3314 142.671 36.4881C141.34 36.6289 140.261 37.7183 140.046 39.1398C139.924 39.9369 139.18 40.4869 138.383 40.3647C137.585 40.2425 137.035 39.4985 137.158 38.7014C137.572 35.9673 139.714 33.863 142.365 33.5813C144.603 33.3449 147.523 34.4874 149.003 38.4038C149.287 39.1584 148.907 40.0034 148.152 40.2877C147.982 40.3514 147.807 40.3833 147.637 40.3833H147.634Z" fill="#1C1C1C"/>
<path d="M193.199 114.384C187.58 108.953 173.386 102.09 156.054 96.898C138.723 91.7061 123.094 89.6337 115.415 91.0791L111.839 90.0083L110.51 93.9938C108.879 99.4381 126.625 109.561 150.148 116.61C173.67 123.657 194.06 124.959 195.692 119.515L197.02 115.529L193.197 114.384H193.199Z" fill="#B7B6BF"/>
<path d="M184.999 123.75C183.675 123.75 182.344 123.699 181.072 123.617C172.404 123.064 161.333 120.872 149.897 117.445C138.458 114.017 128.006 109.761 120.462 105.456C114.891 102.278 108.498 97.6658 109.672 93.7414C109.672 93.7334 109.677 93.7255 109.68 93.7148L111.009 89.7293C111.157 89.2829 111.633 89.0332 112.085 89.1687L115.459 90.181C123.571 88.7462 139.55 91.0419 156.3 96.061C173.047 101.077 187.658 107.948 193.645 113.605L197.266 114.689C197.492 114.756 197.681 114.913 197.79 115.122C197.898 115.332 197.917 115.577 197.843 115.8L196.517 119.775C195.563 122.908 190.326 123.744 184.993 123.744L184.999 123.75ZM111.341 94.2569C110.605 96.7784 116.014 100.913 121.328 103.944C128.76 108.185 139.083 112.386 150.399 115.776C161.715 119.166 172.646 121.332 181.186 121.877C187.3 122.267 194.102 121.786 194.859 119.265C194.859 119.257 194.864 119.249 194.867 119.238L195.911 116.106L192.951 115.218C192.818 115.178 192.696 115.106 192.595 115.011C186.893 109.503 172.455 102.722 155.806 97.7323C139.157 92.745 123.369 90.468 115.579 91.9346C115.443 91.9612 115.302 91.9532 115.167 91.9134L112.401 91.0844L111.343 94.2542L111.341 94.2569Z" fill="#232323"/>
<path d="M197.02 115.529C195.981 119.004 187.295 119.73 175.033 117.968C168.085 116.972 159.984 115.173 151.476 112.625C127.956 105.578 110.207 95.4524 111.838 90.0082C113.47 84.5639 133.86 85.8659 157.382 92.9123C164.179 94.9502 170.492 97.2432 175.997 99.6053C189.543 105.422 198.181 111.66 197.02 115.529Z" fill="#9F9DA8"/>
<path d="M197.017 115.529C195.979 119.004 187.293 119.73 175.031 117.968C175.326 117.979 175.636 117.995 175.961 118.011C200.565 119.249 197.589 109.599 173.492 99.4966L175.995 99.6055C189.541 105.422 198.179 111.66 197.017 115.529Z" fill="white"/>
<path d="M186.335 119.764C185.011 119.764 183.68 119.714 182.408 119.631C173.74 119.078 162.668 116.886 151.233 113.459C139.794 110.031 129.342 105.775 121.798 101.47C116.226 98.2926 109.834 93.68 111.008 89.7556C112.182 85.8338 120.063 85.4964 126.461 85.9029C135.128 86.4556 146.2 88.6476 157.636 92.0752C178.688 98.383 199.939 108.833 197.858 115.776C196.917 118.919 191.67 119.761 186.332 119.761L186.335 119.764ZM122.696 87.5264C117.783 87.5264 113.282 88.2358 112.677 90.2578C111.922 92.7793 117.34 96.9216 122.659 99.9559C130.091 104.197 140.413 108.397 151.73 111.788C163.043 115.178 173.977 117.343 182.516 117.888C188.63 118.279 195.432 117.798 196.189 115.276C196.944 112.755 191.526 108.612 186.207 105.578C178.775 101.338 168.453 97.1368 157.137 93.7465C145.82 90.3561 134.887 88.1906 126.35 87.6459C125.141 87.5689 123.905 87.5264 122.696 87.5264Z" fill="#232323"/>
<path d="M164.6 106.976C164.412 106.976 164.22 106.949 164.029 106.894C162.974 106.58 162.374 105.469 162.69 104.415C163.928 100.264 161.157 98.4788 154.99 95.6544C154.06 95.2293 153.098 94.7882 152.203 94.3339C149.086 92.7503 146.803 92.2773 145.228 92.8964C143.897 93.4172 142.791 94.8467 141.941 97.1423C141.558 98.1732 140.413 98.702 139.38 98.3194C138.349 97.9368 137.82 96.7916 138.203 95.758C139.465 92.3491 141.341 90.1358 143.777 89.1846C147.369 87.779 151.339 89.4237 154.009 90.7814C154.833 91.1986 155.715 91.6051 156.65 92.0329C161.808 94.395 168.87 97.6312 166.508 105.554C166.25 106.418 165.458 106.979 164.6 106.979V106.976Z" fill="#232323"/>
<path d="M153.389 70.5537C139.259 91.3847 144.509 114.857 171.688 90.1492L153.389 70.5537Z" fill="#F4D93B"/>
<path d="M152.855 101.628C150.517 101.628 148.944 100.804 147.929 99.922C145.285 97.629 144.331 93.2529 145.243 87.6014C146.144 82.0243 148.779 75.7962 152.667 70.0624C152.938 69.6638 153.48 69.5602 153.878 69.8312C154.277 70.1022 154.38 70.6443 154.109 71.0428C150.36 76.5694 147.823 82.5477 146.962 87.8804C146.162 92.841 146.93 96.7495 149.069 98.6067C150.918 100.212 156.766 102.534 171.098 89.5065C171.454 89.1823 172.007 89.2089 172.328 89.5649C172.653 89.921 172.626 90.4736 172.27 90.7978C162.957 99.263 156.811 101.63 152.852 101.63L152.855 101.628Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -1,3 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
=description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

View File

@@ -1,36 +1,36 @@
ente is a simple app to backup and share your photos and videos.
ente je jednoduchá aplikace pro automatické zálohování a organizaci vašich fotek a videí.
If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
Pokud hledáte alternativu ke službě Google Photos, která respektuje vaše soukromí, jste na správném místě. S Ente jsou uloženy s koncovým "end-to-end" šifrováním (e2ee). To znamená, že je můžete vidět pouze vy.
We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner.
Máme aplikace napříč všemi platformami a vaše fotky se budou bezproblémově synchronizovat mezi všemi vašimi zařízeními tak, aby byly koncově šifrovány mezi jednotlivými zařízeními (e2ee).
ente also makes it simple to share your albums with your loved ones, even if they aren't on ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app.
ente také usnadňuje sdílení vašich alb s vašimi blízkými, i když nejsou na ente. Můžete sdílet veřejně přístupné odkazy, kde si mohou prohlížet vaše album a spolupracovat přidáváním fotografií, a to i bez účtu nebo aplikace.
Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
Vaše šifrovaná data jsou uložena na 3 místech, včetně protiatomového krytu v Paříži. Bereme budoucnost vážně a usnadňujeme vám zajistit, aby vaše vzpomínky přežily vás samotné.
We are here to make the safest photos app ever, come join our journey!
Jsme tu, abychom vytvořili nejbezpečnější aplikaci pro fotografie, jaká kdy byla. Přidejte se k nám!
FEATURES
- Original quality backups, because every pixel is important
- Family plans, so you can share storage with your family
- Collaborative albums, so you can pool together photos after a trip
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
- Album links, that can be protected with a password
- Ability to free up space, by removing files that have been safely backed up
- Human support, because you're worth it
- Descriptions, so you can caption your memories and find them easily
- Image editor, to add finishing touches
- Favorite, hide and relive your memories, for they are precious
- One-click import from Google, Apple, your hard drive and more
- Dark theme, because your photos look good in it
- 2FA, 3FA, biometric auth
- and a LOT more!
VLASTNOSTI
- Zálohování v původní kvalitě, protože každý pixel je důležitý
- Rodinné plány, takže můžete sdílet úložiště s rodinou
- Společná alba, do kterých můžete po cestě shromažďovat fotografie
- Sdílené složky, aby i váš partner mohl obdivovat vaše fotografie
- Odkazy na alba, které lze chránit heslem a nastavit jejich platnost
- Možnost uvolnit místo odstraněním souborů, které byly bezpečně zálohovány
- Lidská podpora, protože si to zasloužíte
- Popisy, abyste mohli své vzpomínky opatřit popisky a snadno je najít
- Editor obrázků pro doladění detailů
- Označte si své oblíbené fotografie, skryjte je a nebo je prožijte znovu pomocí vzpomínek
- Import jedním kliknutím z Google, Apple, pevného disku a dalších zdrojů
- Tmavý motiv, protože vaše fotografie v něm vypadají dobře
- 2FA, 3FA, biometrické ověření
- a ještě MNOHEM víc!
OPRÁVNĚNÍ
ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
ente žádá o určitá oprávnění, aby mohla plnit funkci poskytovatele úložiště fotografií. Tyto oprávnění si můžete prohlédnout zde: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
PRICING
We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
CENY
Nenabízíme doživotní tarify, protože je pro nás důležité zůstat udržitelnými a obstát ve zkoušce času. Místo toho nabízíme cenově dostupné plány, které můžete svobodně sdílet se svou rodinou. Více informací najdete na ente.io.
PODPORA
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
Jsme hrdí na to, že poskytujeme lidskou podporu. Pokud máte placený tarif, můžete se obrátit na team@ente.io a do 24 hodin od našeho týmu očekávat odpověď.

View File

@@ -1 +1 @@
ente is an end-to-end encrypted photo storage app
ente je aplikace pro ukládání fotografií a videí s koncovým šifrováním

View File

@@ -1 +1 @@
ente - encrypted photo storage
ente šifrované úložiště fotografií

View File

@@ -1,4 +1,4 @@
ente es una aplicación simple para hacer copias de seguridad y compartir tus fotos y videos.
ente es una aplicación simple para hacer copias de seguridad y compartir tus fotos y vídeos.
Si has estado buscando una alternativa a Google Photos que sea amigable con la privacidad, has llegado al lugar correcto. Con Ente, se almacenan cifradas de extremo a extremo (e2ee). Esto significa que solo tú puedes verlas.

View File

@@ -6,23 +6,23 @@ Kami menyediakan app untuk Android, iOS, web, serta desktop, dan fotomu akan ter
ente juga dapat memudahkan kamu untuk membagikan album ke orang tersayang, meski mereka tidak punya akun ente. Kamu dapat membagikan link berbagi publik, di mana mereka bisa melihat album kamu dan berkolaborasi dengan menambahkan foto, tanpa akun atau app.
Data terenkripsi kamu tersimpan di 3 lokasi berbeda, termasuk di salah satu tempat pengungsian di Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
Data terenkripsi kamu tersimpan di 3 lokasi berbeda, termasuk di salah satu tempat pengungsian di Paris. Kami menanggapi keturunan anda dengan serius dan memudahkan untuk memastikan kenangan anda tetap ada setelah anda.
Kami ingin membuat app foto yang paling aman sepanjang masajadi, bergabunglah dengan kami!
FITUR
- Pencadangan kualitas asli, karena setiap piksel berarti
- Paket keluarga, sehingga kamu bisa bagikan kuota penyimpananmu dengan keluarga
- Collaborative albums, so you can pool together photos after a trip
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
- Album kolaboratif, sehingga anda dapat mengumpulkan foto bersama setelah sebuah perjalanan
- Folder bersama, jika anda ingin pasangan anda menikmati hasil jepretan "Kamera" anda
- Link album, yang bisa dilindungi dengan sandi
Kemampuan untuk membebaskan kapasitas, dengan menghilangkan files yang sudah di back-up dengan aman
- Human support, because you're worth it
- Descriptions, so you can caption your memories and find them easily
- Dukungan manusia, karena anda layak mendapatkannya
- Deskripsi, sehingga anda dapat memberi keterangan pada memori anda dan menemukannya dengan mudah
- Editor gambar, untuk menyempurnakan fotomu
- Favorite, hide and relive your memories, for they are precious
- Favoritkan, sembunyikan, dan kenang kembali memori anda, karena itu sangat berharga
- Pengimporan mudah dari Google, Apple, hard drive-mu, dan lainnya
- Dark theme, because your photos look good in it
- Tema gelap, karena foto anda terlihat bagus di dalamnya
- Autentikasi dua atau tiga faktor dan autentikasi biometrik
- dan BANYAK LAGI!

View File

@@ -1,33 +1,33 @@
Ente is a simple app to automatically backup and organize your photos and videos.
Ente je jednoduchá aplikace pro automatické zálohování a organizaci vašich fotek a videí.
If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
Pokud hledáte alternativu, která respektuje vaše soukromí a umožní vám uchovat vaše vzpomínky, jste na správném místě. S Ente jsou uloženy s koncovým "end-to-end" šifrováním (e2ee). To znamená, že je můžete vidět pouze vy.
We have apps across all platforms, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner.
Máme aplikace napříč všemi platformami a vaše fotky se budou bezproblémově synchronizovat mezi všemi vašimi zařízeními tak, aby byly koncově šifrovány mezi jednotlivými zařízeními (e2ee).
Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links.
Ente také zjednodušuje sdílení alb s vašimi blízkými. Můžete je buď sdílet přímo s ostatními uživateli Ente, koncově šifrované; nebo s pomocí veřejně přístupných odkazů.
Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
Vaše šifrovaná data jsou uložena na několika místech, včetně protiatomového krytu v Paříži. Bereme budoucnost vážně a usnadňujeme vám zajistit, aby vaše vzpomínky přežily vás samotné.
We are here to make the safest photos app ever, come join our journey!
Jsme tu, abychom vytvořili nejbezpečnější aplikaci pro fotografie, jaká kdy byla. Přidejte se k nám!
FEATURES
- Original quality backups, because every pixel is important
- Family plans, so you can share storage with your family
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
- Album links, that can be protected with a password and set to expire
- Ability to free up space, by removing files that have been safely backed up
- Image editor, to add finishing touches
- Favorite, hide and relive your memories, for they are precious
- One-click import from all major storage providers
- Dark theme, because your photos look good in it
- 2FA, 3FA, biometric auth
- and a LOT more!
VLASTNOSTI
- Zálohování v původní kvalitě, protože každý pixel je důležitý
- Rodinné plány, takže můžete sdílet úložiště s rodinou
- Sdílené složky, aby i váš partner mohl obdivovat vaše fotografie
- Odkazy na alba, které lze chránit heslem a nastavit jejich platnost
- Možnost uvolnit místo odstraněním souborů, které byly bezpečně zálohovány
- Editor obrázků, pro finální doladění detailů
- Označte si své oblíbené fotografie, skryjte je a nebo je prožijte znovu pomocí vzpomínek
- Import jedním kliknutím ze všech velkých poskytovatelů úložišť
- Tmavý motiv, protože vaše fotografie v něm vypadají dobře
- 2FA, 3FA, biometrické ověření
- a ještě MNOHEM víc!
PRICING
We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
CENY
Nenabízíme doživotní tarify, protože je pro nás důležité zůstat udržitelnými a obstát ve zkoušce času. Místo toho nabízíme cenově dostupné plány, které můžete svobodně sdílet se svou rodinou. Více informací najdete na ente.io.
SUPPORT
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
PODPORA
Jsme hrdí na to, že poskytujeme lidskou podporu. Pokud máte placený tarif, můžete se obrátit na team@ente.io a do 24 hodin od našeho týmu očekávat odpověď.
TERMS
PODMÍNKY
https://ente.io/terms

View File

@@ -1 +1 @@
photos,photography,family,privacy,cloud,backup,videos,photo,encryption,storage,album,alternative
fotky,fotografie,rodina,soukromí,cloud,zálohování,videa,fotka,šifrování,úložiště,album,alternativa

View File

@@ -1 +1 @@
Ente Photos
Ente Fotky

View File

@@ -1 +1 @@
Encrypted photo storage
Šifrované úložiště fotografií

View File

@@ -6,20 +6,20 @@ Kami menyediakan app untuk semua platform, dan fotomu akan tersinkron di semua p
Ente juga memudahkan kamu untuk membagikan album ke kerabatmu. Kamu bisa membagikannya secara langsung ke pengguna Ente lain, terenkripsi ujung ke ujung; atau dengan link yang dapat dilihat publik.
Data terenkripsi kamu tersimpan di berbagai lokasi, termasuk di salah satu tempat pengungsian di Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
Data terenkripsi kamu tersimpan di berbagai lokasi, termasuk di salah satu tempat pengungsian di Paris. Kami menanggapi keturunan anda dengan serius dan memudahkan untuk memastikan kenangan anda tetap ada setelah anda.
Kami ingin membuat app foto yang paling aman sepanjang masajadi, bergabunglah dengan kami!
FITUR
- Pencadangan kualitas asli, karena setiap piksel berarti
- Paket keluarga, sehingga kamu bisa bagikan kuota penyimpananmu dengan keluarga
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
- Folder bersama, jika anda ingin pasangan anda menikmati hasil jepretan "Kamera" anda
- Link album, yang bisa dilindungi dengan sandi dan diatur waktu kedaluwarsanya
- Ability to free up space, by removing files that have been safely backed up
- Kemampuan untuk mengosongkan ruang, dengan menghapus file yang telah dicadangkan dengan aman
- Editor gambar, untuk menyempurnakan fotomu
- Favorite, hide and relive your memories, for they are precious
- One-click import from all major storage providers
- Dark theme, because your photos look good in it
Favoritkan, sembunyikan, dan kenang kembali memori anda, karena itu sangat berharga
Impor sekali klik dari semua penyedia penyimpanan utama
Tema gelap, karena foto anda terlihat bagus di dalamnya
- Autentikasi dua atau tiga faktor dan autentikasi biometrik
- dan BANYAK LAGI!
@@ -27,7 +27,7 @@ HARGA
Kami tidak menyediakan paket yang gratis seumur hidup, karena penting bagi kami untuk tetap berdiri dan bertahan hingga masa depan. Namun, kami menyediakan paket yang terjangkau, yang bisa kamu bagikan dengan keluargamu. Kamu bisa menemukan informasi lebih lanjut di ente.io.
DUKUNGAN
We take pride in offering human support. Jika kamu adalah pelanggan berbayar, kamu bisa menghubungi team@ente.io dan menunggu balasan dari tim kami dalam 24 jam.
Kami bangga dapat menawarkan dukungan manusia. Jika kamu adalah pelanggan berbayar, kamu bisa menghubungi team@ente.io dan menunggu balasan dari tim kami dalam 24 jam.
KETENTUAN
https://ente.io/terms

View File

@@ -1,30 +1,30 @@
Ente is a simple app to automatically backup and organize your photos and videos.
Ente je jednoduchá aplikace pro automatické zálohování a organizaci vašich fotek a videí.
If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
Pokud hledáte alternativu, která respektuje vaše soukromí a umožní vám uchovat vaše vzpomínky, jste na správném místě. S Ente jsou uloženy s koncovým "end-to-end" šifrováním (e2ee). To znamená, že je můžete vidět pouze vy.
We have apps across Android, iOS, web and Desktop, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner.
Máme aplikace napříč všemi platformami a vaše fotky se budou bezproblémově synchronizovat mezi všemi vašimi zařízeními tak, aby byly koncově šifrovány mezi jednotlivými zařízeními (e2ee).
Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links.
Ente také zjednodušuje sdílení alb s vašimi blízkými. Můžete je buď sdílet přímo s ostatními uživateli Ente, koncově šifrované; nebo s pomocí veřejně přístupných odkazů.
Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
Vaše šifrovaná data jsou uložena na několika místech, včetně protiatomového krytu v Paříži. Bereme budoucnost vážně a usnadňujeme vám zajistit, aby vaše vzpomínky přežily vás samotné.
We are here to make the safest photos app ever, come join our journey!
Jsme tu, abychom vytvořili nejbezpečnější aplikaci pro fotografie, jaká kdy byla. Přidejte se k nám!
FEATURES
- Original quality backups, because every pixel is important
- Family plans, so you can share storage with your family
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
- Album links, that can be protected with a password and set to expire
- Ability to free up space, by removing files that have been safely backed up
- Image editor, to add finishing touches
- Favorite, hide and relive your memories, for they are precious
- One-click import from Google, Apple, your hard drive and more
- Dark theme, because your photos look good in it
- 2FA, 3FA, biometric auth
- and a LOT more!
VLASTNOSTI
- Zálohování v původní kvalitě, protože každý pixel je důležitý
- Rodinné plány, takže můžete sdílet úložiště s rodinou
- Sdílené složky, aby i váš partner mohl obdivovat vaše fotografie
- Odkazy na alba, které lze chránit heslem a nastavit jejich platnost
- Možnost uvolnit místo odstraněním souborů, které byly bezpečně zálohovány
- Editor obrázků, pro finální doladění detailů
- Označte si své oblíbené fotografie, skryjte je a nebo je prožijte znovu pomocí vzpomínek
- Import jedním kliknutím ze všech velkých poskytovatelů úložišť
- Tmavý motiv, protože vaše fotografie v něm vypadají dobře
- 2FA, 3FA, biometrické ověření
- a ještě MNOHEM víc!
💲 PRICING
We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
💲 CENY
Nenabízíme doživotní tarify, protože je pro nás důležité zůstat udržitelnými a obstát ve zkoušce času. Místo toho nabízíme cenově dostupné plány, které můžete svobodně sdílet se svou rodinou. Více informací najdete na ente.io.
🙋 SUPPORT
We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
🙋 PODPORA
Jsme hrdí na to, že poskytujeme lidskou podporu. Pokud máte placený tarif, můžete se obrátit na team@ente.io a do 24 hodin od našeho týmu očekávat odpověď.

View File

@@ -1 +1 @@
Encrypted photo storage - backup, organize and share your photos and videos
Šifrované úložiště fotografií zálohujte, organizujte a sdílejte své fotografie a videa

View File

@@ -1 +1 @@
Ente Photos
Ente Fotky

View File

@@ -6,20 +6,20 @@ Kami menyediakan app untuk Android, iOS, Web, serta Desktop, dan fotomu akan ter
Ente juga memudahkan kamu untuk membagikan album ke kerabatmu. Kamu bisa membagikannya secara langsung ke pengguna Ente lain, terenkripsi ujung ke ujung; atau dengan link yang dapat dilihat publik.
Data terenkripsi kamu tersimpan di berbagai lokasi, termasuk di salah satu tempat pengungsian di Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
Data terenkripsi kamu tersimpan di berbagai lokasi, termasuk di salah satu tempat pengungsian di Paris. Kami menanggapi keturunan anda dengan serius dan memudahkan untuk memastikan kenangan anda tetap ada setelah anda.
Kami ingin membuat app foto yang paling aman sepanjang masajadi, bergabunglah dengan kami!
✨ FITUR
- Pencadangan kualitas asli, karena setiap piksel berarti
- Paket keluarga, sehingga kamu bisa bagikan kuota penyimpananmu dengan keluarga
- Shared folders, in case you want your partner to enjoy your "Camera" clicks
- Folder bersama, jika anda ingin pasangan anda menikmati hasil jepretan "Kamera" anda
- Link album, yang bisa dilindungi dengan sandi dan diatur waktu kedaluwarsanya
- Ability to free up space, by removing files that have been safely backed up
- Kemampuan untuk mengosongkan ruang, dengan menghapus file yang telah dicadangkan dengan aman
- Editor gambar, untuk menyempurnakan fotomu
- Favorite, hide and relive your memories, for they are precious
- Favoritkan, sembunyikan, dan kenang kembali memori anda, karena itu sangat berharga
- Pengimporan mudah dari Google, Apple, hard drive-mu, dan lainnya
- Dark theme, because your photos look good in it
- Tema gelap, karena foto anda terlihat bagus di dalamnya
- Autentikasi dua atau tiga faktor dan autentikasi biometrik
- dan BANYAK LAGI!
@@ -27,4 +27,4 @@ Kami ingin membuat app foto yang paling aman sepanjang masajadi, bergabunglah
Kami tidak menyediakan paket yang gratis seumur hidup, karena penting bagi kami untuk tetap berdiri dan bertahan hingga masa depan. Namun, kami menyediakan paket yang terjangkau, yang bisa kamu bagikan dengan keluargamu. Kamu bisa menemukan informasi lebih lanjut di ente.io.
🙋 DUKUNGAN
We take pride in offering human support. Jika kamu adalah pelanggan berbayar, kamu bisa menghubungi team@ente.io dan menunggu balasan dari tim kami dalam 24 jam.
Kami bangga dapat menawarkan dukungan manusia. Jika kamu adalah pelanggan berbayar, kamu bisa menghubungi team@ente.io dan menunggu balasan dari tim kami dalam 24 jam.

View File

@@ -181,6 +181,8 @@ PODS:
- PromisesObjC (2.4.0)
- receive_sharing_intent (1.8.1):
- Flutter
- rive_common (0.0.1):
- Flutter
- rust_lib_photos (0.0.1):
- Flutter
- SDWebImage (5.21.1):
@@ -291,6 +293,7 @@ DEPENDENCIES:
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- rive_common (from `.symlinks/plugins/rive_common/ios`)
- rust_lib_photos (from `.symlinks/plugins/rust_lib_photos/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
@@ -309,7 +312,7 @@ DEPENDENCIES:
- workmanager (from `.symlinks/plugins/workmanager/ios`)
SPEC REPOS:
https://github.com/ente-io/ffmpeg-kit-custom-repo-ios:
https://github.com/ente-io/ffmpeg-kit-custom-repo-ios.git:
- ffmpeg_kit_custom
trunk:
- Firebase
@@ -418,6 +421,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/privacy_screen/ios"
receive_sharing_intent:
:path: ".symlinks/plugins/receive_sharing_intent/ios"
rive_common:
:path: ".symlinks/plugins/rive_common/ios"
rust_lib_photos:
:path: ".symlinks/plugins/rust_lib_photos/ios"
sentry_flutter:
@@ -452,84 +457,85 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/workmanager/ios"
SPEC CHECKSUMS:
app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c
dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
emoji_picker_flutter: ed468d9746c21711e66b2788880519a9de5de211
app_links: f3e17e4ee5e357b39d8b95290a9b2c299fca71c6
battery_info: b6c551049266af31556b93c9d9b9452cfec0219f
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
cupertino_http: 947a233f40cfea55167a49f2facc18434ea117ba
dart_ui_isolate: d5bcda83ca4b04f129d70eb90110b7a567aece14
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
emoji_picker_flutter: fe2e6151c5b548e975d546e6eeb567daf0962a58
ffmpeg_kit_custom: 682b4f2f1ff1f8abae5a92f6c3540f2441d5be99
ffmpeg_kit_flutter: 915b345acc97d4142e8a9a8549d177ff10f043f5
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
ffmpeg_kit_flutter: 9dce4803991478c78c6fb9f972703301101095fe
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
firebase_core: ece862f94b2bc72ee0edbeec7ab5c7cb09fe1ab5
firebase_messaging: e1a5fae495603115be1d0183bc849da748734e2b
firebase_core: cf4d42a8ac915e51c0c2dc103442f3036d941a2d
firebase_messaging: fee490327c1aae28a0da1e65fca856547deca493
FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e
FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4
FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987
flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
flutter_email_sender: e03bdda7637bcd3539bfe718fddd980e9508efaa
flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
flutter_sodium: a00383520fc689c688b66fd3092984174712493e
flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
launcher_icon_switcher: 84c218d233505aa7d8655d8fa61a3ba802c022da
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
launcher_icon_switcher: 8e0ad2131a20c51c1dd939896ee32e70cd845b37
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451
local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
media_extension: 671e2567880d96c95c65c9a82ccceed8f2e309fd
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
motion_sensors: 741e702c17467b9569a92165dda8d4d88c6167f1
motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1
move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84
maps_launcher: 2e5b6a2d664ec6c27f82ffa81b74228d770ab203
media_extension: 6618f07abd762cdbfaadf1b0c56a287e820f0c84
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91
motionphoto: 8b65ce50c7d7ff3c767534fc3768b2eed9ac24e4
move_to_background: cd3091014529ec7829e342ad2d75c0a11f4378a5
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
native_video_player: 6809dec117e8997161dbfb42a6f90d6df71a504d
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2
native_video_player: 29ab24a926804ac8c4a57eb6d744c7d927c2bc3e
objective_c: 77e887b5ba1827970907e10e832eec1683f3431d
onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b
open_mail_app: 7314a609e88eed22d53671279e189af7a0ab0f11
open_mail_app: 70273c53f768beefdafbe310c3d9086e4da3cb02
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62
privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
photo_manager: 81954a1bf804b6e882d0453b3b6bc7fad7b47d3d
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
rust_lib_photos: 04d3901908d2972192944083310b65abf410774c
receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1
rive_common: 4743dbfd2911c99066547a3c6454681e0fa907df
rust_lib_photos: 8813b31af48ff02ca75520cbc81a363a13d51a84
SDWebImage: f29024626962457f3470184232766516dee8dfea
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sentry_flutter: 2df8b0aab7e4aba81261c230cbea31c82a62dd1b
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
sqlite3: 1d85290c3321153511f6e900ede7a1608718bbd5
sqlite3_flutter_libs: e7fc8c9ea2200ff3271f08f127842131746b70e2
system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
thermal: d4c48be750d1ddbab36b0e2dcb2471531bc8df41
ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
vibration: 8e2f50fc35bb736f9eecb7dd9f7047fbb6a6e888
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
workmanager: b89e4e4445d8b57ee2fdbf1c3925696ebe5b8990
sqlite3_flutter_libs: 2c48c4ee7217fd653251975e43412250d5bcbbe2
system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
thermal: a9261044101ae8f532fa29cab4e8270b51b3f55c
ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
vibration: 7d883d141656a1c1a6d8d238616b2042a51a1241
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
video_thumbnail: c4e2a3c539e247d4de13cd545344fd2d26ffafd1
volume_controller: 2e3de73d6e7e81a0067310d17fb70f2f86d71ac7
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
workmanager: 05afacf221f5086e18450250dce57f59bb23e6b0
PODFILE CHECKSUM: cce2cd3351d3488dca65b151118552b680e23635

View File

@@ -565,6 +565,7 @@
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
"${BUILT_PRODUCTS_DIR}/privacy_screen/privacy_screen.framework",
"${BUILT_PRODUCTS_DIR}/receive_sharing_intent/receive_sharing_intent.framework",
"${BUILT_PRODUCTS_DIR}/rive_common/rive_common.framework",
"${BUILT_PRODUCTS_DIR}/rust_lib_photos/rust_lib_photos.framework",
"${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework",
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
@@ -662,6 +663,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/privacy_screen.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/receive_sharing_intent.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/rive_common.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/rust_lib_photos.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",

View File

@@ -0,0 +1,38 @@
{
"images" : [
{
"filename" : "IconDuckyHuggingEAny.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "IconDuckyHuggingEDark.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "IconDuckyHuggingETinted.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@@ -0,0 +1,6 @@
arb-dir: lib/l10n
output-dir: lib/generated/intl
template-arb-file: intl_en.arb
output-localization-file: app_localizations.dart
nullable-getter: false
use-named-parameters: true

View File

@@ -5,7 +5,6 @@ import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import "package:flutter_localizations/flutter_localizations.dart";
import 'package:home_widget/home_widget.dart' as hw;
import 'package:logging/logging.dart';
import 'package:media_extension/media_extension_action_types.dart';
@@ -146,10 +145,7 @@ class _EnteAppState extends State<EnteApp> with WidgetsBindingObserver {
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
...AppLocalizations.localizationsDelegates,
],
),
),
@@ -171,10 +167,7 @@ class _EnteAppState extends State<EnteApp> with WidgetsBindingObserver {
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
...AppLocalizations.localizationsDelegates,
],
),
);

View File

@@ -29,6 +29,10 @@ class LRUMap<K, V> {
}
}
bool containsKey(K key) {
return _map.containsKey(key);
}
void remove(K key) {
_map.remove(key);
}

View File

@@ -1,39 +0,0 @@
import 'dart:typed_data';
import 'package:photos/core/cache/lru_map.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/models/file/file.dart';
class ThumbnailInMemoryLruCache {
static final LRUMap<String, Uint8List?> _map = LRUMap(1000);
static Uint8List? get(EnteFile enteFile, [int? size]) {
return _map.get(
enteFile.cacheKey() +
"_" +
(size != null ? size.toString() : thumbnailLargeSize.toString()),
);
}
static void put(
EnteFile enteFile,
Uint8List? imageData, [
int? size,
]) {
_map.put(
enteFile.cacheKey() +
"_" +
(size != null ? size.toString() : thumbnailLargeSize.toString()),
imageData,
);
}
static void clearCache(EnteFile enteFile) {
_map.remove(
enteFile.cacheKey() + "_" + thumbnailLargeSize.toString(),
);
_map.remove(
enteFile.cacheKey() + "_" + thumbnailSmallSize.toString(),
);
}
}

View File

@@ -11,11 +11,9 @@ import 'package:path_provider/path_provider.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/error-reporting/super_logging.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/collections_db.dart';
import 'package:photos/db/files_db.dart';
import "package:photos/db/memories_db.dart";
import "package:photos/db/ml/db.dart";
import 'package:photos/db/trash_db.dart';
import 'package:photos/db/upload_locks_db.dart';
import "package:photos/events/endpoint_updated_event.dart";
import 'package:photos/events/signed_in_event.dart';
@@ -23,14 +21,16 @@ import 'package:photos/events/user_logged_out_event.dart';
import 'package:photos/models/api/user/key_attributes.dart';
import 'package:photos/models/api/user/key_gen_result.dart';
import 'package:photos/models/api/user/private_key_attributes.dart';
import 'package:photos/module/upload/service/file_uploader.dart';
import "package:photos/service_locator.dart";
import 'package:photos/services/collections_service.dart';
import 'package:photos/services/favorites_service.dart';
import "package:photos/services/home_widget_service.dart";
import 'package:photos/services/ignored_files_service.dart';
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
import "package:photos/services/machine_learning/similar_images_service.dart";
import 'package:photos/services/search_service.dart';
import 'package:photos/services/sync/sync_service.dart';
import 'package:photos/utils/file_uploader.dart';
import "package:photos/utils/lock_screen_settings.dart";
import 'package:photos/utils/validator_util.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -193,13 +193,13 @@ class Configuration {
_cachedToken = null;
_secretKey = null;
await FilesDB.instance.clearTable();
await CollectionsDB.instance.clearTable();
// await CollectionsDB.instance.clearTable();
await MemoriesDB.instance.clearTable();
await MLDataDB.instance.clearTable();
await remoteDB.clearAllTables();
await SimilarImagesService.instance.clearCache();
await UploadLocksDB.instance.clearTable();
await IgnoredFilesService.instance.reset();
await TrashDB.instance.clearTable();
unawaited(HomeWidgetService.instance.clearWidget(autoLogout));
if (!autoLogout) {
// Following services won't be initialized if it's the case of autoLogout

View File

@@ -1,10 +1,12 @@
import "package:flutter/foundation.dart";
const int thumbnailSmallSize = 256;
const int thumbnailQuality = 50;
const int thumbnailLargeSize = 512;
const int compressedThumbnailResolution = 1080;
const int thumbnailDataLimit = 100 * 1024;
// thumbnailSmallSize Thumbnail sizes in pixels 256px
const int thumbnailSmall256 = 256;
// thumbnailMediumSize Thumbnail sizes in pixels 512px
const int thumbnailLarge512 = 512; // 512px
const int compressThumb1080 = 1080;
const int thumbnailDataMaxSize = 100 * 1024;
const String sentryDSN =
"https://2235e5c99219488ea93da34b9ac1cb68@sentry.ente.io/4";
const String sentryDebugDSN =
@@ -109,4 +111,4 @@ final tempDirCleanUpInterval = kDebugMode
const kFilterChipHeight = 32.0;
const kMaxAppbarFilters = 14;
const kLivePhotoHashSeparator = ':';
const kHashSeprator = ':';

View File

@@ -0,0 +1,13 @@
/// Common runtime exceptions that can occur during normal app operation.
/// These are recoverable conditions that should be caught and handled.
class WidgetUnmountedException implements Exception {
final String? message;
WidgetUnmountedException([this.message]);
@override
String toString() => message != null
? 'WidgetUnmountedException: $message'
: 'WidgetUnmountedException';
}

View File

@@ -1,322 +0,0 @@
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import "package:photos/models/api/collection/public_url.dart";
import "package:photos/models/api/collection/user.dart";
import 'package:photos/models/collection/collection.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqflite_migration/sqflite_migration.dart';
class CollectionsDB {
static const _databaseName = "ente.collections.db";
static const table = 'collections';
static const tempTable = 'temp_collections';
static const _sqlBoolTrue = 1;
static const _sqlBoolFalse = 0;
static const columnID = 'collection_id';
static const columnOwner = 'owner';
static const columnEncryptedKey = 'encrypted_key';
static const columnKeyDecryptionNonce = 'key_decryption_nonce';
static const columnName = 'name';
static const columnEncryptedName = 'encrypted_name';
static const columnNameDecryptionNonce = 'name_decryption_nonce';
static const columnType = 'type';
static const columnEncryptedPath = 'encrypted_path';
static const columnPathDecryptionNonce = 'path_decryption_nonce';
static const columnVersion = 'version';
static const columnSharees = 'sharees';
static const columnPublicURLs = 'public_urls';
// MMD -> Magic Metadata
static const columnMMdEncodedJson = 'mmd_encoded_json';
static const columnMMdVersion = 'mmd_ver';
static const columnPubMMdEncodedJson = 'pub_mmd_encoded_json';
static const columnPubMMdVersion = 'pub_mmd_ver';
static const columnSharedMMdJson = 'shared_mmd_json';
static const columnSharedMMdVersion = 'shared_mmd_ver';
static const columnUpdationTime = 'updation_time';
static const columnIsDeleted = 'is_deleted';
static final intitialScript = [...createTable(table)];
static final migrationScripts = [
...alterNameToAllowNULL(),
...addEncryptedName(),
...addVersion(),
...addIsDeleted(),
...addPublicURLs(),
...addPrivateMetadata(),
...addPublicMetadata(),
...addShareeMetadata(),
];
final dbConfig = MigrationConfig(
initializationScript: intitialScript,
migrationScripts: migrationScripts,
);
CollectionsDB._privateConstructor();
static final CollectionsDB instance = CollectionsDB._privateConstructor();
static Future<Database>? _dbFuture;
Future<Database> get database async {
_dbFuture ??= _initDatabase();
return _dbFuture!;
}
Future<Database> _initDatabase() async {
final Directory documentsDirectory =
await getApplicationDocumentsDirectory();
final String path = join(documentsDirectory.path, _databaseName);
return await openDatabaseWithMigration(path, dbConfig);
}
Future<void> clearTable() async {
final db = await instance.database;
await db.delete(table);
}
static List<String> createTable(String tableName) {
return [
'''
CREATE TABLE $tableName (
$columnID INTEGER PRIMARY KEY NOT NULL,
$columnOwner TEXT NOT NULL,
$columnEncryptedKey TEXT NOT NULL,
$columnKeyDecryptionNonce TEXT,
$columnName TEXT,
$columnType TEXT NOT NULL,
$columnEncryptedPath TEXT,
$columnPathDecryptionNonce TEXT,
$columnSharees TEXT,
$columnUpdationTime TEXT NOT NULL
);
'''
];
}
static List<String> alterNameToAllowNULL() {
return [
...createTable(tempTable),
'''
INSERT INTO $tempTable
SELECT *
FROM $table;
DROP TABLE $table;
ALTER TABLE $tempTable
RENAME TO $table;
'''
];
}
static List<String> addEncryptedName() {
return [
'''
ALTER TABLE $table
ADD COLUMN $columnEncryptedName TEXT;
''',
'''ALTER TABLE $table
ADD COLUMN $columnNameDecryptionNonce TEXT;
'''
];
}
static List<String> addVersion() {
return [
'''
ALTER TABLE $table
ADD COLUMN $columnVersion INTEGER DEFAULT 0;
'''
];
}
static List<String> addIsDeleted() {
return [
'''
ALTER TABLE $table
ADD COLUMN $columnIsDeleted INTEGER DEFAULT $_sqlBoolFalse;
'''
];
}
static List<String> addPublicURLs() {
return [
'''
ALTER TABLE $table
ADD COLUMN $columnPublicURLs TEXT;
'''
];
}
static List<String> addPrivateMetadata() {
return [
'''
ALTER TABLE $table ADD COLUMN $columnMMdEncodedJson TEXT DEFAULT '{}';
''',
'''
ALTER TABLE $table ADD COLUMN $columnMMdVersion INTEGER DEFAULT 0;
'''
];
}
static List<String> addPublicMetadata() {
return [
'''
ALTER TABLE $table ADD COLUMN $columnPubMMdEncodedJson TEXT DEFAULT '
{}';
''',
'''
ALTER TABLE $table ADD COLUMN $columnPubMMdVersion INTEGER DEFAULT 0;
'''
];
}
static List<String> addShareeMetadata() {
return [
'''
ALTER TABLE $table ADD COLUMN $columnSharedMMdJson TEXT DEFAULT '
{}';
''',
'''
ALTER TABLE $table ADD COLUMN $columnSharedMMdVersion INTEGER DEFAULT 0;
'''
];
}
Future<void> insert(List<Collection> collections) async {
final db = await instance.database;
var batch = db.batch();
int batchCounter = 0;
for (final collection in collections) {
if (batchCounter == 400) {
await batch.commit(noResult: true);
batch = db.batch();
batchCounter = 0;
}
batch.insert(
table,
_getRowForCollection(collection),
conflictAlgorithm: ConflictAlgorithm.replace,
);
batchCounter++;
}
await batch.commit(noResult: true);
}
Future<List<Collection>> getAllCollections() async {
final db = await instance.database;
final rows = await db.query(table);
final collections = <Collection>[];
for (final row in rows) {
collections.add(_convertToCollection(row));
}
return collections;
}
// getActiveCollectionIDsAndUpdationTime returns map of collectionID to
// updationTime for non-deleted collections
Future<Map<int, int>> getActiveIDsAndRemoteUpdateTime() async {
final db = await instance.database;
final rows = await db.query(
table,
where: '($columnIsDeleted = ? OR $columnIsDeleted IS NULL)',
whereArgs: [_sqlBoolFalse],
columns: [columnID, columnUpdationTime],
);
final collectionIDsAndUpdationTime = <int, int>{};
for (final row in rows) {
collectionIDsAndUpdationTime[row[columnID] as int] =
int.parse(row[columnUpdationTime] as String);
}
return collectionIDsAndUpdationTime;
}
Future<int> deleteCollection(int collectionID) async {
final db = await instance.database;
return db.delete(
table,
where: '$columnID = ?',
whereArgs: [collectionID],
);
}
Map<String, dynamic> _getRowForCollection(Collection collection) {
final row = <String, dynamic>{};
row[columnID] = collection.id;
row[columnOwner] = collection.owner.toJson();
row[columnEncryptedKey] = collection.encryptedKey;
row[columnKeyDecryptionNonce] = collection.keyDecryptionNonce;
// ignore: deprecated_member_use_from_same_package
row[columnName] = collection.name;
row[columnEncryptedName] = collection.encryptedName;
row[columnNameDecryptionNonce] = collection.nameDecryptionNonce;
row[columnType] = typeToString(collection.type);
row[columnEncryptedPath] = collection.attributes.encryptedPath;
row[columnPathDecryptionNonce] = collection.attributes.pathDecryptionNonce;
row[columnVersion] = collection.attributes.version;
row[columnSharees] =
json.encode(collection.sharees.map((x) => x.toMap()).toList());
row[columnPublicURLs] =
json.encode(collection.publicURLs.map((x) => x.toMap()).toList());
row[columnUpdationTime] = collection.updationTime;
if (collection.isDeleted) {
row[columnIsDeleted] = _sqlBoolTrue;
} else {
row[columnIsDeleted] = _sqlBoolFalse;
}
row[columnMMdVersion] = collection.mMdVersion;
row[columnMMdEncodedJson] = collection.mMdEncodedJson ?? '{}';
row[columnPubMMdVersion] = collection.mMbPubVersion;
row[columnPubMMdEncodedJson] = collection.mMdPubEncodedJson ?? '{}';
row[columnSharedMMdVersion] = collection.sharedMmdVersion;
row[columnSharedMMdJson] = collection.sharedMmdJson ?? '{}';
return row;
}
Collection _convertToCollection(Map<String, dynamic> row) {
final Collection result = Collection(
row[columnID],
User.fromJson(row[columnOwner]),
row[columnEncryptedKey],
row[columnKeyDecryptionNonce],
row[columnName],
row[columnEncryptedName],
row[columnNameDecryptionNonce],
typeFromString(row[columnType]),
CollectionAttributes(
encryptedPath: row[columnEncryptedPath],
pathDecryptionNonce: row[columnPathDecryptionNonce],
version: row[columnVersion],
),
List<User>.from(
(json.decode(row[columnSharees]) as List).map((x) => User.fromMap(x)),
),
row[columnPublicURLs] == null
? []
: List<PublicURL>.from(
(json.decode(row[columnPublicURLs]) as List)
.map((x) => PublicURL.fromMap(x)),
),
int.parse(row[columnUpdationTime]),
// default to False is columnIsDeleted is not set
isDeleted: (row[columnIsDeleted] ?? _sqlBoolFalse) == _sqlBoolTrue,
);
result.mMdVersion = row[columnMMdVersion] ?? 0;
result.mMdEncodedJson = row[columnMMdEncodedJson] ?? '{}';
result.mMbPubVersion = row[columnPubMMdVersion] ?? 0;
result.mMdPubEncodedJson = row[columnPubMMdEncodedJson] ?? '{}';
result.sharedMmdVersion = row[columnSharedMMdVersion] ?? 0;
result.sharedMmdJson = row[columnSharedMMdJson] ?? '{}';
return result;
}
}

View File

@@ -2,9 +2,9 @@ import "package:flutter/foundation.dart";
import "package:sqlite_async/sqlite_async.dart";
mixin SqlDbBase {
static const _params = {};
static final _params = {};
static String getParams(int count) {
String getParams(int count) {
if (!_params.containsKey(count)) {
final params = List.generate(count, (_) => "?").join(", ");
_params[count] = params;
@@ -14,9 +14,13 @@ mixin SqlDbBase {
Future<void> migrate(
SqliteDatabase database,
List<String> migrationScripts,
) async {
List<String> migrationScripts, {
bool onForeignKey = false,
}) async {
final result = await database.execute('PRAGMA user_version');
if (onForeignKey) {
await database.execute("PRAGMA foreign_keys = ON");
}
final currentVersion = result[0]['user_version'] as int;
final toVersion = migrationScripts.length;

View File

@@ -1,492 +0,0 @@
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/models/backup_status.dart';
import 'package:photos/models/device_collection.dart';
import 'package:photos/models/file/file.dart';
import 'package:photos/models/file_load_result.dart';
import 'package:photos/models/upload_strategy.dart';
import "package:photos/services/sync/import/model.dart";
import 'package:sqflite/sqlite_api.dart';
import 'package:tuple/tuple.dart';
extension DeviceFiles on FilesDB {
static final Logger _logger = Logger("DeviceFilesDB");
static const _sqlBoolTrue = 1;
static const _sqlBoolFalse = 0;
Future<void> insertPathIDToLocalIDMapping(
Map<String, Set<String>> mappingToAdd, {
ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.ignore,
}) async {
debugPrint("Inserting missing PathIDToLocalIDMapping");
final parameterSets = <List<Object?>>[];
int batchCounter = 0;
for (MapEntry e in mappingToAdd.entries) {
final String pathID = e.key;
for (String localID in e.value) {
parameterSets.add([localID, pathID]);
batchCounter++;
if (batchCounter == 400) {
await _insertBatch(parameterSets, conflictAlgorithm);
parameterSets.clear();
batchCounter = 0;
}
}
}
await _insertBatch(parameterSets, conflictAlgorithm);
parameterSets.clear();
batchCounter = 0;
}
Future<void> deletePathIDToLocalIDMapping(
Map<String, Set<String>> mappingsToRemove,
) async {
debugPrint("removing PathIDToLocalIDMapping");
final parameterSets = <List<Object?>>[];
int batchCounter = 0;
for (MapEntry e in mappingsToRemove.entries) {
final String pathID = e.key;
for (String localID in e.value) {
parameterSets.add([localID, pathID]);
batchCounter++;
if (batchCounter == 400) {
await _deleteBatch(parameterSets);
parameterSets.clear();
batchCounter = 0;
}
}
}
await _deleteBatch(parameterSets);
parameterSets.clear();
batchCounter = 0;
}
Future<Map<String, int>> getDevicePathIDToImportedFileCount() async {
try {
final db = await sqliteAsyncDB;
final rows = await db.getAll(
'''
SELECT count(*) as count, path_id
FROM device_files
GROUP BY path_id
''',
);
final result = <String, int>{};
for (final row in rows) {
result[row['path_id'] as String] = row["count"] as int;
}
return result;
} catch (e) {
_logger.severe("failed to getDevicePathIDToImportedFileCount", e);
rethrow;
}
}
Future<Map<String, Set<String>>> getDevicePathIDToLocalIDMap() async {
try {
final db = await sqliteAsyncDB;
final rows = await db.getAll(
''' SELECT id, path_id FROM device_files; ''',
);
final result = <String, Set<String>>{};
for (final row in rows) {
final String pathID = row['path_id'] as String;
if (!result.containsKey(pathID)) {
result[pathID] = <String>{};
}
result[pathID]!.add(row['id'] as String);
}
return result;
} catch (e) {
_logger.severe("failed to getDevicePathIDToLocalIDMap", e);
rethrow;
}
}
Future<Set<String>> getDevicePathIDs() async {
final db = await sqliteAsyncDB;
final rows = await db.getAll(
'''
SELECT id FROM device_collections
''',
);
final Set<String> result = <String>{};
for (final row in rows) {
result.add(row['id'] as String);
}
return result;
}
Future<void> insertLocalAssets(
List<LocalPathAsset> localPathAssets, {
bool shouldAutoBackup = false,
}) async {
final db = await sqliteAsyncDB;
final Map<String, Set<String>> pathIDToLocalIDsMap = {};
try {
final Set<String> existingPathIds = await getDevicePathIDs();
final parameterSetsForUpdate = <List<Object?>>[];
final parameterSetsForInsert = <List<Object?>>[];
for (LocalPathAsset localPathAsset in localPathAssets) {
if (localPathAsset.localIDs.isNotEmpty) {
pathIDToLocalIDsMap[localPathAsset.pathID] = localPathAsset.localIDs;
}
if (existingPathIds.contains(localPathAsset.pathID)) {
parameterSetsForUpdate
.add([localPathAsset.pathName, localPathAsset.pathID]);
} else if (localPathAsset.localIDs.isNotEmpty) {
parameterSetsForInsert.add([
localPathAsset.pathID,
localPathAsset.pathName,
shouldAutoBackup ? _sqlBoolTrue : _sqlBoolFalse,
]);
}
}
await db.executeBatch(
'''
INSERT OR IGNORE INTO device_collections (id, name, should_backup) VALUES (?, ?, ?);
''',
parameterSetsForInsert,
);
await db.executeBatch(
'''
UPDATE device_collections SET name = ? WHERE id = ?;
''',
parameterSetsForUpdate,
);
// add the mappings for localIDs
if (pathIDToLocalIDsMap.isNotEmpty) {
await insertPathIDToLocalIDMapping(pathIDToLocalIDsMap);
}
} catch (e) {
_logger.severe("failed to save path names", e);
rethrow;
}
}
Future<bool> updateDeviceCoverWithCount(
List<Tuple2<AssetPathEntity, String>> devicePathInfo, {
bool shouldBackup = false,
}) async {
bool hasUpdated = false;
try {
final db = await sqliteAsyncDB;
final Set<String> existingPathIds = await getDevicePathIDs();
for (Tuple2<AssetPathEntity, String> tup in devicePathInfo) {
final AssetPathEntity pathEntity = tup.item1;
final assetCount = await pathEntity.assetCountAsync;
final String localID = tup.item2;
final bool shouldUpdate = existingPathIds.contains(pathEntity.id);
if (shouldUpdate) {
final rowUpdated = await db.writeTransaction((tx) async {
await tx.execute(
"UPDATE device_collections SET name = ?, cover_id = ?, count"
" = ? where id = ? AND (name != ? OR cover_id != ? OR count != ?)",
[
pathEntity.name,
localID,
assetCount,
pathEntity.id,
pathEntity.name,
localID,
assetCount,
],
);
final result = await tx.get("SELECT changes();");
return result["changes()"] as int;
});
if (rowUpdated > 0) {
_logger.info("Updated $rowUpdated rows for ${pathEntity.name}");
hasUpdated = true;
}
} else {
hasUpdated = true;
await db.execute(
'''
INSERT INTO device_collections (id, name, count, cover_id, should_backup)
VALUES (?, ?, ?, ?, ?);
''',
[
pathEntity.id,
pathEntity.name,
assetCount,
localID,
shouldBackup ? _sqlBoolTrue : _sqlBoolFalse,
],
);
}
}
// delete existing pathIDs which are missing on device
existingPathIds.removeAll(devicePathInfo.map((e) => e.item1.id).toSet());
if (existingPathIds.isNotEmpty) {
hasUpdated = true;
_logger.info(
'Deleting non-backed up pathIds from local '
'$existingPathIds',
);
for (String pathID in existingPathIds) {
// do not delete device collection entries for paths which are
// marked for backup. This is to handle "Free up space"
// feature, where we delete files which are backed up. Deleting such
// entries here result in us losing out on the information that
// those folders were marked for automatic backup.
await db.execute(
'''
DELETE FROM device_collections WHERE id = ? AND should_backup = $_sqlBoolFalse;
''',
[pathID],
);
await db.execute(
'''
DELETE FROM device_files WHERE path_id = ?;
''',
[pathID],
);
}
}
return hasUpdated;
} catch (e) {
_logger.severe("failed to save path names", e);
rethrow;
}
}
// getDeviceSyncCollectionIDs returns the collectionIDs for the
// deviceCollections which are marked for auto-backup
Future<Set<int>> getDeviceSyncCollectionIDs() async {
final db = await sqliteAsyncDB;
final rows = await db.getAll(
'''
SELECT collection_id FROM device_collections where should_backup =
$_sqlBoolTrue
and collection_id != -1;
''',
);
final Set<int> result = <int>{};
for (final row in rows) {
result.add(row['collection_id'] as int);
}
return result;
}
Future<void> updateDevicePathSyncStatus(
Map<String, bool> syncStatus,
) async {
final db = await sqliteAsyncDB;
int batchCounter = 0;
final parameterSets = <List<Object?>>[];
for (MapEntry e in syncStatus.entries) {
final String pathID = e.key;
parameterSets.add([e.value ? _sqlBoolTrue : _sqlBoolFalse, pathID]);
batchCounter++;
if (batchCounter == 400) {
await db.executeBatch(
'''
UPDATE device_collections SET should_backup = ? WHERE id = ?;
''',
parameterSets,
);
parameterSets.clear();
batchCounter = 0;
}
}
await db.executeBatch(
'''
UPDATE device_collections SET should_backup = ? WHERE id = ?;
''',
parameterSets,
);
}
Future<void> updateDeviceCollection(
String pathID,
int collectionID,
) async {
final db = await sqliteAsyncDB;
await db.execute(
'''
UPDATE device_collections SET collection_id = ? WHERE id = ?;
''',
[collectionID, pathID],
);
return;
}
Future<FileLoadResult> getFilesInDeviceCollection(
DeviceCollection deviceCollection,
int? ownerID,
int startTime,
int endTime, {
int? limit,
bool? asc,
}) async {
final db = await sqliteAsyncDB;
final order = (asc ?? false ? 'ASC' : 'DESC');
final String rawQuery = '''
SELECT *
FROM ${FilesDB.filesTable}
WHERE ${FilesDB.columnLocalID} IS NOT NULL AND
${FilesDB.columnCreationTime} >= $startTime AND
${FilesDB.columnCreationTime} <= $endTime AND
(${FilesDB.columnOwnerID} IS NULL OR ${FilesDB.columnOwnerID} =
$ownerID ) AND
${FilesDB.columnLocalID} IN
(SELECT id FROM device_files where path_id = '${deviceCollection.id}' )
ORDER BY ${FilesDB.columnCreationTime} $order , ${FilesDB.columnModificationTime} $order
''' +
(limit != null ? ' limit $limit;' : ';');
final results = await db.getAll(rawQuery);
final files = convertToFiles(results);
final dedupe = deduplicateByLocalID(files);
return FileLoadResult(dedupe, files.length == limit);
}
Future<BackedUpFileIDs> getBackedUpForDeviceCollection(
String pathID,
int ownerID,
) async {
final db = await sqliteAsyncDB;
const String rawQuery = '''
SELECT ${FilesDB.columnLocalID}, ${FilesDB.columnUploadedFileID},
${FilesDB.columnFileSize}
FROM ${FilesDB.filesTable}
WHERE ${FilesDB.columnLocalID} IS NOT NULL AND
(${FilesDB.columnOwnerID} IS NULL OR ${FilesDB.columnOwnerID} = ?)
AND (${FilesDB.columnUploadedFileID} IS NOT NULL AND ${FilesDB.columnUploadedFileID} IS NOT -1)
AND
${FilesDB.columnLocalID} IN
(SELECT id FROM device_files where path_id = ?)
''';
final results = await db.getAll(rawQuery, [ownerID, pathID]);
final localIDs = <String>{};
final uploadedIDs = <int>{};
int localSize = 0;
for (final result in results) {
final String localID = result[FilesDB.columnLocalID] as String;
final int? fileSize = result[FilesDB.columnFileSize] as int?;
if (!localIDs.contains(localID) && fileSize != null) {
localSize += fileSize;
}
localIDs.add(localID);
uploadedIDs.add(result[FilesDB.columnUploadedFileID] as int);
}
return BackedUpFileIDs(localIDs.toList(), uploadedIDs.toList(), localSize);
}
Future<List<DeviceCollection>> getDeviceCollections({
bool includeCoverThumbnail = false,
}) async {
debugPrint(
"Fetching DeviceCollections From DB with thumbnail = "
"$includeCoverThumbnail",
);
try {
final db = await sqliteAsyncDB;
final coverFiles = <EnteFile>[];
if (includeCoverThumbnail) {
final fileRows = await db.getAll(
'''SELECT * FROM FILES where local_id in (select cover_id from device_collections) group by local_id;
''',
);
final files = convertToFiles(fileRows);
coverFiles.addAll(files);
}
final deviceCollectionRows = await db.getAll(
'''SELECT * from device_collections''',
);
final List<DeviceCollection> deviceCollections = [];
for (var row in deviceCollectionRows) {
final DeviceCollection deviceCollection = DeviceCollection(
row["id"] as String,
(row['name'] ?? '') as String,
count: row['count'] as int,
collectionID: (row["collection_id"] ?? -1) as int,
coverId: row["cover_id"] as String?,
shouldBackup: (row["should_backup"] ?? _sqlBoolFalse) == _sqlBoolTrue,
uploadStrategy: getUploadType((row["upload_strategy"] ?? 0) as int),
);
if (includeCoverThumbnail) {
deviceCollection.thumbnail = coverFiles.firstWhereOrNull(
(element) => element.localID == deviceCollection.coverId,
);
if (deviceCollection.thumbnail == null) {
final EnteFile? result =
await getDeviceCollectionThumbnail(deviceCollection.id);
if (result == null) {
_logger.info(
'Failed to find coverThumbnail for deviceFolder',
);
continue;
} else {
deviceCollection.thumbnail = result;
}
}
}
deviceCollections.add(deviceCollection);
}
if (includeCoverThumbnail) {
deviceCollections.sort(
(a, b) =>
b.thumbnail!.creationTime!.compareTo(a.thumbnail!.creationTime!),
);
}
return deviceCollections;
} catch (e) {
_logger.severe('Failed to getDeviceCollections', e);
rethrow;
}
}
Future<EnteFile?> getDeviceCollectionThumbnail(String pathID) async {
debugPrint("Call fallback method to get potential thumbnail");
final db = await sqliteAsyncDB;
final fileRows = await db.getAll(
'''SELECT * FROM FILES f JOIN device_files df on f.local_id = df.id
and df.path_id= ? order by f.creation_time DESC limit 1;
''',
[pathID],
);
final files = convertToFiles(fileRows);
if (files.isNotEmpty) {
return files.first;
} else {
return null;
}
}
Future<void> _insertBatch(
List<List<Object?>> parameterSets,
ConflictAlgorithm conflictAlgorithm,
) async {
final db = await sqliteAsyncDB;
await db.executeBatch(
'''
INSERT OR ${conflictAlgorithm.name.toUpperCase()}
INTO device_files (id, path_id) VALUES (?, ?);
''',
parameterSets,
);
}
Future<void> _deleteBatch(List<List<Object?>> parameterSets) async {
final db = await sqliteAsyncDB;
await db.executeBatch(
'''
DELETE FROM device_files WHERE id = ? AND path_id = ?;
''',
parameterSets,
);
}
}

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