minor fixes

This commit is contained in:
Thibault Deckers 2022-02-07 13:05:05 +09:00
parent a71a30130b
commit 3ea5ddd753
7 changed files with 74 additions and 41 deletions

View file

@ -77,29 +77,34 @@ class SearchSuggestionsProvider : MethodChannel.MethodCallHandler, ContentProvid
val backgroundChannel = MethodChannel(messenger, BACKGROUND_CHANNEL)
backgroundChannel.setMethodCallHandler(this)
return suspendCoroutine { cont ->
GlobalScope.launch {
FlutterUtils.runOnUiThread {
backgroundChannel.invokeMethod("getSuggestions", hashMapOf(
"query" to query,
"locale" to Locale.getDefault().toString(),
"use24hour" to DateFormat.is24HourFormat(context),
), object : MethodChannel.Result {
override fun success(result: Any?) {
@Suppress("unchecked_cast")
cont.resume(result as List<FieldMap>)
}
try {
return suspendCoroutine { cont ->
GlobalScope.launch {
FlutterUtils.runOnUiThread {
backgroundChannel.invokeMethod("getSuggestions", hashMapOf(
"query" to query,
"locale" to Locale.getDefault().toString(),
"use24hour" to DateFormat.is24HourFormat(context),
), object : MethodChannel.Result {
override fun success(result: Any?) {
@Suppress("unchecked_cast")
cont.resume(result as List<FieldMap>)
}
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
cont.resumeWithException(Exception("$errorCode: $errorMessage\n$errorDetails"))
}
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
cont.resumeWithException(Exception("$errorCode: $errorMessage\n$errorDetails"))
}
override fun notImplemented() {
cont.resumeWithException(NotImplementedError("getSuggestions"))
}
})
override fun notImplemented() {
cont.resumeWithException(NotImplementedError("getSuggestions"))
}
})
}
}
}
} catch (e: Exception) {
Log.e(LOG_TAG, "failed to get suggestions", e)
return ArrayList()
}
}

View file

@ -80,7 +80,6 @@ import kotlinx.coroutines.launch
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.text.ParseException
import java.util.*
import kotlin.math.roundToInt
import kotlin.math.roundToLong
@ -412,19 +411,19 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
// File type
for (dir in metadata.getDirectoriesOfType(FileTypeDirectory::class.java)) {
// * `metadata-extractor` sometimes detects the wrong MIME type (e.g. `pef` file as `tiff`, `mpeg` as `dvd`)
// * `metadata-extractor` sometimes detects the wrong MIME type (e.g. `pef` file as `tiff`, `mpeg` as `dvd`, `avif` as `mov`)
// * the content resolver / media store sometimes reports the wrong MIME type (e.g. `png` file as `jpeg`, `tiff` as `srw`)
// * `context.getContentResolver().getType()` sometimes returns an incorrect value
// * `MediaMetadataRetriever.setDataSource()` sometimes fails with `status = 0x80000000`
// * file extension is unreliable
// In the end, `metadata-extractor` is the most reliable, except for `tiff`/`dvd` (false positives, false negatives),
// In the end, `metadata-extractor` is the most reliable, except for `tiff`/`dvd`/`mov` (false positives, false negatives),
// in which case we trust the file extension
// cf https://github.com/drewnoakes/metadata-extractor/issues/296
if (path?.matches(TIFF_EXTENSION_PATTERN) == true) {
metadataMap[KEY_MIME_TYPE] = MimeTypes.TIFF
} else {
dir.getSafeString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE) {
if (it != MimeTypes.TIFF && it != MimeTypes.DVD) {
if (it != MimeTypes.TIFF && it != MimeTypes.DVD && it != MimeTypes.MOV) {
metadataMap[KEY_MIME_TYPE] = it
}
}

View file

@ -62,7 +62,7 @@ class GSpherical(xmlBytes: ByteArray) {
}
}
fun describe(): Map<String, String?> = hashMapOf(
fun describe(): Map<String, String> = hashMapOf(
"Spherical" to spherical.toString(),
"Stitched" to stitched.toString(),
"Stitching Software" to stitchingSoftware,
@ -79,7 +79,7 @@ class GSpherical(xmlBytes: ByteArray) {
"Cropped Area Image Height Pixels" to croppedAreaImageHeightPixels?.toString(),
"Cropped Area Left Pixels" to croppedAreaLeftPixels?.toString(),
"Cropped Area Top Pixels" to croppedAreaTopPixels?.toString(),
).filterValues { it != null }
).filterValues { it != null }.mapValues { it.value as String }
companion object SphericalVideo {
private val LOG_TAG = LogUtils.createTag<SphericalVideo>()

View file

@ -6,6 +6,7 @@ object MimeTypes {
const val ANY = "*/*"
// generic raster
private const val AVIF = "image/avif"
const val BMP = "image/bmp"
private const val DJVU = "image/vnd.djvu"
const val GIF = "image/gif"
@ -49,7 +50,7 @@ object MimeTypes {
private const val AVI_VND = "video/vnd.avi"
const val DVD = "video/dvd"
private const val MKV = "video/x-matroska"
private const val MOV = "video/quicktime"
const val MOV = "video/quicktime"
private const val MP2T = "video/mp2t"
private const val MP2TS = "video/mp2ts"
const val MP4 = "video/mp4"
@ -72,7 +73,7 @@ object MimeTypes {
// returns whether the specified MIME type represents
// a raster image format that allows an alpha channel
fun canHaveAlpha(mimeType: String?) = when (mimeType) {
BMP, GIF, ICO, PNG, SVG, TIFF, WEBP -> true
AVIF, BMP, GIF, ICO, PNG, SVG, TIFF, WEBP -> true
else -> false
}
@ -150,6 +151,7 @@ object MimeTypes {
fun extensionFor(mimeType: String): String? = when (mimeType) {
ARW -> ".arw"
AVI, AVI_VND -> ".avi"
AVIF -> ".avif"
BMP -> ".bmp"
CR2 -> ".cr2"
CRW -> ".crw"

View file

@ -158,15 +158,35 @@ class _AvesAppState extends State<AvesApp> {
);
}
// setup before the first page is displayed. keep it short
Future<void> _setup() async {
final stopwatch = Stopwatch()..start();
// TODO TLAD [init] init settings/device w/o platform calls (first platform channel call takes ~800ms):
// 1) use cached values if any,
// 2a) call platform w/ delay if cached
// 2b) call platform w/o delay if not cached
// 3) cache platform call results across app restarts
await device.init();
final isRotationLocked = await windowService.isRotationLocked();
final areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
// TODO TLAD [init] migrate settings away from `shared_preferences` to a platform-free solution
await settings.init(
monitorPlatformSettings: true,
isRotationLocked: await windowService.isRotationLocked(),
areAnimationsRemoved: await AccessibilityService.areAnimationsRemoved(),
isRotationLocked: isRotationLocked,
areAnimationsRemoved: areAnimationsRemoved,
);
await device.init();
FijkLog.setLevel(FijkLogLevel.Warn);
_monitorSettings();
FijkLog.setLevel(FijkLogLevel.Warn);
unawaited(_setupErrorReporting());
debugPrint('App setup in ${stopwatch.elapsed.inMilliseconds}ms');
}
void _monitorSettings() {
// keep screen on
settings.updateStream.where((key) => key == Settings.keepScreenOnKey).listen(
(_) => settings.keepScreenOn.apply(),
@ -183,8 +203,9 @@ class _AvesAppState extends State<AvesApp> {
}
},
);
}
// error reporting
Future<void> _setupErrorReporting() async {
await reportService.init();
settings.updateStream.where((key) => key == Settings.isErrorReportingAllowedKey).listen(
(_) => reportService.setCollectionEnabled(settings.isErrorReportingAllowed),

View file

@ -44,7 +44,7 @@ class AvesDialog extends StatelessWidget {
// and overflow feedback ignores the dialog shape,
// so we restrict scrolling to the content instead
content: _buildContent(context),
contentPadding: scrollableContent != null ? EdgeInsets.zero : EdgeInsets.fromLTRB(horizontalContentPadding, 20, horizontalContentPadding, 0),
contentPadding: scrollableContent != null ? EdgeInsets.zero : EdgeInsets.only(left: horizontalContentPadding, top: 20, right: horizontalContentPadding),
actions: actions,
actionsPadding: const EdgeInsets.symmetric(horizontal: 8),
shape: shape(context),

View file

@ -51,12 +51,14 @@ class _ExportEntryDialogState extends State<ExportEntryDialog> {
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
const contentHorizontalPadding = EdgeInsets.symmetric(horizontal: AvesDialog.defaultHorizontalContentPadding);
return AvesDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
scrollableContent: [
const SizedBox(height: 16),
Padding(
padding: contentHorizontalPadding,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(l10n.exportEntryDialogFormat),
@ -77,7 +79,10 @@ class _ExportEntryDialogState extends State<ExportEntryDialog> {
),
],
),
Row(
),
Padding(
padding: contentHorizontalPadding,
child: Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
@ -108,8 +113,9 @@ class _ExportEntryDialogState extends State<ExportEntryDialog> {
),
],
),
],
),
),
const SizedBox(height: 16),
],
actions: [
TextButton(
onPressed: () => Navigator.pop(context),