mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
rebase
This commit is contained in:
parent
e1cc8f8fe1
commit
8d163ec932
@ -15,9 +15,6 @@ import java.io.ByteArrayOutputStream
|
|||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
private object ThumbnailsPigeonUtils {
|
private object ThumbnailsPigeonUtils {
|
||||||
|
|
||||||
fun createConnectionError(channelName: String): FlutterError {
|
|
||||||
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") }
|
|
||||||
|
|
||||||
fun wrapResult(result: Any?): List<Any?> {
|
fun wrapResult(result: Any?): List<Any?> {
|
||||||
return listOf(result)
|
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<Any?> by lazy {
|
|
||||||
ThumbnailsPigeonCodec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun getThumbnail(assetIdArg: String, widthArg: Long, heightArg: Long, callback: (Result<ByteArray?>) -> Unit)
|
|
||||||
{
|
|
||||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
|
||||||
val channelName = "dev.flutter.pigeon.immich_mobile.PlatformThumbnailApi.getThumbnail$separatedMessageChannelSuffix"
|
|
||||||
val channel = BasicMessageChannel<Any?>(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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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 {
|
private func isNullish(_ value: Any?) -> Bool {
|
||||||
return value is NSNull || value == nil
|
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<FlutterStandardTypedData?, PigeonError>) -> 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<FlutterStandardTypedData?, PigeonError>) -> 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import CryptoKit
|
import CryptoKit
|
||||||
import Flutter
|
import Flutter
|
||||||
import Photos
|
|
||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
|
import Photos
|
||||||
|
|
||||||
// https://stackoverflow.com/a/55839062
|
// https://stackoverflow.com/a/55839062
|
||||||
extension UIImage {
|
extension UIImage {
|
||||||
@ -15,7 +15,9 @@ extension UIImage {
|
|||||||
guard let cgImage = cgImage else { return nil }
|
guard let cgImage = cgImage else { return nil }
|
||||||
return autoreleasepool { () -> Data? in
|
return autoreleasepool { () -> Data? in
|
||||||
let data = NSMutableData()
|
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)
|
CGImageDestinationAddImage(imageDestination, cgImage, options)
|
||||||
CGImageDestinationFinalize(imageDestination)
|
CGImageDestinationFinalize(imageDestination)
|
||||||
return data as Data
|
return data as Data
|
||||||
@ -75,41 +77,10 @@ class ThumbnailApiImpl: ThumbnailApi {
|
|||||||
requestOptions.version = .current
|
requestOptions.version = .current
|
||||||
return requestOptions
|
return requestOptions
|
||||||
}()
|
}()
|
||||||
private static let processingQueue = DispatchQueue(label: "thumbnail.processing", qos: .userInteractive, attributes: .concurrent)
|
private static let processingQueue = DispatchQueue(
|
||||||
private static let imageCache = NSCache<NSString, FlutterStandardTypedData>()
|
label: "thumbnail.processing", qos: .userInteractive, attributes: .concurrent)
|
||||||
|
|
||||||
func requestThumbnail(
|
func getThumbnail(
|
||||||
assetId: String,
|
|
||||||
width: Int64,
|
|
||||||
height: Int64,
|
|
||||||
completion: @escaping (Result<Int32, Error>) -> 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<FlutterStandardTypedData?, PigeonError>) -> Void) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendThumbnail(
|
|
||||||
assetId: String,
|
assetId: String,
|
||||||
width: Int64,
|
width: Int64,
|
||||||
height: Int64,
|
height: Int64,
|
||||||
@ -130,15 +101,12 @@ class ThumbnailApiImpl: ThumbnailApi {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
} catch {
|
} 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 {
|
private func getAsset(assetId: String) throws -> PHAsset {
|
||||||
guard
|
guard
|
||||||
let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: Self.fetchOptions)
|
let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: Self.fetchOptions)
|
||||||
@ -148,4 +116,9 @@ class ThumbnailApiImpl: ThumbnailApi {
|
|||||||
}
|
}
|
||||||
return asset
|
return asset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func cancel(requestId: Int32) {
|
||||||
|
// Self.cacheManager.cancelImageRequest(requestId as PHImageRequestID)
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
62
mobile/lib/platform/thumbnail_api.g.dart
generated
62
mobile/lib/platform/thumbnail_api.g.dart
generated
@ -15,17 +15,6 @@ PlatformException _createConnectionError(String channelName) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Object?> wrapResponse(
|
|
||||||
{Object? result, PlatformException? error, bool empty = false}) {
|
|
||||||
if (empty) {
|
|
||||||
return <Object?>[];
|
|
||||||
}
|
|
||||||
if (error == null) {
|
|
||||||
return <Object?>[result];
|
|
||||||
}
|
|
||||||
return <Object?>[error.code, error.message, error.details];
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PigeonCodec extends StandardMessageCodec {
|
class _PigeonCodec extends StandardMessageCodec {
|
||||||
const _PigeonCodec();
|
const _PigeonCodec();
|
||||||
@override
|
@override
|
||||||
@ -97,54 +86,3 @@ class ThumbnailApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class PlatformThumbnailApi {
|
|
||||||
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
|
|
||||||
|
|
||||||
Future<Uint8List?> 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<Object?> args = (message as List<Object?>?)!;
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -26,7 +26,7 @@ class LocalAlbumThumbnail extends ConsumerWidget {
|
|||||||
|
|
||||||
return ClipRRect(
|
return ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||||
child: Thumbnail(asset: data),
|
child: Thumbnail.fromBaseAsset(asset: data),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
error: (error, stack) {
|
error: (error, stack) {
|
||||||
|
@ -30,8 +30,8 @@ abstract class ThumbnailApi {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
@FlutterApi()
|
// @FlutterApi()
|
||||||
abstract class PlatformThumbnailApi {
|
// abstract class PlatformThumbnailApi {
|
||||||
@async
|
// @async
|
||||||
Uint8List? getThumbnail(String assetId, int width, int height);
|
// Uint8List? getThumbnail(String assetId, int width, int height);
|
||||||
}
|
// }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user