activity_files 0.5.0
activity_files: ^0.5.0 copied to clipboard
Workout file toolkit for Dart with GPX, TCX, FIT, GeoJSON and CSV parsing, editing, validation, and conversion.
activity_files #
Licensed under the BSD 3-Clause License. See LICENSE for details.
A complete Dart toolkit for parsing, editing, validating, and converting workout activity files in GPX, TCX, FIT, GeoJSON, and CSV formats.
Highlights #
- Format-agnostic
RawActivitymodel with builders/editors for GPS points, laps, channels, and device metadata. - Ergonomic
ActivityFilesfacade plus CLI that load, normalize, validate, and export GPX/TCX/FIT 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
ActivitySummaryand enrichedLapfields. - Flexible export targets: emit GPX 1.0/1.1 and TCX v1/v2 via
EncoderOptionsor CLI flags; FIT encoding covers core workout fields.
See the usage guide for the full feature tour and performance notes.
Quick links #
- Usage guide (full README) – Flutter, CLI, streaming, and error-handling walkthroughs.
- Roadmap – Planned features and timeline to 1.0.0.
- Testing guide – Running tests and writing new ones.
- Example app – minimal GPX round-trip.
- CLI reference – conversions/validation from the terminal.
- CHANGELOG – migration notes and release history.
Getting started #
Add the package to pubspec.yaml:
dependencies:
activity_files: ^0.5.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 setallowFilePaths: truewhen you explicitly trust the string to reference local storage. useIsolate/exportInIsolateoffload work when isolates are available. Gate both flags with!kIsWebfor Flutter web builds.- Stream-backed loads keep a replayable buffer so
bytesPayloadremains usable even after parsing completes. - Payload limits: inline strings/bytes and buffered streams are capped at 64MB
(
ActivityFiles.defaultMaxPayloadBytes). Oversized inputs throwFormatException(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.