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,6 +77,7 @@ class SearchSuggestionsProvider : MethodChannel.MethodCallHandler, ContentProvid
val backgroundChannel = MethodChannel(messenger, BACKGROUND_CHANNEL) val backgroundChannel = MethodChannel(messenger, BACKGROUND_CHANNEL)
backgroundChannel.setMethodCallHandler(this) backgroundChannel.setMethodCallHandler(this)
try {
return suspendCoroutine { cont -> return suspendCoroutine { cont ->
GlobalScope.launch { GlobalScope.launch {
FlutterUtils.runOnUiThread { FlutterUtils.runOnUiThread {
@ -101,6 +102,10 @@ class SearchSuggestionsProvider : MethodChannel.MethodCallHandler, ContentProvid
} }
} }
} }
} catch (e: Exception) {
Log.e(LOG_TAG, "failed to get suggestions", e)
return ArrayList()
}
} }
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {

View file

@ -80,7 +80,6 @@ import kotlinx.coroutines.launch
import java.nio.charset.Charset import java.nio.charset.Charset
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.text.ParseException import java.text.ParseException
import java.util.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.math.roundToLong import kotlin.math.roundToLong
@ -412,19 +411,19 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
// File type // File type
for (dir in metadata.getDirectoriesOfType(FileTypeDirectory::class.java)) { 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`) // * 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 // * `context.getContentResolver().getType()` sometimes returns an incorrect value
// * `MediaMetadataRetriever.setDataSource()` sometimes fails with `status = 0x80000000` // * `MediaMetadataRetriever.setDataSource()` sometimes fails with `status = 0x80000000`
// * file extension is unreliable // * 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 // in which case we trust the file extension
// cf https://github.com/drewnoakes/metadata-extractor/issues/296 // cf https://github.com/drewnoakes/metadata-extractor/issues/296
if (path?.matches(TIFF_EXTENSION_PATTERN) == true) { if (path?.matches(TIFF_EXTENSION_PATTERN) == true) {
metadataMap[KEY_MIME_TYPE] = MimeTypes.TIFF metadataMap[KEY_MIME_TYPE] = MimeTypes.TIFF
} else { } else {
dir.getSafeString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE) { 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 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(), "Spherical" to spherical.toString(),
"Stitched" to stitched.toString(), "Stitched" to stitched.toString(),
"Stitching Software" to stitchingSoftware, "Stitching Software" to stitchingSoftware,
@ -79,7 +79,7 @@ class GSpherical(xmlBytes: ByteArray) {
"Cropped Area Image Height Pixels" to croppedAreaImageHeightPixels?.toString(), "Cropped Area Image Height Pixels" to croppedAreaImageHeightPixels?.toString(),
"Cropped Area Left Pixels" to croppedAreaLeftPixels?.toString(), "Cropped Area Left Pixels" to croppedAreaLeftPixels?.toString(),
"Cropped Area Top Pixels" to croppedAreaTopPixels?.toString(), "Cropped Area Top Pixels" to croppedAreaTopPixels?.toString(),
).filterValues { it != null } ).filterValues { it != null }.mapValues { it.value as String }
companion object SphericalVideo { companion object SphericalVideo {
private val LOG_TAG = LogUtils.createTag<SphericalVideo>() private val LOG_TAG = LogUtils.createTag<SphericalVideo>()

View file

@ -6,6 +6,7 @@ object MimeTypes {
const val ANY = "*/*" const val ANY = "*/*"
// generic raster // generic raster
private const val AVIF = "image/avif"
const val BMP = "image/bmp" const val BMP = "image/bmp"
private const val DJVU = "image/vnd.djvu" private const val DJVU = "image/vnd.djvu"
const val GIF = "image/gif" const val GIF = "image/gif"
@ -49,7 +50,7 @@ object MimeTypes {
private const val AVI_VND = "video/vnd.avi" private const val AVI_VND = "video/vnd.avi"
const val DVD = "video/dvd" const val DVD = "video/dvd"
private const val MKV = "video/x-matroska" 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 MP2T = "video/mp2t"
private const val MP2TS = "video/mp2ts" private const val MP2TS = "video/mp2ts"
const val MP4 = "video/mp4" const val MP4 = "video/mp4"
@ -72,7 +73,7 @@ object MimeTypes {
// returns whether the specified MIME type represents // returns whether the specified MIME type represents
// a raster image format that allows an alpha channel // a raster image format that allows an alpha channel
fun canHaveAlpha(mimeType: String?) = when (mimeType) { 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 else -> false
} }
@ -150,6 +151,7 @@ object MimeTypes {
fun extensionFor(mimeType: String): String? = when (mimeType) { fun extensionFor(mimeType: String): String? = when (mimeType) {
ARW -> ".arw" ARW -> ".arw"
AVI, AVI_VND -> ".avi" AVI, AVI_VND -> ".avi"
AVIF -> ".avif"
BMP -> ".bmp" BMP -> ".bmp"
CR2 -> ".cr2" CR2 -> ".cr2"
CRW -> ".crw" 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 { 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( await settings.init(
monitorPlatformSettings: true, monitorPlatformSettings: true,
isRotationLocked: await windowService.isRotationLocked(), isRotationLocked: isRotationLocked,
areAnimationsRemoved: await AccessibilityService.areAnimationsRemoved(), areAnimationsRemoved: areAnimationsRemoved,
); );
await device.init(); _monitorSettings();
FijkLog.setLevel(FijkLogLevel.Warn);
FijkLog.setLevel(FijkLogLevel.Warn);
unawaited(_setupErrorReporting());
debugPrint('App setup in ${stopwatch.elapsed.inMilliseconds}ms');
}
void _monitorSettings() {
// keep screen on // keep screen on
settings.updateStream.where((key) => key == Settings.keepScreenOnKey).listen( settings.updateStream.where((key) => key == Settings.keepScreenOnKey).listen(
(_) => settings.keepScreenOn.apply(), (_) => settings.keepScreenOn.apply(),
@ -183,8 +203,9 @@ class _AvesAppState extends State<AvesApp> {
} }
}, },
); );
}
// error reporting Future<void> _setupErrorReporting() async {
await reportService.init(); await reportService.init();
settings.updateStream.where((key) => key == Settings.isErrorReportingAllowedKey).listen( settings.updateStream.where((key) => key == Settings.isErrorReportingAllowedKey).listen(
(_) => reportService.setCollectionEnabled(settings.isErrorReportingAllowed), (_) => reportService.setCollectionEnabled(settings.isErrorReportingAllowed),

View file

@ -44,7 +44,7 @@ class AvesDialog extends StatelessWidget {
// and overflow feedback ignores the dialog shape, // and overflow feedback ignores the dialog shape,
// so we restrict scrolling to the content instead // so we restrict scrolling to the content instead
content: _buildContent(context), 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, actions: actions,
actionsPadding: const EdgeInsets.symmetric(horizontal: 8), actionsPadding: const EdgeInsets.symmetric(horizontal: 8),
shape: shape(context), shape: shape(context),

View file

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