// To parse this JSON data, do // // final trainData = trainDataFromJson(jsonString); import 'dart:convert'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'train_data.freezed.dart'; part 'train_data.g.dart'; TrainData trainDataFromJson(String str) => TrainData.fromJson(json.decode(str)); String trainDataToJson(TrainData data) => json.encode(data.toJson()); /// Results of scrapping InfoFer website for train info @freezed class TrainData with _$TrainData { const TrainData._(); const factory TrainData({ required String rank, required String number, required String date, required String operator, required List groups, }) = _TrainData; factory TrainData.fromJson(Map json) => _$TrainDataFromJson(json); TrainDataGroup get idealGroup { var result = groups.first; for (final group in groups) { if (result.stations.map((s) => s.linkName).toSet().difference(group.stations.map((s) => s.linkName).toSet()).isEmpty) { result = group; } } return result; } List get stations => idealGroup.stations; TrainDataRoute get route => idealGroup.route; TrainDataStatus? get status => idealGroup.status; } @freezed class TrainDataGroup with _$TrainDataGroup { const factory TrainDataGroup({ required TrainDataRoute route, required List stations, TrainDataStatus? status, }) = _TrainDataGroup; factory TrainDataGroup.fromJson(Map json) => _$TrainDataGroupFromJson(json); } /// Route of the train @freezed class TrainDataRoute with _$TrainDataRoute { const factory TrainDataRoute({ required String from, required String to, }) = _TrainDataRoute; factory TrainDataRoute.fromJson(Map json) => _$TrainDataRouteFromJson(json); } @freezed class TrainDataStation with _$TrainDataStation { const factory TrainDataStation({ required String name, required String linkName, required int km, int? stoppingTime, String? platform, StationArrDepTime? arrival, StationArrDepTime? departure, @TrainDataNoteConverter() required List notes, }) = _TrainDataStation; factory TrainDataStation.fromJson(Map json) => _$TrainDataStationFromJson(json); } @freezed class StationArrDepTime with _$StationArrDepTime { const factory StationArrDepTime({ required DateTime scheduleTime, StationArrDepTimeStatus? status, }) = _StationArrDepTime; factory StationArrDepTime.fromJson(Map json) => _$StationArrDepTimeFromJson(json); } @freezed class StationArrDepTimeStatus with _$StationArrDepTimeStatus { const factory StationArrDepTimeStatus({ required int delay, required bool real, required bool cancelled, }) = _StationArrDepTimeStatus; factory StationArrDepTimeStatus.fromJson(Map json) => _$StationArrDepTimeStatusFromJson(json); } @freezed class TrainDataStatus with _$TrainDataStatus { const TrainDataStatus._(); const factory TrainDataStatus({ required int delay, required String station, required TrainDataStatusState state, }) = _TrainDataStatus; factory TrainDataStatus.fromJson(Map json) => _$TrainDataStatusFromJson(json); @override String toString() { String result = ''; if (delay == 0) { result += 'La timp'; } else { result += '${delay.abs()} min'; } result += ' la '; result += switch (state) { TrainDataStatusState.passing => 'trecerea fără oprire prin', TrainDataStatusState.arrival => 'sosirea în', TrainDataStatusState.departure => 'plecarea din', }; result += station; return result; } } enum TrainDataStatusState { passing, arrival, departure } abstract class TrainDataNote { final String kind; const TrainDataNote({required this.kind}); Map toJson() => { "kind": kind, }; } class TrainDataNoteConverter implements JsonConverter> { const TrainDataNoteConverter(); @override TrainDataNote fromJson(Map json) { return switch(json['kind']) { 'trainNumberChange' => TrainDataNoteTrainNumberChange.fromJson(json), 'departsAs' => TrainDataNoteDepartsAs.fromJson(json), 'detachingWagons' => TrainDataNoteDetachingWagons.fromJson(json), 'receivingWagons' => TrainDataNoteReceivingWagons.fromJson(json), _ => TrainDataNoteUnknown.fromJson(json), }; } @override Map toJson(TrainDataNote object) { return object.toJson(); } } @freezed class TrainDataNoteTrainNumberChange with _$TrainDataNoteTrainNumberChange implements TrainDataNote { @Implements() const factory TrainDataNoteTrainNumberChange({ // base @Default("trainNumberChange") String kind, // impl required String rank, required String number, }) = _TrainDataNoteTrainNumberChange; factory TrainDataNoteTrainNumberChange.fromJson(Map json) => _$TrainDataNoteTrainNumberChangeFromJson(json); } @freezed class TrainDataNoteDepartsAs with _$TrainDataNoteDepartsAs implements TrainDataNote { @Implements() const factory TrainDataNoteDepartsAs({ // base @Default("departsAs") String kind, // impl required String rank, required String number, required DateTime departureDate, }) = _TrainDataNoteDepartsAs; factory TrainDataNoteDepartsAs.fromJson(Map json) => _$TrainDataNoteDepartsAsFromJson(json); } @freezed class TrainDataNoteDetachingWagons with _$TrainDataNoteDetachingWagons implements TrainDataNote { @Implements() const factory TrainDataNoteDetachingWagons({ // base @Default("detachingWagons") String kind, // impl required String station, }) = _TrainDataNoteDetachingWagons; factory TrainDataNoteDetachingWagons.fromJson(Map json) => _$TrainDataNoteDetachingWagonsFromJson(json); } @freezed class TrainDataNoteReceivingWagons with _$TrainDataNoteReceivingWagons implements TrainDataNote { @Implements() const factory TrainDataNoteReceivingWagons({ // base @Default("receivingWagons") String kind, // impl required String station, }) = _TrainDataNoteReceivingWagons; factory TrainDataNoteReceivingWagons.fromJson(Map json) => _$TrainDataNoteReceivingWagonsFromJson(json); } @freezed class TrainDataNoteUnknown with _$TrainDataNoteUnknown implements TrainDataNote { @Implements() const factory TrainDataNoteUnknown({ // base required String kind, // impl required Map extra, }) = _TrainDataNoteUnknown; factory TrainDataNoteUnknown.fromJson(Map json) => TrainDataNoteUnknown( kind: json['kind'], extra: Map.from(json)..remove('kind'), ); }