activity_files 0.6.0 copy "activity_files: ^0.6.0" to clipboard
activity_files: ^0.6.0 copied to clipboard

A pure Dart toolkit for parsing, editing, validating, and converting workout activity files in GPX, TCX, FIT, GeoJSON, and CSV formats.

activity_files #

Pub Package Pub Points Pub Likes codecov License GitHub Stars GitHub Forks GitHub Issues

Licensed under the BSD 3-Clause License. See LICENSE for details.

A pure Dart toolkit for parsing, editing, validating, and converting workout activity files in GPX, TCX, FIT, GeoJSON, and CSV formats.

Highlights #

  • Format-agnostic RawActivity model with builders/editors for GPS points, laps, channels, and device metadata.
  • Ergonomic ActivityFiles facade plus CLI that load, normalize, validate, and convert/export GPX/TCX/FIT/CSV/GeoJSON payloads in a handful of calls.
  • Stream-aware builders (builderFromStreams, convertAndExport) so servers can feed timestamp/value tuples directly without manual model wiring.
  • Diagnostics-first results with sport mappers, validation stats, and namespace-tolerant parsers that never throw on untrusted files.
  • Channel cursors, resampling helpers, and encoder options keep exports fast while letting you control tolerances/precision.
  • FIT session + lap stats are exposed via ActivitySummary and enriched Lap fields.
  • Flexible export targets: emit GPX 1.0/1.1 and TCX v1/v2 via EncoderOptions or CLI flags; FIT encoding covers core workout fields.

See the usage guide for the full feature tour and performance notes.

Getting started #

Add the package to pubspec.yaml:

dependencies:
  activity_files: ^0.6.0

Then install dependencies:

dart pub get

See example/main.dart for a complete sample (uses the generated example/assets/sample.*) or jump straight into the facade:

import 'package:activity_files/activity_files.dart';

Future<void> convertGpxToFit(Uint8List bytes) async {
  // 1) Load + auto-detect format.
  final load = await ActivityFiles.load(
    bytes,
    useIsolate: true,
  );
  if (load.hasErrors) {
    throw StateError('Load failed:\n${load.diagnosticsSummary()}');
  }

  // 2) Normalize (sort/dedup + trim invalid points) before exporting.
  final normalized = ActivityFiles.normalizeActivity(load.activity);

  // 3) Export with validation so warnings/errors surface alongside the payload.
  final export = await ActivityFiles.export(
    activity: normalized,
    to: ActivityFileFormat.fit,
    runValidation: true,
  );
  if (export.hasErrors) {
    throw StateError('Export failed:\n${export.diagnosticsSummary()}');
  }

  // 4) Use the payload. FIT is binary; GPX/TCX use `asString()`.
  final fitBytes = export.asBytes();
  // upload(fitBytes);
}

Need to handle large uploads? The loader caps inline payloads/streams at 64MB (ActivityFiles.defaultMaxPayloadBytes). For bigger files, stream and convert without buffering everything:

Future<ActivityExportResult> streamConvert(File input) {
  return ActivityFiles.convertAndExportStream(
    source: input.openRead(),
    from: ActivityFileFormat.gpx,
    to: ActivityFileFormat.tcx,
    parseInIsolate: true,
    exportInIsolate: true,
    runValidation: true,
  );
}

The usage guide now hosts the detailed Flutter widget, streaming, CLI, and isolate walkthroughs that previously lived in this README. For a complete, runnable walkthrough (load → normalize → validate → export), see example/main.dart.

Source inputs & isolates #

  • String inputs are treated as inline payloads. Pass a File (preferred) or set allowFilePaths: true when you explicitly trust the string to reference local storage.
  • useIsolate / exportInIsolate offload work when isolates are available. Gate both flags with !kIsWeb for Flutter web builds.
  • Stream-backed loads keep a replayable buffer so bytesPayload remains usable even after parsing completes.
  • Payload limits: inline strings/bytes and buffered streams are capped at 64MB (ActivityFiles.defaultMaxPayloadBytes). Oversized inputs throw FormatException (and the CLI rejects them) to avoid unbounded memory use; split very large uploads before parsing.

Diagnostics-first workflows #

Parsing, conversion, and export helpers never throw for malformed files—they surface issues via ParseDiagnostics on the result. Always check hasErrors, diagnosticsSummary, or the diagnostics list before trusting the returned RawActivity. The error-handling section shows ready-to-copy patterns for both load and export flows.

Format limitations #

  • GPX 1.0/1.1 are both parsed/encoded, including metadata/track names, descriptions, and extensions. The parser flattens all tracks/segments into a single stream and ignores waypoints/routes, so files that rely on multiple tracks or saved waypoints will lose that structure on load/export.
  • TCX: only the first <Activity> is parsed. Additional activities in a single file are skipped.

If you need full fidelity for multi-activity or waypoint-heavy files, split inputs before loading or extend the parsers to keep those constructs.

Async export & streaming #

ActivityExportRequest, convertAndExport, and exportAsync share the same builder API for raw location/channel streams plus isolate toggles so you can pin heavy work off the UI thread. See doc/usage_guide.md#async-export--streaming for streamed conversions, CLI pipelines, and memory caveats.

For advanced editing pipelines, parser/encoder samples, and CLI walkthroughs, see the usage guide, which retains the detailed examples previously listed here.

Contributing #

Issues and pull requests are welcome, especially for additional format fixtures. The package is released under the BSD 3-Clause license.

3
likes
160
points
2.69k
downloads

Documentation

API reference

Publisher

verified publishereikedreier.xyz

Weekly Downloads

A pure Dart toolkit for parsing, editing, validating, and converting workout activity files in GPX, TCX, FIT, GeoJSON, and CSV formats.

Repository (GitHub)
View/report issues

Topics

#health #fitness #workout #converter #sports

License

BSD-3-Clause (license)

Dependencies

args, async, collection, csv, xml

More

Packages that depend on activity_files