diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index c5476cd..1f600b1 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -52,14 +52,6 @@ jobs: distribution: temurin java-version: ${{ env.JAVA_VERSION }} - - name: Cache Android SDK - uses: actions/cache@v3 - with: - path: ${{ env.ANDROID_SDK_ROOT }} - key: android-sdk-${{ runner.os }}-java${{ env.JAVA_VERSION }}-platform33-buildtools33.0.2 - restore-keys: | - android-sdk-${{ runner.os }}-java${{ env.JAVA_VERSION }}- - - name: Install Android SDK run: | mkdir -p "$ANDROID_SDK_ROOT"/cmdline-tools diff --git a/lib/objects/objects.dart b/lib/objects/objects.dart index b0ee833..721c513 100644 --- a/lib/objects/objects.dart +++ b/lib/objects/objects.dart @@ -386,7 +386,7 @@ class TripDetail { }); factory TripDetail.fromJson(Map json) => TripDetail( - id: json['trip_id'] ?? 0, + id: json['trip_id'] ?? json['id'] ?? 0, name: json['trip_name'] ?? '', mileage: (json['trip_mileage'] as num?)?.toDouble() ?? 0, legCount: json['leg_count'] ?? ((json['trip_legs'] as List?)?.length ?? 0), @@ -411,14 +411,40 @@ class TripLocoStat { this.name, }); - factory TripLocoStat.fromJson(Map json) => TripLocoStat( - locoClass: json['loco_class'] ?? json['class'] ?? '', - number: json['loco_number'] ?? json['number'] ?? '', - name: json['loco_name'] ?? json['name'], - won: json['won'] == 1 || - json['won'] == true || - (json['won'] is String && json['won'].toString() == '1'), - ); + factory TripLocoStat.fromJson(Map json) { + final locoJson = json['loco'] is Map + ? Map.from(json['loco'] as Map) + : null; + final locoClass = json['loco_class'] ?? + json['class'] ?? + locoJson?['class'] ?? + locoJson?['loco_class'] ?? + ''; + final locoNumber = json['loco_number'] ?? + json['number'] ?? + locoJson?['number'] ?? + locoJson?['loco_number'] ?? + ''; + final locoName = + json['loco_name'] ?? json['name'] ?? locoJson?['name'] ?? locoJson?['loco_name']; + final wonValue = json['won'] ?? json['result'] ?? json['winner']; + final won = _parseWonFlag(wonValue); + + return TripLocoStat( + locoClass: locoClass, + number: locoNumber, + name: locoName, + won: won, + ); + } + + static bool _parseWonFlag(dynamic value) { + if (value == null) return false; + if (value is bool) return value; + if (value is num) return value != 0; + final normalized = value.toString().toLowerCase(); + return ['1', 'true', 'win', 'won', 'yes', 'w'].contains(normalized); + } } class EventField { diff --git a/lib/services/dataService.dart b/lib/services/dataService.dart index 0dfefe5..4b0b392 100644 --- a/lib/services/dataService.dart +++ b/lib/services/dataService.dart @@ -277,26 +277,34 @@ class DataService extends ChangeNotifier { Future> fetchTripLocoStats(int tripId) async { try { - final json = await api.get('/trips/stats?trip_id=$tripId'); - if (json is List) { - return json - .whereType>() - .map((e) => TripLocoStat.fromJson(e)) - .toList(); - } - if (json is Map && json['locos'] is List) { - return (json['locos'] as List) - .whereType>() - .map((e) => TripLocoStat.fromJson(e)) - .toList(); - } - return []; + final json = await api.get('/trips/stats/$tripId'); + return _parseTripLocoStats(json); } catch (e) { debugPrint('Failed to fetch trip loco stats: $e'); return []; } } + List _parseTripLocoStats(dynamic json) { + List? list; + if (json is List) { + list = json.expand((e) => e is List ? e : [e]).toList(); + } else if (json is Map) { + for (final key in ['locos', 'stats', 'data', 'trip_locos']) { + final candidate = json[key]; + if (candidate is List) { + list = candidate.expand((e) => e is List ? e : [e]).toList(); + break; + } + } + } + if (list == null) return []; + return list + .whereType>() + .map((e) => TripLocoStat.fromJson(e)) + .toList(); + } + Future fetchEventFields({bool force = false}) async { if (_eventFields.isNotEmpty && !force) return; _isEventFieldsLoading = true; diff --git a/pubspec.yaml b/pubspec.yaml index bf56c88..a4a8339 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: mileograph_flutter -description: "A new Flutter project." +description: "Native app for the Mileograph website" # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: "none" # Remove this line if you wish to publish to pub.dev