Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ migrate_working_dir/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
.vscode/

# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
Expand Down
10 changes: 5 additions & 5 deletions lib/flutter_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export 'package:flutter_map/src/layer/attribution_layer/rich/widget.dart';
export 'package:flutter_map/src/layer/attribution_layer/simple.dart';
export 'package:flutter_map/src/layer/circle_layer/circle_layer.dart';
export 'package:flutter_map/src/layer/marker_layer/marker_layer.dart';
export 'package:flutter_map/src/layer/modern_tile_layer/tile_loader/bytes_fetchers/network/caching/built_in/built_in_caching_provider.dart';
export 'package:flutter_map/src/layer/modern_tile_layer/tile_loader/bytes_fetchers/network/caching/caching_provider.dart';
export 'package:flutter_map/src/layer/modern_tile_layer/tile_loader/bytes_fetchers/network/caching/disabled/disabled_caching_provider.dart';
export 'package:flutter_map/src/layer/modern_tile_layer/tile_loader/bytes_fetchers/network/caching/tile_metadata.dart';
export 'package:flutter_map/src/layer/modern_tile_layer/tile_loader/bytes_fetchers/network/caching/tile_read_failure_exception.dart';
export 'package:flutter_map/src/layer/overlay_image_layer/overlay_image_layer.dart';
export 'package:flutter_map/src/layer/polygon_layer/label/deprecated_placements.dart';
export 'package:flutter_map/src/layer/polygon_layer/label/placement_calculators/placement_calculator.dart';
Expand All @@ -49,11 +54,6 @@ export 'package:flutter_map/src/layer/tile_layer/tile_provider/asset/provider.da
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/stub_tile_provider.dart'
if (dart.library.io) 'package:flutter_map/src/layer/tile_layer/tile_provider/file/native_tile_provider.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_provider/network/caching/built_in/built_in_caching_provider.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_provider/network/caching/caching_provider.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_provider/network/caching/disabled/disabled_caching_provider.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_provider/network/caching/tile_metadata.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_provider/network/caching/tile_read_failure_exception.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_provider/network/tile_provider.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_update_event.dart';
export 'package:flutter_map/src/layer/tile_layer/tile_update_transformer.dart';
Expand Down
35 changes: 35 additions & 0 deletions lib/src/layer/modern_tile_layer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Modern Tile Layer

The modern tile layer is a rework of the original tile layer which:

* should be significantly more flexible (-> provide better integration support for plugins)
* resolve some hard-to-debug bugs
* improve performance in the default case

It does this by:

* splitting the logic of the current `TileLayer` & `TileProvider` into 3-5 parts:
* `BaseTileLayer`: responsible for tile management (initial workings provided by @mootw)

* a tile loader: responsible for getting the data for individual tiles given the coordinates from the manager
In the default implementation, this is further split:
* a source generator: responsible for telling the source fetcher what to fetch for the tile
* a source fetcher: responsible for actually fetching the tile data
In the default implementation, this is further split:
* a bytes fetcher: responsible for actually fetching the tile data

* a tile renderer: responsible for painting tiled data

* using a canvas implementation for the default raster tile layer

Significant uestions remaining:

* Is the default tile loader setup (with two stages) too much frameworking/overly-complicated?
* Simulating retina mode affects all parts of the system - but only (conceptually/for reasoning) applies to raster tiles (although technically it's no different to a top layer option). How should this be represented?
* What should the top-level options be (`TileLayerOptions`)? See also retina mode simulation.
* Who's responsibility is enforcing the max-zoom level? Is max-zoom = native max-zoom or MapOptions.maxZoom?

This new functionality has no deadline or estimated completion date - although it's something we've been wanting to do for a while, and we have some work in the
background which may be integrating with this.

Contribution greatly appriciated!
80 changes: 80 additions & 0 deletions lib/src/layer/modern_tile_layer/base_tile_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'dart:async';

import 'package:flutter_map/src/layer/modern_tile_layer/base_tile_layer.dart';
import 'package:meta/meta.dart';

/// Data associated with a particular tile coordinate which 'loads'
/// asynchronously.
///
/// These are generated by the [BaseTileLayer.tileLoader] and consumed by the
/// [BaseTileLayer.renderer].
///
/// Association with a tile coordinate is made in the tile layer.
///
/// It is up to the implementation as to what 'loads' means. However, the
/// [BaseTileLayer] will use [whenLoaded], [isLoaded], and [dispose] to manage
/// (such as pruning) the tile for the renderer.
abstract interface class BaseTileData {
/// Completes when the underlying resource is 'loaded'
Future<void> get whenLoaded;

/// Whether the underlying resource is 'loaded'
bool get isLoaded;

/// Called when a tile is removed from the map of visible tiles
///
/// This should usually be used to abort loading of the underlying resource
/// if it has not yet loaded, or release the resources held by it if already
/// loaded.
///
/// This should not usually be called externally.
@internal
void dispose();
}

/// Wrapper for custom-shape data as a [BaseTileData].
///
/// The data carried is usually made available asynchronously, for example as
/// the result of an I/O operation or HTTP request. Alternatively, data may be
/// available synchronously if the data is loaded from prepared memory. This
/// container supports either form of data.
class WrapperTileData<D extends Object?> implements BaseTileData {
D? _data;

/// Data resource
///
/// This may be `null` if [D] is nullable & the data is `null`. In this case,
/// use [isLoaded] to determine whether this accurately reflects the `null`
/// data. Otherwise, `null` means the data is not yet available.
D? get data => _data;

final _loadedTracker = Completer<D>.sync();

/// Completes with loaded data when the data is loaded successfully
///
/// This never completes if the data completes to an error.
@override
Future<D> get whenLoaded => _loadedTracker.future;

/// Whether [data] represents the loaded data
@override
bool get isLoaded => _loadedTracker.isCompleted;

@internal
@override
void dispose() => _dispose?.call();
final void Function()? _dispose;

/// Create a container with the specified data (or the data result of the
/// specified future)
WrapperTileData({
required FutureOr<D> data,
void Function()? dispose,
}) : _dispose = dispose {
if (data is Future<D>) {
data.then((data) => _loadedTracker.complete(_data = data));
} else {
_loadedTracker.complete(_data = data);
}
}
}
Loading
Loading