map style check
This commit is contained in:
parent
068f4d499a
commit
8ced682bfd
15 changed files with 75 additions and 65 deletions
|
@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
- upgraded Flutter to stable v3.0.1
|
||||
- stretching overscroll effect
|
||||
- disabled Google Maps layer on Android Lollipop
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
|
|||
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
|
||||
"canPrint" to (sdkInt >= Build.VERSION_CODES.KITKAT),
|
||||
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
|
||||
// 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 API 19 too,
|
||||
// cf https://github.com/flutter/flutter/issues/23728
|
||||
"canRenderGoogleMaps" to (sdkInt >= Build.VERSION_CODES.KITKAT_WATCH),
|
||||
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
|
||||
"supportEdgeToEdgeUIMode" to (sdkInt >= Build.VERSION_CODES.Q),
|
||||
)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
|
@ -10,7 +11,7 @@ abstract class AvesAvailability {
|
|||
|
||||
Future<bool> get canLocatePlaces;
|
||||
|
||||
Future<bool> get canUseDeviceMaps;
|
||||
List<EntryMapStyle> get mapStyles;
|
||||
}
|
||||
|
||||
class LiveAvesAvailability implements AvesAvailability {
|
||||
|
@ -42,11 +43,11 @@ class LiveAvesAvailability implements AvesAvailability {
|
|||
// local geocoding with `geocoder` seems to require Google Play Services
|
||||
// what about devices with Huawei Mobile Services?
|
||||
@override
|
||||
Future<bool> get canLocatePlaces => Future.wait<bool>([
|
||||
isConnected,
|
||||
PlatformMobileServices().isServiceAvailable(),
|
||||
]).then((results) => results.every((result) => result));
|
||||
Future<bool> get canLocatePlaces async => mobileServices.isServiceAvailable && await isConnected;
|
||||
|
||||
@override
|
||||
Future<bool> get canUseDeviceMaps async => device.canRenderGoogleMaps && await PlatformMobileServices().isServiceAvailable();
|
||||
List<EntryMapStyle> get mapStyles => [
|
||||
...mobileServices.mapStyles,
|
||||
...EntryMapStyle.values.where((v) => !v.needMobileService),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ final Device device = Device._private();
|
|||
|
||||
class Device {
|
||||
late final String _userAgent;
|
||||
late final bool _canGrantDirectoryAccess, _canPinShortcut, _canPrint, _canRenderFlagEmojis, _canRenderGoogleMaps;
|
||||
late final bool _canGrantDirectoryAccess, _canPinShortcut, _canPrint, _canRenderFlagEmojis;
|
||||
late final bool _showPinShortcutFeedback, _supportEdgeToEdgeUIMode;
|
||||
|
||||
String get userAgent => _userAgent;
|
||||
|
@ -18,8 +18,6 @@ class Device {
|
|||
|
||||
bool get canRenderFlagEmojis => _canRenderFlagEmojis;
|
||||
|
||||
bool get canRenderGoogleMaps => _canRenderGoogleMaps;
|
||||
|
||||
bool get showPinShortcutFeedback => _showPinShortcutFeedback;
|
||||
|
||||
bool get supportEdgeToEdgeUIMode => _supportEdgeToEdgeUIMode;
|
||||
|
@ -35,7 +33,6 @@ class Device {
|
|||
_canPinShortcut = capabilities['canPinShortcut'] ?? false;
|
||||
_canPrint = capabilities['canPrint'] ?? false;
|
||||
_canRenderFlagEmojis = capabilities['canRenderFlagEmojis'] ?? false;
|
||||
_canRenderGoogleMaps = capabilities['canRenderGoogleMaps'] ?? false;
|
||||
_showPinShortcutFeedback = capabilities['showPinShortcutFeedback'] ?? false;
|
||||
_supportEdgeToEdgeUIMode = capabilities['supportEdgeToEdgeUIMode'] ?? false;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ extension ExtraEntryMapStyle on EntryMapStyle {
|
|||
}
|
||||
}
|
||||
|
||||
bool get needDeviceService {
|
||||
bool get needMobileService {
|
||||
switch (this) {
|
||||
case EntryMapStyle.osmHot:
|
||||
case EntryMapStyle.stamenToner:
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:aves/model/source/enums.dart';
|
|||
import 'package:aves/services/accessibility_service.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -165,11 +164,11 @@ class Settings extends ChangeNotifier {
|
|||
enableOverlayBlurEffect = performanceClass >= 29;
|
||||
|
||||
// availability
|
||||
final isDeviceMapAvailable = await availability.canUseDeviceMaps;
|
||||
if (isDeviceMapAvailable) {
|
||||
infoMapStyle = PlatformMobileServices().defaultMapStyle;
|
||||
final defaultMapStyle = mobileServices.defaultMapStyle;
|
||||
if (mobileServices.mapStyles.contains(defaultMapStyle)) {
|
||||
infoMapStyle = defaultMapStyle;
|
||||
} else {
|
||||
final styles = EntryMapStyle.values.whereNot((v) => v.needDeviceService).toList();
|
||||
final styles = EntryMapStyle.values.whereNot((v) => v.needMobileService).toList();
|
||||
infoMapStyle = styles[Random().nextInt(styles.length)];
|
||||
}
|
||||
|
||||
|
@ -516,7 +515,11 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
// info
|
||||
|
||||
EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, SettingsDefaults.infoMapStyle, EntryMapStyle.values);
|
||||
EntryMapStyle get infoMapStyle {
|
||||
final preferred = getEnumOrDefault(infoMapStyleKey, SettingsDefaults.infoMapStyle, EntryMapStyle.values);
|
||||
final available = availability.mapStyles;
|
||||
return available.contains(preferred) ? preferred : available.first;
|
||||
}
|
||||
|
||||
set infoMapStyle(EntryMapStyle newValue) => setAndNotify(infoMapStyleKey, newValue.toString());
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ import 'package:aves/services/storage_service.dart';
|
|||
import 'package:aves/services/window_service.dart';
|
||||
import 'package:aves_report/aves_report.dart';
|
||||
import 'package:aves_report_platform/aves_report_platform.dart';
|
||||
import 'package:aves_services/aves_services.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
|
@ -33,6 +35,7 @@ final MediaFileService mediaFileService = getIt<MediaFileService>();
|
|||
final MediaStoreService mediaStoreService = getIt<MediaStoreService>();
|
||||
final MetadataEditService metadataEditService = getIt<MetadataEditService>();
|
||||
final MetadataFetchService metadataFetchService = getIt<MetadataFetchService>();
|
||||
final MobileServices mobileServices = getIt<MobileServices>();
|
||||
final ReportService reportService = getIt<ReportService>();
|
||||
final StorageService storageService = getIt<StorageService>();
|
||||
final WindowService windowService = getIt<WindowService>();
|
||||
|
@ -49,6 +52,7 @@ void initPlatformServices() {
|
|||
getIt.registerLazySingleton<MediaStoreService>(PlatformMediaStoreService.new);
|
||||
getIt.registerLazySingleton<MetadataEditService>(PlatformMetadataEditService.new);
|
||||
getIt.registerLazySingleton<MetadataFetchService>(PlatformMetadataFetchService.new);
|
||||
getIt.registerLazySingleton<MobileServices>(PlatformMobileServices.new);
|
||||
getIt.registerLazySingleton<ReportService>(PlatformReportService.new);
|
||||
getIt.registerLazySingleton<StorageService>(PlatformStorageService.new);
|
||||
getIt.registerLazySingleton<WindowService>(PlatformWindowService.new);
|
||||
|
|
|
@ -15,7 +15,6 @@ import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
|||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:aves/widgets/common/identity/buttons.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -145,7 +144,6 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
|
|||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
final installer = await androidAppService.getAppInstaller();
|
||||
final hasMobileServices = await PlatformMobileServices().isServiceAvailable();
|
||||
final flavor = context.read<AppFlavor>().toString().split('.')[1];
|
||||
return [
|
||||
'Aves version: ${packageInfo.version}-$flavor (Build ${packageInfo.buildNumber})',
|
||||
|
@ -153,7 +151,7 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
|
|||
'Android version: ${androidInfo.version.release} (SDK ${androidInfo.version.sdkInt})',
|
||||
'Android build: ${androidInfo.display}',
|
||||
'Device: ${androidInfo.manufacturer} ${androidInfo.model}',
|
||||
'Mobile services: ${hasMobileServices ? 'ready' : 'not available'}',
|
||||
'Mobile services: ${mobileServices.isServiceAvailable ? 'ready' : 'not available'}',
|
||||
'System locales: ${WidgetsBinding.instance.window.locales.join(', ')}',
|
||||
'Aves locale: ${settings.locale ?? 'system'} -> ${settings.appliedLocale}',
|
||||
'Installer: $installer',
|
||||
|
|
|
@ -30,7 +30,6 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
|||
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
||||
import 'package:aves/widgets/home_page.dart';
|
||||
import 'package:aves/widgets/welcome_page.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:fijkplayer/fijkplayer.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -225,6 +224,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
await device.init();
|
||||
await mobileServices.init();
|
||||
await settings.init(monitorPlatformSettings: true);
|
||||
settings.isRotationLocked = await windowService.isRotationLocked();
|
||||
settings.areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
|
||||
|
@ -273,14 +273,13 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
|
||||
FlutterError.onError = reportService.recordFlutterError;
|
||||
final now = DateTime.now();
|
||||
final hasMobileServices = await PlatformMobileServices().isServiceAvailable();
|
||||
await reportService.setCustomKeys({
|
||||
'build_mode': kReleaseMode
|
||||
? 'release'
|
||||
: kProfileMode
|
||||
? 'profile'
|
||||
: 'debug',
|
||||
'has_mobile_services': hasMobileServices,
|
||||
'has_mobile_services': mobileServices.isServiceAvailable,
|
||||
'locales': WidgetsBinding.instance.window.locales.join(', '),
|
||||
'time_zone': '${now.timeZoneName} (${now.timeZoneOffset})',
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:aves/widgets/common/map/buttons/coordinate_filter.dart';
|
|||
import 'package:aves/widgets/common/map/compass.dart';
|
||||
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -125,24 +124,15 @@ class MapButtonPanel extends StatelessWidget {
|
|||
padding: EdgeInsets.only(top: padding),
|
||||
child: MapOverlayButton(
|
||||
icon: const Icon(AIcons.layers),
|
||||
onPressed: () async {
|
||||
final canUseDeviceMaps = await availability.canUseDeviceMaps;
|
||||
final availableStyles = [
|
||||
if (canUseDeviceMaps) ...PlatformMobileServices().mapStyles,
|
||||
...EntryMapStyle.values.where((v) => !v.needDeviceService),
|
||||
];
|
||||
final preferredStyle = settings.infoMapStyle;
|
||||
final initialStyle = availableStyles.contains(preferredStyle) ? preferredStyle : availableStyles.first;
|
||||
await showSelectionDialog<EntryMapStyle>(
|
||||
onPressed: () => showSelectionDialog<EntryMapStyle>(
|
||||
context: context,
|
||||
builder: (context) => AvesSelectionDialog<EntryMapStyle>(
|
||||
initialValue: initialStyle,
|
||||
options: Map.fromEntries(availableStyles.map((v) => MapEntry(v, v.getName(context)))),
|
||||
initialValue: settings.infoMapStyle,
|
||||
options: Map.fromEntries(availability.mapStyles.map((v) => MapEntry(v, v.getName(context)))),
|
||||
title: context.l10n.mapStyleTitle,
|
||||
),
|
||||
onSelection: (v) => settings.infoMapStyle = v,
|
||||
);
|
||||
},
|
||||
),
|
||||
tooltip: context.l10n.mapStyleTooltip,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:aves/model/entry.dart';
|
|||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/enums/map_style.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/utils/change_notifier.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
|
@ -15,7 +16,6 @@ import 'package:aves/widgets/common/map/decorator.dart';
|
|||
import 'package:aves/widgets/common/map/leaflet/map.dart';
|
||||
import 'package:aves/widgets/common/thumbnail/image.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluster/fluster.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -71,8 +71,6 @@ class _GeoMapState extends State<GeoMap> {
|
|||
|
||||
List<AvesEntry> get entries => widget.entries;
|
||||
|
||||
static final _platformMobileServices = PlatformMobileServices();
|
||||
|
||||
// cap initial zoom to avoid a zoom change
|
||||
// when toggling overlay on Google map initial state
|
||||
static const double minInitialZoom = 3;
|
||||
|
@ -172,7 +170,7 @@ class _GeoMapState extends State<GeoMap> {
|
|||
case EntryMapStyle.googleTerrain:
|
||||
case EntryMapStyle.hmsNormal:
|
||||
case EntryMapStyle.hmsTerrain:
|
||||
child = _platformMobileServices.buildMap<AvesEntry>(
|
||||
child = mobileServices.buildMap<AvesEntry>(
|
||||
controller: widget.controller,
|
||||
clusterListenable: _clusterChangeNotifier,
|
||||
boundsNotifier: _boundsNotifier,
|
||||
|
|
|
@ -5,7 +5,9 @@ import 'package:flutter/widgets.dart';
|
|||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
abstract class MobileServices {
|
||||
Future<bool> isServiceAvailable();
|
||||
Future<void> init();
|
||||
|
||||
bool get isServiceAvailable;
|
||||
|
||||
EntryMapStyle get defaultMapStyle;
|
||||
|
||||
|
|
|
@ -3,28 +3,43 @@ library aves_services_platform;
|
|||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:aves_services/aves_services.dart';
|
||||
import 'package:aves_services_platform/src/map.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:google_api_availability/google_api_availability.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
class PlatformMobileServices extends MobileServices {
|
||||
bool? _isAvailable;
|
||||
bool _isAvailable = false;
|
||||
bool _canRenderMaps = false;
|
||||
|
||||
@override
|
||||
Future<bool> isServiceAvailable() async {
|
||||
if (_isAvailable != null) return SynchronousFuture(_isAvailable!);
|
||||
Future<void> init() async {
|
||||
final result = await GoogleApiAvailability.instance.checkGooglePlayServicesAvailability();
|
||||
_isAvailable = result == GooglePlayServicesAvailability.success;
|
||||
debugPrint('Device has Google Play Services=$_isAvailable');
|
||||
return _isAvailable!;
|
||||
|
||||
// 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 API 19 too,
|
||||
// cf https://github.com/flutter/flutter/issues/23728
|
||||
// as of google_maps_flutter v2.1.5, Flutter v3.0.1 makes the map hide overlay widgets on API <=22
|
||||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
_canRenderMaps = (androidInfo.version.sdkInt ?? 0) >= 23;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isServiceAvailable => _isAvailable;
|
||||
|
||||
@override
|
||||
EntryMapStyle get defaultMapStyle => EntryMapStyle.googleNormal;
|
||||
|
||||
@override
|
||||
List<EntryMapStyle> get mapStyles => [EntryMapStyle.googleNormal, EntryMapStyle.googleHybrid, EntryMapStyle.googleTerrain];
|
||||
List<EntryMapStyle> get mapStyles => (isServiceAvailable && _canRenderMaps)
|
||||
? [
|
||||
EntryMapStyle.googleNormal,
|
||||
EntryMapStyle.googleHybrid,
|
||||
EntryMapStyle.googleTerrain,
|
||||
]
|
||||
: [];
|
||||
|
||||
@override
|
||||
Widget buildMap<T>({
|
||||
|
|
|
@ -12,6 +12,7 @@ dependencies:
|
|||
path: ../aves_map
|
||||
aves_services:
|
||||
path: ../aves_services
|
||||
device_info_plus:
|
||||
google_api_availability:
|
||||
google_maps_flutter:
|
||||
latlong2:
|
||||
|
|
|
@ -3,7 +3,6 @@ library aves_services_platform;
|
|||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:aves_services/aves_services.dart';
|
||||
import 'package:aves_services_platform/src/map.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:huawei_hmsavailability/huawei_hmsavailability.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
@ -12,22 +11,28 @@ class PlatformMobileServices extends MobileServices {
|
|||
// cf https://developer.huawei.com/consumer/en/doc/development/hmscore-common-References/huaweiapiavailability-0000001050121134#section9492524178
|
||||
static const int _hmsCoreAvailable = 0;
|
||||
|
||||
bool? _isAvailable;
|
||||
bool _isAvailable = false;
|
||||
|
||||
@override
|
||||
Future<bool> isServiceAvailable() async {
|
||||
if (_isAvailable != null) return SynchronousFuture(_isAvailable!);
|
||||
Future<void> init() async {
|
||||
final result = await HmsApiAvailability().isHMSAvailable();
|
||||
_isAvailable = result == _hmsCoreAvailable;
|
||||
debugPrint('Device has Huawei Mobile Services=$_isAvailable');
|
||||
return _isAvailable!;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isServiceAvailable => _isAvailable;
|
||||
|
||||
@override
|
||||
EntryMapStyle get defaultMapStyle => EntryMapStyle.hmsNormal;
|
||||
|
||||
@override
|
||||
List<EntryMapStyle> get mapStyles => [EntryMapStyle.hmsNormal, EntryMapStyle.hmsTerrain];
|
||||
List<EntryMapStyle> get mapStyles => isServiceAvailable
|
||||
? [
|
||||
EntryMapStyle.hmsNormal,
|
||||
EntryMapStyle.hmsTerrain,
|
||||
]
|
||||
: [];
|
||||
|
||||
@override
|
||||
Widget buildMap<T>({
|
||||
|
|
Loading…
Reference in a new issue