Skip to content

feat: use immich as an image provider#23155

Draft
ttmx wants to merge 5 commits intoimmich-app:mainfrom
ttmx:image-provider
Draft

feat: use immich as an image provider#23155
ttmx wants to merge 5 commits intoimmich-app:mainfrom
ttmx:image-provider

Conversation

@ttmx
Copy link

@ttmx ttmx commented Oct 22, 2025

Hi! I want to use immich to select images for twitter and reddit, but it is not doable currently as you cannot share an image from immich to a specific reply.

I'm adding the foundations for this feature by adding the ACTION_GET_CONTENT intent and basic replies to it.

The code has heavy LLM usage, so I would kindly request an extra tough code review.

Currently the code fetches the first image on your timeline when you select immich as your image provider when using the system picker to pick an image and does not allow you to select one.
Currently the code uses DriftAssetSelectionTimelinePage to allow you to select an image, but this widget allows you to select multiple images, which means only the first image gets sent to the original Intent. and can return multiple images. We do not show the user that they can only select a single image in some cases, and the interface has awkward multiple loading screens, likely from bad code.

The code likely has too many debug logs which I can fix if the feature seems promising.

@ttmx ttmx requested a review from shenlong-tanwen as a code owner October 22, 2025 12:07
@immich-push-o-matic
Copy link

immich-push-o-matic bot commented Oct 22, 2025

Label error. Requires exactly 1 of: changelog:.*. Found: 📱mobile. A maintainer will add the required label.

@ttmx ttmx changed the title Send first image in immich assets instead of static image Use immich as an image provider Oct 22, 2025
@danieldietzler danieldietzler marked this pull request as draft October 22, 2025 12:09
ttmx added 2 commits October 22, 2025 13:27
(It allows you to select multiple images and only returns the first one, needs fix)
Copy link
Author

@ttmx ttmx left a comment

Choose a reason for hiding this comment

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

The code is surprisingly okay, simple and short.
I left some questions on stuff that should be looked at as I am not sure on how it works.

</activity>

<!-- Image picker provider activity - handles ACTION_GET_CONTENT and ACTION_PICK -->
<activity
Copy link
Author

Choose a reason for hiding this comment

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

Standard intent boilerplate

android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />

<!-- FileProvider for sharing images with other apps -->
Copy link
Author

Choose a reason for hiding this comment

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

Standard file provider

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
Copy link
Author

Choose a reason for hiding this comment

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

Am uncertain if this is the best way to share files, does this look normal?


Log.d(TAG, "ImagePickerActivity started with action: $action, type: $type")

if ((action == Intent.ACTION_GET_CONTENT || action == Intent.ACTION_PICK)) {
Copy link
Author

Choose a reason for hiding this comment

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

Perhaps a bit weird to verify the intent in two different places?


override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
Log.d(TAG, "configureFlutterEngine() called, hasRequestedImage = $hasRequestedImage")
super.configureFlutterEngine(flutterEngine)
Copy link
Author

Choose a reason for hiding this comment

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

Do we need to override and manually setup configureFlutterEngine? Isn't there another place that already does this?

onFailure = { error ->
Log.e(TAG, "Error getting images from Flutter", error)
setResult(Activity.RESULT_CANCELED)
finish()
Copy link
Author

Choose a reason for hiding this comment

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

All looks good


override fun onStart() {
super.onStart()
Log.d(TAG, "onStart() called")
Copy link
Author

Choose a reason for hiding this comment

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

We don't need these many logs I think

initApp().then((_) => dPrint(() => "App Init Completed"));
WidgetsBinding.instance.addPostFrameCallback((_) {
// Initialize the image picker provider service for ACTION_GET_CONTENT handling
ref.read(imagePickerProviderServiceProvider);
Copy link
Author

Choose a reason for hiding this comment

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

Do we have to initialize it here? I think we should only init that service if we're actually retrieving an image through it.

}

/// Gets the URI for a single asset (local, merged, or remote)
Future<String?> _getAssetUri(BaseAsset asset) async {
Copy link
Author

Choose a reason for hiding this comment

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

Do we not have something similar somewhere else in the app? I feel like this might be duplicated


/// API for Android native to request an image from Flutter
@FlutterApi()
abstract class ImagePickerProviderApi {
Copy link
Author

Choose a reason for hiding this comment

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

Looks normal

@bwees bwees changed the title Use immich as an image provider feat: use immich as an image provider Feb 2, 2026
@alextran1502
Copy link
Member

There is WIP that doesn't use 100 LLM #26109

@ttmx
Copy link
Author

ttmx commented Feb 22, 2026

Hey Alex! This doesn't appear to be the same feature.
This PR implements GET_CONTENT/PICK intents, it's not for viewing external images on Immich. Unless I'm incorrectly interpreting the other PR incorrectly, it just implements VIEW.

@alextran1502
Copy link
Member

Ah OK, reopen for tracking

@alextran1502 alextran1502 reopened this Feb 22, 2026
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.

2 participants