deactivate geocoding and Google maps when Play Services are unavailable
This commit is contained in:
parent
910dd1fe54
commit
ab96741a18
11 changed files with 78 additions and 46 deletions
41
lib/model/availability.dart
Normal file
41
lib/model/availability.dart
Normal file
|
@ -0,0 +1,41 @@
|
|||
import 'package:connectivity/connectivity.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:google_api_availability/google_api_availability.dart';
|
||||
|
||||
final AvesAvailability availability = AvesAvailability._private();
|
||||
|
||||
class AvesAvailability {
|
||||
bool _isConnected, _hasPlayServices;
|
||||
|
||||
AvesAvailability._private() {
|
||||
Connectivity().onConnectivityChanged.listen(_updateConnectivityFromResult);
|
||||
}
|
||||
|
||||
void onResume() => _isConnected = null;
|
||||
|
||||
Future<bool> get isConnected async {
|
||||
if (_isConnected != null) return SynchronousFuture(_isConnected);
|
||||
final result = await (Connectivity().checkConnectivity());
|
||||
_updateConnectivityFromResult(result);
|
||||
return _isConnected;
|
||||
}
|
||||
|
||||
void _updateConnectivityFromResult(ConnectivityResult result) {
|
||||
final newValue = result != ConnectivityResult.none;
|
||||
if (_isConnected != newValue) {
|
||||
_isConnected = newValue;
|
||||
debugPrint('Device is connected=$_isConnected');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> get hasPlayServices async {
|
||||
if (_hasPlayServices != null) return SynchronousFuture(_hasPlayServices);
|
||||
final result = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
|
||||
_hasPlayServices = result == GooglePlayServicesAvailability.success;
|
||||
debugPrint('Device has Play Services=$_hasPlayServices');
|
||||
return _hasPlayServices;
|
||||
}
|
||||
|
||||
// local geolocation with `geocoder` requires Play Services
|
||||
Future<bool> get canGeolocate => Future.wait<bool>([isConnected, hasPlayServices]).then((results) => results.every((result) => result));
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
import 'package:connectivity/connectivity.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
final AvesConnectivity connectivity = AvesConnectivity._private();
|
||||
|
||||
class AvesConnectivity {
|
||||
bool _isConnected;
|
||||
|
||||
AvesConnectivity._private() {
|
||||
Connectivity().onConnectivityChanged.listen(_updateFromResult);
|
||||
}
|
||||
|
||||
void onResume() => _isConnected = null;
|
||||
|
||||
Future<bool> get isConnected async {
|
||||
if (_isConnected != null) return SynchronousFuture(_isConnected);
|
||||
final result = await (Connectivity().checkConnectivity());
|
||||
_updateFromResult(result);
|
||||
return _isConnected;
|
||||
}
|
||||
|
||||
Future<bool> get canGeolocate => isConnected;
|
||||
|
||||
void _updateFromResult(ConnectivityResult result) {
|
||||
_isConnected = result != ConnectivityResult.none;
|
||||
debugPrint('Device is connected=$_isConnected');
|
||||
}
|
||||
}
|
|
@ -42,6 +42,10 @@ class AvesEntry {
|
|||
|
||||
final AChangeNotifier imageChangeNotifier = AChangeNotifier(), metadataChangeNotifier = AChangeNotifier(), addressChangeNotifier = AChangeNotifier();
|
||||
|
||||
// Local geocoding requires Google Play Services
|
||||
// Google remote geocoding requires an API key and is not free
|
||||
final Future<List<Address>> Function(Coordinates coordinates) _findAddresses = Geocoder.local.findAddressesFromCoordinates;
|
||||
|
||||
// TODO TLAD make it dynamic if it depends on OS/lib versions
|
||||
static const List<String> undecodable = [MimeTypes.crw, MimeTypes.psd];
|
||||
|
||||
|
@ -441,7 +445,7 @@ class AvesEntry {
|
|||
|
||||
final coordinates = Coordinates(latitude, longitude);
|
||||
try {
|
||||
Future<List<Address>> call() => Geocoder.local.findAddressesFromCoordinates(coordinates);
|
||||
Future<List<Address>> call() => _findAddresses(coordinates);
|
||||
final addresses = await (background
|
||||
? servicePolicy.call(
|
||||
call,
|
||||
|
@ -475,7 +479,7 @@ class AvesEntry {
|
|||
|
||||
final coordinates = Coordinates(latitude, longitude);
|
||||
try {
|
||||
final addresses = await Geocoder.local.findAddressesFromCoordinates(coordinates);
|
||||
final addresses = await _findAddresses(coordinates);
|
||||
if (addresses != null && addresses.isNotEmpty) {
|
||||
final address = addresses.first;
|
||||
return address.addressLine;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/connectivity.dart';
|
||||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/metadata.dart';
|
||||
|
@ -28,7 +28,7 @@ mixin LocationMixin on SourceBase {
|
|||
}
|
||||
|
||||
Future<void> locateEntries() async {
|
||||
if (!(await connectivity.canGeolocate)) return;
|
||||
if (!(await availability.canGeolocate)) return;
|
||||
|
||||
// final stopwatch = Stopwatch()..start();
|
||||
final byLocated = groupBy<AvesEntry, bool>(rawEntries.where((entry) => entry.hasGps), (entry) => entry.isLocated);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/main.dart';
|
||||
import 'package:aves/model/connectivity.dart';
|
||||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/home_page.dart';
|
||||
|
@ -115,7 +115,7 @@ class _HomePageState extends State<HomePage> {
|
|||
// cataloguing is essential for coordinates and video rotation
|
||||
await entry.catalog();
|
||||
// locating is fine in the background
|
||||
unawaited(connectivity.canGeolocate.then((connected) {
|
||||
unawaited(availability.canGeolocate.then((connected) {
|
||||
if (connected) {
|
||||
entry.locate();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/connectivity.dart';
|
||||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/widgets/common/magnifier/pan/scroll_physics.dart';
|
||||
|
@ -152,7 +152,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
|
|||
// make sure to locate the entry,
|
||||
// so that we can display the address instead of coordinates
|
||||
// even when initial collection locating has not reached this entry yet
|
||||
connectivity.canGeolocate.then((connected) {
|
||||
availability.canGeolocate.then((connected) {
|
||||
if (connected) {
|
||||
entry.locate();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/connectivity.dart';
|
||||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/settings/screen_on.dart';
|
||||
|
@ -151,7 +151,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
_pauseVideoControllers();
|
||||
break;
|
||||
case AppLifecycleState.resumed:
|
||||
connectivity.onResume();
|
||||
availability.onResume();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:aves/model/connectivity.dart';
|
||||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/location.dart';
|
||||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
|
@ -104,7 +104,7 @@ class _LocationSectionState extends State<LocationSection> with TickerProviderSt
|
|||
children: [
|
||||
if (widget.showTitle) SectionRow(AIcons.location),
|
||||
FutureBuilder<bool>(
|
||||
future: connectivity.isConnected,
|
||||
future: availability.isConnected,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data != true) return SizedBox();
|
||||
return NotificationListener(
|
||||
|
@ -181,7 +181,7 @@ class _AddressInfoGroupState extends State<_AddressInfoGroup> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_addressLineLoader = connectivity.canGeolocate.then((connected) {
|
||||
_addressLineLoader = availability.canGeolocate.then((connected) {
|
||||
if (connected) {
|
||||
return entry.findAddressLine();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:aves/model/availability.dart';
|
||||
import 'package:aves/model/settings/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/android_app_service.dart';
|
||||
|
@ -73,13 +74,19 @@ class MapButtonPanel extends StatelessWidget {
|
|||
MapOverlayButton(
|
||||
icon: AIcons.layers,
|
||||
onPressed: () async {
|
||||
final hasPlayServices = await availability.hasPlayServices;
|
||||
final availableStyles = EntryMapStyle.values.where((style) => !style.isGoogleMaps || hasPlayServices);
|
||||
final preferredStyle = settings.infoMapStyle;
|
||||
final initialStyle = availableStyles.contains(preferredStyle) ? preferredStyle : availableStyles.first;
|
||||
final style = await showDialog<EntryMapStyle>(
|
||||
context: context,
|
||||
builder: (context) => AvesSelectionDialog<EntryMapStyle>(
|
||||
initialValue: settings.infoMapStyle,
|
||||
options: Map.fromEntries(EntryMapStyle.values.map((v) => MapEntry(v, v.name))),
|
||||
title: 'Map Style',
|
||||
),
|
||||
builder: (context) {
|
||||
return AvesSelectionDialog<EntryMapStyle>(
|
||||
initialValue: initialStyle,
|
||||
options: Map.fromEntries(availableStyles.map((v) => MapEntry(v, v.name))),
|
||||
title: 'Map Style',
|
||||
);
|
||||
},
|
||||
);
|
||||
// wait for the dialog to hide because switching to Google Maps layer may block the UI
|
||||
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);
|
||||
|
|
|
@ -387,6 +387,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
google_api_availability:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_api_availability
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
google_maps_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -55,6 +55,7 @@ dependencies:
|
|||
flutter_staggered_animations:
|
||||
flutter_svg:
|
||||
geocoder:
|
||||
google_api_availability:
|
||||
google_maps_flutter:
|
||||
intl:
|
||||
latlong: # for flutter_map
|
||||
|
|
Loading…
Reference in a new issue