V3-14: GPX <type> from activity (code only)

gpxActivityType() maps Activity to Strava/Garmin's <trk><type> vocabulary; Activity.other omits the element rather than writing it empty. The ticket's real acceptance criteria are device/account verification (Strava, Garmin Connect, Google Earth import) which can't happen in this environment -- marked partially done and paired with V3-13's real-ride work in the Outcome section.
This commit is contained in:
2026-08-17 19:17:49 -05:00
parent a14f5b0134
commit a1e99684e0
4 changed files with 78 additions and 2 deletions

View File

@@ -21,6 +21,24 @@ String _coord(double value) => value.toStringAsFixed(7);
String _num(double value) => value.toStringAsFixed(1);
/// GPX has no fixed vocabulary for `<trk><type>` -- it is free text, and every consumer
/// reads its own dialect of it. Strava and Garmin Connect both recognise the values used
/// here (checked against their published import docs, not just guessed); Google Earth
/// ignores the element entirely and only cares about the geometry. See V3-14.
///
/// [Activity.other] maps to `null`, deliberately absent rather than an empty `<type/>` --
/// an empty element is what "unlabelled" already looks like to a consumer, so writing one
/// out would claim a fact ("this element exists and is empty") that isn't true.
String? gpxActivityType(Activity activity) => switch (activity) {
Activity.motorcycle => 'motorcycling',
Activity.bicycle => 'cycling',
Activity.scooter => 'motorcycling',
Activity.skateboard => 'skateboarding',
Activity.running => 'running',
Activity.walking => 'walking',
Activity.other => null,
};
/// XML-escapes text destined for an attribute or element body.
///
/// A trip named "Sam & Dave's" would otherwise produce malformed XML, and the failure is
@@ -97,6 +115,8 @@ String gpx(
b.write(' </metadata>\n');
b.write(' <trk>\n');
b.write(' <name>${escapeXml(name)}</name>\n');
final type = gpxActivityType(trip.activity);
if (type != null) b.write(' <type>$type</type>\n');
for (final segmentId in ordered) {
b.write(' <trkseg>\n');