feat: add image sharing from external apps#435
feat: add image sharing from external apps#435torlando-tech merged 6 commits intotorlando-tech:mainfrom
Conversation
Greptile OverviewGreptile SummaryImplements external image sharing from Gallery, Camera, and other apps into Columba conversations. Single images are loaded into the composer for manual sending; multiple images trigger a single quality selection dialog followed by automatic compression and individual message sending for each image. Key Implementation:
Issues Found:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant ExtApp as External App
participant Intent as MainActivityIntentHandler
participant SIV as SharedImageViewModel
participant Nav as Navigation
participant Chat as ChatsScreen
participant Msg as MessagingScreen
participant MVM as MessagingViewModel
participant Dialog as ImageQualityDialog
ExtApp->>Intent: Share image(s) via ACTION_SEND/SEND_MULTIPLE
Intent->>Intent: Extract URI(s) from intent
Intent->>Nav: Set PendingNavigation.SharedImage
Nav->>SIV: setImages(uris)
Nav->>Chat: Navigate to ChatsScreen
Note over Chat: User selects conversation
Chat->>SIV: assignToDestination(destHash)
Chat->>Msg: Navigate to MessagingScreen
alt Single Image
Msg->>SIV: consumeForDestination(destHash)
SIV-->>Msg: Return single URI
Msg->>MVM: processImageWithCompression(uri)
MVM->>Dialog: Show quality dialog
Dialog->>MVM: selectImageQuality(preset)
MVM->>MVM: Compress & attach to composer
Note over Msg: User manually sends
else Multiple Images
Msg->>SIV: consumeForDestination(destHash)
SIV-->>Msg: Return multiple URIs
Msg->>MVM: processSharedImages(uris, destHash)
MVM->>MVM: Store in pendingSharedImageUris
MVM->>Dialog: Show quality dialog (first image preview)
Dialog->>MVM: selectImageQualityForSharedImages(preset)
MVM->>MVM: Compress & send each image automatically
end
Last reviewed commit: d409063 |
| private val _qualitySelectionState = MutableStateFlow<QualitySelectionState?>(null) | ||
| val qualitySelectionState: StateFlow<QualitySelectionState?> = _qualitySelectionState.asStateFlow() | ||
|
|
||
| // Multi-image share state: URIs pending compression+send after quality selection | ||
| private var pendingSharedImageUris: List<Uri> = emptyList() | ||
| private var pendingSharedImageDestHash: String? = null | ||
|
|
||
| // Expose current conversation's link state for UI |
There was a problem hiding this comment.
Shared-image state can be overwritten
pendingSharedImageUris/pendingSharedImageDestHash are plain mutable vars used to bridge between processSharedImages() and the quality dialog confirmation. If a second share intent (or another multi-image flow) starts while the dialog is still open, processSharedImages() overwrites these vars, so confirming the dialog can send the wrong set of images and/or send to the wrong destination.
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/com/lxmf/messenger/viewmodel/MessagingViewModel.kt
Line: 207:214
Comment:
**Shared-image state can be overwritten**
`pendingSharedImageUris`/`pendingSharedImageDestHash` are plain mutable vars used to bridge between `processSharedImages()` and the quality dialog confirmation. If a second share intent (or another multi-image flow) starts while the dialog is still open, `processSharedImages()` overwrites these vars, so confirming the dialog can send the wrong set of images and/or send to the wrong destination.
How can I resolve this? If you propose a fix, please make it concise.
Additional Comments (1)
Also triggered from Prompt To Fix With AIThis is a comment left during a code review.
Path: app/src/main/java/com/lxmf/messenger/viewmodel/MessagingViewModel.kt
Line: 1423:1426
Comment:
**Wrong conversation link state**
`processSharedImages()` (multi-share) calls `processImageWithCompression()`, but `processImageWithCompression()` opens the conversation link and derives recommendations from `_currentConversation`/`currentLinkState` (not the `destinationHash` passed to `processSharedImages`). If the user shares images into a different chat than the currently-open conversation (or none), the quality recommendations/transfer estimates and link probing can be for the wrong peer.
Also triggered from `processSharedImages()` at MessagingViewModel.kt:1536-1547.
How can I resolve this? If you propose a fix, please make it concise. |
0351014 to
63e1ebe
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
63e1ebe to
e1baf98
Compare
app/src/main/java/com/lxmf/messenger/viewmodel/MessagingViewModel.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/lxmf/messenger/viewmodel/MessagingViewModel.kt
Outdated
Show resolved
Hide resolved
Move _isSending flag from per-image sendImageMessageDirect() to the caller loop in selectImageQualityForSharedImages(), so it stays true for the entire batch instead of toggling per image.
- Eagerly copy shared content URIs to temp files in incoming_shares/ to survive Activity recreation and permission revocation (critical) - Add SharedImageViewModel.onCleared() cleanup for unconsumed temp files - Hoist pendingSharedText/pendingSharedImages above LazyColumn in ChatsScreen - Append " each" to transfer time estimates when sharing multiple images - Add sharedImageError SharedFlow + Toast for compression failures - Add clarifying comments on plain vars and LaunchedEffect ordering - Fix FQN: List<android.net.Uri> -> List<Uri> in PendingNavigation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9fb3940 to
2f96848
Compare
…test MessagingScreenTest: stub sharedImageError and recentPhotos added by the image sharing feature — Compose collected these from the relaxed mock, causing KotlinNothingValueException in all tests that render the screen. OfflineMapDownloadViewModelTest: replace Turbine awaitItem() with direct state.value assertion in nextStep LOCATION→RADIUS test to avoid races with init-block coroutine emissions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Add support for sharing images from external apps (Gallery, Camera, etc.) into Columba. Users can share one or multiple images, select a destination conversation, and send them.
Features
ACTION_SEND): Image is loaded into the composer with quality selection dialog, user sends manuallyACTION_SEND_MULTIPLE): Single quality selection dialog, then all images are automatically compressed and sent as individual messagesChanges
ACTION_SENDandACTION_SEND_MULTIPLEwithimage/*mimeTypePendingNavigation.SharedImagefor navigation after image shareimageCountparameter to show "Send N Images" title in multi-image modeTesting