Skip to content

Conversation

@PeterOmbodi
Copy link
Contributor

@PeterOmbodi PeterOmbodi commented Jul 31, 2025

Note

UPD: Sync only applies to files from albums included in the device’s backup list. To enable it, tap the button with the cloud icon in the app bar, then select “Select” and choose the folder to back up. I used Immich.

Description

Functionality for synchronizing the local media store when remotely deleting to trash and restoring files has been added. (Android, beta)
This solves the issue of file deletion synchronization on web and mobile apps.

Fixes # (issue)

How Has This Been Tested?

To verify this, you need an Android 11+ device.

  1. Launch the Flutter app on an Android device.
  2. Log in to the app (I used the demo server and demo account).
  3. Go to Settings => Switch timeline to beta mode, then -Advanced and enable the 'Sync remote deletions' switch.
  4. Download any photo or multiple photos from the photo list.
  5. Grant access to local albums, specifically to the Immich album (Cloud icon to the left of the profile icon).
  6. Open the Immich web app and log in with the same account (I used the demo).
  7. In the web app, delete (move to trash) a photo that is locally downloaded on your phone (marked with a cloud + icon).
  8. For devices using Google Photos as the gallery app, make sure that syncing is disabled or paused — otherwise, a file moved to the trash may appear both in the Trash and in the Photos section.
  9. Open the gallery, go to the trash, and you should see the file that is in the trash on the web app.
  10. Return to the mobile app.
  11. In the web app, restore the file from the trash, and make sure it appears in the Flutter app's photo list (with the cloud + icon).
  12. Open the gallery, and the file should be in the Immich folder (restored).

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation if applicable
  • I have no unrelated changes in the PR.
  • I have confirmed that any new dependencies are strictly necessary.
  • I have written tests for new code (if applicable)
  • I have followed naming conventions/patterns in the surrounding code
  • All code in src/services/ uses repositories implementations for database calls, filesystem operations, etc.
  • All code in src/repositories/ is pretty basic/simple and does not have any immich specific logic (that belongs in src/services/)

Peter Ombodi added 2 commits July 31, 2025 18:34
…nts and rescan media

- Handle move to trash and restore from trash for remote assets on Android
- Trigger MediaScannerConnection to rescan affected media files
Peter Ombodi added 2 commits August 5, 2025 17:58
rollback changes in BackgroundServicePlugin
if (localAssetsToTrash.isNotEmpty) {
final mediaUrls = await Future.wait(
localAssetsToTrash.map(
(localAsset) => _storageRepository.getAssetEntityForAsset(localAsset).then((e) => e?.getMediaUrl()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should just pass the list of local Ids to the native side and fetch the media URLs with a single call to the MediaStore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method MediaStore.createTrashRequest(...) requires a list of Uri objects that refer to media files in the MediaStore.
If we pass a list of _id values to the native part of the code, we’ll also need to include the media type (Images, Video, Audio, Files, etc.) and construct the corresponding Uri using ContentUris.withAppendedId(...).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we’ll also need to include the media type (Images, Video, Audio, Files, etc.)

We can use the list of Ids to fetch the type from MediaStore and construct the Media URL, and trash the assets, all in a single call to the native side.

The current code goes through the list of assets, and for each of them, uses two future to fetch the media url, and then once all the futures from the list are resolved, we make one more native call to trash the assets

Copy link
Member

@shenlong-tanwen shenlong-tanwen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for working on this. The changes looks great, only few pending comments to be resolved and we can get this merged.

BTW, Can you also fix the failing lint? You've to format the file before pushing them

@PeterOmbodi
Copy link
Contributor Author

Hi @shenlong-tanwen, I’ve pushed the fixes for the pending comments and lint errors.
When you have some time, could you please continue the review?

Copy link
Member

@shenlong-tanwen shenlong-tanwen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with how this looks. Just some minor nitpicks. I'll get this tested today or tomorrow and we can get this merged! Thanks a lot for working on this and apologies for not getting back sooner

@shenlong-tanwen
Copy link
Member

@PeterOmbodi I did some testing and faced the following issue during my testing:

  • When I restore a mix of merged and remote only assets after trashing them, the local part of the merged assets are properly restored, however, the sync gets stuck and never completes. Can you check this?

@PeterOmbodi
Copy link
Contributor Author

PeterOmbodi commented Aug 28, 2025

@PeterOmbodi I did some testing and faced the following issue during my testing:

  • When I restore a mix of merged and remote only assets after trashing them, the local part of the merged assets are properly restored, however, the sync gets stuck and never completes. Can you check this?

@shenlong-tanwen I’ll pull the latest changes from main and check - hopefully that fixes it.
upd: I was seeing some sync errors in the logs before updating (unrelated to this feature), but with the latest sync code they’re gone. Seems the issues were due to my branch being based on outdated code.

@shenlong-tanwen shenlong-tanwen self-assigned this Aug 29, 2025
@alextran1502
Copy link
Member

Hi @PeterOmbodi, thank you for bringing the PR to the finished line. I just tested the PR I notice one possible bug. You can recreate follow the steps below

  • Be on the beta timeline
  • On web, move asset to trash
  • Open the mobile app, make sure that they are synced, and the asset is in the trash. Check the local gallery to make sure they are in the system's trash as well
  • On web, restore the asset
  • Open the mobile app from the background, and you will see the sync indicator never finishes. You will have to force-kill the app and reopen it to see the restored assets

Peter Ombodi added 2 commits November 7, 2025 15:56
@alextran1502 alextran1502 enabled auto-merge (squash) November 10, 2025 15:41
@alextran1502 alextran1502 merged commit 493cde9 into immich-app:main Nov 10, 2025
51 checks passed
This was referenced Nov 12, 2025
alexlebens pushed a commit to alexlebens/infrastructure that referenced this pull request Nov 24, 2025
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/immich-app/immich-machine-learning](https://github.com/immich-app/immich) | minor | `v2.2.3` -> `v2.3.1` |
| [ghcr.io/immich-app/immich-server](https://github.com/immich-app/immich) | minor | `v2.2.3` -> `v2.3.1` |

---

### Release Notes

<details>
<summary>immich-app/immich (ghcr.io/immich-app/immich-machine-learning)</summary>

### [`v2.3.1`](https://github.com/immich-app/immich/releases/tag/v2.3.1)

[Compare Source](immich-app/immich@v2.3.0...v2.3.1)

##### v2.3.1

##### Hot fixes

Fixed an issue where the new version notification pop-up causes the web app to enter a rendering loop and freeze up.

> \[!IMPORTANT]
> We encourage all users to update to this version to avoid the issue that will happen when the next minor update is available, i.e., `v2.4.0`

##### What's Changed

##### 🐛 Bug fixes

- fix: supporter badge by [@&#8203;jrasm91](https://github.com/jrasm91) in [#&#8203;24012](immich-app/immich#24012)
- fix: new update notification cause rendering loop by [@&#8203;alextran1502](https://github.com/alextran1502) in [#&#8203;24013](immich-app/immich#24013)

**Full Changelog**: <immich-app/immich@v2.3.0...v2.3.1>

### [`v2.3.0`](https://github.com/immich-app/immich/releases/tag/v2.3.0)

[Compare Source](immich-app/immich@v2.2.3...v2.3.0)

##### v2.3.0

*Loa loa loa, the stock is running low on [Retro DVD ](https://immich.store/products/immich-retro)**📀**! If you want to get one for yourself, you still can, but once this batch is gone, we won’t be making any more, **EVER!** So get one while you can from [immich.store](https://immich.store/)!*

<img  alt="image" src="https://github.com/user-attachments/assets/f5977e5f-aabe-4c7a-a8d3-ee44b43b0f15" />

> \[!IMPORTANT]\
> We will start the work on removing the old mobile timeline soon. If you are still using the old timeline, please make sure to switch to the new timeline. If this message does not make sense to you, you can ignore it as you are already on the new timeline

##### Highlights

Welcome to the release `v2.3.0` of Immich. This version comes with enhancements to the OCR feature and many bug fixes. This release also introduces foundational support for workflows and an application restore mechanism directly in the web UI. Let’s dive into some of the highlights below

- OCR Improvements
- Add/move action in mobile app
- Delete synchronization - Android
- Notable fixes: app freezes on resume on iOS
- Sneak peek: Maintenance mode and workflow

##### Add/move action in mobile app

The asset viewer in the mobile app now includes an “Add to” button that lets you quickly add an asset to an album, the locked folder, or the archive. Thanks [@&#8203;happychriss](https://github.com/happychriss)!

<p align="center">
<img width="300"  alt="Tapping the Add to button presents a menu to add/move an asset" src="https://github.com/user-attachments/assets/21327e0b-ae5f-43b2-9f44-b75655895852" />
</p>

##### OCR Improvement

This release includes several enhancements to the OCR feature. There are now language-specific OCR model variants, extending support to Greek, Korean, Russian, Belarusian, Ukrainian, Thai, and languages using the Latin script. All variants (including the existing models) support English as well. There is also an English-only model that performs better for libraries where multilingual support is not needed.

To switch to one of these models, you can navigate to the [OCR settings](https://my.immich.app/admin/system-settings?isOpen=machine-learning+ocr), choose the relevant model, save, then re-run OCR on all assets through the [Job Status](https://my.immich.app/admin/jobs-status) page.

<p align="center">
<img width="800" alt="image" src="https://github.com/user-attachments/assets/86008221-4116-43d3-bd0d-f954e0e1a83a" />
</p>

The OCR information can now be viewed by toggling a button in the web viewer. You can hover the mouse over the text and copy it.

<p align="center">
<img width="500" alt="image" src="https://github.com/user-attachments/assets/693bcfd0-f4f0-40c1-a292-403b04166514" />
</p>

##### Delete synchronization on Android.

This release restores the previous mechanism for synchronizing the deletion action between the web and the mobile app. In addition to putting the asset in Immich’s trash bin, the mechanism also puts the deleted asset in the device’s trash system when the app opens. The mechanism has been reworked to align with the new data sync mechanism in the mobile app. You can enable the mechanism in the `App Settings > Advanced > Sync Remote Deletions`

<p align="center">
<img width="400" alt="image" src="https://github.com/user-attachments/assets/60d3f53d-a5f8-4235-944d-0e2e80040148" />
</p>

##### Notable fixes: app freezes on resume on iOS

Previously, iOS background tasks, such as local or remote data sync and background uploads, could abruptly terminate database operations when the iOS’s background time expires, leaving the database lock unreleased. It leads to an annoying symptom: the app appears to freeze when opening from the background, requiring a hard restart (swipe up to close, then reopen) to regain access to the database. The bug happened sporadically and was incredibly hard to track down. Thanks to the relentless pursuit of the bug, we believe it has been caught through our extensive testing. Please let us know if you are still getting “bugged” by this one in the new version.

##### Sneak peek: Maintenance mode and workflow

We can’t contain the excitement to share two exciting items in the work, which have some portions already merged into the server, and are ready to be built upon

##### Maintenance mode

This mode will allow the admin to put the server into a state where no one can access it without entirely shutting it down. This paves the way for restoring the server from a previous point in time directly from the web UI, no more fidgeting with the terminal.

<https://github.com/user-attachments/assets/26aa5f7f-5e5f-45b5-aa89-347325f10f41>

##### Workflow

The foundation of workflows and plugins also made its way to the server; the UI is being worked on. This feature will enable many more custom use cases that are not available in the core application. The community can write custom plugins and share them. We are very excited to see this happening faster than anticipated. Below is a screenshot of how the feature could look.

<p align="center">
<img width="600" height="4574" alt="image" src="https://github.com/user-attachments/assets/c0fccc92-6d9b-41e9-b271-574568425ba3" />

<img width="600" height="1822" alt="image" src="https://github.com/user-attachments/assets/c8991763-cd45-4c1e-90ad-5a1179eef789" />
</p>

##### What's Changed
##### 🚀 Features
* feat: Add random memories resource by @&#8203;jpg0 in immich-app/immich#20025
* feat(mobile): Quick date picker in the search page by @&#8203;exelix11 in immich-app/immich#22653
* feat: workflow foundation by @&#8203;alextran1502 in immich-app/immich#23621
* feat(mobile): add to album from asset viewer by @&#8203;happychriss in immich-app/immich#23608
* feat: maintenance mode by @&#8203;insertish in immich-app/immich#23431
* feat(mobile): location edit from asset viewer by @&#8203;bwees in immich-app/immich#23925
* feat: timeline e2e tests by @&#8203;midzelis in immich-app/immich#23895
* feat: show OCR bounding box by @&#8203;alextran1502 in immich-app/immich#23717

##### 🌟 Enhancements
* fix(web): add URLs to results in large files utility by @&#8203;Snowknight26 in immich-app/immich#23617
* feat(ml): add preload and fp16 settings for ocr by @&#8203;mertalev in immich-app/immich#23576
* feat(ml): multilingual ocr by @&#8203;mertalev in immich-app/immich#23527
* feat(mobile): Show lens model information in the asset viewer detail panel  by @&#8203;fabianbees in immich-app/immich#23601
* feat: lazy load thumbnails on people and place list by @&#8203;lukashass in immich-app/immich#23682
* feat: make memories slideshow duration configurable by @&#8203;meesfrensel in immich-app/immich#22783
* feat(mobile): chat-style for asset activity view by @&#8203;idubnori in immich-app/immich#23347
* feat: show update version info by @&#8203;alextran1502 in immich-app/immich#23698
* feat(mobile): album activity deep link by @&#8203;idubnori in immich-app/immich#23737
* feat(web): animate gifs on hover by @&#8203;meesfrensel in immich-app/immich#23198
* feat(web): disable searching by disabled features by @&#8203;meesfrensel in immich-app/immich#23798
* feat: library details page by @&#8203;danieldietzler in immich-app/immich#23908
* feat(web): always view original of animated images by @&#8203;meesfrensel in immich-app/immich#23842
* feat: add originalPath for external library assets in dedupe by @&#8203;kprkpr in immich-app/immich#23710

##### 🐛 Bug fixes
* feat: exif medium tests by @&#8203;jrasm91 in immich-app/immich#23561
* fix(web): fix timezone dropdown for timestamps lacking milliseconds by @&#8203;skatsubo in immich-app/immich#23615
* fix(web): "select all" button in trash and permanently deleted count by @&#8203;Yonyc in immich-app/immich#23594
* fix: fully sync local library on app restart by @&#8203;alextran1502 in immich-app/immich#23323
* fix: check if unmetered instead of wifi by @&#8203;shenlong-tanwen in immich-app/immich#23380
* fix(mobile): Add fade-in to asset viewer transition by @&#8203;goalie2002 in immich-app/immich#23692
* fix(web): i18n for admin>users>sessions by @&#8203;meesfrensel in immich-app/immich#23756
* feat: opt-in sync of deletes and restores from web to Android (beta timeline) by @&#8203;PeterOmbodi in immich-app/immich#20473
* fix(mobile): Set dynamic height of actions row in BottomSheet by @&#8203;vitoksmile in immich-app/immich#23755
* fix(mobile): Hide download button in asset viewer "immersive mode" by @&#8203;goalie2002 in immich-app/immich#23720
* fix(mobile): sync album and asset activity state when add/remove asset level activity by @&#8203;idubnori in immich-app/immich#23484
* fix(server): properly handle HEAD requests to SSR paths by @&#8203;dav-wolff in immich-app/immich#23788
* fix(web): make sliding window cover all visible space to show small number of assets by @&#8203;meesfrensel in immich-app/immich#23796
* refactor: shared links modals by @&#8203;danieldietzler in immich-app/immich#23803
* chore: bump background_downloader by @&#8203;shenlong-tanwen in immich-app/immich#23839
* fix(server): include the previous year in memories for January 1, 2, 3 by @&#8203;skatsubo in immich-app/immich#23832
* fix: timeline scroll after navigate by @&#8203;danieldietzler in immich-app/immich#23664
* fix: prefer filename from body over path in mime validation by @&#8203;shenlong-tanwen in immich-app/immich#23810
* fix(web): keep album timeline when selecting cover by @&#8203;roadev in immich-app/immich#23819
* fix: word wrap on custom link preview by @&#8203;100daysummer in immich-app/immich#23942
* fix(mobile): delete from device warning shows incorrectly by @&#8203;YarosMallorca in immich-app/immich#23935
* fix: deep link to last asset by @&#8203;midzelis in immich-app/immich#23920
* fix: null dereference when canceling bucket in album by @&#8203;midzelis in immich-app/immich#23924
* fix: incorrect header height calculation in estimated month height by @&#8203;midzelis in immich-app/immich#23923
* chore: update drift by @&#8203;alextran1502 in immich-app/immich#23877
* chore: reset remote sync on app update by @&#8203;shenlong-tanwen in immich-app/immich#23969
* fix(server): copy relevant panorama tags to preview image by @&#8203;meesfrensel in immich-app/immich#23953
* fix: unarchive action doesn't update archive page by @&#8203;midzelis in immich-app/immich#23987

##### 📚 Documentation
* chore: update config.json example by @&#8203;bo0tzz in immich-app/immich#23471
* fix(docs): bump docs for PG versions by @&#8203;mmomjian in immich-app/immich#23714
* feat: endpoint descriptions by @&#8203;jrasm91 in immich-app/immich#23813
* feat: endpoint versioning by @&#8203;jrasm91 in immich-app/immich#23858
* chore: include link to discord server when referencing contribution channel by @&#8203;Hritik14 in immich-app/immich#23728
* fix(docs): update Readme links by @&#8203;mmomjian in immich-app/immich#23959

##### 🌐 Translations
* chore(web): update translations by @&#8203;weblate in immich-app/immich#23449

##### New Contributors
* @&#8203;FreeWind6 made their first contribution in immich-app/immich#23627
* @&#8203;Yonyc made their first contribution in immich-app/immich#23594
* @&#8203;fabianbees made their first contribution in immich-app/immich#23601
* @&#8203;exelix11 made their first contribution in immich-app/immich#22653
* @&#8203;AlexanderS made their first contribution in immich-app/immich#23838
* @&#8203;Hritik14 made their first contribution in immich-app/immich#23728
* @&#8203;roadev made their first contribution in immich-app/immich#23819
* @&#8203;zebrapurring made their first contribution in immich-app/immich#22145
* @&#8203;happychriss made their first contribution in immich-app/immich#23608
* @&#8203;insertish made their first contribution in immich-app/immich#23948
* @&#8203;100daysummer made their first contribution in immich-app/immich#23942
* @&#8203;kprkpr made their first contribution in immich-app/immich#23710

**Full Changelog**: <immich-app/immich@v2.2.3...v2.3.0>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi41LjAiLCJ1cGRhdGVkSW5WZXIiOiI0Mi41LjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbImltYWdlIl19-->

Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/2112
Co-authored-by: Renovate Bot <[email protected]>
Co-committed-by: Renovate Bot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants