From dac6a1dddab0bdfda34049331ff6c2aee3379c64 Mon Sep 17 00:00:00 2001 From: Luka S Date: Sat, 7 Oct 2023 17:36:01 +0100 Subject: [PATCH] v1 Release Preparation (#1) --- .github/FUNDING.yml | 1 + .github/workflows/branch.yml | 51 +++++++++ README.md | 16 ++- ...flutter_map_cancellable_tile_provider.dart | 108 ++++++++++-------- pubspec.yaml | 11 +- 5 files changed, 129 insertions(+), 58 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/branch.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..2c9cff2 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: "https://docs.fleaflet.dev/supporters#support-us" \ No newline at end of file diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml new file mode 100644 index 0000000..1d05960 --- /dev/null +++ b/.github/workflows/branch.yml @@ -0,0 +1,51 @@ +name: "Branch & Fork CI/CD" +on: + push: + branches: + - '!master' + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + score-package: + name: "Score Package" + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Run Dart Package Analyser + uses: axel-op/dart-package-analyzer@master + id: analysis + with: + githubToken: ${{ secrets.GITHUB_TOKEN }} + - name: Check Package Scores + env: + TOTAL: ${{ steps.analysis.outputs.total }} + TOTAL_MAX: ${{ steps.analysis.outputs.total_max }} + run: | + if (( $TOTAL < $TOTAL_MAX - 10 )) + then + echo Package score less than available score. Improve the score! + exit 1 + fi + + analyse-code: + name: "Analyse Code" + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Setup Flutter Environment + uses: subosito/flutter-action@v2 + with: + channel: "stable" + - name: Get All Dependencies + run: flutter pub get + - name: Check Formatting + run: dart format --output=none --set-exit-if-changed . + - name: Check Lints + run: dart analyze --fatal-infos --fatal-warnings \ No newline at end of file diff --git a/README.md b/README.md index d3a6e83..e55bf8b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,17 @@ # flutter_map_cancellable_tile_provider -Plugin for [flutter_map](https://github.com/fleaflet/flutter_map) that provides a `TileProvider` with the capability to cancel unnecessary HTTP requests (on the web) +Plugin for [flutter_map](https://github.com/fleaflet/flutter_map) that provides a `TileProvider` that fetches tiles from the network, with the capability to cancel unnecessary HTTP tile requests -- Reduce tile loading durations +Tiles that are removed/pruned before they are fully loaded do not need to complete (down)loading, and therefore do not need to complete the HTTP interaction. Cancelling these unnecessary tile requests early could: + +- Reduce tile loading durations (particularly on the web) +- Reduce users' (cellular) data and cache space consumption - Reduce costly tile requests to tile servers* -- Reduce (cellular) data consumption +- Improve performance by reducing CPU and IO work ---- +This provider uses '[dio](https://pub.dev/packages/dio)', which supports aborting unnecessary HTTP requests in-flight, after they have already been sent. -Unlike `NetworkTileProvider`, this uses '[dio](https://pub.dev/packages/dio)' to support cancelling/aborting unnecessary HTTP requests in-flight. Tiles that are removed/pruned before they are fully loaded do not need to complete loading, and therefore do not need to complete the request/download. This results in the tiles currently in the map's camera/viewport being loaded faster, as the tiles loaded whilst panning, zooming, or rotating are pruned, freeing up HTTP connections. It may also result in a reduction of costs, as there are less full tile requests to your tile server, but this will depend on their backend configuration and how quickly the tile is pruned. +Although HTTP request abortion is supported on all platforms, it is especially useful on the web - and therefore recommended for web apps. This is because the web platform has a limited number of simulatous HTTP requests, and so closing the requests allows new requests to be made for new tiles. +On other platforms, the other benefits may still occur, but may not be as visible as on the web. -Note that these advantages only occur on the web, as only the web supports the abortion of HTTP requests. On other platforms, this acts equivalent to `NetworkTileProvider`, except using 'dio' instead of 'http'. +Once HTTP request abortion is [added to Dart's 'native' 'http' package (which already has a PR opened)](https://github.com/dart-lang/http/issues/424), `NetworkTileProvider` will be updated to take advantage of it, replacing and deprecating this provider. This tile provider is currently a separate package and not the default due to the reliance on the additional Dio dependency. diff --git a/lib/flutter_map_cancellable_tile_provider.dart b/lib/flutter_map_cancellable_tile_provider.dart index bb4ecdf..becabe7 100644 --- a/lib/flutter_map_cancellable_tile_provider.dart +++ b/lib/flutter_map_cancellable_tile_provider.dart @@ -6,49 +6,44 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_map/flutter_map.dart'; -/// [TileProvider] to fetch tiles from the network, with cancellation support +/// [TileProvider] that fetches tiles from the network, with the capability to +/// cancel unnecessary HTTP tile requests /// -/// Unlike [NetworkTileProvider], this uses [Dio] and supports -/// cancelling/aborting unnecessary HTTP requests in-flight. Tiles that are -/// removed/pruned before they are fully loaded do not need to complete loading, -/// and therefore do not need to complete the request/download. This results in -/// the tiles currently in the map's camera/viewport being loaded faster, as the -/// tiles loaded whilst panning, zooming, or rotating are pruned, freeing up HTTP -/// connections. It may also result in a reduction of costs, as there are less -/// full tile requests to your tile server, but this will depend on their backend -/// configuration and how quickly the tile is pruned. +/// {@template tp-desc} /// -/// Note that these advantages only occur on the web, as only the web supports -/// the abortion of HTTP requests. On other platforms, this acts equivalent to -/// [NetworkTileProvider], except using 'package:dio' instead of 'package:http'. +/// Tiles that are removed/pruned before they are fully loaded do not need to +/// complete (down)loading, and therefore do not need to complete the HTTP +/// interaction. Cancelling these unnecessary tile requests early could: +/// +/// - Reduce tile loading durations (particularly on the web) +/// - Reduce users' (cellular) data and cache space consumption +/// - Reduce costly tile requests to tile servers* +/// - Improve performance by reducing CPU and IO work +/// +/// This provider uses '[dio](https://pub.dev/packages/dio)', which supports +/// aborting unnecessary HTTP requests in-flight, after they have already been +/// sent. +/// +/// Although HTTP request abortion is supported on all platforms, it is +/// especially useful on the web - and therefore recommended for web apps. This +/// is because the web platform has a limited number of simulatous HTTP requests, +/// and so closing the requests allows new requests to be made for new tiles. +/// On other platforms, the other benefits may still occur, but may not be as +/// visible as on the web. +/// +/// Once HTTP request abortion is [added to Dart's 'native' 'http' package (which already has a PR opened)](https://github.com/dart-lang/http/issues/424), `NetworkTileProvider` will be updated to take advantage of it, replacing and deprecating this provider. This tile provider is currently a seperate package and not the default due to the reliance on the additional Dio dependency. +/// +/// --- /// /// On the web, the 'User-Agent' header cannot be changed as specified in /// [TileLayer.tileProvider]'s documentation, due to a Dart/browser limitation. +/// {@endtemplate} class CancellableNetworkTileProvider extends TileProvider { - /// Create a [TileProvider] to fetch tiles from the network, with cancellation - /// support - /// - /// Unlike [NetworkTileProvider], this uses [Dio] and supports - /// cancelling/aborting unnecessary HTTP requests in-flight. Tiles that are - /// removed/pruned before they are fully loaded do not need to complete - /// loading, and therefore do not need to complete the request/download. This - /// results in the tiles currently in the map's camera/viewport being loaded - /// faster, as the tiles loaded whilst panning, zooming, or rotating are - /// pruned, freeing up HTTP connections. It may also result in a reduction of - /// costs, as there are less full tile requests to your tile server, but this - /// will depend on their backend configuration and how quickly the tile is - /// pruned. - /// - /// Note that these advantages only occur on the web, as only the web supports - /// the abortion of HTTP requests. On other platforms, this acts equivalent to - /// [NetworkTileProvider], except using 'package:dio' instead of - /// 'package:http'. + /// Create a [CancellableNetworkTileProvider] to fetch tiles from the network, + /// with cancellation support /// - /// On the web, the 'User-Agent' header cannot be changed as specified in - /// [TileLayer.tileProvider]'s documentation, due to a Dart/browser limitation. - CancellableNetworkTileProvider({ - super.headers, - }) : _dio = Dio(); + /// {@macro tp-desc} + CancellableNetworkTileProvider({super.headers}) : _dio = Dio(); final Dio _dio; // ignore: use_late_for_private_fields_and_variables @@ -125,17 +120,27 @@ class _CNTPImageProvider extends ImageProvider<_CNTPImageProvider> { final cancelToken = CancelToken(); unawaited(cancelLoading.then((_) => cancelToken.cancel())); - final Uint8List bytes; try { - final response = await tileProvider._dio.get( - useFallback ? fallbackUrl! : url, - cancelToken: cancelToken, - options: Options( - headers: tileProvider.headers, - responseType: ResponseType.bytes, + final codec = decode( + await ImmutableBuffer.fromUint8List( + (await tileProvider._dio.get( + useFallback ? fallbackUrl! : url, + cancelToken: cancelToken, + options: Options( + headers: tileProvider.headers, + responseType: ResponseType.bytes, + ), + )) + .data!, ), - ); - bytes = response.data!; + ).catchError((e) { + // ignore: only_throw_errors + if (useFallback || fallbackUrl == null) throw e as Object; + return _loadAsync(key, chunkEvents, decode, useFallback: true); + }); + + cancelLoading.ignore(); + return codec; } on DioException catch (err) { if (CancelToken.isCancel(err)) { return decode( @@ -147,11 +152,18 @@ class _CNTPImageProvider extends ImageProvider<_CNTPImageProvider> { if (useFallback || fallbackUrl == null) rethrow; return _loadAsync(key, chunkEvents, decode, useFallback: true); } catch (_) { + // This redundancy necessary, do not remove if (useFallback || fallbackUrl == null) rethrow; return _loadAsync(key, chunkEvents, decode, useFallback: true); } - - cancelLoading.ignore(); - return decode(await ImmutableBuffer.fromUint8List(bytes)); } + + @override + bool operator ==(Object other) => + identical(this, other) || + (other is _CNTPImageProvider && fallbackUrl == null && url == other.url); + + @override + int get hashCode => + Object.hashAll([url, if (fallbackUrl != null) fallbackUrl]); } diff --git a/pubspec.yaml b/pubspec.yaml index 12d727e..1592520 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,15 @@ name: flutter_map_cancellable_tile_provider -description: Plugin for flutter_map that provides a `TileProvider` with the capability to cancel unnecessary HTTP requests -version: 1.0.0-preview +description: Plugin for flutter_map that provides a `TileProvider` with the capability to cancel unnecessary HTTP tile requests +version: 1.0.0 homepage: https://github.com/fleaflet/flutter_map repository: https://github.com/fleaflet/flutter_map_cancellable_tile_provider issue_tracker: https://github.com/fleaflet/flutter_map/issues documentation: https://docs.fleaflet.dev +funding: + - https://docs.fleaflet.dev/supporters#support-us + topics: - flutter-map - map @@ -24,7 +27,7 @@ environment: flutter: ">=3.10.0" dependencies: - dio: ^5.3.2 + dio: ^5.3.3 flutter: sdk: flutter - flutter_map: ^6.0.0-dev.3 + flutter_map: ^6.0.0