diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/Thumbnails.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/Thumbnails.g.kt index 7dc61e1bdb..8d6b19beb9 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/Thumbnails.g.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/Thumbnails.g.kt @@ -15,9 +15,6 @@ import java.io.ByteArrayOutputStream import java.nio.ByteBuffer private object ThumbnailsPigeonUtils { - fun createConnectionError(channelName: String): FlutterError { - return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") } - fun wrapResult(result: Any?): List { return listOf(result) } @@ -98,30 +95,3 @@ interface ThumbnailApi { } } } -/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ -class PlatformThumbnailApi(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { - companion object { - /** The codec used by PlatformThumbnailApi. */ - val codec: MessageCodec by lazy { - ThumbnailsPigeonCodec() - } - } - fun getThumbnail(assetIdArg: String, widthArg: Long, heightArg: Long, callback: (Result) -> Unit) -{ - val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" - val channelName = "dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail$separatedMessageChannelSuffix" - val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(assetIdArg, widthArg, heightArg)) { - if (it is List<*>) { - if (it.size > 1) { - callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) - } else { - val output = it[0] as ByteArray? - callback(Result.success(output)) - } - } else { - callback(Result.failure(ThumbnailsPigeonUtils.createConnectionError(channelName))) - } - } - } -} diff --git a/mobile/ios/Runner/Images/Thumbnails.g.swift b/mobile/ios/Runner/Images/Thumbnails.g.swift index 9469a9c630..66475fbc1a 100644 --- a/mobile/ios/Runner/Images/Thumbnails.g.swift +++ b/mobile/ios/Runner/Images/Thumbnails.g.swift @@ -37,10 +37,6 @@ private func wrapError(_ error: Any) -> [Any?] { ] } -private func createConnectionError(withChannelName channelName: String) -> PigeonError { - return PigeonError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") -} - private func isNullish(_ value: Any?) -> Bool { return value is NSNull || value == nil } @@ -104,37 +100,3 @@ class ThumbnailApiSetup { } } } -/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. -protocol PlatformThumbnailApiProtocol { - func getThumbnail(assetId assetIdArg: String, width widthArg: Int64, height heightArg: Int64, completion: @escaping (Result) -> Void) -} -class PlatformThumbnailApi: PlatformThumbnailApiProtocol { - private let binaryMessenger: FlutterBinaryMessenger - private let messageChannelSuffix: String - init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { - self.binaryMessenger = binaryMessenger - self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - } - var codec: ThumbnailsPigeonCodec { - return ThumbnailsPigeonCodec.shared - } - func getThumbnail(assetId assetIdArg: String, width widthArg: Int64, height heightArg: Int64, completion: @escaping (Result) -> Void) { - let channelName: String = "dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail\(messageChannelSuffix)" - let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) - channel.sendMessage([assetIdArg, widthArg, heightArg] as [Any?]) { response in - guard let listResponse = response as? [Any?] else { - completion(.failure(createConnectionError(withChannelName: channelName))) - return - } - if listResponse.count > 1 { - let code: String = listResponse[0] as! String - let message: String? = nilOrValue(listResponse[1]) - let details: String? = nilOrValue(listResponse[2]) - completion(.failure(PigeonError(code: code, message: message, details: details))) - } else { - let result: FlutterStandardTypedData? = nilOrValue(listResponse[0]) - completion(.success(result)) - } - } - } -} diff --git a/mobile/ios/Runner/Images/ThumbnailsImpl.swift b/mobile/ios/Runner/Images/ThumbnailsImpl.swift index 937d021e68..ab3e674711 100644 --- a/mobile/ios/Runner/Images/ThumbnailsImpl.swift +++ b/mobile/ios/Runner/Images/ThumbnailsImpl.swift @@ -1,21 +1,23 @@ import CryptoKit import Flutter -import Photos import MobileCoreServices +import Photos // https://stackoverflow.com/a/55839062 extension UIImage { - func toData (options: NSDictionary?, type: ImageType) -> Data? { + func toData(options: NSDictionary?, type: ImageType) -> Data? { guard cgImage != nil else { return nil } return toData(options: options, type: type.value) } - + // about properties: https://developer.apple.com/documentation/imageio/1464962-cgimagedestinationaddimage - func toData (options: NSDictionary?, type: CFString) -> Data? { + func toData(options: NSDictionary?, type: CFString) -> Data? { guard let cgImage = cgImage else { return nil } return autoreleasepool { () -> Data? in let data = NSMutableData() - guard let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) else { return nil } + guard + let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) + else { return nil } CGImageDestinationAddImage(imageDestination, cgImage, options) CGImageDestinationFinalize(imageDestination) return data as Data @@ -23,21 +25,21 @@ extension UIImage { } enum ImageType { - case image // abstract image data - case jpeg // JPEG image - case jpeg2000 // JPEG-2000 image - case tiff // TIFF image - case pict // Quickdraw PICT format - case gif // GIF image - case png // PNG image - case quickTimeImage // QuickTime image format (OSType 'qtif') - case appleICNS // Apple icon data - case bmp // Windows bitmap - case ico // Windows icon data - case rawImage // base type for raw image data (.raw) - case scalableVectorGraphics // SVG image - case livePhoto // Live Photo - + case image // abstract image data + case jpeg // JPEG image + case jpeg2000 // JPEG-2000 image + case tiff // TIFF image + case pict // Quickdraw PICT format + case gif // GIF image + case png // PNG image + case quickTimeImage // QuickTime image format (OSType 'qtif') + case appleICNS // Apple icon data + case bmp // Windows bitmap + case ico // Windows icon data + case rawImage // base type for raw image data (.raw) + case scalableVectorGraphics // SVG image + case livePhoto // Live Photo + var value: CFString { switch self { case .image: return kUTTypeImage @@ -75,41 +77,10 @@ class ThumbnailApiImpl: ThumbnailApi { requestOptions.version = .current return requestOptions }() - private static let processingQueue = DispatchQueue(label: "thumbnail.processing", qos: .userInteractive, attributes: .concurrent) - private static let imageCache = NSCache() + private static let processingQueue = DispatchQueue( + label: "thumbnail.processing", qos: .userInteractive, attributes: .concurrent) - func requestThumbnail( - assetId: String, - width: Int64, - height: Int64, - completion: @escaping (Result) -> Void - ) { - Self.processingQueue.async { - do { - let asset = try self.getAsset(assetId: assetId) - - let requestId = Self.cacheManager.requestImage( - for: asset, - targetSize: CGSize(width: Double(width), height: Double(height)), - contentMode: .aspectFill, - options: Self.requestOptions, - resultHandler: { (image, info) -> Void in - guard let data = image?.toData(options: nil, type: .bmp) else { return } - Self.imageCache.setObject(FlutterStandardTypedData(bytes: data), forKey: assetId as NSString) - } - ) - completion(.success(requestId)) - } catch { - completion(.failure(PigeonError(code: "", message: "Could not get asset data", details: nil))) - } - } - } - - func getThumbnail(assetId assetIdArg: String, width widthArg: Int64, height heightArg: Int64, completion: @escaping (Result) -> Void) { - - } - - func sendThumbnail( + func getThumbnail( assetId: String, width: Int64, height: Int64, @@ -118,7 +89,7 @@ class ThumbnailApiImpl: ThumbnailApi { Self.processingQueue.async { do { let asset = try self.getAsset(assetId: assetId) - + Self.cacheManager.requestImage( for: asset, targetSize: CGSize(width: Double(width), height: Double(height)), @@ -130,15 +101,12 @@ class ThumbnailApiImpl: ThumbnailApi { } ) } catch { - completion(.failure(PigeonError(code: "", message: "Could not get asset data", details: nil))) + completion( + .failure(PigeonError(code: "", message: "Could not get asset data", details: nil))) } } } - func cancel(requestId: Int32) { - Self.cacheManager.cancelImageRequest(requestId as PHImageRequestID) - } - private func getAsset(assetId: String) throws -> PHAsset { guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: Self.fetchOptions) @@ -148,4 +116,9 @@ class ThumbnailApiImpl: ThumbnailApi { } return asset } + + // func cancel(requestId: Int32) { + // Self.cacheManager.cancelImageRequest(requestId as PHImageRequestID) + // } + } diff --git a/mobile/lib/platform/thumbnail_api.g.dart b/mobile/lib/platform/thumbnail_api.g.dart index 6158a4755d..279867223b 100644 --- a/mobile/lib/platform/thumbnail_api.g.dart +++ b/mobile/lib/platform/thumbnail_api.g.dart @@ -15,17 +15,6 @@ PlatformException _createConnectionError(String channelName) { ); } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { - if (empty) { - return []; - } - if (error == null) { - return [result]; - } - return [error.code, error.message, error.details]; -} - class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -97,54 +86,3 @@ class ThumbnailApi { } } } - -abstract class PlatformThumbnailApi { - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - Future getThumbnail(String assetId, int width, int height); - - static void setUp( - PlatformThumbnailApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail was null.'); - final List args = (message as List?)!; - final String? arg_assetId = (args[0] as String?); - assert(arg_assetId != null, - 'Argument for dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail was null, expected non-null String.'); - final int? arg_width = (args[1] as int?); - assert(arg_width != null, - 'Argument for dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail was null, expected non-null int.'); - final int? arg_height = (args[2] as int?); - assert(arg_height != null, - 'Argument for dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail was null, expected non-null int.'); - try { - final Uint8List? output = - await api.getThumbnail(arg_assetId!, arg_width!, arg_height!); - return wrapResponse(result: output); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - } -} diff --git a/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart b/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart index 8b9ede4c6d..0c4c89233b 100644 --- a/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart +++ b/mobile/lib/presentation/widgets/images/local_album_thumbnail.widget.dart @@ -26,7 +26,7 @@ class LocalAlbumThumbnail extends ConsumerWidget { return ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(16)), - child: Thumbnail(asset: data), + child: Thumbnail.fromBaseAsset(asset: data), ); }, error: (error, stack) { diff --git a/mobile/pigeon/thumbnail_api.dart b/mobile/pigeon/thumbnail_api.dart index 7273365e1b..c025c5822c 100644 --- a/mobile/pigeon/thumbnail_api.dart +++ b/mobile/pigeon/thumbnail_api.dart @@ -30,8 +30,8 @@ abstract class ThumbnailApi { // }); } -@FlutterApi() -abstract class PlatformThumbnailApi { - @async - Uint8List? getThumbnail(String assetId, int width, int height); -} +// @FlutterApi() +// abstract class PlatformThumbnailApi { +// @async +// Uint8List? getThumbnail(String assetId, int width, int height); +// }