Remove JPEG conversion and preserve original image formats and filenames
to test support for all image file types. Refactor image processing logic
for clarity and maintainability.
Changes:
- Remove forced JPEG conversion (was using 0.9 compression quality)
- Preserve original filename extensions instead of forcing .jpg
- Refactor from 3 branches to 2 (removed unlikely UIImage branch)
- Replace if statement with guard for non-image attachment filtering
- Simplify error check from optional binding to nil check
- Extract filename extension helper method to reduce duplication
- Update default filename from "shared-image.jpg" to "shared-image"
The only conversion that may occur is to PNG (lossless) when raw data
cannot be read from a file URL, preserving image quality while ensuring
compatibility.
- Fix large images not loading from share sheet (exceeded UserDefaults 4MB limit)
- Store all shared images as files in App Group container instead of base64 in UserDefaults
- Fix image refresh when sharing new image while already on SharedPhotoView
- Add route query watcher to detect _refresh parameter changes
- Remove debug logging and redundant UIImage check
The previous implementation tried to store base64-encoded images in UserDefaults,
which failed for large images (HEIF images were often 6MB+ when base64 encoded). Now all images
are stored as files in the App Group container, with only the file path stored
in UserDefaults. This supports images of any size and provides consistent
behavior regardless of format.
Also fixes an issue where sharing a new image while already viewing
SharedPhotoView wouldn't refresh the displayed image.
Fix share extension not appearing in share sheet on iOS 18.6 and earlier
versions by updating deployment target and resolving API availability issues.
Changes:
- Update share extension deployment target from 26.1 to 14.0
- iOS 18.6 cannot use extensions requiring iOS 26.1
- UTType API requires iOS 14.0+ (used in ShareViewController)
- Update share extension display name from "TimeSafariShareExtension" to
"TimeSafari" for cleaner appearance in share sheet
- Fix compiler warning: replace unused error binding with boolean check
(if let error = error → if error != nil)
The share extension now works on iOS 14.0+ (matching UTType requirements)
and displays properly in the share sheet on older iOS versions.
Improve iOS share extension implementation to skip interstitial UI and
fix issues with subsequent image shares not updating the view.
iOS Share Extension Improvements:
- Replace SLComposeServiceViewController with custom UIViewController
to eliminate interstitial "Post" button UI
- Use minimal URL (timesafari://) instead of deep link for app launch
- Implement app lifecycle detection via Capacitor appStateChange listener
instead of relying solely on deep links
Deep Link and Navigation Fixes:
- Remove "shared-photo" from deep link schemas (no longer needed)
- Add empty path URL handling for share extension launches
- Implement processing lock to prevent duplicate image processing
- Add retry mechanism (300ms delay) to handle race conditions with
AppDelegate writing temp files
- Use router.replace() when already on /shared-photo route to force refresh
- Clear old images from temp DB before storing new ones
- Delete temp file immediately after reading to prevent stale data
SharedPhotoView Component:
- Add route watcher (@Watch) to reload image when fileName query
parameter changes
- Extract image loading logic into reusable loadSharedImage() method
- Improve error handling to clear image state on failures
This fixes the issue where sharing a second image while already on
SharedPhotoView would display the previous image instead of the new one.
Implement iOS Share Extension to enable native image sharing from Photos
and other apps directly into TimeSafari. Users can now share images from
the iOS share sheet, which will open in SharedPhotoView for use as gifts
or profile pictures.
iOS Native Implementation:
- Add TimeSafariShareExtension target with ShareViewController
- Configure App Groups for data sharing between extension and main app
- Implement ShareViewController to process shared images and convert to base64
- Store shared image data in App Group UserDefaults
- Add ShareImageBridge utility to read shared data from App Group
- Update AppDelegate to handle shared-photo deep link and bridge data to JS
JavaScript Integration:
- Add checkAndStoreNativeSharedImage() in main.capacitor.ts to read shared
images from native layer via temporary file bridge
- Convert base64 data to data URL format for compatibility with base64ToBlob
- Integrate with existing SharedPhotoView component
- Add "shared-photo" to deep link validation schema
Build System:
- Integrate Xcode 26 / CocoaPods compatibility workaround into build-ios.sh
- Add run_pod_install_with_workaround() for explicit pod install
- Add run_cap_sync_with_workaround() for Capacitor sync (which runs pod
install internally)
- Automatically detect project format version 70 and apply workaround
- Remove standalone pod-install-workaround.sh script
Code Cleanup:
- Remove verbose debug logs from ShareViewController, AppDelegate, and
main.capacitor.ts
- Retain essential logger calls for production debugging
Documentation:
- Add ios-share-extension-setup.md with manual Xcode setup instructions
- Add ios-share-extension-git-commit-guide.md for version control best practices
- Add ios-share-implementation-status.md tracking implementation progress
- Add native-share-target-implementation.md with overall architecture
- Add xcode-26-cocoapods-workaround.md documenting the compatibility issue
The implementation uses a temporary file bridge (AppDelegate writes to Documents
directory, JS reads via Capacitor Filesystem plugin) as a workaround for
Capacitor plugin auto-discovery issues. This can be improved in the future by
properly registering ShareImagePlugin in Capacitor's plugin registry.