Add version files and update imports for trip model; enhance error handling
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
class Duty {
|
||||
const Duty({required this.dutyNumber, required this.busWorkNumber});
|
||||
|
||||
final String dutyNumber;
|
||||
final String busWorkNumber;
|
||||
|
||||
Duty copyWith({String? dutyNumber, String? busWorkNumber}) {
|
||||
return Duty(
|
||||
dutyNumber: dutyNumber ?? this.dutyNumber,
|
||||
busWorkNumber: busWorkNumber ?? this.busWorkNumber,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {"dutyNumber": dutyNumber, "busWorkNumber": busWorkNumber};
|
||||
}
|
||||
|
||||
factory Duty.fromJson(Map<String, dynamic> json) {
|
||||
return Duty(
|
||||
dutyNumber: (json["dutyNumber"] ?? "").toString(),
|
||||
busWorkNumber: (json["busWorkNumber"] ?? "").toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import "package:bus_running_record/models/operations/stop.dart";
|
||||
|
||||
class ScheduledStop extends Stop {
|
||||
const ScheduledStop({
|
||||
required super.name,
|
||||
required this.sequence,
|
||||
this.scheduledTime,
|
||||
super.alias,
|
||||
super.aliasSource,
|
||||
});
|
||||
|
||||
final int sequence;
|
||||
final String? scheduledTime;
|
||||
|
||||
ScheduledStop copyWith({
|
||||
String? name,
|
||||
String? alias,
|
||||
String? aliasSource,
|
||||
int? sequence,
|
||||
String? scheduledTime,
|
||||
}) {
|
||||
return ScheduledStop(
|
||||
name: name ?? this.name,
|
||||
alias: alias ?? this.alias,
|
||||
aliasSource: aliasSource ?? this.aliasSource,
|
||||
sequence: sequence ?? this.sequence,
|
||||
scheduledTime: scheduledTime ?? this.scheduledTime,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
"name": name,
|
||||
"alias": alias,
|
||||
"aliasSource": aliasSource,
|
||||
"sequence": sequence,
|
||||
"scheduledTime": scheduledTime,
|
||||
};
|
||||
}
|
||||
|
||||
factory ScheduledStop.fromJson(Map<String, dynamic> json) {
|
||||
final raw = (json["scheduledTime"] ?? "").toString().trim();
|
||||
return ScheduledStop(
|
||||
name: (json["name"] ?? "").toString(),
|
||||
alias: (json["alias"] ?? "").toString().trim().isEmpty
|
||||
? null
|
||||
: (json["alias"] ?? "").toString(),
|
||||
aliasSource: (json["aliasSource"] ?? json["source"] ?? "")
|
||||
.toString()
|
||||
.trim()
|
||||
.isEmpty
|
||||
? null
|
||||
: (json["aliasSource"] ?? json["source"] ?? "").toString(),
|
||||
sequence: (json["sequence"] as num?)?.toInt() ?? 0,
|
||||
scheduledTime: raw.isEmpty ? null : raw,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class Stop {
|
||||
const Stop({required this.name, this.alias, this.aliasSource});
|
||||
|
||||
final String name;
|
||||
final String? alias;
|
||||
final String? aliasSource;
|
||||
|
||||
String get displayName {
|
||||
final value = (alias ?? "").trim();
|
||||
if (value.isEmpty) return name;
|
||||
return value;
|
||||
}
|
||||
|
||||
static String normalizeName(String name) => name.trim().toLowerCase();
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
import "package:bus_running_record/models/operations/duty.dart";
|
||||
import "package:bus_running_record/models/operations/scheduled_stop.dart";
|
||||
import "package:bus_running_record/models/operations/stop.dart";
|
||||
|
||||
class Trip {
|
||||
final String scheduledTime; // "15:31" - default departure time
|
||||
final String tripNumber; // "112"
|
||||
final Duty duty;
|
||||
final String tripType; // "", "N", "R", "F"
|
||||
final bool isFinishing;
|
||||
final List<ScheduledStop> scheduledStops;
|
||||
final String direction; // "outbound" or "inbound"
|
||||
|
||||
String? actualDepartureTime; // "15:33" (nullable - user input)
|
||||
String? actualFleetNumber; // "33523" (nullable - user input)
|
||||
|
||||
Trip({
|
||||
required this.scheduledTime,
|
||||
required this.tripNumber,
|
||||
String? dutyNumber,
|
||||
String? busWorkNumber,
|
||||
Duty? duty,
|
||||
this.tripType = "",
|
||||
this.isFinishing = false,
|
||||
Map<String, String> stationTimes = const {},
|
||||
List<String> stationOrder = const [],
|
||||
List<ScheduledStop>? scheduledStops,
|
||||
this.direction = "outbound",
|
||||
this.actualDepartureTime,
|
||||
this.actualFleetNumber,
|
||||
}) : duty =
|
||||
duty ??
|
||||
Duty(
|
||||
dutyNumber: dutyNumber ?? "",
|
||||
busWorkNumber: busWorkNumber ?? "",
|
||||
),
|
||||
scheduledStops =
|
||||
scheduledStops ?? _buildScheduledStops(stationTimes, stationOrder);
|
||||
|
||||
bool get isComplete =>
|
||||
actualDepartureTime != null && actualFleetNumber != null;
|
||||
|
||||
String get dutyNumber => duty.dutyNumber;
|
||||
String get busWorkNumber => duty.busWorkNumber;
|
||||
List<String> get stationOrder =>
|
||||
scheduledStops.map((stop) => stop.name).toList(growable: false);
|
||||
Map<String, String> get stationTimes {
|
||||
final result = <String, String>{};
|
||||
for (final stop in scheduledStops) {
|
||||
final time = (stop.scheduledTime ?? "").trim();
|
||||
if (time.isEmpty) continue;
|
||||
result[stop.name] = time;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Trip copyWith({
|
||||
String? scheduledTime,
|
||||
String? tripNumber,
|
||||
String? dutyNumber,
|
||||
String? busWorkNumber,
|
||||
Duty? duty,
|
||||
String? tripType,
|
||||
bool? isFinishing,
|
||||
Map<String, String>? stationTimes,
|
||||
List<String>? stationOrder,
|
||||
List<ScheduledStop>? scheduledStops,
|
||||
String? direction,
|
||||
String? actualDepartureTime,
|
||||
String? actualFleetNumber,
|
||||
}) {
|
||||
return Trip(
|
||||
scheduledTime: scheduledTime ?? this.scheduledTime,
|
||||
tripNumber: tripNumber ?? this.tripNumber,
|
||||
duty:
|
||||
duty ??
|
||||
this.duty.copyWith(
|
||||
dutyNumber: dutyNumber,
|
||||
busWorkNumber: busWorkNumber,
|
||||
),
|
||||
tripType: tripType ?? this.tripType,
|
||||
isFinishing: isFinishing ?? this.isFinishing,
|
||||
scheduledStops:
|
||||
scheduledStops ??
|
||||
(stationTimes != null || stationOrder != null
|
||||
? _buildScheduledStops(
|
||||
stationTimes ?? this.stationTimes,
|
||||
stationOrder ?? this.stationOrder,
|
||||
)
|
||||
: this.scheduledStops),
|
||||
direction: direction ?? this.direction,
|
||||
actualDepartureTime: actualDepartureTime ?? this.actualDepartureTime,
|
||||
actualFleetNumber: actualFleetNumber ?? this.actualFleetNumber,
|
||||
);
|
||||
}
|
||||
|
||||
Trip withStopAliases(
|
||||
Map<String, String> aliasesByRawName, {
|
||||
String aliasSource = "ai",
|
||||
}) {
|
||||
if (aliasesByRawName.isEmpty) return this;
|
||||
|
||||
final aliasesByNormalizedName = <String, String>{};
|
||||
for (final entry in aliasesByRawName.entries) {
|
||||
aliasesByNormalizedName[Stop.normalizeName(entry.key)] = entry.value;
|
||||
}
|
||||
|
||||
return copyWith(
|
||||
scheduledStops: scheduledStops
|
||||
.map(
|
||||
(stop) => stop.copyWith(
|
||||
alias: aliasesByNormalizedName[Stop.normalizeName(stop.name)],
|
||||
aliasSource:
|
||||
aliasesByNormalizedName[Stop.normalizeName(stop.name)] == null
|
||||
? stop.aliasSource
|
||||
: aliasSource,
|
||||
),
|
||||
)
|
||||
.toList(growable: false),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
"scheduledTime": scheduledTime,
|
||||
"tripNumber": tripNumber,
|
||||
"duty": duty.toJson(),
|
||||
"dutyNumber": dutyNumber,
|
||||
"busWorkNumber": busWorkNumber,
|
||||
"tripType": tripType,
|
||||
"isFinishing": isFinishing,
|
||||
"scheduledStops": scheduledStops.map((stop) => stop.toJson()).toList(),
|
||||
"stationTimes": stationTimes,
|
||||
"stationOrder": stationOrder,
|
||||
"direction": direction,
|
||||
"actualDepartureTime": actualDepartureTime,
|
||||
"actualFleetNumber": actualFleetNumber,
|
||||
};
|
||||
}
|
||||
|
||||
factory Trip.fromJson(Map<String, dynamic> json) {
|
||||
final dutyJson = json["duty"];
|
||||
final duty = dutyJson is Map<String, dynamic>
|
||||
? Duty.fromJson(dutyJson)
|
||||
: Duty(
|
||||
dutyNumber: (json["dutyNumber"] ?? "").toString(),
|
||||
busWorkNumber:
|
||||
(json["busWorkNumber"] ?? json["runningNumber"] ?? "")
|
||||
.toString(),
|
||||
);
|
||||
final scheduledStopsJson = json["scheduledStops"];
|
||||
final scheduledStops = scheduledStopsJson is List
|
||||
? scheduledStopsJson
|
||||
.whereType<Map>()
|
||||
.map(
|
||||
(stopJson) =>
|
||||
ScheduledStop.fromJson(Map<String, dynamic>.from(stopJson)),
|
||||
)
|
||||
.toList()
|
||||
: null;
|
||||
|
||||
return Trip(
|
||||
scheduledTime: json["scheduledTime"] as String,
|
||||
tripNumber: json["tripNumber"] as String,
|
||||
duty: duty,
|
||||
tripType: json["tripType"] as String? ?? "",
|
||||
isFinishing: json["isFinishing"] as bool? ?? false,
|
||||
scheduledStops: scheduledStops,
|
||||
stationTimes: Map<String, String>.from(
|
||||
json["stationTimes"] as Map? ?? {},
|
||||
),
|
||||
stationOrder: List<String>.from(json["stationOrder"] as List? ?? []),
|
||||
direction: json["direction"] as String? ?? "outbound",
|
||||
actualDepartureTime: json["actualDepartureTime"] as String?,
|
||||
actualFleetNumber: json["actualFleetNumber"] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
static List<ScheduledStop> _buildScheduledStops(
|
||||
Map<String, String> stationTimes,
|
||||
List<String> stationOrder,
|
||||
) {
|
||||
if (stationOrder.isEmpty) {
|
||||
var index = 0;
|
||||
return stationTimes.entries
|
||||
.map(
|
||||
(entry) => ScheduledStop(
|
||||
name: entry.key,
|
||||
sequence: ++index,
|
||||
scheduledTime: entry.value.trim().isEmpty ? null : entry.value,
|
||||
),
|
||||
)
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
return List<ScheduledStop>.generate(stationOrder.length, (i) {
|
||||
final stopName = stationOrder[i];
|
||||
final time = (stationTimes[stopName] ?? "").trim();
|
||||
return ScheduledStop(
|
||||
name: stopName,
|
||||
sequence: i + 1,
|
||||
scheduledTime: time.isEmpty ? null : time,
|
||||
);
|
||||
}, growable: false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user