buffer byte loading
This commit is contained in:
parent
5ce66fbd8a
commit
04b6576190
11 changed files with 161 additions and 46 deletions
|
@ -12,8 +12,10 @@ import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import app.loup.streams_channel.StreamsChannel
|
import app.loup.streams_channel.StreamsChannel
|
||||||
|
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
|
||||||
import deckers.thibault.aves.channel.calls.DeviceHandler
|
import deckers.thibault.aves.channel.calls.DeviceHandler
|
||||||
import deckers.thibault.aves.channel.calls.MediaFetchHandler
|
import deckers.thibault.aves.channel.calls.MediaFetchBytesHandler
|
||||||
|
import deckers.thibault.aves.channel.calls.MediaFetchObjectHandler
|
||||||
import deckers.thibault.aves.channel.calls.MediaStoreHandler
|
import deckers.thibault.aves.channel.calls.MediaStoreHandler
|
||||||
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
|
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
|
||||||
import deckers.thibault.aves.channel.streams.MediaStoreStreamHandler
|
import deckers.thibault.aves.channel.streams.MediaStoreStreamHandler
|
||||||
|
@ -190,7 +192,8 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
||||||
// - need Context
|
// - need Context
|
||||||
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(context))
|
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(context))
|
||||||
MethodChannel(messenger, MediaStoreHandler.CHANNEL).setMethodCallHandler(MediaStoreHandler(context))
|
MethodChannel(messenger, MediaStoreHandler.CHANNEL).setMethodCallHandler(MediaStoreHandler(context))
|
||||||
MethodChannel(messenger, MediaFetchHandler.CHANNEL).setMethodCallHandler(MediaFetchHandler(context))
|
MethodChannel(messenger, MediaFetchBytesHandler.CHANNEL, AvesByteSendingMethodCodec.INSTANCE).setMethodCallHandler(MediaFetchBytesHandler(context))
|
||||||
|
MethodChannel(messenger, MediaFetchObjectHandler.CHANNEL).setMethodCallHandler(MediaFetchObjectHandler(context))
|
||||||
|
|
||||||
// result streaming: dart -> platform ->->-> dart
|
// result streaming: dart -> platform ->->-> dart
|
||||||
// - need Context
|
// - need Context
|
||||||
|
|
|
@ -16,6 +16,7 @@ import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import app.loup.streams_channel.StreamsChannel
|
import app.loup.streams_channel.StreamsChannel
|
||||||
|
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
|
||||||
import deckers.thibault.aves.channel.calls.*
|
import deckers.thibault.aves.channel.calls.*
|
||||||
import deckers.thibault.aves.channel.calls.window.ActivityWindowHandler
|
import deckers.thibault.aves.channel.calls.window.ActivityWindowHandler
|
||||||
import deckers.thibault.aves.channel.calls.window.WindowHandler
|
import deckers.thibault.aves.channel.calls.window.WindowHandler
|
||||||
|
@ -70,7 +71,8 @@ open class MainActivity : FlutterActivity() {
|
||||||
MethodChannel(messenger, GeocodingHandler.CHANNEL).setMethodCallHandler(GeocodingHandler(this))
|
MethodChannel(messenger, GeocodingHandler.CHANNEL).setMethodCallHandler(GeocodingHandler(this))
|
||||||
MethodChannel(messenger, GlobalSearchHandler.CHANNEL).setMethodCallHandler(GlobalSearchHandler(this))
|
MethodChannel(messenger, GlobalSearchHandler.CHANNEL).setMethodCallHandler(GlobalSearchHandler(this))
|
||||||
MethodChannel(messenger, HomeWidgetHandler.CHANNEL).setMethodCallHandler(HomeWidgetHandler(this))
|
MethodChannel(messenger, HomeWidgetHandler.CHANNEL).setMethodCallHandler(HomeWidgetHandler(this))
|
||||||
MethodChannel(messenger, MediaFetchHandler.CHANNEL).setMethodCallHandler(MediaFetchHandler(this))
|
MethodChannel(messenger, MediaFetchBytesHandler.CHANNEL, AvesByteSendingMethodCodec.INSTANCE).setMethodCallHandler(MediaFetchBytesHandler(this))
|
||||||
|
MethodChannel(messenger, MediaFetchObjectHandler.CHANNEL).setMethodCallHandler(MediaFetchObjectHandler(this))
|
||||||
MethodChannel(messenger, MediaStoreHandler.CHANNEL).setMethodCallHandler(MediaStoreHandler(this))
|
MethodChannel(messenger, MediaStoreHandler.CHANNEL).setMethodCallHandler(MediaStoreHandler(this))
|
||||||
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
||||||
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
|
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.service.dreams.DreamService
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import app.loup.streams_channel.StreamsChannel
|
import app.loup.streams_channel.StreamsChannel
|
||||||
|
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
|
||||||
import deckers.thibault.aves.channel.calls.*
|
import deckers.thibault.aves.channel.calls.*
|
||||||
import deckers.thibault.aves.channel.calls.window.ServiceWindowHandler
|
import deckers.thibault.aves.channel.calls.window.ServiceWindowHandler
|
||||||
import deckers.thibault.aves.channel.calls.window.WindowHandler
|
import deckers.thibault.aves.channel.calls.window.WindowHandler
|
||||||
|
@ -99,7 +100,8 @@ class ScreenSaverService : DreamService() {
|
||||||
// - need Context
|
// - need Context
|
||||||
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(this))
|
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(this))
|
||||||
MethodChannel(messenger, EmbeddedDataHandler.CHANNEL).setMethodCallHandler(EmbeddedDataHandler(this))
|
MethodChannel(messenger, EmbeddedDataHandler.CHANNEL).setMethodCallHandler(EmbeddedDataHandler(this))
|
||||||
MethodChannel(messenger, MediaFetchHandler.CHANNEL).setMethodCallHandler(MediaFetchHandler(this))
|
MethodChannel(messenger, MediaFetchBytesHandler.CHANNEL, AvesByteSendingMethodCodec.INSTANCE).setMethodCallHandler(MediaFetchBytesHandler(this))
|
||||||
|
MethodChannel(messenger, MediaFetchObjectHandler.CHANNEL).setMethodCallHandler(MediaFetchObjectHandler(this))
|
||||||
MethodChannel(messenger, MediaStoreHandler.CHANNEL).setMethodCallHandler(MediaStoreHandler(this))
|
MethodChannel(messenger, MediaStoreHandler.CHANNEL).setMethodCallHandler(MediaStoreHandler(this))
|
||||||
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
||||||
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
|
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import app.loup.streams_channel.StreamsChannel
|
import app.loup.streams_channel.StreamsChannel
|
||||||
|
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
|
||||||
import deckers.thibault.aves.channel.calls.*
|
import deckers.thibault.aves.channel.calls.*
|
||||||
import deckers.thibault.aves.channel.calls.window.ActivityWindowHandler
|
import deckers.thibault.aves.channel.calls.window.ActivityWindowHandler
|
||||||
import deckers.thibault.aves.channel.calls.window.WindowHandler
|
import deckers.thibault.aves.channel.calls.window.WindowHandler
|
||||||
|
@ -34,7 +35,8 @@ class WallpaperActivity : FlutterActivity() {
|
||||||
// - need Context
|
// - need Context
|
||||||
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(this))
|
MethodChannel(messenger, DeviceHandler.CHANNEL).setMethodCallHandler(DeviceHandler(this))
|
||||||
MethodChannel(messenger, EmbeddedDataHandler.CHANNEL).setMethodCallHandler(EmbeddedDataHandler(this))
|
MethodChannel(messenger, EmbeddedDataHandler.CHANNEL).setMethodCallHandler(EmbeddedDataHandler(this))
|
||||||
MethodChannel(messenger, MediaFetchHandler.CHANNEL).setMethodCallHandler(MediaFetchHandler(this))
|
MethodChannel(messenger, MediaFetchBytesHandler.CHANNEL, AvesByteSendingMethodCodec.INSTANCE).setMethodCallHandler(MediaFetchBytesHandler(context))
|
||||||
|
MethodChannel(messenger, MediaFetchObjectHandler.CHANNEL).setMethodCallHandler(MediaFetchObjectHandler(this))
|
||||||
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
MethodChannel(messenger, MetadataFetchHandler.CHANNEL).setMethodCallHandler(MetadataFetchHandler(this))
|
||||||
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
|
MethodChannel(messenger, StorageHandler.CHANNEL).setMethodCallHandler(StorageHandler(this))
|
||||||
// - need ContextWrapper
|
// - need ContextWrapper
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package deckers.thibault.aves.channel
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import deckers.thibault.aves.utils.LogUtils
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import io.flutter.plugin.common.MethodCodec
|
||||||
|
import io.flutter.plugin.common.StandardMessageCodec
|
||||||
|
import io.flutter.plugin.common.StandardMethodCodec
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class AvesByteSendingMethodCodec private constructor() : MethodCodec {
|
||||||
|
override fun decodeMethodCall(methodCall: ByteBuffer): MethodCall {
|
||||||
|
return STANDARD.decodeMethodCall(methodCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun decodeEnvelope(envelope: ByteBuffer): Any {
|
||||||
|
return STANDARD.decodeEnvelope(envelope)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encodeMethodCall(methodCall: MethodCall): ByteBuffer {
|
||||||
|
return STANDARD.encodeMethodCall(methodCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encodeSuccessEnvelope(result: Any?): ByteBuffer {
|
||||||
|
if (result is ByteArray) {
|
||||||
|
val size = result.size
|
||||||
|
return ByteBuffer.allocateDirect(4 + size).apply {
|
||||||
|
put(0)
|
||||||
|
put(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.e(LOG_TAG, "encodeSuccessEnvelope failed with result=$result")
|
||||||
|
return ByteBuffer.allocateDirect(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encodeErrorEnvelope(errorCode: String, errorMessage: String?, errorDetails: Any?): ByteBuffer {
|
||||||
|
Log.e(LOG_TAG, "encodeErrorEnvelope failed with errorCode=$errorCode, errorMessage=$errorMessage, errorDetails=$errorDetails")
|
||||||
|
return ByteBuffer.allocateDirect(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun encodeErrorEnvelopeWithStacktrace(errorCode: String, errorMessage: String?, errorDetails: Any?, errorStacktrace: String?): ByteBuffer {
|
||||||
|
Log.e(LOG_TAG, "encodeErrorEnvelopeWithStacktrace failed with errorCode=$errorCode, errorMessage=$errorMessage, errorDetails=$errorDetails, errorStacktrace=$errorStacktrace")
|
||||||
|
return ByteBuffer.allocateDirect(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOG_TAG = LogUtils.createTag<AvesByteSendingMethodCodec>()
|
||||||
|
val INSTANCE = AvesByteSendingMethodCodec()
|
||||||
|
private val STANDARD = StandardMethodCodec(StandardMessageCodec.INSTANCE)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,16 +3,11 @@ package deckers.thibault.aves.channel.calls
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
|
||||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safeSuspend
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safeSuspend
|
||||||
import deckers.thibault.aves.channel.calls.fetchers.RegionFetcher
|
import deckers.thibault.aves.channel.calls.fetchers.RegionFetcher
|
||||||
import deckers.thibault.aves.channel.calls.fetchers.SvgRegionFetcher
|
import deckers.thibault.aves.channel.calls.fetchers.SvgRegionFetcher
|
||||||
import deckers.thibault.aves.channel.calls.fetchers.ThumbnailFetcher
|
import deckers.thibault.aves.channel.calls.fetchers.ThumbnailFetcher
|
||||||
import deckers.thibault.aves.channel.calls.fetchers.TiffRegionFetcher
|
import deckers.thibault.aves.channel.calls.fetchers.TiffRegionFetcher
|
||||||
import deckers.thibault.aves.model.FieldMap
|
|
||||||
import deckers.thibault.aves.model.provider.ImageProvider.ImageOpCallback
|
|
||||||
import deckers.thibault.aves.model.provider.ImageProviderFactory.getProvider
|
|
||||||
import deckers.thibault.aves.utils.MimeTypes
|
import deckers.thibault.aves.utils.MimeTypes
|
||||||
import io.flutter.plugin.common.MethodCall
|
import io.flutter.plugin.common.MethodCall
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
@ -23,7 +18,7 @@ import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class MediaFetchHandler(private val context: Context) : MethodCallHandler {
|
class MediaFetchBytesHandler(private val context: Context) : MethodCallHandler {
|
||||||
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
private val density = context.resources.displayMetrics.density
|
private val density = context.resources.displayMetrics.density
|
||||||
|
|
||||||
|
@ -31,34 +26,12 @@ class MediaFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
|
|
||||||
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"getEntry" -> ioScope.launch { safe(call, result, ::getEntry) }
|
|
||||||
"getThumbnail" -> ioScope.launch { safeSuspend(call, result, ::getThumbnail) }
|
"getThumbnail" -> ioScope.launch { safeSuspend(call, result, ::getThumbnail) }
|
||||||
"getRegion" -> ioScope.launch { safeSuspend(call, result, ::getRegion) }
|
"getRegion" -> ioScope.launch { safeSuspend(call, result, ::getRegion) }
|
||||||
"clearSizedThumbnailDiskCache" -> ioScope.launch { safe(call, result, ::clearSizedThumbnailDiskCache) }
|
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getEntry(call: MethodCall, result: MethodChannel.Result) {
|
|
||||||
val mimeType = call.argument<String>("mimeType") // MIME type is optional
|
|
||||||
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
|
||||||
if (uri == null) {
|
|
||||||
result.error("getEntry-args", "missing arguments", null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val provider = getProvider(uri)
|
|
||||||
if (provider == null) {
|
|
||||||
result.error("getEntry-provider", "failed to find provider for uri=$uri", null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
provider.fetchSingle(context, uri, mimeType, object : ImageOpCallback {
|
|
||||||
override fun onSuccess(fields: FieldMap) = result.success(fields)
|
|
||||||
override fun onFailure(throwable: Throwable) = result.error("getEntry-failure", "failed to get entry for uri=$uri", throwable.message)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getThumbnail(call: MethodCall, result: MethodChannel.Result) {
|
private suspend fun getThumbnail(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val uri = call.argument<String>("uri")
|
val uri = call.argument<String>("uri")
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
|
@ -137,12 +110,7 @@ class MediaFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearSizedThumbnailDiskCache(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
|
||||||
Glide.get(context).clearDiskCache()
|
|
||||||
result.success(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CHANNEL = "deckers.thibault/aves/media_fetch"
|
const val CHANNEL = "deckers.thibault/aves/media_fetch_bytes"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package deckers.thibault.aves.channel.calls
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||||
|
import deckers.thibault.aves.model.FieldMap
|
||||||
|
import deckers.thibault.aves.model.provider.ImageProvider.ImageOpCallback
|
||||||
|
import deckers.thibault.aves.model.provider.ImageProviderFactory.getProvider
|
||||||
|
import io.flutter.plugin.common.MethodCall
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class MediaFetchObjectHandler(private val context: Context) : MethodCallHandler {
|
||||||
|
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
|
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
when (call.method) {
|
||||||
|
"getEntry" -> ioScope.launch { safe(call, result, ::getEntry) }
|
||||||
|
"clearSizedThumbnailDiskCache" -> ioScope.launch { safe(call, result, ::clearSizedThumbnailDiskCache) }
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEntry(call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
val mimeType = call.argument<String>("mimeType") // MIME type is optional
|
||||||
|
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
||||||
|
if (uri == null) {
|
||||||
|
result.error("getEntry-args", "missing arguments", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val provider = getProvider(uri)
|
||||||
|
if (provider == null) {
|
||||||
|
result.error("getEntry-provider", "failed to find provider for uri=$uri", null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
provider.fetchSingle(context, uri, mimeType, object : ImageOpCallback {
|
||||||
|
override fun onSuccess(fields: FieldMap) = result.success(fields)
|
||||||
|
override fun onFailure(throwable: Throwable) = result.error("getEntry-failure", "failed to get entry for uri=$uri", throwable.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearSizedThumbnailDiskCache(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
|
||||||
|
Glide.get(context).clearDiskCache()
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CHANNEL = "deckers.thibault/aves/media_fetch_object"
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ class TopoJson {
|
||||||
|
|
||||||
static Topology? _isoParse(String jsonData) {
|
static Topology? _isoParse(String jsonData) {
|
||||||
try {
|
try {
|
||||||
final data = json.decode(jsonData) as Map<String, dynamic>;
|
final data = jsonDecode(jsonData) as Map<String, dynamic>;
|
||||||
return Topology.parse(data);
|
return Topology.parse(data);
|
||||||
} catch (error, stack) {
|
} catch (error, stack) {
|
||||||
// an unhandled error in a spawn isolate would make the app crash
|
// an unhandled error in a spawn isolate would make the app crash
|
||||||
|
|
27
lib/services/media/byte_receiving_codec.dart
Normal file
27
lib/services/media/byte_receiving_codec.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class AvesByteReceivingMethodCodec extends StandardMethodCodec {
|
||||||
|
const AvesByteReceivingMethodCodec() : super();
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic decodeEnvelope(ByteData envelope) {
|
||||||
|
// First byte is zero in success case, and non-zero otherwise.
|
||||||
|
if (envelope.lengthInBytes == 0) {
|
||||||
|
throw const FormatException('Expected envelope, got nothing');
|
||||||
|
}
|
||||||
|
final ReadBuffer buffer = ReadBuffer(envelope);
|
||||||
|
if (buffer.getUint8() == 0) {
|
||||||
|
return envelope.buffer.asUint8List(envelope.offsetInBytes + 1, envelope.lengthInBytes - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object? errorCode = messageCodec.readValue(buffer);
|
||||||
|
final Object? errorMessage = messageCodec.readValue(buffer);
|
||||||
|
final Object? errorDetails = messageCodec.readValue(buffer);
|
||||||
|
final String? errorStacktrace = (buffer.hasRemaining) ? messageCodec.readValue(buffer) as String? : null;
|
||||||
|
if (errorCode is String && (errorMessage == null || errorMessage is String) && !buffer.hasRemaining) {
|
||||||
|
throw PlatformException(code: errorCode, message: errorMessage as String?, details: errorDetails, stacktrace: errorStacktrace);
|
||||||
|
} else {
|
||||||
|
throw const FormatException('Invalid envelope');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/services/common/output_buffer.dart';
|
import 'package:aves/services/common/output_buffer.dart';
|
||||||
import 'package:aves/services/common/service_policy.dart';
|
import 'package:aves/services/common/service_policy.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves/services/media/byte_receiving_codec.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:streams_channel/streams_channel.dart';
|
import 'package:streams_channel/streams_channel.dart';
|
||||||
|
@ -66,14 +67,15 @@ abstract class MediaFetchService {
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlatformMediaFetchService implements MediaFetchService {
|
class PlatformMediaFetchService implements MediaFetchService {
|
||||||
static const _platform = MethodChannel('deckers.thibault/aves/media_fetch');
|
static const _platformObject = MethodChannel('deckers.thibault/aves/media_fetch_object');
|
||||||
|
static const _platformBytes = MethodChannel('deckers.thibault/aves/media_fetch_bytes', AvesByteReceivingMethodCodec());
|
||||||
static final _byteStream = StreamsChannel('deckers.thibault/aves/media_byte_stream');
|
static final _byteStream = StreamsChannel('deckers.thibault/aves/media_byte_stream');
|
||||||
static const double _thumbnailDefaultSize = 64.0;
|
static const double _thumbnailDefaultSize = 64.0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<AvesEntry?> getEntry(String uri, String? mimeType) async {
|
Future<AvesEntry?> getEntry(String uri, String? mimeType) async {
|
||||||
try {
|
try {
|
||||||
final result = await _platform.invokeMethod('getEntry', <String, dynamic>{
|
final result = await _platformObject.invokeMethod('getEntry', <String, dynamic>{
|
||||||
'uri': uri,
|
'uri': uri,
|
||||||
'mimeType': mimeType,
|
'mimeType': mimeType,
|
||||||
}) as Map;
|
}) as Map;
|
||||||
|
@ -171,7 +173,7 @@ class PlatformMediaFetchService implements MediaFetchService {
|
||||||
return servicePolicy.call(
|
return servicePolicy.call(
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
final result = await _platform.invokeMethod('getRegion', <String, dynamic>{
|
final result = await _platformBytes.invokeMethod('getRegion', <String, dynamic>{
|
||||||
'uri': uri,
|
'uri': uri,
|
||||||
'mimeType': mimeType,
|
'mimeType': mimeType,
|
||||||
'pageId': pageId,
|
'pageId': pageId,
|
||||||
|
@ -211,7 +213,7 @@ class PlatformMediaFetchService implements MediaFetchService {
|
||||||
return servicePolicy.call(
|
return servicePolicy.call(
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
final result = await _platform.invokeMethod('getThumbnail', <String, dynamic>{
|
final result = await _platformBytes.invokeMethod('getThumbnail', <String, dynamic>{
|
||||||
'uri': uri,
|
'uri': uri,
|
||||||
'mimeType': mimeType,
|
'mimeType': mimeType,
|
||||||
'dateModifiedSecs': dateModifiedSecs,
|
'dateModifiedSecs': dateModifiedSecs,
|
||||||
|
@ -238,7 +240,7 @@ class PlatformMediaFetchService implements MediaFetchService {
|
||||||
@override
|
@override
|
||||||
Future<void> clearSizedThumbnailDiskCache() async {
|
Future<void> clearSizedThumbnailDiskCache() async {
|
||||||
try {
|
try {
|
||||||
return _platform.invokeMethod('clearSizedThumbnailDiskCache');
|
return _platformObject.invokeMethod('clearSizedThumbnailDiskCache');
|
||||||
} on PlatformException catch (e, stack) {
|
} on PlatformException catch (e, stack) {
|
||||||
await reportService.recordError(e, stack);
|
await reportService.recordError(e, stack);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ class _XmpDirTileState extends State<XmpDirTile> {
|
||||||
super.initState();
|
super.initState();
|
||||||
_tags = Map.from(widget.tags)..remove(schemaRegistryPrefixesKey);
|
_tags = Map.from(widget.tags)..remove(schemaRegistryPrefixesKey);
|
||||||
final prefixesJson = widget.allTags[schemaRegistryPrefixesKey];
|
final prefixesJson = widget.allTags[schemaRegistryPrefixesKey];
|
||||||
final Map<String, dynamic> prefixesDecoded = prefixesJson != null ? json.decode(prefixesJson) : {};
|
final Map<String, dynamic> prefixesDecoded = prefixesJson != null ? jsonDecode(prefixesJson) : {};
|
||||||
_schemaRegistryPrefixes = Map.fromEntries(prefixesDecoded.entries.map((kv) => MapEntry(kv.key, kv.value as String)));
|
_schemaRegistryPrefixes = Map.fromEntries(prefixesDecoded.entries.map((kv) => MapEntry(kv.key, kv.value as String)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue