#1087 open external map app from map views
This commit is contained in:
parent
2d5a7f6c27
commit
4d80dfe1d6
8 changed files with 109 additions and 56 deletions
|
@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
- Viewer: display more items in tag/copy/move quick action choosers
|
||||
- Collection: sort by duration
|
||||
- Map: open external map app from map views
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ extension ExtraMapActionView on MapAction {
|
|||
final l10n = context.l10n;
|
||||
return switch (this) {
|
||||
MapAction.selectStyle => l10n.mapStyleTooltip,
|
||||
MapAction.openMapApp => l10n.entryActionOpenMap,
|
||||
MapAction.zoomIn => l10n.mapZoomInTooltip,
|
||||
MapAction.zoomOut => l10n.mapZoomOutTooltip,
|
||||
};
|
||||
|
@ -18,6 +19,7 @@ extension ExtraMapActionView on MapAction {
|
|||
IconData _getIconData() {
|
||||
return switch (this) {
|
||||
MapAction.selectStyle => AIcons.layers,
|
||||
MapAction.openMapApp => AIcons.openOutside,
|
||||
MapAction.zoomIn => AIcons.zoomIn,
|
||||
MapAction.zoomOut => AIcons.zoomOut,
|
||||
};
|
||||
|
|
|
@ -124,7 +124,13 @@ class MapButtonPanel extends StatelessWidget {
|
|||
Padding(
|
||||
padding: EdgeInsets.only(top: padding),
|
||||
// key is expected by test driver
|
||||
child: _buildButton(context, MapAction.selectStyle, buttonKey: const Key('map-menu-layers')),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildButton(context, MapAction.selectStyle, buttonKey: const Key('map-menu-layers')),
|
||||
SizedBox(height: padding),
|
||||
_buildButton(context, MapAction.openMapApp),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -26,6 +26,8 @@ class MapActionDelegate {
|
|||
),
|
||||
onSelection: (v) => settings.mapStyle = v,
|
||||
);
|
||||
case MapAction.openMapApp:
|
||||
OpenMapAppNotification().dispatch(context);
|
||||
case MapAction.zoomIn:
|
||||
controller?.zoomBy(1);
|
||||
case MapAction.zoomOut:
|
||||
|
@ -33,3 +35,5 @@ class MapActionDelegate {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OpenMapAppNotification extends Notification {}
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:aves/model/settings/enums/map_style.dart';
|
|||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/model/source/tag.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/view/view.dart';
|
||||
|
@ -28,6 +29,7 @@ import 'package:aves/widgets/common/map/geo_map.dart';
|
|||
import 'package:aves/widgets/common/map/map_action_delegate.dart';
|
||||
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
|
||||
import 'package:aves/widgets/common/providers/map_theme_provider.dart';
|
||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/action_delegates/chip.dart';
|
||||
import 'package:aves/widgets/map/scroller.dart';
|
||||
import 'package:aves/widgets/viewer/controls/notifications.dart';
|
||||
|
@ -188,6 +190,8 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
_goToCollection(notification.filter);
|
||||
} else if (notification is FilterNotification) {
|
||||
_goToCollection(notification.filter);
|
||||
} else if (notification is OpenMapAppNotification) {
|
||||
_openMapApp();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -434,6 +438,15 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _openMapApp() async {
|
||||
final latLng = _dotEntryNotifier.value?.latLng ?? _mapController.idleBounds?.projectedCenter;
|
||||
if (latLng != null) {
|
||||
await appService.openMap(latLng).then((success) {
|
||||
if (!success) showNoMatchingAppDialog(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// overlay
|
||||
|
||||
void _toggleOverlay() => _overlayVisible.value = !_overlayVisible.value;
|
||||
|
|
|
@ -10,7 +10,9 @@ import 'package:aves/theme/icons.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/map/geo_map.dart';
|
||||
import 'package:aves/widgets/common/map/map_action_delegate.dart';
|
||||
import 'package:aves/widgets/common/providers/map_theme_provider.dart';
|
||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||
import 'package:aves/widgets/map/map_page.dart';
|
||||
import 'package:aves/widgets/viewer/info/common.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
|
@ -76,7 +78,15 @@ class _LocationSectionState extends State<LocationSection> {
|
|||
if (!entry.hasGps) return const SizedBox();
|
||||
|
||||
final canNavigate = context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canNavigate);
|
||||
return Column(
|
||||
return NotificationListener(
|
||||
onNotification: (notification) {
|
||||
if (notification is OpenMapAppNotification) {
|
||||
_openMapApp();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.showTitle) const SectionRow(icon: AIcons.location),
|
||||
|
@ -133,6 +143,7 @@ class _LocationSectionState extends State<LocationSection> {
|
|||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -155,6 +166,15 @@ class _LocationSectionState extends State<LocationSection> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _openMapApp() async {
|
||||
final latLng = entry.latLng;
|
||||
if (latLng != null) {
|
||||
await appService.openMap(latLng).then((success) {
|
||||
if (!success) showNoMatchingAppDialog(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _onMetadataChanged() {
|
||||
setState(() {});
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ import 'package:latlong2/latlong.dart';
|
|||
|
||||
class AvesMapController {
|
||||
final StreamController _streamController = StreamController.broadcast();
|
||||
ZoomedBounds? _idleBounds;
|
||||
|
||||
ZoomedBounds? get idleBounds => _idleBounds;
|
||||
|
||||
Stream<dynamic> get _events => _streamController.stream;
|
||||
|
||||
|
@ -38,7 +41,10 @@ class AvesMapController {
|
|||
|
||||
void zoomBy(double delta) => _streamController.add(MapControllerZoomEvent(delta));
|
||||
|
||||
void notifyIdle(ZoomedBounds bounds) => _streamController.add(MapIdleUpdate(bounds));
|
||||
void notifyIdle(ZoomedBounds bounds) {
|
||||
_idleBounds = bounds;
|
||||
_streamController.add(MapIdleUpdate(bounds));
|
||||
}
|
||||
|
||||
void notifyMarkerLocationChange() => _streamController.add(MapMarkerLocationChangeEvent());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
enum MapAction {
|
||||
selectStyle,
|
||||
openMapApp,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue