support for kitkat (API 19)

This commit is contained in:
Thibault Deckers 2021-11-24 11:16:16 +09:00
parent 2d5f125431
commit 0f5bf13634
13 changed files with 65 additions and 41 deletions

View file

@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- add and remove tags to JPEG/GIF/PNG/TIFF images
- French translation
- restored support for Android KitKat (without Google Maps)
## [v1.5.6] - 2021-11-12

View file

@ -29,7 +29,7 @@ It scans your media collection to identify **motion photos**, **panoramas** (aka
**Navigation and search** is an important part of Aves. The goal is for users to easily flow from albums to photos to tags to maps, etc.
Aves integrates with Android (from **API 20 to 31**, i.e. from Lollipop to S) with features such as **app shortcuts** and **global search** handling. It also works as a **media viewer and picker**.
Aves integrates with Android (from **API 19 to 31**, i.e. from KitKat to S) with features such as **app shortcuts** and **global search** handling. It also works as a **media viewer and picker**.
## Screenshots
@ -82,5 +82,10 @@ To run the app:
# flutter run -t lib/main_play.dart --flavor play
```
To run the app on API 19 emulators:
```
# flutter run -t lib/main_play.dart --flavor play --enable-software-rendering
```
[Version badge]: https://img.shields.io/github/v/release/deckerst/aves?include_prereleases&sort=semver
[Build badge]: https://img.shields.io/github/workflow/status/deckerst/aves/Quality%20check

View file

@ -55,9 +55,9 @@ android {
applicationId appId
// minSdkVersion constraints:
// - Flutter & other plugins: 16
// - google_maps_flutter v2.0.5: 20
// - google_maps_flutter v2.1.1: 20
// - Aves native: 19
minSdkVersion 20
minSdkVersion 19
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

View file

@ -4,21 +4,12 @@
android:installLocation="auto">
<!--
Scoped storage for primary storage is unusable on Android Q,
because users are required to confirm each file to be edited or deleted.
These items can only be deleted one by one after catching
a `RecoverableSecurityException` and requesting permission for each.
Android R improvements:
- bulk changes (e.g. `createDeleteRequest`):
https://developer.android.com/preview/privacy/storage#media-file-access
- raw path access:
https://developer.android.com/preview/privacy/storage#media-files-raw-paths
Scoped storage on Android Q is inconvenient because users need to confirm edition on each individual file.
So we request `WRITE_EXTERNAL_STORAGE` until Q (29), and enable `requestLegacyExternalStorage`
-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- request write permission until Q (29) included, because scoped storage is unusable -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
@ -34,6 +25,9 @@
<!-- for API < 26 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- allow install on API 19, but Google Maps is from API 20 -->
<uses-sdk tools:overrideLibrary="io.flutter.plugins.googlemaps" />
<!-- from Android R, we should define <queries> to make other apps visible to this app -->
<queries>
<intent>

View file

@ -27,7 +27,7 @@ class AccessibilityHandler(private val activity: Activity) : MethodCallHandler {
try {
removed = Settings.Global.getFloat(activity.contentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE) == 0f
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get settings", e)
Log.w(LOG_TAG, "failed to get settings with error=${e.message}", null)
}
result.success(removed)
}

View file

@ -45,7 +45,7 @@ class WindowHandler(private val activity: Activity) : MethodCallHandler {
try {
locked = Settings.System.getInt(activity.contentResolver, Settings.System.ACCELEROMETER_ROTATION) == 0
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get settings", e)
Log.w(LOG_TAG, "failed to get settings with error=${e.message}", null)
}
result.success(locked)
}

View file

@ -56,7 +56,7 @@ class SettingsChangeStreamHandler(private val context: Context) : EventChannel.S
}
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to get settings", e)
Log.w(LOG_TAG, "failed to get settings with error=${e.message}", null)
}
return changed
}

View file

@ -2,4 +2,4 @@
<b>Navigation und Suche</b> ist ein wichtiger Bestandteil von <i>Aves</i>. Das Ziel besteht darin, dass Benutzer problemlos von Alben zu Fotos zu Tags zu Karten usw. wechseln können.
<i>Aves</i> lässt sich mit Android (von <b>API 20 bis 31</b>, d. h. von Lollipop bis S) mit Funktionen wie <b>App-Verknüpfungen</b> und <b>globaler Suche</b> integrieren. Es funktioniert auch als <b>Medienbetrachter und -auswahl</b>.
<i>Aves</i> lässt sich mit Android (von <b>API 19 bis 31</b>, d. h. von KitKat bis S) mit Funktionen wie <b>App-Verknüpfungen</b> und <b>globaler Suche</b> integrieren. Es funktioniert auch als <b>Medienbetrachter und -auswahl</b>.

View file

@ -2,4 +2,4 @@
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
<i>Aves</i> integrates with Android (from <b>API 20 to 31</b>, i.e. from Lollipop to S) with features such as <b>app shortcuts</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
<i>Aves</i> integrates with Android (from <b>API 19 to 31</b>, i.e. from KitKat to S) with features such as <b>app shortcuts</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.

View file

@ -1,6 +1,7 @@
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/durations.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:github/github.dart';
@ -17,6 +18,8 @@ abstract class AvesAvailability {
Future<bool> get canLocatePlaces;
Future<bool> get canUseGoogleMaps;
Future<bool> get isNewVersionAvailable;
}
@ -59,6 +62,13 @@ class LiveAvesAvailability implements AvesAvailability {
@override
Future<bool> get canLocatePlaces => Future.wait<bool>([isConnected, hasPlayServices]).then((results) => results.every((result) => result));
// as of google_maps_flutter v2.1.1, minSDK is 20 because of default PlatformView usage,
// but using hybrid composition would make it usable on 19 too, cf https://github.com/flutter/flutter/issues/23728
Future<bool> get _isUseGoogleMapRenderingSupported => DeviceInfoPlugin().androidInfo.then((androidInfo) => (androidInfo.version.sdkInt ?? 0) >= 20);
@override
Future<bool> get canUseGoogleMaps => Future.wait<bool>([_isUseGoogleMapRenderingSupported, hasPlayServices]).then((results) => results.every((result) => result));
@override
Future<bool> get isNewVersionAvailable async {
if (_isNewVersionAvailable != null) return SynchronousFuture(_isNewVersionAvailable!);

View file

@ -152,8 +152,8 @@ class Settings extends ChangeNotifier {
enableOverlayBlurEffect = performanceClass >= 29;
// availability
final hasPlayServices = await availability.hasPlayServices;
if (hasPlayServices) {
final canUseGoogleMaps = await availability.canUseGoogleMaps;
if (canUseGoogleMaps) {
infoMapStyle = EntryMapStyle.googleNormal;
} else {
final styles = EntryMapStyle.values.whereNot((v) => v.isGoogleMaps).toList();

View file

@ -135,8 +135,8 @@ class MapButtonPanel extends StatelessWidget {
child: MapOverlayButton(
icon: const Icon(AIcons.layers),
onPressed: () async {
final hasPlayServices = await availability.hasPlayServices;
final availableStyles = EntryMapStyle.values.where((style) => !style.isGoogleMaps || hasPlayServices);
final canUseGoogleMaps = await availability.canUseGoogleMaps;
final availableStyles = EntryMapStyle.values.where((style) => !style.isGoogleMaps || canUseGoogleMaps);
final preferredStyle = settings.infoMapStyle;
final initialStyle = availableStyles.contains(preferredStyle) ? preferredStyle : availableStyles.first;
final style = await showDialog<EntryMapStyle>(

View file

@ -119,14 +119,14 @@ packages:
name: connectivity_plus
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
connectivity_plus_linux:
dependency: transitive
description:
name: connectivity_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
connectivity_plus_macos:
dependency: transitive
description:
@ -140,7 +140,7 @@ packages:
name: connectivity_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
connectivity_plus_web:
dependency: transitive
description:
@ -196,7 +196,7 @@ packages:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.6"
version: "0.6.6"
decorated_icon:
dependency: "direct main"
description:
@ -340,7 +340,7 @@ packages:
name: flex_color_picker
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.2.0"
fluster:
dependency: "direct main"
description:
@ -404,7 +404,7 @@ packages:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.5"
flutter_staggered_animations:
dependency: "direct main"
description:
@ -468,7 +468,7 @@ packages:
name: google_maps_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
google_maps_flutter_platform_interface:
dependency: transitive
description:
@ -573,7 +573,7 @@ packages:
name: markdown
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
version: "4.0.1"
matcher:
dependency: transitive
description:
@ -629,7 +629,7 @@ packages:
name: nm
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.1"
node_preamble:
dependency: transitive
description:
@ -727,7 +727,7 @@ packages:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.2"
path_provider_platform_interface:
dependency: transitive
description:
@ -741,14 +741,14 @@ packages:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.4"
pdf:
dependency: "direct main"
description:
name: pdf
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.1"
version: "3.6.3"
pedantic:
dependency: transitive
description:
@ -769,7 +769,7 @@ packages:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "8.2.6"
version: "8.3.0"
permission_handler_platform_interface:
dependency: transitive
description:
@ -818,7 +818,7 @@ packages:
name: printing
url: "https://pub.dartlang.org"
source: hosted
version: "5.6.0"
version: "5.6.3"
process:
dependency: transitive
description:
@ -867,6 +867,20 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
shared_preferences_linux:
dependency: transitive
@ -874,7 +888,7 @@ packages:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
shared_preferences_macos:
dependency: transitive
description:
@ -902,7 +916,7 @@ packages:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
shelf:
dependency: transitive
description:
@ -1084,7 +1098,7 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.12"
version: "6.0.15"
url_launcher_linux:
dependency: transitive
description:
@ -1175,7 +1189,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.10"
version: "2.3.0"
wkt_parser:
dependency: transitive
description: