startForeground method

Stream<DownloadProgress> startForeground(
  1. {required DownloadableRegion<List<Object>> region,
  2. FMTCTileProviderSettings? tileProviderSettings,
  3. bool disableRecovery = false,
  4. DownloadBufferMode bufferMode = DownloadBufferMode.disabled,
  5. int? bufferLimit,
  6. BaseClient? httpClient}
)

Download a specified DownloadableRegion in the foreground, with a recovery session

To check the number of tiles that need to be downloaded before using this function, use check.

httpClient defaults to a HttpPlusClient which supports HTTP/2 and falls back to a standard IOClient/HttpClient for HTTP/1.1 servers. Timeout is set to 5 seconds by default.

Streams a DownloadProgress object containing statistics and information about the download's progression status. This must be listened to.


bufferMode and bufferLimit control how this download will use buffering. For information about buffering, and it's advantages and disadvantages, see this docs page. Also see DownloadBufferMode's documentation.

Implementation

Stream<DownloadProgress> startForeground({
  required DownloadableRegion region,
  FMTCTileProviderSettings? tileProviderSettings,
  bool disableRecovery = false,
  DownloadBufferMode bufferMode = DownloadBufferMode.disabled,
  int? bufferLimit,
  BaseClient? httpClient,
}) async* {
  // Start recovery
  _recoveryId = DateTime.now().millisecondsSinceEpoch;
  if (!disableRecovery) {
    await FMTC.instance.rootDirectory.recovery._start(
      id: _recoveryId!,
      storeName: _storeDirectory.storeName,
      region: region,
    );
  }

  // Count number of tiles
  final maxTiles = await check(region);

  // Get the tile provider
  final FMTCTileProvider tileProvider =
      _storeDirectory.getTileProvider(tileProviderSettings);

  // Initialise HTTP client
  _httpClient = httpClient ??
      HttpPlusClient(
        http1Client: IOClient(
          HttpClient()
            ..connectionTimeout = const Duration(seconds: 5)
            ..userAgent = null,
        ),
        connectionTimeout: const Duration(seconds: 5),
      );

  // Initialise the sea tile removal system
  Uint8List? seaTileBytes;
  if (region.seaTileRemoval) {
    try {
      seaTileBytes = (await _httpClient!.get(
        Uri.parse(
          tileProvider.getTileUrl(
            const TileCoordinates(0, 0, 17),
            region.options,
          ),
        ),
      ))
          .bodyBytes;
    } catch (e) {
      seaTileBytes = null;
    }
  }

  // Initialise variables
  final List<String> failedTiles = [];
  int bufferedTiles = 0;
  int bufferedSize = 0;
  int persistedTiles = 0;
  int persistedSize = 0;
  int seaTiles = 0;
  int existingTiles = 0;
  _tileProgressStreamController = StreamController();
  _cancelRequestSignal = Completer();
  _cancelCompleteSignal = Completer();

  // Start progress management
  final DateTime startTime = DateTime.now();
  _progressManagement = InternalProgressTimingManagement()..start();

  // Start writing isolates
  await BulkTileWriter.start(
    provider: tileProvider,
    bufferMode: bufferMode,
    bufferLimit: bufferLimit,
    directory: FMTC.instance.rootDirectory.directory.absolute.path,
    streamController: _tileProgressStreamController!,
  );

  // Start the bulk downloader
  final Stream<TileProgress> downloadStream = await bulkDownloader(
    streamController: _tileProgressStreamController!,
    cancelRequestSignal: _cancelRequestSignal!,
    cancelCompleteSignal: _cancelCompleteSignal!,
    region: region,
    provider: tileProvider,
    seaTileBytes: seaTileBytes,
    progressManagement: _progressManagement!,
    client: _httpClient!,
  );

  // Listen to download progress, and report results
  await for (final TileProgress evt in downloadStream) {
    if (evt.failedUrl == null) {
      if (!evt.wasCancelOperation) {
        bufferedTiles++;
      } else {
        bufferedTiles = 0;
      }
      bufferedSize += evt.sizeBytes;
      if (evt.bulkTileWriterResponse != null) {
        persistedTiles = evt.bulkTileWriterResponse![0];
        persistedSize = evt.bulkTileWriterResponse![1];
      }
    } else {
      failedTiles.add(evt.failedUrl!);
    }

    if (evt.wasSeaTile) seaTiles += 1;
    if (evt.wasExistingTile) existingTiles += 1;

    final DownloadProgress prog = DownloadProgress._(
      downloadID: _recoveryId!,
      maxTiles: maxTiles,
      successfulTiles: bufferedTiles,
      persistedTiles: persistedTiles,
      failedTiles: failedTiles,
      successfulSize: bufferedSize / 1024,
      persistedSize: persistedSize / 1024,
      seaTiles: seaTiles,
      existingTiles: existingTiles,
      duration: DateTime.now().difference(startTime),
      tileImage: evt.tileImage == null ? null : MemoryImage(evt.tileImage!),
      bufferMode: bufferMode,
      progressManagement: _progressManagement!,
    );

    yield prog;
    if (prog.percentageProgress >= 100) break;
  }

  _internalCancel();
}