Small cleanups on imagePicker code

pull/23155/head
ttmx 2025-10-22 17:28:57 +07:00
parent 1ef4fcbb10
commit 162682ef8b
2 changed files with 79 additions and 80 deletions

@ -14,6 +14,7 @@ import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import java.io.File
/**
* Activity that handles ACTION_GET_CONTENT and ACTION_PICK intents
* Communicates with Flutter to get the selected image URI
@ -25,7 +26,7 @@ class ImagePickerActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate() called")
super.onCreate(savedInstanceState)
val action = intent.action
val type = intent.type
@ -36,7 +37,7 @@ class ImagePickerActivity : FlutterActivity() {
} else {
// Invalid intent, finish immediately
Log.w(TAG, "Invalid intent action or type, finishing activity")
setResult(Activity.RESULT_CANCELED)
setResult(RESULT_CANCELED)
finish()
}
Log.d(TAG, "onCreate() finished")
@ -45,17 +46,17 @@ class ImagePickerActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
Log.d(TAG, "configureFlutterEngine() called, hasRequestedImage = $hasRequestedImage")
super.configureFlutterEngine(flutterEngine)
// Register all plugins
Log.d(TAG, "Registering plugins...")
MainActivity.registerPlugins(this, flutterEngine)
Log.d(TAG, "Plugins registered")
// Set up the image picker API
Log.d(TAG, "Setting up ImagePickerProviderApi...")
imagePickerApi = ImagePickerProviderApi(flutterEngine.dartExecutor.binaryMessenger)
Log.d(TAG, "ImagePickerProviderApi set up: ${imagePickerApi != null}")
Log.d(TAG, "ImagePickerProviderApi set up: ${true}")
// Check if this is a valid image picker intent and we haven't requested yet
val action = intent.action
if (!hasRequestedImage && (action == Intent.ACTION_GET_CONTENT || action == Intent.ACTION_PICK)) {
@ -63,7 +64,10 @@ class ImagePickerActivity : FlutterActivity() {
hasRequestedImage = true
requestImageFromFlutter()
} else {
Log.w(TAG, "NOT calling requestImageFromFlutter() - hasRequestedImage: $hasRequestedImage, action: $action")
Log.w(
TAG,
"NOT calling requestImageFromFlutter() - hasRequestedImage: $hasRequestedImage, action: $action"
)
}
Log.d(TAG, "configureFlutterEngine() finished")
}
@ -71,82 +75,77 @@ class ImagePickerActivity : FlutterActivity() {
private fun requestImageFromFlutter() {
Log.d(TAG, "=== requestImageFromFlutter() CALLED ===")
Log.d(TAG, "imagePickerApi is null: ${imagePickerApi == null}")
// Check if the calling app allows multiple selection
val allowMultiple = intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)
Log.d(TAG, "Intent allows multiple selection: $allowMultiple")
imagePickerApi?.pickImagesForIntent { result ->
Log.d(TAG, "pickImagesForIntent callback received")
result.fold(
onSuccess = { imageUriList ->
Log.d(TAG, "SUCCESS: Received ${imageUriList?.size ?: 0} image URI(s) from Flutter")
if (imageUriList.isNullOrEmpty()) {
// User cancelled or no images selected
Log.d(TAG, "No images selected, returning RESULT_CANCELED")
setResult(Activity.RESULT_CANCELED)
result.fold(onSuccess = { imageUriList ->
Log.d(TAG, "SUCCESS: Received ${imageUriList?.size ?: 0} image URI(s) from Flutter")
if (imageUriList.isNullOrEmpty()) {
// User cancelled or no images selected
Log.d(TAG, "No images selected, returning RESULT_CANCELED")
setResult(RESULT_CANCELED)
finish()
return@fold
}
try {
// Convert all URIs to content URIs
val contentUris = imageUriList.filterNotNull().map { uriString ->
try {
convertToContentUri(uriString)
} catch (e: Exception) {
Log.e(TAG, "Error converting URI: $uriString", e)
null
}
}
if (contentUris.isEmpty()) {
Log.e(TAG, "No valid content URIs after conversion")
setResult(RESULT_CANCELED)
finish()
return@fold
}
try {
// Convert all URIs to content URIs
val contentUris = imageUriList.mapNotNull { uriString ->
uriString?.let {
try {
convertToContentUri(it)
} catch (e: Exception) {
Log.e(TAG, "Error converting URI: $it", e)
null
}
}
}
if (contentUris.isEmpty()) {
Log.e(TAG, "No valid content URIs after conversion")
setResult(Activity.RESULT_CANCELED)
finish()
return@fold
}
val resultIntent = Intent()
if (contentUris.size == 1 || !allowMultiple) {
// Single image or app doesn't support multiple
Log.d(TAG, "Returning single image URI: ${contentUris.first()}")
resultIntent.data = contentUris.first()
} else {
// Multiple images - use ClipData
Log.d(TAG, "Returning ${contentUris.size} images using ClipData")
val clipData = ClipData.newUri(contentResolver, "Images", contentUris.first())
// Add the rest of the URIs to ClipData
for (i in 1 until contentUris.size) {
clipData.addItem(ClipData.Item(contentUris[i]))
}
resultIntent.clipData = clipData
resultIntent.data = contentUris.first() // Also set primary URI for compatibility
val resultIntent = Intent()
if (contentUris.size == 1 || !allowMultiple) {
// Single image or app doesn't support multiple
Log.d(TAG, "Returning single image URI: ${contentUris.first()}")
resultIntent.data = contentUris.first()
} else {
// Multiple images - use ClipData
Log.d(TAG, "Returning ${contentUris.size} images using ClipData")
val clipData = ClipData.newUri(contentResolver, "Images", contentUris.first())
// Add the rest of the URIs to ClipData
for (i in 1 until contentUris.size) {
clipData.addItem(ClipData.Item(contentUris[i]))
}
// Grant temporary read permission to all URIs
resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
setResult(Activity.RESULT_OK, resultIntent)
finish()
} catch (e: Exception) {
Log.e(TAG, "Error processing URIs", e)
setResult(Activity.RESULT_CANCELED)
finish()
resultIntent.clipData = clipData
resultIntent.data = contentUris.first() // Also set primary URI for compatibility
}
},
onFailure = { error ->
Log.e(TAG, "Error getting images from Flutter", error)
setResult(Activity.RESULT_CANCELED)
// Grant temporary read permission to all URIs
resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
setResult(RESULT_OK, resultIntent)
finish()
} catch (e: Exception) {
Log.e(TAG, "Error processing URIs", e)
setResult(RESULT_CANCELED)
finish()
}
)
}, onFailure = { error ->
Log.e(TAG, "Error getting images from Flutter", error)
setResult(RESULT_CANCELED)
finish()
})
}
}
@ -156,13 +155,11 @@ class ImagePickerActivity : FlutterActivity() {
*/
private fun convertToContentUri(uriString: String): Uri {
val uri = uriString.toUri()
return if (uri.scheme == "file") {
val file = File(uri.path!!)
FileProvider.getUriForFile(
this,
"${applicationContext.packageName}.fileprovider",
file
this, "${applicationContext.packageName}.fileprovider", file
)
} else {
// Already a content URI or other type
@ -172,7 +169,7 @@ class ImagePickerActivity : FlutterActivity() {
override fun getCachedEngineId(): String? {
// Try to use the cached engine if available
val hasCachedEngine = FlutterEngineCache.getInstance().contains("immich_engine")
val hasCachedEngine = FlutterEngineCache.getInstance().contains(ENGINE_CACHE_KEY)
Log.d(TAG, "getCachedEngineId() called, has cached engine: $hasCachedEngine")
return if (hasCachedEngine) {
Log.d(TAG, "Using cached engine 'immich_engine'")
@ -182,22 +179,22 @@ class ImagePickerActivity : FlutterActivity() {
null
}
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart() called")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume() called")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause() called")
}
override fun onDestroy() {
Log.d(TAG, "onDestroy() called")
super.onDestroy()
@ -205,5 +202,7 @@ class ImagePickerActivity : FlutterActivity() {
companion object {
private const val TAG = "ImagePickerActivity"
const val ENGINE_CACHE_KEY = "immich::image_picker::engine"
}
}

@ -56,7 +56,7 @@ class ImagePickerProviderService implements ImagePickerProviderApi {
dPrint(() => "User selected ${selectedAssets.length} asset(s)");
// Process all selected assets
final List<String?> imageUris = [];
final List<String> imageUris = [];
for (final asset in selectedAssets) {
dPrint(() => "Processing asset: ${asset.runtimeType}");