support new fields in adding
All checks were successful
All checks were successful
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
@@ -20,6 +22,35 @@ String _asString(dynamic value, [String fallback = '']) {
|
||||
return (str == null) ? fallback : str;
|
||||
}
|
||||
|
||||
List<String> _asStringList(dynamic value) {
|
||||
if (value is List) {
|
||||
return value.map((e) => e.toString()).toList();
|
||||
}
|
||||
final trimmed = value?.toString().trim() ?? '';
|
||||
if (trimmed.isEmpty) return const [];
|
||||
try {
|
||||
final decoded = jsonDecode(trimmed);
|
||||
if (decoded is List) {
|
||||
return decoded.map((e) => e.toString()).toList();
|
||||
}
|
||||
} catch (_) {}
|
||||
if (trimmed.contains('->')) {
|
||||
return trimmed
|
||||
.split('->')
|
||||
.map((e) => e.trim())
|
||||
.where((e) => e.isNotEmpty)
|
||||
.toList();
|
||||
}
|
||||
if (trimmed.contains(',')) {
|
||||
return trimmed
|
||||
.split(',')
|
||||
.map((e) => e.trim())
|
||||
.where((e) => e.isNotEmpty)
|
||||
.toList();
|
||||
}
|
||||
return [trimmed];
|
||||
}
|
||||
|
||||
bool _asBool(dynamic value, [bool fallback = false]) {
|
||||
if (value is bool) return value;
|
||||
if (value is num) return value != 0;
|
||||
@@ -487,25 +518,45 @@ class TripSummary {
|
||||
final int tripId;
|
||||
final String tripName;
|
||||
final double tripMileage;
|
||||
final int legCount;
|
||||
final List<TripLocoStat> locoStats;
|
||||
|
||||
int get locoHadCount => locoStats.length;
|
||||
int get winnersCount => locoStats.where((e) => e.won).length;
|
||||
|
||||
TripSummary({
|
||||
required this.tripId,
|
||||
required this.tripName,
|
||||
required this.tripMileage,
|
||||
});
|
||||
this.legCount = 0,
|
||||
List<TripLocoStat>? locoStats,
|
||||
}) : locoStats = locoStats ?? const [];
|
||||
|
||||
factory TripSummary.fromJson(Map<String, dynamic> json) => TripSummary(
|
||||
tripId: _asInt(json['trip_id']),
|
||||
tripName: _asString(json['trip_name']),
|
||||
tripMileage: _asDouble(json['trip_mileage']),
|
||||
legCount: _asInt(
|
||||
json['leg_count'],
|
||||
(json['trip_legs'] as List?)?.length ?? 0,
|
||||
),
|
||||
locoStats: TripLocoStat.listFromJson(
|
||||
json['stats'] ?? json['trip_locos'] ?? json['locos'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class Leg {
|
||||
final int id, tripId, timezone, driving;
|
||||
final String start, end, route, network, notes, headcode, user;
|
||||
final String start, end, network, notes, headcode, user;
|
||||
final String origin, destination;
|
||||
final List<String> route;
|
||||
final DateTime beginTime;
|
||||
final DateTime? endTime;
|
||||
final DateTime? originTime;
|
||||
final DateTime? destinationTime;
|
||||
final double mileage;
|
||||
final int? beginDelayMinutes, endDelayMinutes;
|
||||
final List<Loco> locos;
|
||||
|
||||
Leg({
|
||||
@@ -523,27 +574,55 @@ class Leg {
|
||||
required this.driving,
|
||||
required this.user,
|
||||
required this.locos,
|
||||
this.endTime,
|
||||
this.originTime,
|
||||
this.destinationTime,
|
||||
this.beginDelayMinutes,
|
||||
this.endDelayMinutes,
|
||||
this.origin = '',
|
||||
this.destination = '',
|
||||
});
|
||||
|
||||
factory Leg.fromJson(Map<String, dynamic> json) => Leg(
|
||||
id: _asInt(json['leg_id']),
|
||||
tripId: _asInt(json['leg_trip']),
|
||||
start: _asString(json['leg_start']),
|
||||
end: _asString(json['leg_end']),
|
||||
beginTime: _asDateTime(json['leg_begin_time']),
|
||||
timezone: _asInt(json['leg_timezone']),
|
||||
network: _asString(json['leg_network']),
|
||||
route: _asString(json['leg_route']),
|
||||
mileage: _asDouble(json['leg_mileage']),
|
||||
notes: _asString(json['leg_notes']),
|
||||
headcode: _asString(json['leg_headcode']),
|
||||
driving: _asInt(json['leg_driving']),
|
||||
user: _asString(json['leg_user']),
|
||||
locos: (json['locos'] is List ? (json['locos'] as List) : const [])
|
||||
.whereType<Map>()
|
||||
.map((e) => Loco.fromJson(Map<String, dynamic>.from(e)))
|
||||
.toList(),
|
||||
);
|
||||
factory Leg.fromJson(Map<String, dynamic> json) {
|
||||
final endTimeRaw = json['leg_end_time'];
|
||||
final parsedEndTime = (endTimeRaw == null || '$endTimeRaw'.isEmpty)
|
||||
? null
|
||||
: _asDateTime(endTimeRaw);
|
||||
return Leg(
|
||||
id: _asInt(json['leg_id']),
|
||||
tripId: _asInt(json['leg_trip']),
|
||||
start: _asString(json['leg_start']),
|
||||
end: _asString(json['leg_end']),
|
||||
beginTime: _asDateTime(json['leg_begin_time']),
|
||||
endTime: parsedEndTime,
|
||||
originTime: json['leg_origin_time'] == null
|
||||
? null
|
||||
: _asDateTime(json['leg_origin_time']),
|
||||
destinationTime: json['leg_destination_time'] == null
|
||||
? null
|
||||
: _asDateTime(json['leg_destination_time']),
|
||||
timezone: _asInt(json['leg_timezone']),
|
||||
network: _asString(json['leg_network']),
|
||||
route: _asStringList(json['leg_route']),
|
||||
mileage: _asDouble(json['leg_mileage']),
|
||||
notes: _asString(json['leg_notes']),
|
||||
headcode: _asString(json['leg_headcode']),
|
||||
driving: _asInt(json['leg_driving']),
|
||||
user: _asString(json['leg_user']),
|
||||
locos: (json['locos'] is List ? (json['locos'] as List) : const [])
|
||||
.whereType<Map>()
|
||||
.map((e) => Loco.fromJson(Map<String, dynamic>.from(e)))
|
||||
.toList(),
|
||||
beginDelayMinutes: json['leg_begin_delay'] == null
|
||||
? null
|
||||
: _asInt(json['leg_begin_delay']),
|
||||
endDelayMinutes: json['leg_end_delay'] == null
|
||||
? null
|
||||
: _asInt(json['leg_end_delay']),
|
||||
origin: _asString(json['leg_origin']),
|
||||
destination: _asString(json['leg_destination']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RouteError {
|
||||
@@ -625,17 +704,23 @@ class TripLeg {
|
||||
});
|
||||
|
||||
factory TripLeg.fromJson(Map<String, dynamic> json) => TripLeg(
|
||||
id: json['leg_id'],
|
||||
start: json['leg_start'] ?? '',
|
||||
end: json['leg_end'] ?? '',
|
||||
id: _asInt(json['leg_id']),
|
||||
start: _asString(json['leg_start']),
|
||||
end: _asString(json['leg_end']),
|
||||
beginTime:
|
||||
json['leg_begin_time'] != null && json['leg_begin_time'] is String
|
||||
? DateTime.tryParse(json['leg_begin_time'])
|
||||
: (json['leg_begin_time'] is DateTime ? json['leg_begin_time'] : null),
|
||||
network: json['leg_network'],
|
||||
route: json['leg_route'],
|
||||
network: _asString(json['leg_network'], ''),
|
||||
route: () {
|
||||
final route = json['leg_route'];
|
||||
if (route is List) {
|
||||
return route.whereType<String>().join(' → ');
|
||||
}
|
||||
return _asString(route, '');
|
||||
}(),
|
||||
mileage: (json['leg_mileage'] as num?)?.toDouble(),
|
||||
notes: json['leg_notes'],
|
||||
notes: _asString(json['leg_notes'], ''),
|
||||
locos:
|
||||
(json['locos'] as List?)
|
||||
?.map((e) => Loco.fromJson(e as Map<String, dynamic>))
|
||||
@@ -649,21 +734,32 @@ class TripDetail {
|
||||
final String name;
|
||||
final double mileage;
|
||||
final int legCount;
|
||||
final List<TripLocoStat> locoStats;
|
||||
final List<TripLeg> legs;
|
||||
|
||||
int get locoHadCount => locoStats.length;
|
||||
int get winnersCount => locoStats.where((e) => e.won).length;
|
||||
|
||||
TripDetail({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.mileage,
|
||||
required this.legCount,
|
||||
required this.legs,
|
||||
});
|
||||
List<TripLocoStat>? locoStats,
|
||||
}) : locoStats = locoStats ?? const [];
|
||||
|
||||
factory TripDetail.fromJson(Map<String, dynamic> json) => TripDetail(
|
||||
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),
|
||||
legCount: _asInt(
|
||||
json['leg_count'],
|
||||
(json['trip_legs'] as List?)?.length ?? 0,
|
||||
),
|
||||
locoStats: TripLocoStat.listFromJson(
|
||||
json['stats'] ?? json['trip_locos'] ?? json['locos'],
|
||||
),
|
||||
legs:
|
||||
(json['trip_legs'] as List?)
|
||||
?.map((e) => TripLeg.fromJson(e as Map<String, dynamic>))
|
||||
@@ -712,6 +808,26 @@ class TripLocoStat {
|
||||
);
|
||||
}
|
||||
|
||||
static List<TripLocoStat> listFromJson(dynamic json) {
|
||||
List<dynamic>? 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 const [];
|
||||
return list
|
||||
.whereType<Map>()
|
||||
.map((e) => TripLocoStat.fromJson(Map<String, dynamic>.from(e)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
static bool _parseWonFlag(dynamic value) {
|
||||
if (value == null) return false;
|
||||
if (value is bool) return value;
|
||||
|
||||
Reference in New Issue
Block a user