From fccc71eeb501ca7deeacafb71d97da6c46475246 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Wed, 29 Jun 2022 18:30:36 +0100 Subject: [PATCH 01/12] Added `userAgentPackageName` implementation Improved headers implementation Deprecated `NonCachingNetworkTileProvider` in favour of `NetworkNoRetryTileProvider` Updated example pages with changes Improved documentation --- .../lib/pages/animated_map_controller.dart | 8 +- example/lib/pages/circle.dart | 8 +- example/lib/pages/epsg4326_crs.dart | 1 + example/lib/pages/esri.dart | 1 + example/lib/pages/home.dart | 2 +- example/lib/pages/interactive_test_page.dart | 1 + example/lib/pages/live_location.dart | 5 +- example/lib/pages/many_markers.dart | 1 + example/lib/pages/map_controller.dart | 8 +- example/lib/pages/map_inside_listview.dart | 1 + example/lib/pages/marker_anchor.dart | 8 +- example/lib/pages/marker_rotate.dart | 8 +- example/lib/pages/max_bounds.dart | 1 + example/lib/pages/moving_markers.dart | 8 +- example/lib/pages/network_tile_provider.dart | 17 ++-- example/lib/pages/offline_map.dart | 2 +- example/lib/pages/on_tap.dart | 8 +- example/lib/pages/overlay_image.dart | 8 +- example/lib/pages/plugin_api.dart | 8 +- example/lib/pages/plugin_scalebar.dart | 1 + example/lib/pages/plugin_zoombuttons.dart | 2 +- example/lib/pages/point_to_latlng.dart | 8 +- example/lib/pages/polygon.dart | 8 +- example/lib/pages/polyline.dart | 9 +- example/lib/pages/reset_tile_layer.dart | 8 +- example/lib/pages/sliding_map.dart | 2 +- example/lib/pages/stateful_markers.dart | 5 +- example/lib/pages/tap_to_add.dart | 1 + example/lib/pages/tile_builder_example.dart | 2 +- .../lib/pages/tile_loading_error_handle.dart | 2 +- example/lib/pages/widgets.dart | 1 + example/lib/pages/wms_tile_layer.dart | 1 + example/lib/test_app.dart | 8 +- .../layer/tile_layer/tile_layer_options.dart | 95 +++++++++++-------- .../tile_provider/file_tile_provider_io.dart | 4 +- .../tile_provider/file_tile_provider_web.dart | 8 +- .../tile_provider/tile_provider.dart | 50 +++++++++- 37 files changed, 207 insertions(+), 112 deletions(-) diff --git a/example/lib/pages/animated_map_controller.dart b/example/lib/pages/animated_map_controller.dart index afc824657..fbc0ab7f2 100644 --- a/example/lib/pages/animated_map_controller.dart +++ b/example/lib/pages/animated_map_controller.dart @@ -182,9 +182,11 @@ class AnimatedMapControllerPageState extends State minZoom: 3.0), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions(markers: markers) ], ), diff --git a/example/lib/pages/circle.dart b/example/lib/pages/circle.dart index 0d2e98189..90fdcd835 100644 --- a/example/lib/pages/circle.dart +++ b/example/lib/pages/circle.dart @@ -40,9 +40,11 @@ class CirclePage extends StatelessWidget { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), CircleLayerOptions(circles: circleMarkers) ], ), diff --git a/example/lib/pages/epsg4326_crs.dart b/example/lib/pages/epsg4326_crs.dart index 2a5052a03..8ad4cbd0f 100644 --- a/example/lib/pages/epsg4326_crs.dart +++ b/example/lib/pages/epsg4326_crs.dart @@ -37,6 +37,7 @@ class EPSG4326Page extends StatelessWidget { baseUrl: 'https://ows.mundialis.de/services/service?', layers: ['TOPO-OSM-WMS'], ), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ) ], ), diff --git a/example/lib/pages/esri.dart b/example/lib/pages/esri.dart index 845332f96..d1130d83c 100644 --- a/example/lib/pages/esri.dart +++ b/example/lib/pages/esri.dart @@ -32,6 +32,7 @@ class EsriPage extends StatelessWidget { TileLayerOptions( urlTemplate: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ], ), diff --git a/example/lib/pages/home.dart b/example/lib/pages/home.dart index 12f3bb9d2..5c949d19b 100644 --- a/example/lib/pages/home.dart +++ b/example/lib/pages/home.dart @@ -63,7 +63,7 @@ class HomePage extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], - tileProvider: const NonCachingNetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), MarkerLayerOptions(markers: markers) ], diff --git a/example/lib/pages/interactive_test_page.dart b/example/lib/pages/interactive_test_page.dart index b853148ec..e0a43cfa4 100644 --- a/example/lib/pages/interactive_test_page.dart +++ b/example/lib/pages/interactive_test_page.dart @@ -181,6 +181,7 @@ class _InteractiveTestPageState extends State { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ], ), diff --git a/example/lib/pages/live_location.dart b/example/lib/pages/live_location.dart index ddf5b3e58..1f32e4095 100644 --- a/example/lib/pages/live_location.dart +++ b/example/lib/pages/live_location.dart @@ -145,10 +145,7 @@ class _LiveLocationPageState extends State { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], - // For example purposes. It is recommended to use - // TileProvider with a caching and retry strategy, like - // NetworkTileProvider or CachedNetworkTileProvider - tileProvider: const NonCachingNetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), MarkerLayerOptions(markers: markers) ], diff --git a/example/lib/pages/many_markers.dart b/example/lib/pages/many_markers.dart index d76fda483..163fa398d 100644 --- a/example/lib/pages/many_markers.dart +++ b/example/lib/pages/many_markers.dart @@ -83,6 +83,7 @@ class _ManyMarkersPageState extends State { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), MarkerLayerOptions( markers: allMarkers.sublist( diff --git a/example/lib/pages/map_controller.dart b/example/lib/pages/map_controller.dart index 6df32c2b7..072eba33a 100644 --- a/example/lib/pages/map_controller.dart +++ b/example/lib/pages/map_controller.dart @@ -162,9 +162,11 @@ class MapControllerPageState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions(markers: markers) ], ), diff --git a/example/lib/pages/map_inside_listview.dart b/example/lib/pages/map_inside_listview.dart index da1e2a6da..f3b199032 100644 --- a/example/lib/pages/map_inside_listview.dart +++ b/example/lib/pages/map_inside_listview.dart @@ -45,6 +45,7 @@ class MapInsideListViewPage extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ), ], diff --git a/example/lib/pages/marker_anchor.dart b/example/lib/pages/marker_anchor.dart index 68c4ea32c..4efee60b1 100644 --- a/example/lib/pages/marker_anchor.dart +++ b/example/lib/pages/marker_anchor.dart @@ -115,9 +115,11 @@ class MarkerAnchorPageState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions(markers: markers) ], ), diff --git a/example/lib/pages/marker_rotate.dart b/example/lib/pages/marker_rotate.dart index dd9c43006..40911e8a1 100644 --- a/example/lib/pages/marker_rotate.dart +++ b/example/lib/pages/marker_rotate.dart @@ -140,9 +140,11 @@ class MarkerRotatePageState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions( rotate: rotateMarkerLayerOptions, markers: markers, diff --git a/example/lib/pages/max_bounds.dart b/example/lib/pages/max_bounds.dart index feb526ea6..5b29256ed 100644 --- a/example/lib/pages/max_bounds.dart +++ b/example/lib/pages/max_bounds.dart @@ -38,6 +38,7 @@ class MaxBoundsPage extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ], ), diff --git a/example/lib/pages/moving_markers.dart b/example/lib/pages/moving_markers.dart index a33327463..3313c363a 100644 --- a/example/lib/pages/moving_markers.dart +++ b/example/lib/pages/moving_markers.dart @@ -61,9 +61,11 @@ class _MovingMarkersPageState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions(markers: [_marker!]) ], ), diff --git a/example/lib/pages/network_tile_provider.dart b/example/lib/pages/network_tile_provider.dart index 2d7635992..cd26ea582 100644 --- a/example/lib/pages/network_tile_provider.dart +++ b/example/lib/pages/network_tile_provider.dart @@ -50,11 +50,14 @@ class NetworkTileProviderPage extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.only(top: 8.0, bottom: 8.0), - child: Wrap(children: const [ - Text('This Provider does not provide caching.'), - Text( - 'For further options about that, check flutter_map\'s README on GitHub.'), - ]), + child: Wrap( + children: const [ + Text( + 'This provider will automatically retry failed requests, unlike the other pages.'), + Text( + 'For further information, check the documentation website.'), + ], + ), ), Flexible( child: FlutterMap( @@ -67,10 +70,8 @@ class NetworkTileProviderPage extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], - // For example purposes. It is recommended to use - // TileProvider with a caching and retry strategy, like - // NetworkTileProvider or CachedNetworkTileProvider tileProvider: NetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), MarkerLayerOptions(markers: markers) ], diff --git a/example/lib/pages/offline_map.dart b/example/lib/pages/offline_map.dart index 1f796f090..510131e43 100644 --- a/example/lib/pages/offline_map.dart +++ b/example/lib/pages/offline_map.dart @@ -35,7 +35,7 @@ class OfflineMapPage extends StatelessWidget { ), layers: [ TileLayerOptions( - tileProvider: const AssetTileProvider(), + tileProvider: AssetTileProvider(), maxZoom: 14.0, urlTemplate: 'assets/map/anholt_osmbright/{z}/{x}/{y}.png', ), diff --git a/example/lib/pages/on_tap.dart b/example/lib/pages/on_tap.dart index 7e45d4965..85c490057 100644 --- a/example/lib/pages/on_tap.dart +++ b/example/lib/pages/on_tap.dart @@ -87,9 +87,11 @@ class OnTapPageState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions(markers: markers) ], ), diff --git a/example/lib/pages/overlay_image.dart b/example/lib/pages/overlay_image.dart index b0bd3498f..1eb577cae 100644 --- a/example/lib/pages/overlay_image.dart +++ b/example/lib/pages/overlay_image.dart @@ -38,9 +38,11 @@ class OverlayImagePage extends StatelessWidget { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), OverlayImageLayerOptions(overlayImages: overlayImages) ], ), diff --git a/example/lib/pages/plugin_api.dart b/example/lib/pages/plugin_api.dart index cd6bb1750..d39a0b9cf 100644 --- a/example/lib/pages/plugin_api.dart +++ b/example/lib/pages/plugin_api.dart @@ -29,9 +29,11 @@ class PluginPage extends StatelessWidget { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), ], nonRotatedLayers: [ MyCustomPluginOptions(text: "I'm a plugin!"), diff --git a/example/lib/pages/plugin_scalebar.dart b/example/lib/pages/plugin_scalebar.dart index dce6910d0..c4aaa19f1 100644 --- a/example/lib/pages/plugin_scalebar.dart +++ b/example/lib/pages/plugin_scalebar.dart @@ -33,6 +33,7 @@ class PluginScaleBar extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ], nonRotatedLayers: [ diff --git a/example/lib/pages/plugin_zoombuttons.dart b/example/lib/pages/plugin_zoombuttons.dart index c00d8cf01..051a2989e 100644 --- a/example/lib/pages/plugin_zoombuttons.dart +++ b/example/lib/pages/plugin_zoombuttons.dart @@ -33,7 +33,7 @@ class PluginZoomButtons extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], - tileProvider: const NonCachingNetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ], nonRotatedLayers: [ diff --git a/example/lib/pages/point_to_latlng.dart b/example/lib/pages/point_to_latlng.dart index e6b7f787a..54bb75231 100644 --- a/example/lib/pages/point_to_latlng.dart +++ b/example/lib/pages/point_to_latlng.dart @@ -69,9 +69,11 @@ class PointToLatlngPage extends State { children: [ TileLayerWidget( options: TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c'])), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + )), if (latLng != null) MarkerLayerWidget( options: MarkerLayerOptions( diff --git a/example/lib/pages/polygon.dart b/example/lib/pages/polygon.dart index 4aac2a0e5..c019f8b83 100644 --- a/example/lib/pages/polygon.dart +++ b/example/lib/pages/polygon.dart @@ -55,9 +55,11 @@ class PolygonPage extends StatelessWidget { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), PolygonLayerOptions(polygons: [ Polygon( points: notFilledPoints, diff --git a/example/lib/pages/polyline.dart b/example/lib/pages/polyline.dart index b65db5109..aca0f705f 100644 --- a/example/lib/pages/polyline.dart +++ b/example/lib/pages/polyline.dart @@ -83,9 +83,12 @@ class _PolylinePageState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: + 'dev.fleaflet.flutter_map.example', + ), PolylineLayerOptions( polylines: [ Polyline( diff --git a/example/lib/pages/reset_tile_layer.dart b/example/lib/pages/reset_tile_layer.dart index d24d8837c..6a72203c6 100644 --- a/example/lib/pages/reset_tile_layer.dart +++ b/example/lib/pages/reset_tile_layer.dart @@ -78,9 +78,11 @@ class ResetTileLayerPageState extends State { ), layers: [ TileLayerOptions( - reset: resetController.stream, - urlTemplate: layerToggle ? layer1 : layer2, - subdomains: ['a', 'b', 'c']), + reset: resetController.stream, + urlTemplate: layerToggle ? layer1 : layer2, + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), MarkerLayerOptions(markers: markers) ], ), diff --git a/example/lib/pages/sliding_map.dart b/example/lib/pages/sliding_map.dart index 80938f69c..364c13318 100644 --- a/example/lib/pages/sliding_map.dart +++ b/example/lib/pages/sliding_map.dart @@ -37,7 +37,7 @@ class SlidingMapPage extends StatelessWidget { ), layers: [ TileLayerOptions( - tileProvider: const AssetTileProvider(), + tileProvider: AssetTileProvider(), maxZoom: 14.0, urlTemplate: 'assets/map/anholt_osmbright/{z}/{x}/{y}.png', ), diff --git a/example/lib/pages/stateful_markers.dart b/example/lib/pages/stateful_markers.dart index 43615ff63..1fe7b49db 100644 --- a/example/lib/pages/stateful_markers.dart +++ b/example/lib/pages/stateful_markers.dart @@ -69,10 +69,7 @@ class _StatefulMarkersPageState extends State { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], - // For example purposes. It is recommended to use - // TileProvider with a caching and retry strategy, like - // NetworkTileProvider or CachedNetworkTileProvider - tileProvider: const NonCachingNetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), MarkerLayerOptions(markers: _markers) ], diff --git a/example/lib/pages/tap_to_add.dart b/example/lib/pages/tap_to_add.dart index f51d63e44..40acd30b2 100644 --- a/example/lib/pages/tap_to_add.dart +++ b/example/lib/pages/tap_to_add.dart @@ -51,6 +51,7 @@ class TapToAddPageState extends State { TileLayerOptions( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), MarkerLayerOptions(markers: markers) ], diff --git a/example/lib/pages/tile_builder_example.dart b/example/lib/pages/tile_builder_example.dart index 6c97bfd83..2e382348a 100644 --- a/example/lib/pages/tile_builder_example.dart +++ b/example/lib/pages/tile_builder_example.dart @@ -116,7 +116,7 @@ class _TileBuilderPageState extends State { TileLayerOptions( urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], - tileProvider: const NonCachingNetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', tileBuilder: tileBuilder, tilesContainerBuilder: darkMode ? darkModeTilesContainerBuilder : null, diff --git a/example/lib/pages/tile_loading_error_handle.dart b/example/lib/pages/tile_loading_error_handle.dart index 7870912a5..ecd893497 100644 --- a/example/lib/pages/tile_loading_error_handle.dart +++ b/example/lib/pages/tile_loading_error_handle.dart @@ -47,7 +47,7 @@ class _TileLoadingErrorHandleState extends State { // For example purposes. It is recommended to use // TileProvider with a caching and retry strategy, like // NetworkTileProvider or CachedNetworkTileProvider - tileProvider: const NonCachingNetworkTileProvider(), + userAgentPackageName: 'dev.fleaflet.flutter_map.example', errorTileCallback: (Tile tile, error) { if (needLoadingError) { WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/example/lib/pages/widgets.dart b/example/lib/pages/widgets.dart index c004df44b..11646a743 100644 --- a/example/lib/pages/widgets.dart +++ b/example/lib/pages/widgets.dart @@ -55,6 +55,7 @@ class WidgetsPage extends StatelessWidget { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ), ), const MovingWithoutRefreshAllMapMarkers(), diff --git a/example/lib/pages/wms_tile_layer.dart b/example/lib/pages/wms_tile_layer.dart index 34bece41b..e71ea9271 100644 --- a/example/lib/pages/wms_tile_layer.dart +++ b/example/lib/pages/wms_tile_layer.dart @@ -35,6 +35,7 @@ class WMSLayerPage extends StatelessWidget { layers: ['s2cloudless-2018_3857'], ), subdomains: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', ) ], ), diff --git a/example/lib/test_app.dart b/example/lib/test_app.dart index d3548703d..9908cc7ab 100644 --- a/example/lib/test_app.dart +++ b/example/lib/test_app.dart @@ -34,9 +34,11 @@ class _TestAppState extends State { ), layers: [ TileLayerOptions( - urlTemplate: - 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - subdomains: ['a', 'b', 'c']), + urlTemplate: + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + subdomains: ['a', 'b', 'c'], + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ), ], ), ), diff --git a/lib/src/layer/tile_layer/tile_layer_options.dart b/lib/src/layer/tile_layer/tile_layer_options.dart index 86ff7b1f6..575357eb2 100644 --- a/lib/src/layer/tile_layer/tile_layer_options.dart +++ b/lib/src/layer/tile_layer/tile_layer_options.dart @@ -20,6 +20,10 @@ typedef ErrorTileCallBack = void Function(Tile tile, dynamic error); /// Describes the needed properties to create a tile-based layer. A tile is an /// image bound to a specific geographical position. +/// +/// You should read up about the options by exploring each one, or visiting +/// https://docs.fleaflet.dev/usage/layers/tile-layer. Some are important to +/// avoid issues. class TileLayerOptions extends LayerOptions { /// Defines the structure to create the URLs for the tiles. `{s}` means one of /// the available subdomains (can be omitted) `{z}` zoom level `{x}` and `{y}` @@ -88,36 +92,43 @@ class TileLayerOptions extends LayerOptions { /// https://c.tile.openstreetmap.org/{z}/{x}/{y}.png final List subdomains; - /// Color shown behind the tiles. + /// Color shown behind the tiles final Color backgroundColor; /// Opacity of the rendered tile final double opacity; - /// Provider to load the tiles. The default is `NonCachingNetworkTileProvider()` which - /// doesn't cache tiles and won't retry the HTTP request. Use `NetworkTileProvider()` for - /// a provider which will retry requests. For the best caching implementations, see the - /// flutter_map readme. + /// Provider with which to load map tiles /// - /// In order to use images from the asset folder set this option to - /// AssetTileProvider() Note that it requires the urlTemplate to target - /// assets, for example: + /// The default is [NetworkNoRetryTileProvider]. Alternatively, use + /// [NetworkTileProvider] for a provider which will retry requests. /// - /// ```dart - /// urlTemplate: "assets/map/anholt_osmbright/{z}/{x}/{y}.png", - /// ``` + /// Both providers will use some form of caching, although not reliable. For + /// better options, see https://docs.fleaflet.dev/usage/layers/tile-layer#caching. /// - /// In order to use images from the filesystem set this option to - /// FileTileProvider() Note that it requires the urlTemplate to target the - /// file system, for example: + /// `userAgentPackageName` is a construction parameter, which should be passed + /// the application's correct package name, such as 'com.example.app'. If no + /// value is passed, it defaults to 'unknown'. This parameter is used to form + /// part of the 'User-Agent' header, which is important to avoid blocking by + /// tile servers. Namely, the header is the following 'flutter_map ()'. /// - /// ```dart - /// urlTemplate: "/storage/emulated/0/tiles/some_place/{z}/{x}/{y}.png", - /// ``` + /// Header rules are as follows, after 'User-Agent' is generated as above: + /// + /// * If no provider is specified here, the default will be used with + /// 'User-Agent' header injected (recommended) + /// * If a provider is specified here with no 'User-Agent' header, that + /// provider will be used and the 'User-Agent' header will be injected + /// * If a provider is specified here with a 'User-Agent' header, that + /// provider will be used and the 'User-Agent' header will not be changed to any created here /// - /// Furthermore you create your custom implementation by subclassing - /// TileProvider - final TileProvider tileProvider; + /// [AssetTileProvider] and [FileTileProvider] are alternatives to network + /// providers, which use the [urlTemplate] as a path instead. + /// For example, 'assets/map/{z}/{x}/{y}.png' or + /// '/storage/emulated/0/map_app/tiles/{z}/{x}/{y}.png'. + /// + /// Custom [TileProvider]s can also be used, but these will not follow the header + /// rules above. + late final TileProvider tileProvider; /// When panning the map, keep this many rows and columns of tiles before /// unloading them. @@ -264,22 +275,22 @@ class TileLayerOptions extends LayerOptions { @Deprecated('`placeholderImage` has been deprecated with no current replacement or workaround. Usage no longer has an effect internally.') this.placeholderImage, this.errorImage, - this.tileProvider = const NonCachingNetworkTileProvider(), + TileProvider? tileProvider, this.tms = false, // ignore: avoid_init_to_null this.wmsOptions = null, this.opacity = 1.0, - // Tiles will not update more than once every `updateInterval` milliseconds - // (default 200) when panning. It can be 0 (but it will calculating for - // loading tiles every frame when panning / zooming, flutter is fast) This - // can save some fps and even bandwidth (ie. when fast panning / animating - // between long distances in short time) - // TODO: change to Duration - int updateInterval = 200, - // Tiles fade in duration in milliseconds (default 100). This can be set to - // 0 to avoid fade in - // TODO: change to Duration - int tileFadeInDuration = 100, + + /// Tiles will not update more than once every `updateInterval` milliseconds + /// (default 200) when panning. It can be 0 (but it will calculating for + /// loading tiles every frame when panning / zooming, flutter is fast) This + /// can save some fps and even bandwidth (ie. when fast panning / animating + /// between long distances in short time) + Duration updateInterval = const Duration(milliseconds: 200), + + /// Tiles fade in duration in milliseconds (default 100). This can be set to + /// 0 to avoid fade in + Duration tileFadeInDuration = const Duration(milliseconds: 100), this.tileFadeInStart = 0.0, this.tileFadeInStartWhenOverride = 0.0, this.overrideTilesWhenUrlChanges = false, @@ -293,11 +304,15 @@ class TileLayerOptions extends LayerOptions { this.fastReplace = false, this.reset, this.tileBounds, + + /// Used in constructing the 'User-Agent' header in [TileProvider]s. + /// + /// Always specify if possible, otherwise defaults to 'unknown'. + String userAgentPackageName = 'unknown', }) : updateInterval = - updateInterval <= 0 ? null : Duration(milliseconds: updateInterval), - tileFadeInDuration = tileFadeInDuration <= 0 - ? null - : Duration(milliseconds: tileFadeInDuration), + updateInterval <= Duration.zero ? null : updateInterval, + tileFadeInDuration = + tileFadeInDuration <= Duration.zero ? null : tileFadeInDuration, assert(tileFadeInStart >= 0.0 && tileFadeInStart <= 1.0), assert(tileFadeInStartWhenOverride >= 0.0 && tileFadeInStartWhenOverride <= 1.0), @@ -315,11 +330,15 @@ class TileLayerOptions extends LayerOptions { tileSize = wmsOptions == null && retinaMode && maxZoom > 0.0 ? (tileSize / 2.0).floorToDouble() : tileSize, - // copy additionalOptions Map if not null, so we can safely compare old - // and new Map inside didUpdateWidget with MapEquality. additionalOptions = additionalOptions == null ? const {} : Map.from(additionalOptions), + tileProvider = tileProvider == null + ? NetworkNoRetryTileProvider( + headers: {'User-Agent': 'flutter_map ($userAgentPackageName)'}) + : (tileProvider + ..headers.putIfAbsent( + 'User-Agent', () => 'flutter_map ($userAgentPackageName)')), super(key: key, rebuild: rebuild); } diff --git a/lib/src/layer/tile_layer/tile_provider/file_tile_provider_io.dart b/lib/src/layer/tile_layer/tile_provider/file_tile_provider_io.dart index 564345245..0085d4236 100644 --- a/lib/src/layer/tile_layer/tile_provider/file_tile_provider_io.dart +++ b/lib/src/layer/tile_layer/tile_provider/file_tile_provider_io.dart @@ -3,9 +3,9 @@ import 'dart:io'; import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; -/// FileTileProvider +/// [TileProvider] that uses [FileImage] internally on platforms other than web class FileTileProvider extends TileProvider { - const FileTileProvider(); + FileTileProvider(); @override ImageProvider getImage(Coords coords, TileLayerOptions options) { diff --git a/lib/src/layer/tile_layer/tile_provider/file_tile_provider_web.dart b/lib/src/layer/tile_layer/tile_provider/file_tile_provider_web.dart index 31da2b069..0c842f4c1 100644 --- a/lib/src/layer/tile_layer/tile_provider/file_tile_provider_web.dart +++ b/lib/src/layer/tile_layer/tile_provider/file_tile_provider_web.dart @@ -1,10 +1,12 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; -/// FileTileProvider - +/// [TileProvider] that uses [NetworkImage] internally on the web +/// +/// Note that this is not recommended, as important headers cannot be passed. +/// Use [NetworkNoRetryTileProvider] if you know the platform is the web. class FileTileProvider extends TileProvider { - const FileTileProvider(); + FileTileProvider(); @override ImageProvider getImage(Coords coords, TileLayerOptions options) { diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart index 4ffddef66..c0d4ebb5b 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart @@ -3,7 +3,11 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_with_retry.dart'; abstract class TileProvider { - const TileProvider(); + Map headers; + + TileProvider({ + this.headers = const {'User-Agent': 'flutter_map (unknown)'}, + }); ImageProvider getImage(Coords coords, TileLayerOptions options); @@ -55,24 +59,60 @@ abstract class TileProvider { } } +/// [TileProvider] that uses [NetworkImageWithRetry] internally +/// +/// Note that this is not recommended, as there is no way to set headers with this method: see https://github.com/flutter/flutter/issues/19532. class NetworkTileProvider extends TileProvider { + NetworkTileProvider({ + Map headers = const {'User-Agent': 'flutter_map (unknown)'}, + }) { + this.headers = headers; + } + @override ImageProvider getImage(Coords coords, TileLayerOptions options) { return NetworkImageWithRetry(getTileUrl(coords, options)); } } +/// [TileProvider] that uses [NetworkImage] internally +class NetworkNoRetryTileProvider extends TileProvider { + NetworkNoRetryTileProvider({ + Map headers = const {'User-Agent': 'flutter_map (unknown)'}, + }) { + this.headers = headers; + } + + @override + ImageProvider getImage(Coords coords, TileLayerOptions options) { + return NetworkImage( + getTileUrl(coords, options), + headers: headers, + ); + } +} + +/// Deprecated due to internal refactoring. The name is misleading, as the internal [ImageProvider] always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to [NetworkNoRetryTileProvider]. This will continue to work for now. +@Deprecated( + '`NonCachingTileProvider` has been deprecated due to internal refactoring. The name is misleading, as the internal `ImageProvider` always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to `NetworkNoRetryTileProvider`.') class NonCachingNetworkTileProvider extends TileProvider { - const NonCachingNetworkTileProvider(); + NonCachingNetworkTileProvider({ + Map headers = const {'User-Agent': 'flutter_map (unknown)'}, + }) { + this.headers = headers; + } @override ImageProvider getImage(Coords coords, TileLayerOptions options) { - return NetworkImage(getTileUrl(coords, options)); + return NetworkImage( + getTileUrl(coords, options), + headers: headers, + ); } } class AssetTileProvider extends TileProvider { - const AssetTileProvider(); + AssetTileProvider(); @override ImageProvider getImage(Coords coords, TileLayerOptions options) { @@ -83,7 +123,7 @@ class AssetTileProvider extends TileProvider { class CustomTileProvider extends TileProvider { final String Function(Coords coors, TileLayerOptions options) customTileUrl; - const CustomTileProvider({required this.customTileUrl}); + CustomTileProvider({required this.customTileUrl}); @override String getTileUrl(Coords coords, TileLayerOptions options) { From a66dfd60f42e60bb21058c2079326e9ff0876e74 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Thu, 30 Jun 2022 21:39:32 +0100 Subject: [PATCH 02/12] Temporarily fixed multiple User-Agent headers Fixed usage of `NetworkTileProvider` Fixed deprecation notice invalid symbol reference --- .../tile_provider/tile_provider.dart | 36 ++++++++++++++----- pubspec.yaml | 3 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart index c0d4ebb5b..1b1a445f4 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart @@ -1,4 +1,6 @@ import 'package:flutter/widgets.dart'; +import 'package:universal_io/io.dart'; + import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_with_retry.dart'; @@ -62,11 +64,12 @@ abstract class TileProvider { /// [TileProvider] that uses [NetworkImageWithRetry] internally /// /// Note that this is not recommended, as there is no way to set headers with this method: see https://github.com/flutter/flutter/issues/19532. +/// The parameter is only provided for potential forward-compatibility. class NetworkTileProvider extends TileProvider { NetworkTileProvider({ - Map headers = const {'User-Agent': 'flutter_map (unknown)'}, + Map? headers, }) { - this.headers = headers; + this.headers = headers ?? {'User-Agent': 'flutter_map (unknown)'}; } @override @@ -78,28 +81,38 @@ class NetworkTileProvider extends TileProvider { /// [TileProvider] that uses [NetworkImage] internally class NetworkNoRetryTileProvider extends TileProvider { NetworkNoRetryTileProvider({ - Map headers = const {'User-Agent': 'flutter_map (unknown)'}, + Map? headers, }) { - this.headers = headers; + this.headers = headers ?? {'User-Agent': 'flutter_map (unknown)'}; + HttpOverrides.global = _FlutterMapHTTPOverrides(); } @override ImageProvider getImage(Coords coords, TileLayerOptions options) { + print('Header: ${headers['User-Agent']}'); + + /*return HttpOverrides.runZoned( + () =>*/ return NetworkImage( getTileUrl(coords, options), headers: headers, - ); + ); /*, + createHttpClient: (c) { + print(httpClient.userAgent); + return httpClient; + }, + );*/ } } /// Deprecated due to internal refactoring. The name is misleading, as the internal [ImageProvider] always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to [NetworkNoRetryTileProvider]. This will continue to work for now. @Deprecated( - '`NonCachingTileProvider` has been deprecated due to internal refactoring. The name is misleading, as the internal `ImageProvider` always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to `NetworkNoRetryTileProvider`.') + '`NonCachingNetworkTileProvider` has been deprecated due to internal refactoring. The name is misleading, as the internal `ImageProvider` always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to `NetworkNoRetryTileProvider`.') class NonCachingNetworkTileProvider extends TileProvider { NonCachingNetworkTileProvider({ - Map headers = const {'User-Agent': 'flutter_map (unknown)'}, + Map? headers, }) { - this.headers = headers; + this.headers = headers ?? {'User-Agent': 'flutter_map (unknown)'}; } @override @@ -135,3 +148,10 @@ class CustomTileProvider extends TileProvider { return AssetImage(getTileUrl(coords, options)); } } + +class _FlutterMapHTTPOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context)..userAgent = null; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 476bed06c..c5f915606 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_map description: A versatile mapping package for Flutter, based off leaflet.js, that's simple and easy to learn, yet completely customizable and configurable. -version: 1.1.1 +version: 2.0.0 repository: https://github.com/fleaflet/flutter_map documentation: https://docs.fleaflet.dev @@ -21,6 +21,7 @@ dependencies: proj4dart: ^2.0.0 tuple: ^2.0.0 vector_math: ^2.1.0 + universal_io: ^2.0.4 dev_dependencies: flutter_lints: ">=1.0.4" From ce5d283928c353b826233b99861931d05c1a57b4 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Fri, 1 Jul 2022 21:46:45 +0100 Subject: [PATCH 03/12] Removed some old TODOs Simplified `_positionedForOverlay` (solved TODO) Improved maintainability Improved documentation --- lib/src/geo/crs/crs.dart | 2 +- lib/src/gestures/gestures.dart | 1 - lib/src/layer/overlay_image_layer.dart | 8 ++--- .../layer/tile_layer/tile_layer_options.dart | 28 ++++++----------- .../tile_provider/tile_provider.dart | 31 ++++++++++--------- 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/lib/src/geo/crs/crs.dart b/lib/src/geo/crs/crs.dart index 55b6db150..e7f8a7b3a 100644 --- a/lib/src/geo/crs/crs.dart +++ b/lib/src/geo/crs/crs.dart @@ -130,7 +130,7 @@ class Epsg3857 extends Earth { transformation = const Transformation(_scale, 0.5, -_scale, 0.5), super(); -// TODO Epsg3857 seems to have latitude limits. https://epsg.io/3857 +// Epsg3857 seems to have latitude limits. https://epsg.io/3857 //@override //Tuple2 get wrapLat => const Tuple2(-85.06, 85.06); } diff --git a/lib/src/gestures/gestures.dart b/lib/src/gestures/gestures.dart index cec76503e..48002d46e 100644 --- a/lib/src/gestures/gestures.dart +++ b/lib/src/gestures/gestures.dart @@ -709,7 +709,6 @@ abstract class MapGestureMixin extends State _doubleTapHoldMaxDelay?.cancel(); final flags = options.interactiveFlags; - // TODO: is this pinchZoom? never seen this fired if (InteractiveFlag.hasFlag(flags, InteractiveFlag.pinchZoom)) { final zoom = mapState.zoom; final focalOffset = details.localFocalPoint; diff --git a/lib/src/layer/overlay_image_layer.dart b/lib/src/layer/overlay_image_layer.dart index 8df75667c..bf1265081 100644 --- a/lib/src/layer/overlay_image_layer.dart +++ b/lib/src/layer/overlay_image_layer.dart @@ -67,15 +67,11 @@ class OverlayImageLayer extends StatelessWidget { } Positioned _positionedForOverlay(OverlayImage overlayImage) { - final zoomScale = - map.getZoomScale(map.zoom, map.zoom); // TODO replace with 1? final pixelOrigin = map.getPixelOrigin(); final upperLeftPixel = - map.project(overlayImage.bounds.northWest).multiplyBy(zoomScale) - - pixelOrigin; + map.project(overlayImage.bounds.northWest) - pixelOrigin; final bottomRightPixel = - map.project(overlayImage.bounds.southEast).multiplyBy(zoomScale) - - pixelOrigin; + map.project(overlayImage.bounds.southEast) - pixelOrigin; return Positioned( left: upperLeftPixel.x.toDouble(), top: upperLeftPixel.y.toDouble(), diff --git a/lib/src/layer/tile_layer/tile_layer_options.dart b/lib/src/layer/tile_layer/tile_layer_options.dart index 575357eb2..4cca5d3ef 100644 --- a/lib/src/layer/tile_layer/tile_layer_options.dart +++ b/lib/src/layer/tile_layer/tile_layer_options.dart @@ -101,9 +101,9 @@ class TileLayerOptions extends LayerOptions { /// Provider with which to load map tiles /// /// The default is [NetworkNoRetryTileProvider]. Alternatively, use - /// [NetworkTileProvider] for a provider which will retry requests. + /// [NetworkTileProvider] for a network provider which will retry requests. /// - /// Both providers will use some form of caching, although not reliable. For + /// Both network providers will use some form of caching, although not reliable. For /// better options, see https://docs.fleaflet.dev/usage/layers/tile-layer#caching. /// /// `userAgentPackageName` is a construction parameter, which should be passed @@ -259,7 +259,6 @@ class TileLayerOptions extends LayerOptions { ) this.attributionBuilder, Key? key, - // TODO: make required this.urlTemplate, double tileSize = 256.0, double minZoom = 0.0, @@ -277,8 +276,7 @@ class TileLayerOptions extends LayerOptions { this.errorImage, TileProvider? tileProvider, this.tms = false, - // ignore: avoid_init_to_null - this.wmsOptions = null, + this.wmsOptions, this.opacity = 1.0, /// Tiles will not update more than once every `updateInterval` milliseconds @@ -287,9 +285,6 @@ class TileLayerOptions extends LayerOptions { /// can save some fps and even bandwidth (ie. when fast panning / animating /// between long distances in short time) Duration updateInterval = const Duration(milliseconds: 200), - - /// Tiles fade in duration in milliseconds (default 100). This can be set to - /// 0 to avoid fade in Duration tileFadeInDuration = const Duration(milliseconds: 100), this.tileFadeInStart = 0.0, this.tileFadeInStartWhenOverride = 0.0, @@ -304,10 +299,6 @@ class TileLayerOptions extends LayerOptions { this.fastReplace = false, this.reset, this.tileBounds, - - /// Used in constructing the 'User-Agent' header in [TileProvider]s. - /// - /// Always specify if possible, otherwise defaults to 'unknown'. String userAgentPackageName = 'unknown', }) : updateInterval = updateInterval <= Duration.zero ? null : updateInterval, @@ -346,14 +337,13 @@ class WMSTileLayerOptions { final service = 'WMS'; final request = 'GetMap'; - /// url of WMS service. - /// Ex.: 'http://ows.mundialis.de/services/service?' + /// WMS service's URL, for example 'http://ows.mundialis.de/services/service?' final String baseUrl; - /// list of WMS layers to show + /// List of WMS layers to show final List layers; - /// list of WMS styles + /// List of WMS styles final List styles; /// WMS image format (use 'image/png' for layers with transparency) @@ -362,16 +352,16 @@ class WMSTileLayerOptions { /// Version of the WMS service to use final String version; - /// tile transparency flag + /// Whether to make tiles transparent final bool transparent; /// Encode boolean values as uppercase in request final bool uppercaseBoolValue; - // TODO find a way to implicit pass of current map [Crs] + /// Sets map projection standard final Crs crs; - /// other request parameters + /// Other request parameters final Map otherParameters; late final String _encodedBaseUrl; diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart index 1b1a445f4..8624163ac 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart @@ -4,11 +4,15 @@ import 'package:universal_io/io.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_with_retry.dart'; +const Map _defaultHeader = { + 'User-Agent': 'flutter_map via Dart (unknown)', +}; + abstract class TileProvider { Map headers; TileProvider({ - this.headers = const {'User-Agent': 'flutter_map (unknown)'}, + this.headers = _defaultHeader, }); ImageProvider getImage(Coords coords, TileLayerOptions options); @@ -65,11 +69,13 @@ abstract class TileProvider { /// /// Note that this is not recommended, as there is no way to set headers with this method: see https://github.com/flutter/flutter/issues/19532. /// The parameter is only provided for potential forward-compatibility. +/// +/// TODO: Add header capabilities through `HttpOverrides` or (preferably) by changing the image provider's implementation class NetworkTileProvider extends TileProvider { NetworkTileProvider({ Map? headers, }) { - this.headers = headers ?? {'User-Agent': 'flutter_map (unknown)'}; + this.headers = headers ?? _defaultHeader; } @override @@ -83,12 +89,13 @@ class NetworkNoRetryTileProvider extends TileProvider { NetworkNoRetryTileProvider({ Map? headers, }) { - this.headers = headers ?? {'User-Agent': 'flutter_map (unknown)'}; + this.headers = headers ?? _defaultHeader; HttpOverrides.global = _FlutterMapHTTPOverrides(); } @override ImageProvider getImage(Coords coords, TileLayerOptions options) { + // ignore: avoid_print print('Header: ${headers['User-Agent']}'); /*return HttpOverrides.runZoned( @@ -98,30 +105,26 @@ class NetworkNoRetryTileProvider extends TileProvider { headers: headers, ); /*, createHttpClient: (c) { - print(httpClient.userAgent); - return httpClient; + print('Is creating HTTP client for zone'); + return _FlutterMapHTTPOverrides().createHttpClient(c); }, );*/ } } -/// Deprecated due to internal refactoring. The name is misleading, as the internal [ImageProvider] always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to [NetworkNoRetryTileProvider]. This will continue to work for now. +/// Deprecated due to internal refactoring. The name is misleading, as the internal [ImageProvider] always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to [NetworkNoRetryTileProvider] before the next minor update. @Deprecated( - '`NonCachingNetworkTileProvider` has been deprecated due to internal refactoring. The name is misleading, as the internal `ImageProvider` always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to `NetworkNoRetryTileProvider`.') + '`NonCachingNetworkTileProvider` has been deprecated due to internal refactoring. The name is misleading, as the internal `ImageProvider` always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to `NetworkNoRetryTileProvider` before the next minor update.') class NonCachingNetworkTileProvider extends TileProvider { NonCachingNetworkTileProvider({ Map? headers, }) { - this.headers = headers ?? {'User-Agent': 'flutter_map (unknown)'}; + this.headers = headers ?? _defaultHeader; } @override - ImageProvider getImage(Coords coords, TileLayerOptions options) { - return NetworkImage( - getTileUrl(coords, options), - headers: headers, - ); - } + ImageProvider getImage(Coords coords, TileLayerOptions options) => + NetworkNoRetryTileProvider(headers: headers).getImage(coords, options); } class AssetTileProvider extends TileProvider { From 9dcdfde4b1a7f85ed0c077dd01fed2c6c139cf3d Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Fri, 1 Jul 2022 22:01:43 +0100 Subject: [PATCH 04/12] Removed old deprecations (`placeholderImage` and `attributionBuilder`) --- lib/src/layer/tile_layer/tile_layer.dart | 12 +----------- .../layer/tile_layer/tile_layer_options.dart | 19 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_layer.dart b/lib/src/layer/tile_layer/tile_layer.dart index 9bc665936..1d442759e 100644 --- a/lib/src/layer/tile_layer/tile_layer.dart +++ b/lib/src/layer/tile_layer/tile_layer.dart @@ -201,21 +201,11 @@ class _TileLayerState extends State with TickerProviderStateMixin { tilesToRender, ); - final attributionLayer = - // ignore: deprecated_member_use_from_same_package - widget.options.attributionBuilder?.call(context); - return Opacity( opacity: options.opacity, child: Container( color: options.backgroundColor, - child: Stack( - alignment: widget.options.attributionAlignment, - children: [ - tilesLayer, - if (attributionLayer != null) attributionLayer, - ], - ), + child: tilesLayer, ), ); }, diff --git a/lib/src/layer/tile_layer/tile_layer_options.dart b/lib/src/layer/tile_layer/tile_layer_options.dart index 4cca5d3ef..1e7e60e88 100644 --- a/lib/src/layer/tile_layer/tile_layer_options.dart +++ b/lib/src/layer/tile_layer/tile_layer_options.dart @@ -134,13 +134,6 @@ class TileLayerOptions extends LayerOptions { /// unloading them. final int keepBuffer; - /// Placeholder to show until tile images are fetched by the provider. - /// - /// _`placeholderImage` has been deprecated with no current replacement or workaround. Usage no longer has an effect internally._ - @Deprecated( - '`placeholderImage` has been deprecated with no current replacement or workaround. Usage no longer has an effect internally.') - final ImageProvider? placeholderImage; - /// Tile image to show in place of the tile that failed to load. final ImageProvider? errorImage; @@ -237,12 +230,6 @@ class TileLayerOptions extends LayerOptions { /// When set to `true`, the `tileFadeIn*` options will be ignored. final bool fastReplace; - /// [attributionBuilder] has been deprecated. Usage will continue to work, however not as expected. As an alternative, use [AttributionWidget] inside `nonRotatedChildren`. - @Deprecated( - '`attributionBuilder` has been deprecated. Usage will continue to work, however not as expected. As an alternative, use `AttributionWidget` inside `nonRotatedChildren`.', - ) - final WidgetBuilder? attributionBuilder; - ///aligment of the attribution text on the map widget final Alignment attributionAlignment; @@ -254,10 +241,6 @@ class TileLayerOptions extends LayerOptions { TileLayerOptions({ this.attributionAlignment = Alignment.bottomRight, - @Deprecated( - '`attributionBuilder` has been deprecated. Usage will continue to work, however not as expected. As an alternative, use `AttributionWidget` inside `nonRotatedChildren`.', - ) - this.attributionBuilder, Key? key, this.urlTemplate, double tileSize = 256.0, @@ -271,8 +254,6 @@ class TileLayerOptions extends LayerOptions { this.subdomains = const [], this.keepBuffer = 2, this.backgroundColor = const Color(0xFFE0E0E0), - @Deprecated('`placeholderImage` has been deprecated with no current replacement or workaround. Usage no longer has an effect internally.') - this.placeholderImage, this.errorImage, TileProvider? tileProvider, this.tms = false, From d7c76489566e8f4c91d237f4216079f755762dee Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Fri, 8 Jul 2022 20:35:27 +0100 Subject: [PATCH 05/12] Atempt to fix `HttpOverrides` issue - unsuccessful: https://github.com/dart-lang/sdk/issues/49382#issuecomment-1179302726 --- .../tile_provider/tile_provider.dart | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart index 8624163ac..df8c27f0b 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart @@ -1,3 +1,8 @@ +// ignore_for_file: avoid_print +// TODO: Remove print statements + +import 'dart:async'; + import 'package:flutter/widgets.dart'; import 'package:universal_io/io.dart'; @@ -90,25 +95,29 @@ class NetworkNoRetryTileProvider extends TileProvider { Map? headers, }) { this.headers = headers ?? _defaultHeader; - HttpOverrides.global = _FlutterMapHTTPOverrides(); + //HttpOverrides.global = _FlutterMapHTTPOverrides(); } @override ImageProvider getImage(Coords coords, TileLayerOptions options) { - // ignore: avoid_print print('Header: ${headers['User-Agent']}'); - - /*return HttpOverrides.runZoned( - () =>*/ - return NetworkImage( - getTileUrl(coords, options), - headers: headers, - ); /*, + print("Running in ${Zone.current.toString()}"); + return HttpOverrides.runZoned( + () { + /*print("Running in ${Zone.current}");*/ + final HttpClient httpClient = HttpClient(); + print("userAgent = ${httpClient.userAgent}"); + + return NetworkImage( + getTileUrl(coords, options), + headers: headers, + ); + }, createHttpClient: (c) { print('Is creating HTTP client for zone'); return _FlutterMapHTTPOverrides().createHttpClient(c); }, - );*/ + ); } } From ad2adb651ef6374449f63e177a5fa169698784df Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sat, 9 Jul 2022 10:06:48 +0100 Subject: [PATCH 06/12] Fixed issues Added custom `ImageProvider`s Reduced reliance on 'universal_io' library Prepared for review --- .../layer/tile_layer/tile_layer_options.dart | 10 +- .../tile_provider/network_image_provider.dart | 55 +++++++++++ .../network_image_with_retry.dart | 46 --------- .../network_no_retry_image_provider.dart | 99 +++++++++++++++++++ .../tile_provider/tile_provider.dart | 88 +++++++++-------- 5 files changed, 207 insertions(+), 91 deletions(-) create mode 100644 lib/src/layer/tile_layer/tile_provider/network_image_provider.dart delete mode 100644 lib/src/layer/tile_layer/tile_provider/network_image_with_retry.dart create mode 100644 lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart diff --git a/lib/src/layer/tile_layer/tile_layer_options.dart b/lib/src/layer/tile_layer/tile_layer_options.dart index 1e7e60e88..2a06f503e 100644 --- a/lib/src/layer/tile_layer/tile_layer_options.dart +++ b/lib/src/layer/tile_layer/tile_layer_options.dart @@ -307,10 +307,14 @@ class TileLayerOptions extends LayerOptions { : Map.from(additionalOptions), tileProvider = tileProvider == null ? NetworkNoRetryTileProvider( - headers: {'User-Agent': 'flutter_map ($userAgentPackageName)'}) + headers: {'User-Agent': 'flutter_map ($userAgentPackageName)'}, + ) : (tileProvider - ..headers.putIfAbsent( - 'User-Agent', () => 'flutter_map ($userAgentPackageName)')), + ..headers = { + ...tileProvider.headers, + if (!tileProvider.headers.containsKey('User-Agent')) + 'User-Agent': 'flutter_map ($userAgentPackageName)', + }), super(key: key, rebuild: rebuild); } diff --git a/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart b/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart new file mode 100644 index 000000000..9380b8fca --- /dev/null +++ b/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart @@ -0,0 +1,55 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/painting.dart'; +import 'package:http/http.dart'; +import 'package:http/retry.dart'; + +class NetworkImageProvider extends ImageProvider { + /// The URL from which the image will be fetched. + final String url; + + /// The http RetryClient that is used for the requests + final RetryClient retryClient; + + /// Custom headers to add to the image fetch request + final Map headers; + + NetworkImageProvider( + this.url, { + RetryClient? retryClient, + this.headers = const {}, + }) : retryClient = retryClient ?? RetryClient(Client()); + + @override + ImageStreamCompleter load(NetworkImageProvider key, DecoderCallback decode) { + return OneFrameImageStreamCompleter(_loadWithRetry(key, decode), + informationCollector: () sync* { + yield ErrorDescription('Image provider: $this'); + yield ErrorDescription('Image key: $key'); + }); + } + + @override + Future obtainKey(ImageConfiguration configuration) { + return SynchronousFuture(this); + } + + Future _loadWithRetry( + NetworkImageProvider key, + DecoderCallback decode, + ) async { + assert(key == this); + + final uri = Uri.parse(url); + final response = await retryClient.get(uri, headers: headers); + + if (response.statusCode != 200) { + throw NetworkImageLoadException( + statusCode: response.statusCode, uri: uri); + } + + final codec = await decode(response.bodyBytes); + final image = (await codec.getNextFrame()).image; + + return ImageInfo(image: image); + } +} diff --git a/lib/src/layer/tile_layer/tile_provider/network_image_with_retry.dart b/lib/src/layer/tile_layer/tile_provider/network_image_with_retry.dart deleted file mode 100644 index 7689413a1..000000000 --- a/lib/src/layer/tile_layer/tile_provider/network_image_with_retry.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/painting.dart'; -import 'package:http/http.dart'; -import 'package:http/retry.dart'; - -class NetworkImageWithRetry extends ImageProvider { - /// The URL from which the image will be fetched. - final String url; - - /// The scale to place in the [ImageInfo] object of the image. - final double scale; - - /// The http RetryClient that is used for the requests - final RetryClient retryClient = RetryClient(Client()); - - NetworkImageWithRetry(this.url, {this.scale = 1.0}); - - @override - ImageStreamCompleter load(NetworkImageWithRetry key, DecoderCallback decode) { - return OneFrameImageStreamCompleter(_loadWithRetry(key, decode), - informationCollector: () sync* { - yield ErrorDescription('Image provider: $this'); - yield ErrorDescription('Image key: $key'); - }); - } - - @override - Future obtainKey(ImageConfiguration configuration) { - return SynchronousFuture(this); - } - - Future _loadWithRetry( - NetworkImageWithRetry key, DecoderCallback decode) async { - assert(key == this); - - final uri = Uri.parse(url); - final response = await retryClient.get(uri); - final codec = await decode(response.bodyBytes); - final image = (await codec.getNextFrame()).image; - - return ImageInfo( - image: image, - scale: key.scale, - ); - } -} diff --git a/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart b/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart new file mode 100644 index 000000000..406efc371 --- /dev/null +++ b/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart @@ -0,0 +1,99 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/painting.dart'; + +class NetworkNoRetryImageProvider + extends ImageProvider { + /// A valid URL, which is the location of the image to be fetched + final String url; + + /// The client which will be used to fetch the image + final HttpClient httpClient; + + /// Custom headers to add to the image fetch request + final Map headers; + + NetworkNoRetryImageProvider( + this.url, { + HttpClient? httpClient, + this.headers = const {}, + }) : httpClient = httpClient ?? HttpClient() + ..userAgent = null; + + @override + ImageStreamCompleter load( + NetworkNoRetryImageProvider key, + DecoderCallback decode, + ) { + final StreamController chunkEvents = + StreamController(); + + return MultiFrameImageStreamCompleter( + codec: _loadAsync(key: key, decode: decode, chunkEvents: chunkEvents), + chunkEvents: chunkEvents.stream, + scale: 1, + debugLabel: key.url, + informationCollector: () => [ + DiagnosticsProperty('Image provider', this), + DiagnosticsProperty('Image key', key), + ], + ); + } + + @override + Future obtainKey( + ImageConfiguration configuration) { + return SynchronousFuture(this); + } + + Future _loadAsync({ + required NetworkNoRetryImageProvider key, + required DecoderCallback decode, + required StreamController chunkEvents, + }) async { + try { + assert(key == this); + + final Uri resolved = Uri.base.resolve(key.url); + + final HttpClientRequest request = await httpClient.getUrl(resolved); + + headers.forEach((String name, String value) { + request.headers.add(name, value); + }); + + final HttpClientResponse response = await request.close(); + if (response.statusCode != HttpStatus.ok) { + await response.drain>([]); + throw NetworkImageLoadException( + statusCode: response.statusCode, uri: resolved); + } + + final Uint8List bytes = await consolidateHttpClientResponseBytes( + response, + onBytesReceived: (int cumulative, int? total) { + chunkEvents.add(ImageChunkEvent( + cumulativeBytesLoaded: cumulative, + expectedTotalBytes: total, + )); + }, + ); + if (bytes.lengthInBytes == 0) { + throw Exception('NetworkImage is an empty file: $resolved'); + } + + return decode(bytes); + } catch (e) { + scheduleMicrotask(() { + PaintingBinding.instance.imageCache.evict(key); + }); + rethrow; + } finally { + chunkEvents.close(); + } + } +} diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart index df8c27f0b..7cc9ca15f 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider.dart @@ -1,23 +1,17 @@ -// ignore_for_file: avoid_print -// TODO: Remove print statements - -import 'dart:async'; - import 'package:flutter/widgets.dart'; +import 'package:http/http.dart'; +import 'package:http/retry.dart'; import 'package:universal_io/io.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_with_retry.dart'; - -const Map _defaultHeader = { - 'User-Agent': 'flutter_map via Dart (unknown)', -}; +import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart'; +import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_provider.dart'; abstract class TileProvider { Map headers; TileProvider({ - this.headers = _defaultHeader, + this.headers = const {}, }); ImageProvider getImage(Coords coords, TileLayerOptions options); @@ -70,55 +64,57 @@ abstract class TileProvider { } } -/// [TileProvider] that uses [NetworkImageWithRetry] internally +/// [TileProvider] that uses [NetworkImageProvider] internally /// -/// Note that this is not recommended, as there is no way to set headers with this method: see https://github.com/flutter/flutter/issues/19532. -/// The parameter is only provided for potential forward-compatibility. +/// This image provider automatically retries some failed requests up to 3 times. /// -/// TODO: Add header capabilities through `HttpOverrides` or (preferably) by changing the image provider's implementation +/// Note that this provider may be slower than [NetworkNoRetryTileProvider] when fetching tiles due to internal reasons. class NetworkTileProvider extends TileProvider { NetworkTileProvider({ Map? headers, + RetryClient? retryClient, }) { - this.headers = headers ?? _defaultHeader; + this.headers = headers ?? {}; + this.retryClient = retryClient ?? RetryClient(Client()); } + late final RetryClient retryClient; + @override ImageProvider getImage(Coords coords, TileLayerOptions options) { - return NetworkImageWithRetry(getTileUrl(coords, options)); + return HttpOverrides.runZoned( + () => NetworkImageProvider( + getTileUrl(coords, options), + headers: headers, + retryClient: retryClient, + ), + createHttpClient: (c) => _FlutterMapHTTPOverrides().createHttpClient(c), + ); } } -/// [TileProvider] that uses [NetworkImage] internally +/// [TileProvider] that uses [NetworkNoRetryImageProvider] internally +/// +/// This image provider does not automatically retry any failed requests. This provider is the default and the recommended provider, unless your tile server is especially unreliable. class NetworkNoRetryTileProvider extends TileProvider { NetworkNoRetryTileProvider({ Map? headers, + HttpClient? httpClient, }) { - this.headers = headers ?? _defaultHeader; - //HttpOverrides.global = _FlutterMapHTTPOverrides(); + this.headers = headers ?? {}; + this.httpClient = httpClient ?? HttpClient() + ..userAgent = null; } + late final HttpClient httpClient; + @override - ImageProvider getImage(Coords coords, TileLayerOptions options) { - print('Header: ${headers['User-Agent']}'); - print("Running in ${Zone.current.toString()}"); - return HttpOverrides.runZoned( - () { - /*print("Running in ${Zone.current}");*/ - final HttpClient httpClient = HttpClient(); - print("userAgent = ${httpClient.userAgent}"); - - return NetworkImage( - getTileUrl(coords, options), - headers: headers, - ); - }, - createHttpClient: (c) { - print('Is creating HTTP client for zone'); - return _FlutterMapHTTPOverrides().createHttpClient(c); - }, - ); - } + ImageProvider getImage(Coords coords, TileLayerOptions options) => + NetworkNoRetryImageProvider( + getTileUrl(coords, options), + headers: headers, + httpClient: httpClient, + ); } /// Deprecated due to internal refactoring. The name is misleading, as the internal [ImageProvider] always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to [NetworkNoRetryTileProvider] before the next minor update. @@ -127,13 +123,21 @@ class NetworkNoRetryTileProvider extends TileProvider { class NonCachingNetworkTileProvider extends TileProvider { NonCachingNetworkTileProvider({ Map? headers, + HttpClient? httpClient, }) { - this.headers = headers ?? _defaultHeader; + this.headers = headers ?? {}; + this.httpClient = httpClient ?? HttpClient() + ..userAgent = null; } + late final HttpClient httpClient; + @override ImageProvider getImage(Coords coords, TileLayerOptions options) => - NetworkNoRetryTileProvider(headers: headers).getImage(coords, options); + NetworkNoRetryTileProvider( + headers: headers, + httpClient: httpClient, + ).getImage(coords, options); } class AssetTileProvider extends TileProvider { From cc61383777ed3bb90d5199f4b43ae34b4094ae66 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sat, 9 Jul 2022 11:34:16 +0100 Subject: [PATCH 07/12] Fixed web platform support Seperated tile_provider.dart for web and other plaforms Removed 'universal_io' dependency Updated CHANGELOG --- CHANGELOG.md | 27 ++++ lib/flutter_map.dart | 3 +- .../tile_provider/network_image_provider.dart | 13 +- .../network_no_retry_image_provider.dart | 16 +- ...le_provider.dart => tile_provider_io.dart} | 30 ++-- .../tile_provider/tile_provider_web.dart | 148 ++++++++++++++++++ pubspec.yaml | 1 - 7 files changed, 207 insertions(+), 31 deletions(-) rename lib/src/layer/tile_layer/tile_provider/{tile_provider.dart => tile_provider_io.dart} (90%) create mode 100644 lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index e0a55803f..c4b686d5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## [2.0.0] - 2022/XX/XX + +Contains the following additions/removals: + +- Added adjustable mouse wheel zoom speed - [#1289](https://github.com/fleaflet/flutter_map/pull/1289) +- Multiple changes - [#1294](https://github.com/fleaflet/flutter_map/pull/1294) + - Added advanced header support, including 'User-Agent' + - Refactored `TileProvider`s + - Resolved multiple TODOs within codebase + - Removed old deprecated code + +Contains the following bug fixes: + +- Fixed unsymmetrical markers disappearing with unusually positioned anchors - [#1291](https://github.com/fleaflet/flutter_map/pull/1291) +- Fixed potential for error 403s due to invalid/blocked 'User-Agent' header - [#1294](https://github.com/fleaflet/flutter_map/pull/1294) + +In other news: + +- None + +Many thanks to these contributors (in no particular order): + +- @mboe +- @aytunch +- @MichalTorma +- ... and all the maintainers + ## [1.1.1] - 2022/06/25 Contains the following additions/removals: diff --git a/lib/flutter_map.dart b/lib/flutter_map.dart index a8d90ba3c..baab5ba75 100644 --- a/lib/flutter_map.dart +++ b/lib/flutter_map.dart @@ -40,7 +40,8 @@ export 'package:flutter_map/src/layer/tile_layer/tile_builder.dart'; export 'package:flutter_map/src/layer/tile_layer/tile_layer.dart'; export 'package:flutter_map/src/layer/tile_layer/tile_provider/file_tile_provider_io.dart' if (dart.library.html) 'package:flutter_map/src/layer/tile_layer/tile_provider/file_tile_provider_web.dart'; -export 'package:flutter_map/src/layer/tile_layer/tile_provider/tile_provider.dart'; +export 'package:flutter_map/src/layer/tile_layer/tile_provider/tile_provider_io.dart' + if (dart.library.html) 'package:flutter_map/src/layer/tile_layer/tile_provider/tile_provider_web.dart'; export 'package:flutter_map/src/plugins/plugin.dart'; /// Renders a map composed of a list of layers powered by [LayerOptions]. diff --git a/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart b/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart index 9380b8fca..42596d951 100644 --- a/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/network_image_provider.dart @@ -3,7 +3,7 @@ import 'package:flutter/painting.dart'; import 'package:http/http.dart'; import 'package:http/retry.dart'; -class NetworkImageProvider extends ImageProvider { +class FMNetworkImageProvider extends ImageProvider { /// The URL from which the image will be fetched. final String url; @@ -13,14 +13,15 @@ class NetworkImageProvider extends ImageProvider { /// Custom headers to add to the image fetch request final Map headers; - NetworkImageProvider( + FMNetworkImageProvider( this.url, { RetryClient? retryClient, this.headers = const {}, }) : retryClient = retryClient ?? RetryClient(Client()); @override - ImageStreamCompleter load(NetworkImageProvider key, DecoderCallback decode) { + ImageStreamCompleter load( + FMNetworkImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter(_loadWithRetry(key, decode), informationCollector: () sync* { yield ErrorDescription('Image provider: $this'); @@ -29,12 +30,12 @@ class NetworkImageProvider extends ImageProvider { } @override - Future obtainKey(ImageConfiguration configuration) { - return SynchronousFuture(this); + Future obtainKey(ImageConfiguration configuration) { + return SynchronousFuture(this); } Future _loadWithRetry( - NetworkImageProvider key, + FMNetworkImageProvider key, DecoderCallback decode, ) async { assert(key == this); diff --git a/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart b/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart index 406efc371..1fcb0b2cb 100644 --- a/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart @@ -6,8 +6,8 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; -class NetworkNoRetryImageProvider - extends ImageProvider { +class FMNetworkNoRetryImageProvider + extends ImageProvider { /// A valid URL, which is the location of the image to be fetched final String url; @@ -17,7 +17,7 @@ class NetworkNoRetryImageProvider /// Custom headers to add to the image fetch request final Map headers; - NetworkNoRetryImageProvider( + FMNetworkNoRetryImageProvider( this.url, { HttpClient? httpClient, this.headers = const {}, @@ -26,7 +26,7 @@ class NetworkNoRetryImageProvider @override ImageStreamCompleter load( - NetworkNoRetryImageProvider key, + FMNetworkNoRetryImageProvider key, DecoderCallback decode, ) { final StreamController chunkEvents = @@ -39,19 +39,19 @@ class NetworkNoRetryImageProvider debugLabel: key.url, informationCollector: () => [ DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), + DiagnosticsProperty('Image key', key), ], ); } @override - Future obtainKey( + Future obtainKey( ImageConfiguration configuration) { - return SynchronousFuture(this); + return SynchronousFuture(this); } Future _loadAsync({ - required NetworkNoRetryImageProvider key, + required FMNetworkNoRetryImageProvider key, required DecoderCallback decode, required StreamController chunkEvents, }) async { diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart similarity index 90% rename from lib/src/layer/tile_layer/tile_provider/tile_provider.dart rename to lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart index 7cc9ca15f..d954ce7d0 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart @@ -1,11 +1,12 @@ +import 'dart:io'; + import 'package:flutter/widgets.dart'; import 'package:http/http.dart'; import 'package:http/retry.dart'; -import 'package:universal_io/io.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_provider.dart'; +import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart'; abstract class TileProvider { Map headers; @@ -64,7 +65,7 @@ abstract class TileProvider { } } -/// [TileProvider] that uses [NetworkImageProvider] internally +/// [TileProvider] that uses [FMNetworkImageProvider] internally /// /// This image provider automatically retries some failed requests up to 3 times. /// @@ -81,19 +82,18 @@ class NetworkTileProvider extends TileProvider { late final RetryClient retryClient; @override - ImageProvider getImage(Coords coords, TileLayerOptions options) { - return HttpOverrides.runZoned( - () => NetworkImageProvider( - getTileUrl(coords, options), - headers: headers, - retryClient: retryClient, - ), - createHttpClient: (c) => _FlutterMapHTTPOverrides().createHttpClient(c), - ); - } + ImageProvider getImage(Coords coords, TileLayerOptions options) => + HttpOverrides.runZoned( + () => FMNetworkImageProvider( + getTileUrl(coords, options), + headers: headers, + retryClient: retryClient, + ), + createHttpClient: (c) => _FlutterMapHTTPOverrides().createHttpClient(c), + ); } -/// [TileProvider] that uses [NetworkNoRetryImageProvider] internally +/// [TileProvider] that uses [FMNetworkNoRetryImageProvider] internally /// /// This image provider does not automatically retry any failed requests. This provider is the default and the recommended provider, unless your tile server is especially unreliable. class NetworkNoRetryTileProvider extends TileProvider { @@ -110,7 +110,7 @@ class NetworkNoRetryTileProvider extends TileProvider { @override ImageProvider getImage(Coords coords, TileLayerOptions options) => - NetworkNoRetryImageProvider( + FMNetworkNoRetryImageProvider( getTileUrl(coords, options), headers: headers, httpClient: httpClient, diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart new file mode 100644 index 000000000..86bb458a1 --- /dev/null +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart @@ -0,0 +1,148 @@ +import 'package:flutter/widgets.dart'; +import 'package:http/retry.dart'; + +import 'package:flutter_map/flutter_map.dart'; +import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_provider.dart'; + +abstract class TileProvider { + Map headers; + + TileProvider({ + this.headers = const {}, + }); + + ImageProvider getImage(Coords coords, TileLayerOptions options); + + void dispose() {} + + String getTileUrl(Coords coords, TileLayerOptions options) { + final urlTemplate = (options.wmsOptions != null) + ? options.wmsOptions! + .getUrl(coords, options.tileSize.toInt(), options.retinaMode) + : options.urlTemplate; + + final z = _getZoomForUrl(coords, options); + + final data = { + 'x': coords.x.round().toString(), + 'y': coords.y.round().toString(), + 'z': z.round().toString(), + 's': getSubdomain(coords, options), + 'r': '@2x', + }; + if (options.tms) { + data['y'] = invertY(coords.y.round(), z.round()).toString(); + } + final allOpts = Map.from(data) + ..addAll(options.additionalOptions); + return options.templateFunction(urlTemplate!, allOpts); + } + + double _getZoomForUrl(Coords coords, TileLayerOptions options) { + var zoom = coords.z; + + if (options.zoomReverse) { + zoom = options.maxZoom - zoom; + } + + return zoom += options.zoomOffset; + } + + int invertY(int y, int z) { + return ((1 << z) - 1) - y; + } + + String getSubdomain(Coords coords, TileLayerOptions options) { + if (options.subdomains.isEmpty) { + return ''; + } + final index = (coords.x + coords.y).round() % options.subdomains.length; + return options.subdomains[index]; + } +} + +/// [TileProvider] that uses [FMNetworkImageProvider] internally +/// +/// This image provider automatically retries some failed requests up to 3 times. +/// +/// Note that this provider may be slower than [NetworkNoRetryTileProvider] when fetching tiles due to internal reasons. +/// +/// Note that the 'User-Agent' header cannot be changed on the web. +class NetworkTileProvider extends TileProvider { + NetworkTileProvider({ + Map? headers, + }) { + this.headers = headers ?? {}; + } + + late final RetryClient retryClient; + + @override + ImageProvider getImage(Coords coords, TileLayerOptions options) => + FMNetworkImageProvider( + getTileUrl(coords, options), + headers: headers, + ); +} + +/// [TileProvider] that uses [NetworkImage] internally +/// +/// This image provider does not automatically retry any failed requests. This provider is the default and the recommended provider, unless your tile server is especially unreliable. +/// +/// Note that the 'User-Agent' header cannot be changed on the web. +class NetworkNoRetryTileProvider extends TileProvider { + NetworkNoRetryTileProvider({ + Map? headers, + }) { + this.headers = headers ?? {}; + } + + @override + ImageProvider getImage(Coords coords, TileLayerOptions options) => + NetworkImage( + getTileUrl(coords, options), + headers: headers, + ); +} + +/// Deprecated due to internal refactoring. The name is misleading, as the internal [ImageProvider] always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to [NetworkNoRetryTileProvider] before the next minor update. +@Deprecated( + '`NonCachingNetworkTileProvider` has been deprecated due to internal refactoring. The name is misleading, as the internal `ImageProvider` always caches, and this is recommended by most tile servers anyway. For the same functionality, migrate to `NetworkNoRetryTileProvider` before the next minor update.') +class NonCachingNetworkTileProvider extends TileProvider { + NonCachingNetworkTileProvider({ + Map? headers, + }) { + this.headers = headers ?? {}; + } + + @override + ImageProvider getImage(Coords coords, TileLayerOptions options) => + NetworkNoRetryTileProvider( + headers: headers, + ).getImage(coords, options); +} + +class AssetTileProvider extends TileProvider { + AssetTileProvider(); + + @override + ImageProvider getImage(Coords coords, TileLayerOptions options) { + return AssetImage(getTileUrl(coords, options)); + } +} + +class CustomTileProvider extends TileProvider { + final String Function(Coords coors, TileLayerOptions options) customTileUrl; + + CustomTileProvider({required this.customTileUrl}); + + @override + String getTileUrl(Coords coords, TileLayerOptions options) { + return customTileUrl(coords, options); + } + + @override + ImageProvider getImage(Coords coords, TileLayerOptions options) { + return AssetImage(getTileUrl(coords, options)); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index c5f915606..17d0cc92d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,6 @@ dependencies: proj4dart: ^2.0.0 tuple: ^2.0.0 vector_math: ^2.1.0 - universal_io: ^2.0.4 dev_dependencies: flutter_lints: ">=1.0.4" From f5569d5de4e8c0a4e378847939619d5ade0043cc Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sat, 9 Jul 2022 11:51:10 +0100 Subject: [PATCH 08/12] Fixed 'Refused to set unsafe header' error --- lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart index 86bb458a1..837f79fe8 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart @@ -81,7 +81,7 @@ class NetworkTileProvider extends TileProvider { ImageProvider getImage(Coords coords, TileLayerOptions options) => FMNetworkImageProvider( getTileUrl(coords, options), - headers: headers, + headers: headers..remove('User-Agent'), ); } @@ -101,7 +101,7 @@ class NetworkNoRetryTileProvider extends TileProvider { ImageProvider getImage(Coords coords, TileLayerOptions options) => NetworkImage( getTileUrl(coords, options), - headers: headers, + headers: headers..remove('User-Agent'), ); } From 2f5ef9774d277c1219b830db0d77bf2f7ac02996 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sat, 9 Jul 2022 11:55:10 +0100 Subject: [PATCH 09/12] Improved in-code documentation --- lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart | 4 ++++ lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart index d954ce7d0..b8005c030 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart @@ -70,6 +70,8 @@ abstract class TileProvider { /// This image provider automatically retries some failed requests up to 3 times. /// /// Note that this provider may be slower than [NetworkNoRetryTileProvider] when fetching tiles due to internal reasons. +/// +/// Note that the 'User-Agent' header and the [RetryClient] cannot be changed, on the web platform. class NetworkTileProvider extends TileProvider { NetworkTileProvider({ Map? headers, @@ -96,6 +98,8 @@ class NetworkTileProvider extends TileProvider { /// [TileProvider] that uses [FMNetworkNoRetryImageProvider] internally /// /// This image provider does not automatically retry any failed requests. This provider is the default and the recommended provider, unless your tile server is especially unreliable. +/// +/// Note that the 'User-Agent' header and the [HttpClient] cannot be changed, on the web platform. class NetworkNoRetryTileProvider extends TileProvider { NetworkNoRetryTileProvider({ Map? headers, diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart index 837f79fe8..100cf8036 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart @@ -67,7 +67,7 @@ abstract class TileProvider { /// /// Note that this provider may be slower than [NetworkNoRetryTileProvider] when fetching tiles due to internal reasons. /// -/// Note that the 'User-Agent' header cannot be changed on the web. +/// Note that the 'User-Agent' header and the `RetryClient` cannot be changed, on the web platform. class NetworkTileProvider extends TileProvider { NetworkTileProvider({ Map? headers, @@ -89,7 +89,7 @@ class NetworkTileProvider extends TileProvider { /// /// This image provider does not automatically retry any failed requests. This provider is the default and the recommended provider, unless your tile server is especially unreliable. /// -/// Note that the 'User-Agent' header cannot be changed on the web. +/// Note that the 'User-Agent' header and the `HttpClient` cannot be changed, on the web platform. class NetworkNoRetryTileProvider extends TileProvider { NetworkNoRetryTileProvider({ Map? headers, From b0063981c3d9b16ad06bb9744b853478ed8bdde1 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sat, 9 Jul 2022 19:08:45 +0100 Subject: [PATCH 10/12] Removed deprecated API remenant `attributionAlignment` from `TileLayerOptions` --- lib/src/layer/tile_layer/tile_layer_options.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/src/layer/tile_layer/tile_layer_options.dart b/lib/src/layer/tile_layer/tile_layer_options.dart index 2a06f503e..af76b482d 100644 --- a/lib/src/layer/tile_layer/tile_layer_options.dart +++ b/lib/src/layer/tile_layer/tile_layer_options.dart @@ -230,9 +230,6 @@ class TileLayerOptions extends LayerOptions { /// When set to `true`, the `tileFadeIn*` options will be ignored. final bool fastReplace; - ///aligment of the attribution text on the map widget - final Alignment attributionAlignment; - /// Stream to notify the [TileLayer] that it needs resetting Stream? reset; @@ -240,7 +237,6 @@ class TileLayerOptions extends LayerOptions { LatLngBounds? tileBounds; TileLayerOptions({ - this.attributionAlignment = Alignment.bottomRight, Key? key, this.urlTemplate, double tileSize = 256.0, From cb81eae65eb559897a88440e113dd694fe4dbf01 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sun, 10 Jul 2022 10:00:21 +0100 Subject: [PATCH 11/12] Fix false positive linter warning: see https://github.com/dart-lang/linter/issues/1381 --- .../tile_provider/network_no_retry_image_provider.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart b/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart index 1fcb0b2cb..059add3bf 100644 --- a/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart +++ b/lib/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart @@ -29,6 +29,7 @@ class FMNetworkNoRetryImageProvider FMNetworkNoRetryImageProvider key, DecoderCallback decode, ) { + //ignore: close_sinks final StreamController chunkEvents = StreamController(); From 640203455231ce60b06f0b1fe790e61992785fe1 Mon Sep 17 00:00:00 2001 From: JaffaKetchup Date: Sun, 10 Jul 2022 10:59:58 +0100 Subject: [PATCH 12/12] Improved documentation Refactored base `TileProvider` into independent file --- lib/flutter_map.dart | 6 +- .../tile_provider/base_tile_provider.dart | 71 +++++++++++++++++++ .../tile_provider/tile_provider_io.dart | 60 +--------------- .../tile_provider/tile_provider_web.dart | 60 +--------------- 4 files changed, 81 insertions(+), 116 deletions(-) create mode 100644 lib/src/layer/tile_layer/tile_provider/base_tile_provider.dart diff --git a/lib/flutter_map.dart b/lib/flutter_map.dart index baab5ba75..7b198a5b3 100644 --- a/lib/flutter_map.dart +++ b/lib/flutter_map.dart @@ -5,6 +5,9 @@ import 'dart:math'; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:positioned_tap_detector_2/positioned_tap_detector_2.dart'; + import 'package:flutter_map/src/core/center_zoom.dart'; import 'package:flutter_map/src/core/point.dart'; import 'package:flutter_map/src/geo/crs/crs.dart'; @@ -16,8 +19,6 @@ import 'package:flutter_map/src/layer/layer.dart'; import 'package:flutter_map/src/map/flutter_map_state.dart'; import 'package:flutter_map/src/map/map.dart'; import 'package:flutter_map/src/plugins/plugin.dart'; -import 'package:latlong2/latlong.dart'; -import 'package:positioned_tap_detector_2/positioned_tap_detector_2.dart'; export 'package:flutter_map/src/core/center_zoom.dart'; export 'package:flutter_map/src/core/point.dart'; @@ -38,6 +39,7 @@ export 'package:flutter_map/src/layer/tile_layer/coords.dart'; export 'package:flutter_map/src/layer/tile_layer/tile.dart'; export 'package:flutter_map/src/layer/tile_layer/tile_builder.dart'; export 'package:flutter_map/src/layer/tile_layer/tile_layer.dart'; +export 'package:flutter_map/src/layer/tile_layer/tile_provider/base_tile_provider.dart'; export 'package:flutter_map/src/layer/tile_layer/tile_provider/file_tile_provider_io.dart' if (dart.library.html) 'package:flutter_map/src/layer/tile_layer/tile_provider/file_tile_provider_web.dart'; export 'package:flutter_map/src/layer/tile_layer/tile_provider/tile_provider_io.dart' diff --git a/lib/src/layer/tile_layer/tile_provider/base_tile_provider.dart b/lib/src/layer/tile_layer/tile_provider/base_tile_provider.dart new file mode 100644 index 000000000..9ede51ece --- /dev/null +++ b/lib/src/layer/tile_layer/tile_provider/base_tile_provider.dart @@ -0,0 +1,71 @@ +import 'package:flutter/widgets.dart'; + +import 'package:flutter_map/flutter_map.dart'; + +/// The base tile provider implementation, extended by other classes such as [NetworkTileProvider] +/// +/// Visit the online documentation at https://docs.fleaflet.dev/usage/layers/tile-layer/tile-providers for more information. +abstract class TileProvider { + /// Custom headers that may be sent with each tile request, if the specific implementation supports it + Map headers; + + /// The base tile provider implementation, extended by other classes such as [NetworkTileProvider] + /// + /// Visit the online documentation at https://docs.fleaflet.dev/usage/layers/tile-layer/tile-providers for more information. + TileProvider({ + this.headers = const {}, + }); + + /// Retrieve a tile as an image, based on it's coordinates and the current [TileLayerOptions] + ImageProvider getImage(Coords coords, TileLayerOptions options); + + /// Called when the [TileLayerWidget] is disposed + void dispose() {} + + /// Generate a valid URL for a tile, based on it's coordinates and the current [TileLayerOptions] + String getTileUrl(Coords coords, TileLayerOptions options) { + final urlTemplate = (options.wmsOptions != null) + ? options.wmsOptions! + .getUrl(coords, options.tileSize.toInt(), options.retinaMode) + : options.urlTemplate; + + final z = _getZoomForUrl(coords, options); + + final data = { + 'x': coords.x.round().toString(), + 'y': coords.y.round().toString(), + 'z': z.round().toString(), + 's': getSubdomain(coords, options), + 'r': '@2x', + }; + if (options.tms) { + data['y'] = invertY(coords.y.round(), z.round()).toString(); + } + final allOpts = Map.from(data) + ..addAll(options.additionalOptions); + return options.templateFunction(urlTemplate!, allOpts); + } + + double _getZoomForUrl(Coords coords, TileLayerOptions options) { + var zoom = coords.z; + + if (options.zoomReverse) { + zoom = options.maxZoom - zoom; + } + + return zoom += options.zoomOffset; + } + + int invertY(int y, int z) { + return ((1 << z) - 1) - y; + } + + /// Get a subdomain value for a tile, based on it's coordinates and the current [TileLayerOptions] + String getSubdomain(Coords coords, TileLayerOptions options) { + if (options.subdomains.isEmpty) { + return ''; + } + final index = (coords.x + coords.y).round() % options.subdomains.length; + return options.subdomains[index]; + } +} diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart index b8005c030..f1e126af6 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_io.dart @@ -8,63 +8,6 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_provider.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_no_retry_image_provider.dart'; -abstract class TileProvider { - Map headers; - - TileProvider({ - this.headers = const {}, - }); - - ImageProvider getImage(Coords coords, TileLayerOptions options); - - void dispose() {} - - String getTileUrl(Coords coords, TileLayerOptions options) { - final urlTemplate = (options.wmsOptions != null) - ? options.wmsOptions! - .getUrl(coords, options.tileSize.toInt(), options.retinaMode) - : options.urlTemplate; - - final z = _getZoomForUrl(coords, options); - - final data = { - 'x': coords.x.round().toString(), - 'y': coords.y.round().toString(), - 'z': z.round().toString(), - 's': getSubdomain(coords, options), - 'r': '@2x', - }; - if (options.tms) { - data['y'] = invertY(coords.y.round(), z.round()).toString(); - } - final allOpts = Map.from(data) - ..addAll(options.additionalOptions); - return options.templateFunction(urlTemplate!, allOpts); - } - - double _getZoomForUrl(Coords coords, TileLayerOptions options) { - var zoom = coords.z; - - if (options.zoomReverse) { - zoom = options.maxZoom - zoom; - } - - return zoom += options.zoomOffset; - } - - int invertY(int y, int z) { - return ((1 << z) - 1) - y; - } - - String getSubdomain(Coords coords, TileLayerOptions options) { - if (options.subdomains.isEmpty) { - return ''; - } - final index = (coords.x + coords.y).round() % options.subdomains.length; - return options.subdomains[index]; - } -} - /// [TileProvider] that uses [FMNetworkImageProvider] internally /// /// This image provider automatically retries some failed requests up to 3 times. @@ -153,6 +96,9 @@ class AssetTileProvider extends TileProvider { } } +/// A very basic [TileProvider] implementation, that can be extended to create your own provider +/// +/// Using this method is not recommended any more, except for very simple custom [TileProvider]s. Instead, visit the online documentation at https://docs.fleaflet.dev/plugins/making-a-plugin/creating-new-tile-providers. class CustomTileProvider extends TileProvider { final String Function(Coords coors, TileLayerOptions options) customTileUrl; diff --git a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart index 100cf8036..b4ed8cd47 100644 --- a/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart +++ b/lib/src/layer/tile_layer/tile_provider/tile_provider_web.dart @@ -4,63 +4,6 @@ import 'package:http/retry.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/layer/tile_layer/tile_provider/network_image_provider.dart'; -abstract class TileProvider { - Map headers; - - TileProvider({ - this.headers = const {}, - }); - - ImageProvider getImage(Coords coords, TileLayerOptions options); - - void dispose() {} - - String getTileUrl(Coords coords, TileLayerOptions options) { - final urlTemplate = (options.wmsOptions != null) - ? options.wmsOptions! - .getUrl(coords, options.tileSize.toInt(), options.retinaMode) - : options.urlTemplate; - - final z = _getZoomForUrl(coords, options); - - final data = { - 'x': coords.x.round().toString(), - 'y': coords.y.round().toString(), - 'z': z.round().toString(), - 's': getSubdomain(coords, options), - 'r': '@2x', - }; - if (options.tms) { - data['y'] = invertY(coords.y.round(), z.round()).toString(); - } - final allOpts = Map.from(data) - ..addAll(options.additionalOptions); - return options.templateFunction(urlTemplate!, allOpts); - } - - double _getZoomForUrl(Coords coords, TileLayerOptions options) { - var zoom = coords.z; - - if (options.zoomReverse) { - zoom = options.maxZoom - zoom; - } - - return zoom += options.zoomOffset; - } - - int invertY(int y, int z) { - return ((1 << z) - 1) - y; - } - - String getSubdomain(Coords coords, TileLayerOptions options) { - if (options.subdomains.isEmpty) { - return ''; - } - final index = (coords.x + coords.y).round() % options.subdomains.length; - return options.subdomains[index]; - } -} - /// [TileProvider] that uses [FMNetworkImageProvider] internally /// /// This image provider automatically retries some failed requests up to 3 times. @@ -131,6 +74,9 @@ class AssetTileProvider extends TileProvider { } } +/// A very basic [TileProvider] implementation, that can be extended to create your own provider +/// +/// Using this method is not recommended any more, except for very simple custom [TileProvider]s. Instead, visit the online documentation at https://docs.fleaflet.dev/plugins/making-a-plugin/creating-new-tile-providers. class CustomTileProvider extends TileProvider { final String Function(Coords coors, TileLayerOptions options) customTileUrl;