downloadWithProgress method

Future<DownloadProgress> downloadWithProgress({
  1. required String url,
  2. required String filename,
  3. required dynamic onProgress(
    1. double
    ),
  4. dynamic onSpeed(
    1. int
    )?,
  5. dynamic onComplete(
    1. int
    )?,
})

Implementation

Future<DownloadProgress> downloadWithProgress({
  required String url,
  required String filename,
  required Function(double) onProgress,
  Function(int)? onSpeed,
  Function(int)? onComplete,
}) async {
  final cancelToken = CancelToken();
  _cancelTokens[url] = cancelToken;

  try {
    final filePath = await _getDownloadPath(filename);
    debugPrint('📥 Downloading: $url');
    debugPrint('📥 To: $filePath');

    int lastReceived = 0;
    DateTime lastTime = DateTime.now();
    final startTime = DateTime.now();

    await _dio.download(
      url,
      filePath,
      cancelToken: cancelToken,
      onReceiveProgress: (received, total) {
        if (total != -1) {
          final progress = received / total;
          onProgress(progress);

          // Calculate speed
          final now = DateTime.now();
          final timeDiff = now.difference(lastTime).inMilliseconds;
          if (timeDiff >= 500 && onSpeed != null) {
            final bytesDiff = received - lastReceived;
            final speed = (bytesDiff * 1000 / timeDiff)
                .round(); // bytes per second
            onSpeed(speed);
            lastReceived = received;
            lastTime = now;
          }
        }
      },
    );

    // Calculate total download time
    final totalTime = DateTime.now().difference(startTime).inSeconds;
    if (onComplete != null) {
      onComplete(totalTime);
    }

    return DownloadProgress(
      state: DownloadState.completed,
      progress: 1.0,
      filePath: filePath,
    );
  } on DioException catch (e) {
    if (e.type == DioExceptionType.cancel) {
      return DownloadProgress(
        state: DownloadState.idle,
        error: 'Download cancelled',
      );
    }
    return DownloadProgress(
      state: DownloadState.failed,
      error: e.message ?? 'Download failed',
    );
  } catch (e) {
    return DownloadProgress(state: DownloadState.failed, error: e.toString());
  } finally {
    _cancelTokens.remove(url);
  }
}