map shortcut, geo: uri handling
This commit is contained in:
parent
fb0b4dcab2
commit
ec59e348c5
15 changed files with 143 additions and 55 deletions
|
@ -183,6 +183,13 @@
|
||||||
<data android:scheme="content" />
|
<data android:scheme="content" />
|
||||||
<data android:scheme="file" />
|
<data android:scheme="file" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:scheme="geo" />
|
||||||
|
</intent-filter>
|
||||||
<!--
|
<!--
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.EDIT" />
|
<action android:name="android.intent.action.EDIT" />
|
||||||
|
|
|
@ -313,6 +313,13 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
"com.android.camera.action.REVIEW",
|
"com.android.camera.action.REVIEW",
|
||||||
"com.android.camera.action.SPLIT_SCREEN_REVIEW" -> {
|
"com.android.camera.action.SPLIT_SCREEN_REVIEW" -> {
|
||||||
(intent.data ?: intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM))?.let { uri ->
|
(intent.data ?: intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM))?.let { uri ->
|
||||||
|
if (uri.scheme == "geo") {
|
||||||
|
return hashMapOf(
|
||||||
|
INTENT_DATA_KEY_ACTION to INTENT_ACTION_VIEW_GEO,
|
||||||
|
INTENT_DATA_KEY_URI to uri.toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// MIME type is optional
|
// MIME type is optional
|
||||||
val type = intent.type ?: intent.resolveType(this)
|
val type = intent.type ?: intent.resolveType(this)
|
||||||
val fields = hashMapOf<String, Any?>(
|
val fields = hashMapOf<String, Any?>(
|
||||||
|
@ -484,7 +491,16 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
.setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_search else R.drawable.ic_shortcut_search))
|
.setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_search else R.drawable.ic_shortcut_search))
|
||||||
.setIntent(
|
.setIntent(
|
||||||
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
|
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
|
||||||
.putExtra(EXTRA_KEY_PAGE, "/search")
|
.putExtra(EXTRA_KEY_PAGE, SEARCH_PAGE_ROUTE_NAME)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val map = ShortcutInfoCompat.Builder(this, "map")
|
||||||
|
.setShortLabel(getString(R.string.map_shortcut_short_label))
|
||||||
|
.setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_map else R.drawable.ic_shortcut_map))
|
||||||
|
.setIntent(
|
||||||
|
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
|
||||||
|
.putExtra(EXTRA_KEY_PAGE, MAP_PAGE_ROUTE_NAME)
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -493,21 +509,12 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
.setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_movie else R.drawable.ic_shortcut_movie))
|
.setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_movie else R.drawable.ic_shortcut_movie))
|
||||||
.setIntent(
|
.setIntent(
|
||||||
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
|
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
|
||||||
.putExtra(EXTRA_KEY_PAGE, "/collection")
|
.putExtra(EXTRA_KEY_PAGE, COLLECTION_PAGE_ROUTE_NAME)
|
||||||
.putExtra("filters", arrayOf("{\"type\":\"mime\",\"mime\":\"video/*\"}"))
|
.putExtra("filters", arrayOf("{\"type\":\"mime\",\"mime\":\"video/*\"}"))
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val safeMode = ShortcutInfoCompat.Builder(this, "safeMode")
|
val shortcutInfoList = listOf(videos, search, map)
|
||||||
.setShortLabel(getString(R.string.safe_mode_shortcut_short_label))
|
|
||||||
.setIcon(IconCompat.createWithResource(this, if (supportAdaptiveIcon) R.mipmap.ic_shortcut_safe_mode else R.drawable.ic_shortcut_safe_mode))
|
|
||||||
.setIntent(
|
|
||||||
Intent(Intent.ACTION_MAIN, null, this, MainActivity::class.java)
|
|
||||||
.putExtra(EXTRA_KEY_SAFE_MODE, true)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val shortcutInfoList = listOf(videos, search, safeMode)
|
|
||||||
ShortcutManagerCompat.setDynamicShortcuts(this, shortcutInfoList)
|
ShortcutManagerCompat.setDynamicShortcuts(this, shortcutInfoList)
|
||||||
Log.i(LOG_TAG, "set shortcuts: ${shortcutInfoList.joinToString(", ") { v -> v.id }}")
|
Log.i(LOG_TAG, "set shortcuts: ${shortcutInfoList.joinToString(", ") { v -> v.id }}")
|
||||||
}
|
}
|
||||||
|
@ -537,6 +544,7 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
const val INTENT_ACTION_SEARCH = "search"
|
const val INTENT_ACTION_SEARCH = "search"
|
||||||
const val INTENT_ACTION_SET_WALLPAPER = "set_wallpaper"
|
const val INTENT_ACTION_SET_WALLPAPER = "set_wallpaper"
|
||||||
const val INTENT_ACTION_VIEW = "view"
|
const val INTENT_ACTION_VIEW = "view"
|
||||||
|
const val INTENT_ACTION_VIEW_GEO = "view_geo"
|
||||||
const val INTENT_ACTION_WIDGET_OPEN = "widget_open"
|
const val INTENT_ACTION_WIDGET_OPEN = "widget_open"
|
||||||
const val INTENT_ACTION_WIDGET_SETTINGS = "widget_settings"
|
const val INTENT_ACTION_WIDGET_SETTINGS = "widget_settings"
|
||||||
|
|
||||||
|
@ -560,6 +568,11 @@ open class MainActivity : FlutterFragmentActivity() {
|
||||||
const val EXTRA_KEY_SAFE_MODE = "safeMode"
|
const val EXTRA_KEY_SAFE_MODE = "safeMode"
|
||||||
const val EXTRA_KEY_WIDGET_ID = "widgetId"
|
const val EXTRA_KEY_WIDGET_ID = "widgetId"
|
||||||
|
|
||||||
|
// dart page routes
|
||||||
|
const val COLLECTION_PAGE_ROUTE_NAME = "/collection"
|
||||||
|
const val MAP_PAGE_ROUTE_NAME = "/map"
|
||||||
|
const val SEARCH_PAGE_ROUTE_NAME = "/search"
|
||||||
|
|
||||||
// request code to pending runnable
|
// request code to pending runnable
|
||||||
val pendingStorageAccessResultHandlers = ConcurrentHashMap<Int, PendingStorageAccessResultHandler>()
|
val pendingStorageAccessResultHandlers = ConcurrentHashMap<Int, PendingStorageAccessResultHandler>()
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:tint="@color/ic_shortcut_foreground"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<group
|
|
||||||
android:scaleX="1.7226"
|
|
||||||
android:scaleY="1.7226"
|
|
||||||
android:translateX="33.3288"
|
|
||||||
android:translateY="33.3288">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/white"
|
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM19.46,9.12l-2.78,1.15c-0.51,-1.36 -1.58,-2.44 -2.95,-2.94l1.15,-2.78C16.98,5.35 18.65,7.02 19.46,9.12zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,15 12,15zM9.13,4.54l1.17,2.78c-1.38,0.5 -2.47,1.59 -2.98,2.97L4.54,9.13C5.35,7.02 7.02,5.35 9.13,4.54zM4.54,14.87l2.78,-1.15c0.51,1.38 1.59,2.46 2.97,2.96l-1.17,2.78C7.02,18.65 5.35,16.98 4.54,14.87zM14.88,19.46l-1.15,-2.78c1.37,-0.51 2.45,-1.59 2.95,-2.97l2.78,1.17C18.65,16.98 16.98,18.65 14.88,19.46z" />
|
|
||||||
</group>
|
|
||||||
</vector>
|
|
16
android/app/src/main/res/drawable/ic_shortcut_map.xml
Normal file
16
android/app/src/main/res/drawable/ic_shortcut_map.xml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/ic_shortcut_background"
|
||||||
|
android:pathData="M0,24 A1,1 0 1,1 48,24 A1,1 0 1,1 0,24" />
|
||||||
|
<group
|
||||||
|
android:translateX="12"
|
||||||
|
android:translateY="12">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/ic_shortcut_foreground"
|
||||||
|
android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48L3,20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48L21,3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM10,5.47l4,1.4v11.66l-4,-1.4L10,5.47zM5,6.46l3,-1.01v11.7l-3,1.16L5,6.46zM19,17.54l-3,1.01L16,6.86l3,-1.16v11.84z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:tint="@color/ic_shortcut_foreground"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<group
|
||||||
|
android:scaleX="1.7226"
|
||||||
|
android:scaleY="1.7226"
|
||||||
|
android:translateX="33.3288"
|
||||||
|
android:translateY="33.3288">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48L3,20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48L21,3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM10,5.47l4,1.4v11.66l-4,-1.4L10,5.47zM5,6.46l3,-1.01v11.7l-3,1.16L5,6.46zM19,17.54l-3,1.01L16,6.86l3,-1.16v11.84z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
|
@ -1,16 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="48dp"
|
|
||||||
android:height="48dp"
|
|
||||||
android:viewportWidth="48"
|
|
||||||
android:viewportHeight="48">
|
|
||||||
<path
|
|
||||||
android:fillColor="@color/ic_shortcut_background"
|
|
||||||
android:pathData="M0,24 A1,1 0 1,1 48,24 A1,1 0 1,1 0,24" />
|
|
||||||
<group
|
|
||||||
android:translateX="12"
|
|
||||||
android:translateY="12">
|
|
||||||
<path
|
|
||||||
android:fillColor="@color/ic_shortcut_foreground"
|
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM19.46,9.12l-2.78,1.15c-0.51,-1.36 -1.58,-2.44 -2.95,-2.94l1.15,-2.78C16.98,5.35 18.65,7.02 19.46,9.12zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3s3,1.34 3,3S13.66,15 12,15zM9.13,4.54l1.17,2.78c-1.38,0.5 -2.47,1.59 -2.98,2.97L4.54,9.13C5.35,7.02 7.02,5.35 9.13,4.54zM4.54,14.87l2.78,-1.15c0.51,1.38 1.59,2.46 2.97,2.96l-1.17,2.78C7.02,18.65 5.35,16.98 4.54,14.87zM14.88,19.46l-1.15,-2.78c1.37,-0.51 2.45,-1.59 2.95,-2.97l2.78,1.17C18.65,16.98 16.98,18.65 14.88,19.46z" />
|
|
||||||
</group>
|
|
||||||
</vector>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_shortcut_background" />
|
<background android:drawable="@color/ic_shortcut_background" />
|
||||||
<foreground android:drawable="@drawable/ic_shortcut_safe_mode_foreground" />
|
<foreground android:drawable="@drawable/ic_shortcut_map_foreground" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
|
@ -3,7 +3,7 @@
|
||||||
<string name="app_name">Aves</string>
|
<string name="app_name">Aves</string>
|
||||||
<string name="app_widget_label">Photo Frame</string>
|
<string name="app_widget_label">Photo Frame</string>
|
||||||
<string name="wallpaper">Wallpaper</string>
|
<string name="wallpaper">Wallpaper</string>
|
||||||
<string name="safe_mode_shortcut_short_label">Safe mode</string>
|
<string name="map_shortcut_short_label">Map</string>
|
||||||
<string name="search_shortcut_short_label">Search</string>
|
<string name="search_shortcut_short_label">Search</string>
|
||||||
<string name="videos_shortcut_short_label">Videos</string>
|
<string name="videos_shortcut_short_label">Videos</string>
|
||||||
<string name="analysis_channel_name">Media scan</string>
|
<string name="analysis_channel_name">Media scan</string>
|
||||||
|
|
|
@ -7,6 +7,7 @@ class IntentActions {
|
||||||
static const search = 'search';
|
static const search = 'search';
|
||||||
static const setWallpaper = 'set_wallpaper';
|
static const setWallpaper = 'set_wallpaper';
|
||||||
static const view = 'view';
|
static const view = 'view';
|
||||||
|
static const viewGeo = 'view_geo';
|
||||||
static const widgetOpen = 'widget_open';
|
static const widgetOpen = 'widget_open';
|
||||||
static const widgetSettings = 'widget_settings';
|
static const widgetSettings = 'widget_settings';
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,8 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
|
||||||
|
|
||||||
Future<void> _goToViewer(CollectionLens collection, AvesEntry entry) async {
|
Future<void> _goToViewer(CollectionLens collection, AvesEntry entry) async {
|
||||||
// track viewer entry for dynamic hero placeholder
|
// track viewer entry for dynamic hero placeholder
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => context.read<ViewerEntryNotifier>().value = entry);
|
final viewerEntryNotifier = context.read<ViewerEntryNotifier>();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => viewerEntryNotifier.value = entry);
|
||||||
|
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
final selection = context.read<Selection<AvesEntry>>();
|
||||||
await Navigator.maybeOf(context)?.push(
|
await Navigator.maybeOf(context)?.push(
|
||||||
|
@ -284,7 +285,7 @@ class _CollectionGridContentState extends State<_CollectionGridContent> {
|
||||||
// TODO TLAD fix timing when transition is incomplete, e.g. when going back while going to the viewer
|
// TODO TLAD fix timing when transition is incomplete, e.g. when going back while going to the viewer
|
||||||
await Future.delayed(ADurations.pageTransitionExact * timeDilation);
|
await Future.delayed(ADurations.pageTransitionExact * timeDilation);
|
||||||
}
|
}
|
||||||
context.read<ViewerEntryNotifier>().value = null;
|
viewerEntryNotifier.value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:aves/widgets/common/map/map_action_delegate.dart';
|
||||||
import 'package:aves_map/aves_map.dart';
|
import 'package:aves_map/aves_map.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -42,6 +43,12 @@ class MapButtonPanel extends StatelessWidget {
|
||||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case MapNavigationButton.close:
|
||||||
|
navigationButton = MapOverlayButton(
|
||||||
|
icon: const CloseButtonIcon(),
|
||||||
|
onPressed: SystemNavigator.pop,
|
||||||
|
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
|
||||||
|
);
|
||||||
case MapNavigationButton.map:
|
case MapNavigationButton.map:
|
||||||
if (openMapPage != null) {
|
if (openMapPage != null) {
|
||||||
navigationButton = MapOverlayButton(
|
navigationButton = MapOverlayButton(
|
||||||
|
|
|
@ -36,6 +36,7 @@ class GeoMap extends StatefulWidget {
|
||||||
final List<AvesEntry> entries;
|
final List<AvesEntry> entries;
|
||||||
final Size availableSize;
|
final Size availableSize;
|
||||||
final LatLng? initialCenter;
|
final LatLng? initialCenter;
|
||||||
|
final double? initialZoom;
|
||||||
final ValueNotifier<bool> isAnimatingNotifier;
|
final ValueNotifier<bool> isAnimatingNotifier;
|
||||||
final ValueNotifier<LatLng?>? dotLocationNotifier;
|
final ValueNotifier<LatLng?>? dotLocationNotifier;
|
||||||
final ValueNotifier<double>? overlayOpacityNotifier;
|
final ValueNotifier<double>? overlayOpacityNotifier;
|
||||||
|
@ -62,6 +63,7 @@ class GeoMap extends StatefulWidget {
|
||||||
required this.entries,
|
required this.entries,
|
||||||
required this.availableSize,
|
required this.availableSize,
|
||||||
this.initialCenter,
|
this.initialCenter,
|
||||||
|
this.initialZoom,
|
||||||
required this.isAnimatingNotifier,
|
required this.isAnimatingNotifier,
|
||||||
this.dotLocationNotifier,
|
this.dotLocationNotifier,
|
||||||
this.overlayOpacityNotifier,
|
this.overlayOpacityNotifier,
|
||||||
|
@ -313,6 +315,8 @@ class _GeoMapState extends State<GeoMap> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final initialZoom = widget.initialZoom ?? settings.infoMapZoom;
|
||||||
if (bounds == null) {
|
if (bounds == null) {
|
||||||
LatLng? centerToSave;
|
LatLng? centerToSave;
|
||||||
final initialCenter = widget.initialCenter;
|
final initialCenter = widget.initialCenter;
|
||||||
|
@ -320,7 +324,7 @@ class _GeoMapState extends State<GeoMap> {
|
||||||
// fit map for specified center and user zoom
|
// fit map for specified center and user zoom
|
||||||
bounds = ZoomedBounds.fromPoints(
|
bounds = ZoomedBounds.fromPoints(
|
||||||
points: {initialCenter},
|
points: {initialCenter},
|
||||||
collocationZoom: settings.infoMapZoom,
|
collocationZoom: initialZoom,
|
||||||
);
|
);
|
||||||
centerToSave = initialCenter;
|
centerToSave = initialCenter;
|
||||||
} else {
|
} else {
|
||||||
|
@ -345,7 +349,7 @@ class _GeoMapState extends State<GeoMap> {
|
||||||
}
|
}
|
||||||
bounds = ZoomedBounds.fromPoints(
|
bounds = ZoomedBounds.fromPoints(
|
||||||
points: {center},
|
points: {center},
|
||||||
collocationZoom: settings.infoMapZoom,
|
collocationZoom: initialZoom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/app_mode.dart';
|
import 'package:aves/app_mode.dart';
|
||||||
|
import 'package:aves/model/app/intent.dart';
|
||||||
import 'package:aves/model/app/permissions.dart';
|
import 'package:aves/model/app/permissions.dart';
|
||||||
import 'package:aves/model/app_inventory.dart';
|
import 'package:aves/model/app_inventory.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/catalog.dart';
|
import 'package:aves/model/entry/extensions/catalog.dart';
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/app/intent.dart';
|
import 'package:aves/model/filters/location.dart';
|
||||||
import 'package:aves/model/settings/enums/home_page.dart';
|
import 'package:aves/model/settings/enums/home_page.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
|
@ -29,6 +30,7 @@ import 'package:aves/widgets/editor/entry_editor_page.dart';
|
||||||
import 'package:aves/widgets/explorer/explorer_page.dart';
|
import 'package:aves/widgets/explorer/explorer_page.dart';
|
||||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||||
|
import 'package:aves/widgets/map/map_page.dart';
|
||||||
import 'package:aves/widgets/search/search_delegate.dart';
|
import 'package:aves/widgets/search/search_delegate.dart';
|
||||||
import 'package:aves/widgets/settings/home_widget_settings_page.dart';
|
import 'package:aves/widgets/settings/home_widget_settings_page.dart';
|
||||||
import 'package:aves/widgets/settings/screen_saver_settings_page.dart';
|
import 'package:aves/widgets/settings/screen_saver_settings_page.dart';
|
||||||
|
@ -38,6 +40,7 @@ import 'package:aves/widgets/wallpaper_page.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -62,12 +65,14 @@ class _HomePageState extends State<HomePage> {
|
||||||
String? _initialRouteName, _initialSearchQuery;
|
String? _initialRouteName, _initialSearchQuery;
|
||||||
Set<CollectionFilter>? _initialFilters;
|
Set<CollectionFilter>? _initialFilters;
|
||||||
String? _initialExplorerPath;
|
String? _initialExplorerPath;
|
||||||
|
(LatLng, double)? _initialLocationZoom;
|
||||||
List<String>? _secureUris;
|
List<String>? _secureUris;
|
||||||
|
|
||||||
static const allowedShortcutRoutes = [
|
static const allowedShortcutRoutes = [
|
||||||
AlbumListPage.routeName,
|
AlbumListPage.routeName,
|
||||||
CollectionPage.routeName,
|
CollectionPage.routeName,
|
||||||
ExplorerPage.routeName,
|
ExplorerPage.routeName,
|
||||||
|
MapPage.routeName,
|
||||||
SearchPage.routeName,
|
SearchPage.routeName,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -118,6 +123,32 @@ class _HomePageState extends State<HomePage> {
|
||||||
case IntentActions.view:
|
case IntentActions.view:
|
||||||
appMode = AppMode.view;
|
appMode = AppMode.view;
|
||||||
_secureUris = (intentData[IntentDataKeys.secureUris] as List?)?.cast<String>();
|
_secureUris = (intentData[IntentDataKeys.secureUris] as List?)?.cast<String>();
|
||||||
|
case IntentActions.viewGeo:
|
||||||
|
error = true;
|
||||||
|
if (intentUri != null) {
|
||||||
|
final geoUri = Uri.tryParse(intentUri);
|
||||||
|
if (geoUri != null) {
|
||||||
|
// e.g. `geo:44.4361283,26.1027248?z=4.0(Bucharest)`
|
||||||
|
// cf https://en.wikipedia.org/wiki/Geo_URI_scheme
|
||||||
|
// cf https://developer.android.com/guide/components/intents-common#ViewMap
|
||||||
|
final coordinates = geoUri.path.split(',');
|
||||||
|
if (coordinates.length == 2) {
|
||||||
|
final lat = double.tryParse(coordinates[0]);
|
||||||
|
final lon = double.tryParse(coordinates[1]);
|
||||||
|
if (lat != null && lon != null) {
|
||||||
|
double? zoom;
|
||||||
|
final zoomString = geoUri.queryParameters['z'];
|
||||||
|
if (zoomString != null) {
|
||||||
|
zoom = double.tryParse(zoomString);
|
||||||
|
}
|
||||||
|
_initialRouteName = MapPage.routeName;
|
||||||
|
_initialLocationZoom = (LatLng(lat, lon), zoom ?? settings.infoMapZoom);
|
||||||
|
error = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case IntentActions.edit:
|
case IntentActions.edit:
|
||||||
appMode = AppMode.edit;
|
appMode = AppMode.edit;
|
||||||
case IntentActions.setWallpaper:
|
case IntentActions.setWallpaper:
|
||||||
|
@ -361,6 +392,18 @@ class _HomePageState extends State<HomePage> {
|
||||||
return buildRoute((context) => const AlbumListPage());
|
return buildRoute((context) => const AlbumListPage());
|
||||||
case TagListPage.routeName:
|
case TagListPage.routeName:
|
||||||
return buildRoute((context) => const TagListPage());
|
return buildRoute((context) => const TagListPage());
|
||||||
|
case MapPage.routeName:
|
||||||
|
return buildRoute((context) {
|
||||||
|
final mapCollection = CollectionLens(
|
||||||
|
source: source,
|
||||||
|
filters: {LocationFilter.located},
|
||||||
|
);
|
||||||
|
return MapPage(
|
||||||
|
collection: mapCollection,
|
||||||
|
initialLocation: _initialLocationZoom?.$1,
|
||||||
|
initialZoom: _initialLocationZoom?.$2,
|
||||||
|
);
|
||||||
|
});
|
||||||
case ExplorerPage.routeName:
|
case ExplorerPage.routeName:
|
||||||
final path = _initialExplorerPath ?? settings.homeCustomExplorerPath;
|
final path = _initialExplorerPath ?? settings.homeCustomExplorerPath;
|
||||||
return buildRoute((context) => ExplorerPage(path: path));
|
return buildRoute((context) => ExplorerPage(path: path));
|
||||||
|
|
|
@ -43,15 +43,19 @@ import 'package:latlong2/latlong.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class MapPage extends StatelessWidget {
|
class MapPage extends StatelessWidget {
|
||||||
static const routeName = '/collection/map';
|
static const routeName = '/map';
|
||||||
|
|
||||||
final CollectionLens collection;
|
final CollectionLens collection;
|
||||||
|
final LatLng? initialLocation;
|
||||||
|
final double? initialZoom;
|
||||||
final AvesEntry? initialEntry;
|
final AvesEntry? initialEntry;
|
||||||
final MappedGeoTiff? overlayEntry;
|
final MappedGeoTiff? overlayEntry;
|
||||||
|
|
||||||
const MapPage({
|
const MapPage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.collection,
|
required this.collection,
|
||||||
|
this.initialLocation,
|
||||||
|
this.initialZoom,
|
||||||
this.initialEntry,
|
this.initialEntry,
|
||||||
this.overlayEntry,
|
this.overlayEntry,
|
||||||
});
|
});
|
||||||
|
@ -70,6 +74,8 @@ class MapPage extends StatelessWidget {
|
||||||
bottom: true,
|
bottom: true,
|
||||||
child: _Content(
|
child: _Content(
|
||||||
collection: collection,
|
collection: collection,
|
||||||
|
initialLocation: initialLocation,
|
||||||
|
initialZoom: initialZoom,
|
||||||
initialEntry: initialEntry,
|
initialEntry: initialEntry,
|
||||||
overlayEntry: overlayEntry,
|
overlayEntry: overlayEntry,
|
||||||
),
|
),
|
||||||
|
@ -81,11 +87,15 @@ class MapPage extends StatelessWidget {
|
||||||
|
|
||||||
class _Content extends StatefulWidget {
|
class _Content extends StatefulWidget {
|
||||||
final CollectionLens collection;
|
final CollectionLens collection;
|
||||||
|
final LatLng? initialLocation;
|
||||||
|
final double? initialZoom;
|
||||||
final AvesEntry? initialEntry;
|
final AvesEntry? initialEntry;
|
||||||
final MappedGeoTiff? overlayEntry;
|
final MappedGeoTiff? overlayEntry;
|
||||||
|
|
||||||
const _Content({
|
const _Content({
|
||||||
required this.collection,
|
required this.collection,
|
||||||
|
this.initialLocation,
|
||||||
|
this.initialZoom,
|
||||||
this.initialEntry,
|
this.initialEntry,
|
||||||
this.overlayEntry,
|
this.overlayEntry,
|
||||||
});
|
});
|
||||||
|
@ -252,10 +262,11 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMap() {
|
Widget _buildMap() {
|
||||||
|
final canPop = Navigator.maybeOf(context)?.canPop() == true;
|
||||||
Widget child = MapTheme(
|
Widget child = MapTheme(
|
||||||
interactive: true,
|
interactive: true,
|
||||||
showCoordinateFilter: true,
|
showCoordinateFilter: true,
|
||||||
navigationButton: MapNavigationButton.back,
|
navigationButton: canPop ? MapNavigationButton.back : MapNavigationButton.close,
|
||||||
scale: _overlayScale,
|
scale: _overlayScale,
|
||||||
child: GeoMap(
|
child: GeoMap(
|
||||||
// key is expected by test driver
|
// key is expected by test driver
|
||||||
|
@ -264,7 +275,8 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
collectionListenable: openingCollection,
|
collectionListenable: openingCollection,
|
||||||
entries: openingCollection.sortedEntries,
|
entries: openingCollection.sortedEntries,
|
||||||
availableSize: MediaQuery.sizeOf(context),
|
availableSize: MediaQuery.sizeOf(context),
|
||||||
initialCenter: widget.initialEntry?.latLng ?? widget.overlayEntry?.center,
|
initialCenter: widget.initialLocation ?? widget.initialEntry?.latLng ?? widget.overlayEntry?.center,
|
||||||
|
initialZoom: widget.initialZoom,
|
||||||
isAnimatingNotifier: _isPageAnimatingNotifier,
|
isAnimatingNotifier: _isPageAnimatingNotifier,
|
||||||
dotLocationNotifier: _dotLocationNotifier,
|
dotLocationNotifier: _dotLocationNotifier,
|
||||||
overlayOpacityNotifier: _overlayOpacityNotifier,
|
overlayOpacityNotifier: _overlayOpacityNotifier,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
enum MapNavigationButton { back, map, none }
|
enum MapNavigationButton { back, close, map, none }
|
||||||
|
|
||||||
class MapThemeData {
|
class MapThemeData {
|
||||||
final bool interactive, showCoordinateFilter;
|
final bool interactive, showCoordinateFilter;
|
||||||
|
|
Loading…
Reference in a new issue