- 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.
108 lines
3.8 KiB
Swift
108 lines
3.8 KiB
Swift
//
|
|
// SharedImageUtility.swift
|
|
// App
|
|
//
|
|
// Shared utility for accessing shared image data from App Group container
|
|
// Images are stored as files in the App Group container to avoid UserDefaults size limits
|
|
// Used by both AppDelegate and SharedImagePlugin
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public class SharedImageUtility {
|
|
private static let appGroupIdentifier = "group.app.timesafari"
|
|
private static let sharedPhotoFileNameKey = "sharedPhotoFileName"
|
|
private static let sharedPhotoFilePathKey = "sharedPhotoFilePath"
|
|
private static let sharedPhotoReadyKey = "sharedPhotoReady"
|
|
|
|
/// Get the App Group container URL for accessing shared files
|
|
private static var appGroupContainerURL: URL? {
|
|
return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
|
|
}
|
|
|
|
/**
|
|
* Get shared image data from App Group container file
|
|
* All images are stored as files for consistency and to avoid UserDefaults size limits
|
|
* Clears the data after reading to prevent re-reading
|
|
*
|
|
* @returns Dictionary with "base64" and "fileName" keys, or nil if no shared image
|
|
*/
|
|
static func getSharedImageData() -> [String: String]? {
|
|
guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier) else {
|
|
return nil
|
|
}
|
|
|
|
// Get file path and filename from UserDefaults
|
|
guard let filePath = userDefaults.string(forKey: sharedPhotoFilePathKey),
|
|
let containerURL = appGroupContainerURL else {
|
|
return nil
|
|
}
|
|
|
|
let fileName = userDefaults.string(forKey: sharedPhotoFileNameKey) ?? "shared-image.jpg"
|
|
let fileURL = containerURL.appendingPathComponent(filePath)
|
|
|
|
// Read image data from file
|
|
guard let imageData = try? Data(contentsOf: fileURL) else {
|
|
return nil
|
|
}
|
|
|
|
// Convert file data to base64 for JavaScript consumption
|
|
let base64String = imageData.base64EncodedString()
|
|
|
|
// Clear the shared data after reading
|
|
userDefaults.removeObject(forKey: sharedPhotoFilePathKey)
|
|
userDefaults.removeObject(forKey: sharedPhotoFileNameKey)
|
|
|
|
// Remove the file
|
|
try? FileManager.default.removeItem(at: fileURL)
|
|
|
|
userDefaults.synchronize()
|
|
|
|
return ["base64": base64String, "fileName": fileName]
|
|
}
|
|
|
|
/**
|
|
* Check if shared image exists without reading it
|
|
*
|
|
* @returns true if shared image file exists, false otherwise
|
|
*/
|
|
static func hasSharedImage() -> Bool {
|
|
guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier),
|
|
let filePath = userDefaults.string(forKey: sharedPhotoFilePathKey),
|
|
let containerURL = appGroupContainerURL else {
|
|
return false
|
|
}
|
|
|
|
let fileURL = containerURL.appendingPathComponent(filePath)
|
|
return FileManager.default.fileExists(atPath: fileURL.path)
|
|
}
|
|
|
|
/**
|
|
* Check if shared photo ready flag is set
|
|
* This flag is set by the Share Extension when image is ready
|
|
*
|
|
* @returns true if flag is set, false otherwise
|
|
*/
|
|
static func isSharedPhotoReady() -> Bool {
|
|
guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier) else {
|
|
return false
|
|
}
|
|
|
|
return userDefaults.bool(forKey: sharedPhotoReadyKey)
|
|
}
|
|
|
|
/**
|
|
* Clear the shared photo ready flag
|
|
* Called after processing the shared image
|
|
*/
|
|
static func clearSharedPhotoReadyFlag() {
|
|
guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier) else {
|
|
return
|
|
}
|
|
|
|
userDefaults.removeObject(forKey: sharedPhotoReadyKey)
|
|
userDefaults.synchronize()
|
|
}
|
|
}
|
|
|