Browse Source

Move to API v3

master
Kenneth Bruen 1 year ago
parent
commit
17d8fac893
Signed by: kbruen
GPG Key ID: C1980A470C3EE5B1
  1. 8
      lib/api/station_data.dart
  2. 2
      lib/api/train_data.dart
  3. 6
      lib/models.dart
  4. 2
      lib/models/station_arrdep.freezed.dart
  5. 4
      lib/models/station_data.freezed.dart
  6. 2
      lib/models/station_status.freezed.dart
  7. 3
      lib/models/station_train.freezed.dart
  8. 3
      lib/models/stations_result.freezed.dart
  9. 361
      lib/models/train_data.dart
  10. 2365
      lib/models/train_data.freezed.dart
  11. 217
      lib/models/train_data.g.dart
  12. 2
      lib/models/trains_result.freezed.dart
  13. 3
      lib/pages/station_arrdep_page/view_station/view_station.dart
  14. 111
      lib/pages/train_info_page/view_train/train_info.dart
  15. 4
      lib/pages/train_info_page/view_train/train_info_cupertino.dart
  16. 315
      lib/pages/train_info_page/view_train/train_info_cupertino_DisplayTrainStation.dart
  17. 2
      lib/pages/train_info_page/view_train/train_info_fluent.dart
  18. 352
      lib/pages/train_info_page/view_train/train_info_fluent_DisplayTrainStation.dart
  19. 125
      lib/pages/train_info_page/view_train/train_info_material.dart
  20. 390
      lib/pages/train_info_page/view_train/train_info_material_DisplayTrainStation.dart
  21. 13
      lib/providers.dart
  22. 120
      lib/providers.g.dart

8
lib/api/station_data.dart

@ -4,7 +4,11 @@ import 'package:http/http.dart' as http;
import 'package:info_tren/api/common.dart';
import 'package:info_tren/models.dart';
Future<StationData> getStationData(String stationName) async {
final response = await http.get(Uri.https(authority, 'v3/stations/$stationName'));
Future<StationData> getStationData(String stationName, [DateTime? date]) async {
final uri = Uri.https(authority, 'v3/stations/$stationName');
if (date != null) {
uri.queryParameters['date'] = date.toIso8601String();
}
final response = await http.get(uri);
return StationData.fromJson(jsonDecode(response.body));
}

2
lib/api/train_data.dart

@ -4,7 +4,7 @@ import 'package:info_tren/models.dart';
Future<TrainData> getTrain(String trainNumber, {DateTime? date}) async {
date ??= DateTime.now();
final response = await http.get(Uri.https(authority, 'v2/train/$trainNumber', {
final response = await http.get(Uri.https(authority, 'v3/trains/$trainNumber', {
'date': date.toUtc().toIso8601String(),
}),);
return trainDataFromJson(response.body);

6
lib/models.dart

@ -4,11 +4,11 @@ export 'package:info_tren/models/station_data.dart';
export 'package:info_tren/models/station_status.dart';
export 'package:info_tren/models/station_train.dart';
export 'package:info_tren/models/stations_result.dart';
export 'package:info_tren/models/train_data.dart' hide State;
export 'package:info_tren/models/train_data.dart';
export 'package:info_tren/models/trains_result.dart';
export 'package:info_tren/models/ui_design.dart';
export 'package:info_tren/models/ui_timezone.dart';
import 'package:info_tren/models/train_data.dart' show State;
import 'package:info_tren/models/train_data.dart' show TrainDataStatusState;
typedef TrainDataState = State;
typedef TrainDataState = TrainDataStatusState;

2
lib/models/station_arrdep.freezed.dart

@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'station_arrdep.dart';

4
lib/models/station_data.freezed.dart

@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'station_data.dart';
@ -158,6 +158,7 @@ class _$_StationData implements _StationData {
List<StationArrDep>? get arrivals {
final value = _arrivals;
if (value == null) return null;
if (_arrivals is EqualUnmodifiableListView) return _arrivals;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@ -167,6 +168,7 @@ class _$_StationData implements _StationData {
List<StationArrDep>? get departures {
final value = _departures;
if (value == null) return null;
if (_departures is EqualUnmodifiableListView) return _departures;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}

2
lib/models/station_status.freezed.dart

@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'station_status.dart';

3
lib/models/station_train.freezed.dart

@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'station_train.dart';
@ -189,6 +189,7 @@ class _$_StationTrain implements _StationTrain {
List<String>? get route {
final value = _route;
if (value == null) return null;
if (_route is EqualUnmodifiableListView) return _route;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}

3
lib/models/stations_result.freezed.dart

@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'stations_result.dart';
@ -121,6 +121,7 @@ class _$_StationsResult implements _StationsResult {
List<String>? get stoppedAtBy {
final value = _stoppedAtBy;
if (value == null) return null;
if (_stoppedAtBy is EqualUnmodifiableListView) return _stoppedAtBy;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}

361
lib/models/train_data.dart

@ -4,181 +4,106 @@
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
class TrainData {
TrainData({
required this.date,
required this.number,
required this.operator,
required this.rank,
required this.route,
required this.stations,
this.status,
});
final String date;
final String number;
final String operator;
final String rank;
final Route route;
final List<Station> stations;
final TrainDataStatus? status;
factory TrainData.fromJson(Map<String, dynamic> json) => TrainData(
date: json["date"],
number: json["number"],
operator: json["operator"],
rank: json["rank"],
route: Route.fromJson(json["route"]),
stations: List<Station>.from(
json["stations"].map((x) => Station.fromJson(x))),
status: json["status"] == null
? null
: TrainDataStatus.fromJson(json["status"]),
);
@freezed
class TrainData with _$TrainData {
const TrainData._();
const factory TrainData({
required String rank,
required String number,
required String date,
required String operator,
required List<TrainDataGroup> groups,
}) = _TrainData;
factory TrainData.fromJson(Map<String, dynamic> json) => _$TrainDataFromJson(json);
List<TrainDataStation> get stations => groups.first.stations;
TrainDataRoute get route => groups.first.route;
TrainDataStatus? get status => groups.first.status;
}
Map<String, dynamic> toJson() => {
"date": date,
"number": number,
"operator": operator,
"rank": rank,
"route": route.toJson(),
"stations": List<dynamic>.from(stations.map((x) => x.toJson())),
"status": status?.toJson(),
};
@freezed
class TrainDataGroup with _$TrainDataGroup {
const factory TrainDataGroup({
required TrainDataRoute route,
required List<TrainDataStation> stations,
TrainDataStatus? status,
}) = _TrainDataGroup;
factory TrainDataGroup.fromJson(Map<String, dynamic> json) => _$TrainDataGroupFromJson(json);
}
/// Route of the train
class Route {
Route({
required this.from,
required this.to,
});
final String from;
final String to;
factory Route.fromJson(Map<String, dynamic> json) => Route(
from: json["from"],
to: json["to"],
);
Map<String, dynamic> toJson() => {
"from": from,
"to": to,
};
@freezed
class TrainDataRoute with _$TrainDataRoute {
const factory TrainDataRoute({
required String from,
required String to,
}) = _TrainDataRoute;
factory TrainDataRoute.fromJson(Map<String, dynamic> json) => _$TrainDataRouteFromJson(json);
}
class Station {
Station({
this.arrival,
this.departure,
required this.km,
required this.name,
this.platform,
this.stoppingTime,
});
final StationArrDepTime? arrival;
final StationArrDepTime? departure;
final int km;
final String name;
final String? platform;
final int? stoppingTime;
factory Station.fromJson(Map<String, dynamic> json) => Station(
arrival: json["arrival"] == null
? null
: StationArrDepTime.fromJson(json["arrival"]),
departure: json["departure"] == null
? null
: StationArrDepTime.fromJson(json["departure"]),
km: json["km"],
name: json["name"],
platform: json["platform"],
stoppingTime:
json["stoppingTime"],
);
Map<String, dynamic> toJson() => {
"arrival": arrival?.toJson(),
"departure": departure?.toJson(),
"km": km,
"name": name,
"platform": platform,
"stoppingTime": stoppingTime,
};
@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<TrainDataNote> notes,
}) = _TrainDataStation;
factory TrainDataStation.fromJson(Map<String, dynamic> json) => _$TrainDataStationFromJson(json);
}
class StationArrDepTime {
StationArrDepTime({
required this.scheduleTime,
this.status,
});
final DateTime scheduleTime;
final StationArrDepTimeStatus? status;
@freezed
class StationArrDepTime with _$StationArrDepTime {
const factory StationArrDepTime({
required DateTime scheduleTime,
StationArrDepTimeStatus? status,
}) = _StationArrDepTime;
factory StationArrDepTime.fromJson(Map<String, dynamic> json) =>
StationArrDepTime(
scheduleTime: DateTime.parse(json["scheduleTime"] as String),
status: json["status"] == null ? null : StationArrDepTimeStatus.fromJson(json["status"]),
);
Map<String, dynamic> toJson() => {
"scheduleTime": scheduleTime.toIso8601String(),
"status": status?.toJson(),
};
factory StationArrDepTime.fromJson(Map<String, dynamic> json) => _$StationArrDepTimeFromJson(json);
}
class StationArrDepTimeStatus {
StationArrDepTimeStatus({
required this.delay,
required this.real,
});
@freezed
class StationArrDepTimeStatus with _$StationArrDepTimeStatus {
const factory StationArrDepTimeStatus({
required int delay,
required bool real,
required bool cancelled,
}) = _StationArrDepTimeStatus;
final int delay;
final bool real;
factory StationArrDepTimeStatus.fromJson(Map<String, dynamic> json) =>
StationArrDepTimeStatus(
delay: json["delay"],
real: json["real"],
);
Map<String, dynamic> toJson() => {
"delay": delay,
"real": real,
};
factory StationArrDepTimeStatus.fromJson(Map<String, dynamic> json) => _$StationArrDepTimeStatusFromJson(json);
}
class TrainDataStatus {
TrainDataStatus({
required this.delay,
required this.state,
required this.station,
});
@freezed
class TrainDataStatus with _$TrainDataStatus {
const TrainDataStatus._();
final int delay;
final State state;
final String station;
const factory TrainDataStatus({
required int delay,
required String station,
required TrainDataStatusState state,
}) = _TrainDataStatus;
factory TrainDataStatus.fromJson(Map<String, dynamic> json) =>
TrainDataStatus(
delay: json["delay"],
state: stateValues.map[json["state"]]!,
station: json["station"],
);
Map<String, dynamic> toJson() => {
"delay": delay,
"state": stateValues.reverse[state],
"station": station,
};
factory TrainDataStatus.fromJson(Map<String, dynamic> json) => _$TrainDataStatusFromJson(json);
@override
String toString() {
@ -190,38 +115,118 @@ class TrainDataStatus {
result += '${delay.abs()} min';
}
result += ' la ';
switch (state) {
case State.PASSING:
result += 'trecerea fără oprire prin';
break;
case State.ARRIVAL:
result += 'sosirea în';
break;
case State.DEPARTURE:
result += 'plecarea din';
break;
}
result += switch (state) {
TrainDataStatusState.passing => 'trecerea fără oprire prin',
TrainDataStatusState.arrival => 'sosirea în',
TrainDataStatusState.departure => 'plecarea din',
};
result += station;
return result;
}
}
enum State { PASSING, ARRIVAL, DEPARTURE }
enum TrainDataStatusState { passing, arrival, departure }
abstract class TrainDataNote {
final String kind;
const TrainDataNote({required this.kind});
final stateValues = EnumValues({
"arrival": State.ARRIVAL,
"departure": State.DEPARTURE,
"passing": State.PASSING
});
Map<String, dynamic> toJson() => {
"kind": kind,
};
}
class EnumValues<T> {
Map<String, T> map;
Map<T, String>? reverseMap;
class TrainDataNoteConverter implements JsonConverter<TrainDataNote, Map<String, dynamic>> {
const TrainDataNoteConverter();
EnumValues(this.map);
@override
TrainDataNote fromJson(Map<String, dynamic> json) {
return switch(json['kind']) {
'trainNumberChange' => TrainDataNoteTrainNumberChange.fromJson(json),
'departsAs' => TrainDataNoteDepartsAs.fromJson(json),
'detachingWagons' => TrainDataNoteDetachingWagons.fromJson(json),
'receivingWagons' => TrainDataNoteReceivingWagons.fromJson(json),
_ => TrainDataNoteUnknown.fromJson(json),
};
}
Map<T, String> get reverse {
reverseMap ??= map.map((k, v) => MapEntry(v, k));
return reverseMap!;
@override
Map<String, dynamic> toJson(TrainDataNote object) {
return object.toJson();
}
}
@freezed
class TrainDataNoteTrainNumberChange with _$TrainDataNoteTrainNumberChange implements TrainDataNote {
@Implements<TrainDataNote>()
const factory TrainDataNoteTrainNumberChange({
// base
@Default("trainNumberChange")
String kind,
// impl
required String rank,
required String number,
}) = _TrainDataNoteTrainNumberChange;
factory TrainDataNoteTrainNumberChange.fromJson(Map<String, dynamic> json) => _$TrainDataNoteTrainNumberChangeFromJson(json);
}
@freezed
class TrainDataNoteDepartsAs with _$TrainDataNoteDepartsAs implements TrainDataNote {
@Implements<TrainDataNote>()
const factory TrainDataNoteDepartsAs({
// base
@Default("departsAs")
String kind,
// impl
required String rank,
required String number,
required DateTime departureDate,
}) = _TrainDataNoteDepartsAs;
factory TrainDataNoteDepartsAs.fromJson(Map<String, dynamic> json) => _$TrainDataNoteDepartsAsFromJson(json);
}
@freezed
class TrainDataNoteDetachingWagons with _$TrainDataNoteDetachingWagons implements TrainDataNote {
@Implements<TrainDataNote>()
const factory TrainDataNoteDetachingWagons({
// base
@Default("detachingWagons")
String kind,
// impl
required String station,
}) = _TrainDataNoteDetachingWagons;
factory TrainDataNoteDetachingWagons.fromJson(Map<String, dynamic> json) => _$TrainDataNoteDetachingWagonsFromJson(json);
}
@freezed
class TrainDataNoteReceivingWagons with _$TrainDataNoteReceivingWagons implements TrainDataNote {
@Implements<TrainDataNote>()
const factory TrainDataNoteReceivingWagons({
// base
@Default("receivingWagons")
String kind,
// impl
required String station,
}) = _TrainDataNoteReceivingWagons;
factory TrainDataNoteReceivingWagons.fromJson(Map<String, dynamic> json) => _$TrainDataNoteReceivingWagonsFromJson(json);
}
@freezed
class TrainDataNoteUnknown with _$TrainDataNoteUnknown implements TrainDataNote {
@Implements<TrainDataNote>()
const factory TrainDataNoteUnknown({
// base
required String kind,
// impl
required Map<String, dynamic> extra,
}) = _TrainDataNoteUnknown;
factory TrainDataNoteUnknown.fromJson(Map<String, dynamic> json) => TrainDataNoteUnknown(
kind: json['kind'],
extra: Map.from(json)..remove('kind'),
);
}

2365
lib/models/train_data.freezed.dart

File diff suppressed because it is too large Load Diff

217
lib/models/train_data.g.dart

@ -0,0 +1,217 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'train_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_TrainData _$$_TrainDataFromJson(Map<String, dynamic> json) => _$_TrainData(
rank: json['rank'] as String,
number: json['number'] as String,
date: json['date'] as String,
operator: json['operator'] as String,
groups: (json['groups'] as List<dynamic>)
.map((e) => TrainDataGroup.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$_TrainDataToJson(_$_TrainData instance) =>
<String, dynamic>{
'rank': instance.rank,
'number': instance.number,
'date': instance.date,
'operator': instance.operator,
'groups': instance.groups,
};
_$_TrainDataGroup _$$_TrainDataGroupFromJson(Map<String, dynamic> json) =>
_$_TrainDataGroup(
route: TrainDataRoute.fromJson(json['route'] as Map<String, dynamic>),
stations: (json['stations'] as List<dynamic>)
.map((e) => TrainDataStation.fromJson(e as Map<String, dynamic>))
.toList(),
status: json['status'] == null
? null
: TrainDataStatus.fromJson(json['status'] as Map<String, dynamic>),
);
Map<String, dynamic> _$$_TrainDataGroupToJson(_$_TrainDataGroup instance) =>
<String, dynamic>{
'route': instance.route,
'stations': instance.stations,
'status': instance.status,
};
_$_TrainDataRoute _$$_TrainDataRouteFromJson(Map<String, dynamic> json) =>
_$_TrainDataRoute(
from: json['from'] as String,
to: json['to'] as String,
);
Map<String, dynamic> _$$_TrainDataRouteToJson(_$_TrainDataRoute instance) =>
<String, dynamic>{
'from': instance.from,
'to': instance.to,
};
_$_TrainDataStation _$$_TrainDataStationFromJson(Map<String, dynamic> json) =>
_$_TrainDataStation(
name: json['name'] as String,
linkName: json['linkName'] as String,
km: json['km'] as int,
stoppingTime: json['stoppingTime'] as int?,
platform: json['platform'] as String?,
arrival: json['arrival'] == null
? null
: StationArrDepTime.fromJson(json['arrival'] as Map<String, dynamic>),
departure: json['departure'] == null
? null
: StationArrDepTime.fromJson(
json['departure'] as Map<String, dynamic>),
notes: (json['notes'] as List<dynamic>)
.map((e) => const TrainDataNoteConverter()
.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$_TrainDataStationToJson(_$_TrainDataStation instance) =>
<String, dynamic>{
'name': instance.name,
'linkName': instance.linkName,
'km': instance.km,
'stoppingTime': instance.stoppingTime,
'platform': instance.platform,
'arrival': instance.arrival,
'departure': instance.departure,
'notes':
instance.notes.map(const TrainDataNoteConverter().toJson).toList(),
};
_$_StationArrDepTime _$$_StationArrDepTimeFromJson(Map<String, dynamic> json) =>
_$_StationArrDepTime(
scheduleTime: DateTime.parse(json['scheduleTime'] as String),
status: json['status'] == null
? null
: StationArrDepTimeStatus.fromJson(
json['status'] as Map<String, dynamic>),
);
Map<String, dynamic> _$$_StationArrDepTimeToJson(
_$_StationArrDepTime instance) =>
<String, dynamic>{
'scheduleTime': instance.scheduleTime.toIso8601String(),
'status': instance.status,
};
_$_StationArrDepTimeStatus _$$_StationArrDepTimeStatusFromJson(
Map<String, dynamic> json) =>
_$_StationArrDepTimeStatus(
delay: json['delay'] as int,
real: json['real'] as bool,
cancelled: json['cancelled'] as bool,
);
Map<String, dynamic> _$$_StationArrDepTimeStatusToJson(
_$_StationArrDepTimeStatus instance) =>
<String, dynamic>{
'delay': instance.delay,
'real': instance.real,
'cancelled': instance.cancelled,
};
_$_TrainDataStatus _$$_TrainDataStatusFromJson(Map<String, dynamic> json) =>
_$_TrainDataStatus(
delay: json['delay'] as int,
station: json['station'] as String,
state: $enumDecode(_$TrainDataStatusStateEnumMap, json['state']),
);
Map<String, dynamic> _$$_TrainDataStatusToJson(_$_TrainDataStatus instance) =>
<String, dynamic>{
'delay': instance.delay,
'station': instance.station,
'state': _$TrainDataStatusStateEnumMap[instance.state]!,
};
const _$TrainDataStatusStateEnumMap = {
TrainDataStatusState.passing: 'passing',
TrainDataStatusState.arrival: 'arrival',
TrainDataStatusState.departure: 'departure',
};
_$_TrainDataNoteTrainNumberChange _$$_TrainDataNoteTrainNumberChangeFromJson(
Map<String, dynamic> json) =>
_$_TrainDataNoteTrainNumberChange(
kind: json['kind'] as String? ?? "trainNumberChange",
rank: json['rank'] as String,
number: json['number'] as String,
);
Map<String, dynamic> _$$_TrainDataNoteTrainNumberChangeToJson(
_$_TrainDataNoteTrainNumberChange instance) =>
<String, dynamic>{
'kind': instance.kind,
'rank': instance.rank,
'number': instance.number,
};
_$_TrainDataNoteDepartsAs _$$_TrainDataNoteDepartsAsFromJson(
Map<String, dynamic> json) =>
_$_TrainDataNoteDepartsAs(
kind: json['kind'] as String? ?? "departsAs",
rank: json['rank'] as String,
number: json['number'] as String,
departureDate: DateTime.parse(json['departureDate'] as String),
);
Map<String, dynamic> _$$_TrainDataNoteDepartsAsToJson(
_$_TrainDataNoteDepartsAs instance) =>
<String, dynamic>{
'kind': instance.kind,
'rank': instance.rank,
'number': instance.number,
'departureDate': instance.departureDate.toIso8601String(),
};
_$_TrainDataNoteDetachingWagons _$$_TrainDataNoteDetachingWagonsFromJson(
Map<String, dynamic> json) =>
_$_TrainDataNoteDetachingWagons(
kind: json['kind'] as String? ?? "detachingWagons",
station: json['station'] as String,
);
Map<String, dynamic> _$$_TrainDataNoteDetachingWagonsToJson(
_$_TrainDataNoteDetachingWagons instance) =>
<String, dynamic>{
'kind': instance.kind,
'station': instance.station,
};
_$_TrainDataNoteReceivingWagons _$$_TrainDataNoteReceivingWagonsFromJson(
Map<String, dynamic> json) =>
_$_TrainDataNoteReceivingWagons(
kind: json['kind'] as String? ?? "receivingWagons",
station: json['station'] as String,
);
Map<String, dynamic> _$$_TrainDataNoteReceivingWagonsToJson(
_$_TrainDataNoteReceivingWagons instance) =>
<String, dynamic>{
'kind': instance.kind,
'station': instance.station,
};
_$_TrainDataNoteUnknown _$$_TrainDataNoteUnknownFromJson(
Map<String, dynamic> json) =>
_$_TrainDataNoteUnknown(
kind: json['kind'] as String,
extra: json['extra'] as Map<String, dynamic>,
);
Map<String, dynamic> _$$_TrainDataNoteUnknownToJson(
_$_TrainDataNoteUnknown instance) =>
<String, dynamic>{
'kind': instance.kind,
'extra': instance.extra,
};

2
lib/models/trains_result.freezed.dart

@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'trains_result.dart';

3
lib/pages/station_arrdep_page/view_station/view_station.dart

@ -43,8 +43,9 @@ class ViewStationPage extends HookConsumerWidget {
class ViewStationArguments {
final String stationName;
final DateTime? date;
const ViewStationArguments({required this.stationName});
const ViewStationArguments({required this.stationName, this.date});
}
abstract class ViewStationPageShared extends StatelessWidget {

111
lib/pages/train_info_page/view_train/train_info.dart

@ -1,4 +1,7 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:info_tren/api/train_data.dart';
import 'package:info_tren/components/loading/loading.dart';
@ -9,59 +12,93 @@ import 'package:info_tren/pages/train_info_page/view_train/train_info_fluent.dar
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
import 'package:info_tren/providers.dart';
class TrainInfo extends ConsumerWidget {
class TrainInfo extends HookConsumerWidget {
static String routeName = "/trainInfo/display";
const TrainInfo({super.key,});
const TrainInfo({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final uiDesign = ref.watch(uiDesignProvider);
final args = ref.watch(trainInfoArgumentsProvider);
final trainNumber = args.trainNumber;
final date = args.date;
return RefreshFutureBuilder<TrainData>(
futureCreator: () => getTrain(trainNumber, date: date),
builder: (context, refresh, replaceFutureBuilder, snapshot) {
void onViewYesterdayTrain() {
replaceFutureBuilder(() => getTrain(trainNumber, date: DateTime.now().subtract(const Duration(days: 1))));
}
final viewYesterday = useState(false);
final date = args.date ??
DateTime.now().copyWith(
hour: 12,
minute: 0,
second: 0,
millisecond: 0,
microsecond: 0,
);
final requestDate =
viewYesterday.value ? date.subtract(const Duration(days: 1)) : date;
final trainDataAsync = ref
.watch(trainInfoProvider(trainNumber: trainNumber, date: requestDate));
Future refresh() async {
ref.invalidate(
trainInfoProvider(trainNumber: trainNumber, date: requestDate),
);
await Future.delayed(const Duration(seconds: 1));
}
if ([RefreshFutureBuilderState.none, RefreshFutureBuilderState.waiting].contains(snapshot.state)) {
return TrainInfoLoading(title: trainNumber.toString(), loadingText: "Se încarcă...",);
}
else if (snapshot.state == RefreshFutureBuilderState.error) {
return TrainInfoError(title: '$trainNumber - Error', error: snapshot.error!, refresh: refresh,);
}
void onViewYesterdayTrain() {
viewYesterday.value = !viewYesterday.value;
}
useEffect(() {
final handle = Timer.periodic(const Duration(minutes: 1), (timer) {
refresh();
});
return () {
handle.cancel();
};
});
return trainDataAsync.when(
data: (data) {
switch (uiDesign) {
case UiDesign.MATERIAL:
return TrainInfoMaterial(
trainData: snapshot.data!,
trainData: data,
refresh: refresh,
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
isRefreshing: trainDataAsync.isRefreshing,
onViewYesterdayTrain: onViewYesterdayTrain,
);
case UiDesign.CUPERTINO:
return TrainInfoCupertino(
trainData: snapshot.data!,
refresh: refresh,
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
trainData: data,
refresh: refresh,
isRefreshing: trainDataAsync.isRefreshing,
onViewYesterdayTrain: onViewYesterdayTrain,
);
case UiDesign.FLUENT:
return TrainInfoFluent(
trainData: snapshot.data!,
trainData: data,
refresh: refresh,
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
isRefreshing: trainDataAsync.isRefreshing,
onViewYesterdayTrain: onViewYesterdayTrain,
);
default:
throw UnmatchedUiDesignException(uiDesign);
}
},
error: (e, st) {
return TrainInfoError(
title: '$trainNumber - Error',
error: e,
refresh: refresh,
);
},
loading: () {
return TrainInfoLoading(
title: trainNumber.toString(),
loadingText: "Se încarcă...",
);
},
);
}
}
@ -129,10 +166,12 @@ abstract class TrainInfoLoadingShared extends StatelessWidget {
final Widget loadingWidget;
TrainInfoLoadingShared({
required this.title,
String? loadingText,
required this.title,
String? loadingText,
super.key,
}) : loadingWidget = Loading(text: loadingText,);
}) : loadingWidget = Loading(
text: loadingText,
);
}
class TrainInfoError extends ConsumerWidget {
@ -181,7 +220,12 @@ abstract class TrainInfoErrorShared extends StatelessWidget {
final Object error;
final Future Function()? refresh;
const TrainInfoErrorShared({required this.title, required this.error, this.refresh, super.key,});
const TrainInfoErrorShared({
required this.title,
required this.error,
this.refresh,
super.key,
});
}
class TrainInfoBody extends ConsumerWidget {
@ -246,10 +290,15 @@ abstract class TrainInfoBodyShared extends StatelessWidget {
}
abstract class DisplayTrainYesterdayWarningCommon extends StatelessWidget {
static const trainDidNotDepart = 'Acest tren nu a plecat încă din prima gară.';
static const seeYesterdayTrain = 'Apasă aici pentru a vedea trenul care a plecat ieri.';
static const trainDidNotDepart =
'Acest tren nu a plecat încă din prima gară.';
static const seeYesterdayTrain =
'Apasă aici pentru a vedea trenul care a plecat ieri.';
final void Function() onViewYesterdayTrain;
const DisplayTrainYesterdayWarningCommon(this.onViewYesterdayTrain, {super.key,});
const DisplayTrainYesterdayWarningCommon(
this.onViewYesterdayTrain, {
super.key,
});
}

4
lib/pages/train_info_page/view_train/train_info_cupertino.dart

@ -1051,8 +1051,8 @@ class DisplayTrainYesterdayWarningCupertino extends DisplayTrainYesterdayWarning
const TextSpan(text: '\n'),
TextSpan(
text: DisplayTrainYesterdayWarningCommon.seeYesterdayTrain,
style: const TextStyle(
color: CupertinoColors.link,
style: TextStyle(
color: CupertinoTheme.of(context).primaryColor,
),
recognizer: TapGestureRecognizer()
..onTap = onViewYesterdayTrain,

315
lib/pages/train_info_page/view_train/train_info_cupertino_DisplayTrainStation.dart

@ -1,13 +1,18 @@
import 'package:flutter/cupertino.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:info_tren/components/badge/badge.dart';
import 'package:info_tren/components/cupertino_divider.dart';
import 'package:info_tren/components/train_id_text_span.dart';
import 'package:info_tren/models.dart';
import 'package:info_tren/providers.dart';
class DisplayTrainStation extends StatelessWidget {
final Station station;
final TrainDataStation station;
const DisplayTrainStation({required this.station, super.key,});
const DisplayTrainStation({
required this.station,
super.key,
});
@override
Widget build(BuildContext context) {
@ -15,6 +20,26 @@ class DisplayTrainStation extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
if (station.notes.whereType<TrainDataNoteDepartsAs>().isNotEmpty) ...[
Builder(
builder: (context) {
final note =
station.notes.whereType<TrainDataNoteDepartsAs>().first;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Trenul pleacă cu numărul '),
trainIdSpan(rank: note.rank, number: note.number),
],
),
),
);
},
),
const CupertinoDivider(),
],
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
@ -22,42 +47,38 @@ class DisplayTrainStation extends StatelessWidget {
flex: 1,
child: Align(
alignment: Alignment.centerLeft,
child: Builder(
builder: (context) {
final departureStatus = station.departure?.status;
final arrivalStatus = station.arrival?.status;
int delay;
bool real;
if (departureStatus == null) {
delay = arrivalStatus?.delay ?? 0;
real = arrivalStatus?.real ?? false;
}
else if (arrivalStatus == null) {
delay = departureStatus.delay;
real = departureStatus.real;
}
else {
delay = departureStatus.delay;
real = departureStatus.real;
if (!real && arrivalStatus.real) {
delay = arrivalStatus.delay;
real = arrivalStatus.real;
}
child: Builder(builder: (context) {
final departureStatus = station.departure?.status;
final arrivalStatus = station.arrival?.status;
int delay;
bool real;
if (departureStatus == null) {
delay = arrivalStatus?.delay ?? 0;
real = arrivalStatus?.real ?? false;
} else if (arrivalStatus == null) {
delay = departureStatus.delay;
real = departureStatus.real;
} else {
delay = departureStatus.delay;
real = departureStatus.real;
if (!real && arrivalStatus.real) {
delay = arrivalStatus.delay;
real = arrivalStatus.real;
}
final isDelayed = delay > 0 && real == true;
final isOnTime = delay <= 0 && real == true;
const isNotScheduled = false;
return Badge(
text: station.km.toString(),
caption: 'km',
isNotScheduled: isNotScheduled,
isDelayed: isDelayed,
isOnTime: isOnTime,
);
}
),
final isDelayed = delay > 0 && real == true;
final isOnTime = delay <= 0 && real == true;
const isNotScheduled = false;
return Badge(
text: station.km.toString(),
caption: 'km',
isNotScheduled: isNotScheduled,
isDelayed: isDelayed,
isOnTime: isOnTime,
);
}),
),
),
Title(
@ -67,7 +88,9 @@ class DisplayTrainStation extends StatelessWidget {
flex: 1,
child: Align(
alignment: Alignment.centerRight,
child: station.platform == null ? Container() : Badge(text: station.platform!, caption: 'linia'),
child: station.platform == null
? Container()
: Badge(text: station.platform!, caption: 'linia'),
),
),
],
@ -75,16 +98,61 @@ class DisplayTrainStation extends StatelessWidget {
Time(
station: station,
),
if (station.notes.whereType<TrainDataNoteDetachingWagons>().isNotEmpty)
Builder(
builder: (context) {
final note =
station.notes.whereType<TrainDataNoteDetachingWagons>().first;
return Text(
'Trenul detașează vagoane către ${note.station}',
textAlign: TextAlign.center,
);
},
),
if (station.notes.whereType<TrainDataNoteReceivingWagons>().isNotEmpty)
Builder(
builder: (context) {
final note =
station.notes.whereType<TrainDataNoteReceivingWagons>().first;
return Text(
'Trenul primește vagoane de la ${note.station}',
textAlign: TextAlign.center,
);
},
),
Delay(
station: station,
),
if (station.notes
.whereType<TrainDataNoteTrainNumberChange>()
.isNotEmpty) ...[
const CupertinoDivider(),
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteTrainNumberChange>()
.first;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Trenul își schimbă numărul în '),
trainIdSpan(rank: note.rank, number: note.number),
],
),
),
);
},
),
],
],
);
}
}
class Title extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Title({
required this.station,
@ -96,17 +164,19 @@ class Title extends StatelessWidget {
return Text(
station.name,
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 22,
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w500 : FontWeight.w300,
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
),
fontSize: 22,
fontWeight: MediaQuery.of(context).boldText
? FontWeight.w500
: FontWeight.w300,
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
),
textAlign: TextAlign.center,
);
}
}
class Time extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Time({
required this.station,
@ -137,21 +207,35 @@ class Time extends StatelessWidget {
Text(
"",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
Container(
width: 2,
),
ArrivalTime(
station: station,
),
Expanded(
child: Container(),
),
StopTime(
station: station,
),
Expanded(
child: Container(),
),
DepartureTime(
station: station,
),
Container(
width: 2,
),
Container(width: 2,),
ArrivalTime(station: station,),
Expanded(child: Container(),),
StopTime(station: station,),
Expanded(child: Container(),),
DepartureTime(station: station,),
Container(width: 2,),
Text(
"",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
],
);
@ -159,7 +243,7 @@ class Time extends StatelessWidget {
}
class ArrivalTime extends ConsumerWidget {
final Station station;
final TrainDataStation station;
final bool finalStation;
const ArrivalTime({
@ -179,24 +263,29 @@ class ArrivalTime extends ConsumerWidget {
Text(
"",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
Container(
width: 2,
),
Container(width: 2,),
const Text("sosire la "),
ArrivalTime(station: station,),
Expanded(child: Container(),),
ArrivalTime(
station: station,
),
Expanded(
child: Container(),
),
],
);
}
else {
} else {
final delay = station.arrival!.status?.delay ?? 0;
final time = tz.convertDateTime(station.arrival!.scheduleTime);
if (delay == 0) {
return Text("${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}");
}
else if (delay > 0) {
return Text(
"${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}");
} else if (delay > 0) {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -206,19 +295,18 @@ class ArrivalTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
color: CupertinoColors.destructiveRed,
),
color: CupertinoColors.destructiveRed,
),
),
],
);
}
else {
} else {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -228,14 +316,14 @@ class ArrivalTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
color: CupertinoColors.systemGreen,
),
color: CupertinoColors.systemGreen,
),
),
],
);
@ -245,7 +333,7 @@ class ArrivalTime extends ConsumerWidget {
}
class StopTime extends StatelessWidget {
final Station station;
final TrainDataStation station;
const StopTime({
required this.station,
@ -275,14 +363,12 @@ class StopTime extends StatelessWidget {
minutes ? '1 minut' : '1 secundă',
textAlign: TextAlign.center,
);
}
else if (stopsForInt < 20) {
} else if (stopsForInt < 20) {
return Text(
'$stopsForInt ${minutes ? 'minute' : 'seconde'}',
'$stopsForInt ${minutes ? 'minute' : 'seconde'}',
textAlign: TextAlign.center,
);
}
else {
} else {
return Text(
'$stopsForInt de ${minutes ? 'minute' : 'secunde'}',
textAlign: TextAlign.center,
@ -296,7 +382,7 @@ class StopTime extends StatelessWidget {
}
class DepartureTime extends ConsumerWidget {
final Station station;
final TrainDataStation station;
final bool firstStation;
const DepartureTime({
@ -312,27 +398,32 @@ class DepartureTime extends ConsumerWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(child: Container(),),
Expanded(
child: Container(),
),
const Text("plecare la "),
DepartureTime(station: station,),
Container(width: 2,),
DepartureTime(
station: station,
),
Container(
width: 2,
),
Text(
"",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
],
);
}
else {
} else {
final delay = station.departure!.status?.delay ?? 0;
final time = tz.convertDateTime(station.departure!.scheduleTime);
if (delay == 0) {
return Text("${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}");
}
else if (delay > 0) {
return Text(
"${time.hour.toString().padLeft(2, "0")}:${time.minute.toString().padLeft(2, "0")}");
} else if (delay > 0) {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -342,19 +433,18 @@ class DepartureTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
color: CupertinoColors.destructiveRed,
),
color: CupertinoColors.destructiveRed,
),
),
],
);
}
else {
} else {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -364,14 +454,14 @@ class DepartureTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
color: CupertinoColors.systemGreen,
),
color: CupertinoColors.systemGreen,
),
),
],
);
@ -381,7 +471,7 @@ class DepartureTime extends ConsumerWidget {
}
class Delay extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Delay({
required this.station,
@ -404,20 +494,19 @@ class Delay extends StatelessWidget {
return Text(
"$delay ${delay == 1 ? 'minut' : 'minute'} întârziere",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
color: CupertinoColors.destructiveRed,
fontSize: 14,
fontStyle: FontStyle.italic,
),
color: CupertinoColors.destructiveRed,
fontSize: 14,
fontStyle: FontStyle.italic,
),
);
}
else if (delay < 0) {
} else if (delay < 0) {
return Text(
"${-delay} ${delay == -1 ? 'minut' : 'minute'} mai devreme",
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
color: CupertinoColors.systemGreen,
fontSize: 14,
fontStyle: FontStyle.italic,
),
color: CupertinoColors.systemGreen,
fontSize: 14,
fontStyle: FontStyle.italic,
),
);
}

2
lib/pages/train_info_page/view_train/train_info_fluent.dart

@ -748,7 +748,7 @@ class DisplayTrainYesterdayWarningFluent
TextSpan(
text: DisplayTrainYesterdayWarningCommon.seeYesterdayTrain,
style: TextStyle(
color: Colors.blue,
color: FluentTheme.of(context).accentColor,// Colors.blue,
),
recognizer: TapGestureRecognizer()
..onTap = onViewYesterdayTrain,

352
lib/pages/train_info_page/view_train/train_info_fluent_DisplayTrainStation.dart

@ -1,37 +1,62 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:info_tren/components/badge/badge.dart';
import 'package:info_tren/components/train_id_text_span.dart';
import 'package:info_tren/models.dart';
import 'package:info_tren/providers.dart';
class DisplayTrainStation extends StatelessWidget {
final Station station;
final TrainDataStation station;
final void Function()? onTap;
const DisplayTrainStation({required this.station, this.onTap, super.key,});
const DisplayTrainStation({
required this.station,
this.onTap,
super.key,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(2),
child: HoverButton(
onPressed: onTap,
builder: (context, states) {
return Card(
padding: const EdgeInsets.all(2),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (station.notes.whereType<TrainDataNoteDepartsAs>().isNotEmpty)
Builder(
builder: (context) {
final note =
station.notes.whereType<TrainDataNoteDepartsAs>().first;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Trenul pleacă cu numărul '),
trainIdSpan(rank: note.rank, number: note.number),
],
),
),
);
},
),
Padding(
padding: const EdgeInsets.all(2),
child: HoverButton(
onPressed: onTap,
builder: (context, states) {
return Card(
padding: const EdgeInsets.all(2),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: Align(
alignment: Alignment.centerLeft,
child: Builder(
builder: (context) {
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
flex: 1,
child: Align(
alignment: Alignment.centerLeft,
child: Builder(builder: (context) {
final departureStatus = station.departure?.status;
final arrivalStatus = station.arrival?.status;
int delay;
@ -39,12 +64,10 @@ class DisplayTrainStation extends StatelessWidget {
if (departureStatus == null) {
delay = arrivalStatus?.delay ?? 0;
real = arrivalStatus?.real ?? false;
}
else if (arrivalStatus == null) {
} else if (arrivalStatus == null) {
delay = departureStatus.delay;
real = departureStatus.real;
}
else {
} else {
delay = departureStatus.delay;
real = departureStatus.real;
if (!real && arrivalStatus.real) {
@ -64,41 +87,94 @@ class DisplayTrainStation extends StatelessWidget {
isDelayed: isDelayed,
isOnTime: isOnTime,
);
}
}),
),
),
),
Title(
station: station,
),
Expanded(
flex: 1,
child: (station.platform == null)
? Container()
: Align(
alignment: Alignment.centerRight,
child: Badge(
text: station.platform!,
caption: 'linia',
),
),
),
],
),
Title(
Time(
station: station,
),
Expanded(
flex: 1,
child: (station.platform == null)
? Container()
: Align(
alignment: Alignment.centerRight,
child: Badge(text: station.platform!, caption: 'linia',),
if (station.notes
.whereType<TrainDataNoteDetachingWagons>()
.isNotEmpty)
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteDetachingWagons>()
.first;
return Text(
'Trenul detașează vagoane către ${note.station}',
textAlign: TextAlign.center,
);
},
),
if (station.notes
.whereType<TrainDataNoteReceivingWagons>()
.isNotEmpty)
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteReceivingWagons>()
.first;
return Text(
'Trenul primește vagoane de la ${note.station}',
textAlign: TextAlign.center,
);
},
),
Delay(
station: station,
),
],
),
Time(
station: station,
),
Delay(
station: station,
);
},
),
),
if (station.notes
.whereType<TrainDataNoteTrainNumberChange>()
.isNotEmpty)
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteTrainNumberChange>()
.first;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Trenul își schimbă numărul în '),
trainIdSpan(rank: note.rank, number: note.number),
],
),
),
],
),
);
},
),
);
},
),
],
);
}
}
class Title extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Title({
required this.station,
@ -107,20 +183,22 @@ class Title extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
return Text(
station.name,
style: FluentTheme.of(context).typography.body?.copyWith(
fontSize: 22,
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w500 : FontWeight.w300,
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
),
fontSize: 22,
fontWeight: MediaQuery.of(context).boldText
? FontWeight.w500
: FontWeight.w300,
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
),
textAlign: TextAlign.center,
);
}
}
class Time extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Time({
required this.station,
@ -151,21 +229,35 @@ class Time extends StatelessWidget {
Text(
"",
style: FluentTheme.of(context).typography.body?.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
Container(
width: 2,
),
ArrivalTime(
station: station,
),
Expanded(
child: Container(),
),
StopTime(
station: station,
),
Expanded(
child: Container(),
),
DepartureTime(
station: station,
),
Container(
width: 2,
),
Container(width: 2,),
ArrivalTime(station: station,),
Expanded(child: Container(),),
StopTime(station: station,),
Expanded(child: Container(),),
DepartureTime(station: station,),
Container(width: 2,),
Text(
"",
style: FluentTheme.of(context).typography.body?.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
],
);
@ -173,7 +265,7 @@ class Time extends StatelessWidget {
}
class ArrivalTime extends ConsumerWidget {
final Station station;
final TrainDataStation station;
final bool finalStation;
const ArrivalTime({
@ -195,24 +287,29 @@ class ArrivalTime extends ConsumerWidget {
Text(
"",
style: FluentTheme.of(context).typography.body?.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
Container(
width: 2,
),
Container(width: 2,),
const Text("sosire la "),
ArrivalTime(station: station,),
Expanded(child: Container(),),
ArrivalTime(
station: station,
),
Expanded(
child: Container(),
),
],
);
}
else {
} else {
final delay = station.arrival!.status?.delay ?? 0;
final time = tz.convertDateTime(station.arrival!.scheduleTime);
if (delay == 0) {
return Text("${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
}
else if (delay > 0) {
return Text(
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
} else if (delay > 0) {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -222,20 +319,19 @@ class ArrivalTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
// color: Colors.red.shade300,
color: Colors.red.lighter,
),
// color: Colors.red.shade300,
color: Colors.red.lighter,
),
),
],
);
}
else {
} else {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -245,15 +341,15 @@ class ArrivalTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
// color: Colors.green.shade300,
color: Colors.green.lighter,
),
// color: Colors.green.shade300,
color: Colors.green.lighter,
),
),
],
);
@ -263,7 +359,7 @@ class ArrivalTime extends ConsumerWidget {
}
class StopTime extends StatelessWidget {
final Station station;
final TrainDataStation station;
const StopTime({
required this.station,
@ -292,14 +388,12 @@ class StopTime extends StatelessWidget {
"1 ${minutes ? 'minut' : 'secundă'}",
textAlign: TextAlign.center,
);
}
else if (stopsForInt < 20) {
} else if (stopsForInt < 20) {
return Text(
"$stopsForInt ${minutes ? 'minute' : 'secunde'}",
textAlign: TextAlign.center,
);
}
else {
} else {
return Text(
"$stopsForInt de ${minutes ? 'minute' : 'secunde'}",
textAlign: TextAlign.center,
@ -313,7 +407,7 @@ class StopTime extends StatelessWidget {
}
class DepartureTime extends ConsumerWidget {
final Station station;
final TrainDataStation station;
final bool firstStation;
const DepartureTime({
@ -332,27 +426,32 @@ class DepartureTime extends ConsumerWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(child: Container(),),
Expanded(
child: Container(),
),
const Text("plecare la "),
DepartureTime(station: station,),
Container(width: 2,),
DepartureTime(
station: station,
),
Container(
width: 2,
),
Text(
"",
style: FluentTheme.of(context).typography.body?.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
],
);
}
else {
} else {
final delay = station.departure!.status?.delay ?? 0;
final time = tz.convertDateTime(station.departure!.scheduleTime);
if (delay == 0) {
return Text("${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
}
else if (delay > 0) {
return Text(
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
} else if (delay > 0) {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -362,20 +461,19 @@ class DepartureTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
// color: Colors.red.shade300,
color: Colors.red.lighter,
),
// color: Colors.red.shade300,
color: Colors.red.lighter,
),
),
],
);
}
else {
} else {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -385,15 +483,15 @@ class DepartureTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: FluentTheme.of(context).typography.body?.copyWith(
// color: Colors.green.shade300,
color: Colors.green.lighter,
),
// color: Colors.green.shade300,
color: Colors.green.lighter,
),
),
],
);
@ -402,9 +500,8 @@ class DepartureTime extends ConsumerWidget {
}
}
class Delay extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Delay({
required this.station,
@ -427,22 +524,21 @@ class Delay extends StatelessWidget {
return Text(
"$delay ${delay == 1 ? 'minut' : 'minute'} întârziere",
style: FluentTheme.of(context).typography.body?.copyWith(
// color: Colors.red.shade300,
color: Colors.red.lighter,
fontSize: 14,
fontStyle: FontStyle.italic,
),
// color: Colors.red.shade300,
color: Colors.red.lighter,
fontSize: 14,
fontStyle: FontStyle.italic,
),
);
}
else if (delay < 0) {
} else if (delay < 0) {
return Text(
"${-delay} ${delay == -1 ? 'minut' : 'minute'} mai devreme",
style: FluentTheme.of(context).typography.body?.copyWith(
// color: Colors.green.shade300,
color: Colors.green.lighter,
fontSize: 14,
fontStyle: FontStyle.italic,
),
// color: Colors.green.shade300,
color: Colors.green.lighter,
fontSize: 14,
fontStyle: FontStyle.italic,
),
);
}

125
lib/pages/train_info_page/view_train/train_info_material.dart

@ -9,7 +9,11 @@ import 'package:info_tren/pages/train_info_page/view_train/train_info_material_D
import 'package:info_tren/utils/state_to_string.dart';
class TrainInfoLoadingMaterial extends TrainInfoLoadingShared {
TrainInfoLoadingMaterial({required super.title, super.loadingText, super.key,});
TrainInfoLoadingMaterial({
required super.title,
super.loadingText,
super.key,
});
@override
Widget build(BuildContext context) {
@ -77,13 +81,34 @@ class TrainInfoMaterial extends TrainInfoShared {
builder: (context) {
return Scaffold(
appBar: isSmallScreen(context)
? null
: AppBar(
centerTitle: true,
title: Text(
"Informații despre ${trainData.rank} ${trainData.number}",
? null
: AppBar(
centerTitle: true,
title: Text(
'Informații despre ${trainData.rank} ${trainData.number}',
),
actions: [
IconButton(
tooltip: 'Reîncarcă',
icon: (isRefreshing ?? false)
? const Center(
child: SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
)
: const Icon(Icons.refresh),
onPressed: (isRefreshing ?? false)
? null
: () {
refresh?.call();
},
),
],
),
),
body: Column(
children: <Widget>[
if (isSmallScreen(context))
@ -172,16 +197,15 @@ class TrainInfoBodyMaterial extends TrainInfoBodyShared {
if (onViewYesterdayTrain != null &&
trainData.stations.first.departure!.scheduleTime
.compareTo(DateTime.now()) >
0)
...[
DisplayTrainYesterdayWarningMaterial(
onViewYesterdayTrain!,
),
Divider(
color: Colors.white70,
height: isSmallScreen(context) ? 8 : 16,
),
],
0) ...[
DisplayTrainYesterdayWarningMaterial(
onViewYesterdayTrain!,
),
Divider(
color: Colors.white70,
height: isSmallScreen(context) ? 8 : 16,
),
],
],
),
),
@ -193,10 +217,7 @@ class TrainInfoBodyMaterial extends TrainInfoBodyShared {
),
SliverToBoxAdapter(
child: Container(
height: MediaQuery
.of(context)
.viewPadding
.bottom,
height: MediaQuery.of(context).viewPadding.bottom,
),
),
],
@ -204,8 +225,7 @@ class TrainInfoBodyMaterial extends TrainInfoBodyShared {
),
],
);
}
else {
} else {
return CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
@ -281,11 +301,11 @@ class TrainInfoBodyMaterial extends TrainInfoBodyShared {
),
if (onViewYesterdayTrain != null &&
trainData.stations.first.departure!.scheduleTime
.compareTo(DateTime.now()) >
.compareTo(DateTime.now()) >
0) ...[
SliverToBoxAdapter(
child: DisplayTrainYesterdayWarningMaterial(
onViewYesterdayTrain!),
child:
DisplayTrainYesterdayWarningMaterial(onViewYesterdayTrain!),
),
SliverToBoxAdapter(
child: Divider(
@ -299,10 +319,7 @@ class TrainInfoBodyMaterial extends TrainInfoBodyShared {
),
SliverToBoxAdapter(
child: Container(
height: MediaQuery
.of(context)
.viewPadding
.bottom,
height: MediaQuery.of(context).viewPadding.bottom,
),
),
],
@ -314,7 +331,10 @@ class TrainInfoBodyMaterial extends TrainInfoBodyShared {
class DisplayTrainID extends StatelessWidget {
final TrainData trainData;
const DisplayTrainID({required this.trainData, super.key,});
const DisplayTrainID({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -335,7 +355,10 @@ class DisplayTrainID extends StatelessWidget {
class DisplayTrainOperator extends StatelessWidget {
final TrainData trainData;
const DisplayTrainOperator({required this.trainData, super.key,});
const DisplayTrainOperator({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -353,7 +376,10 @@ class DisplayTrainOperator extends StatelessWidget {
class DisplayTrainRoute extends StatelessWidget {
final TrainData trainData;
const DisplayTrainRoute({required this.trainData, super.key,});
const DisplayTrainRoute({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -418,7 +444,10 @@ class DisplayTrainDeparture extends StatelessWidget {
class DisplayTrainLastInfo extends StatelessWidget {
final TrainData trainData;
const DisplayTrainLastInfo({required this.trainData, super.key,});
const DisplayTrainLastInfo({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -610,7 +639,10 @@ class DisplayTrainLastInfo extends StatelessWidget {
class DisplayTrainDestination extends StatelessWidget {
final TrainData trainData;
const DisplayTrainDestination({required this.trainData, super.key,});
const DisplayTrainDestination({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -714,7 +746,10 @@ class DisplayTrainDestination extends StatelessWidget {
class DisplayTrainRouteDistance extends StatelessWidget {
final TrainData trainData;
const DisplayTrainRouteDistance({required this.trainData, super.key,});
const DisplayTrainRouteDistance({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -751,7 +786,10 @@ class DisplayTrainRouteDistance extends StatelessWidget {
class DisplayTrainRouteDuration extends StatelessWidget {
final TrainData trainData;
const DisplayTrainRouteDuration({required this.trainData, super.key,});
const DisplayTrainRouteDuration({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -834,7 +872,10 @@ class DisplayTrainRouteDuration extends StatelessWidget {
class DisplayTrainYesterdayWarningMaterial
extends DisplayTrainYesterdayWarningCommon {
const DisplayTrainYesterdayWarningMaterial(super.onViewYesterdayTrain, {super.key,});
const DisplayTrainYesterdayWarningMaterial(
super.onViewYesterdayTrain, {
super.key,
});
@override
Widget build(BuildContext context) {
@ -870,7 +911,10 @@ class DisplayTrainYesterdayWarningMaterial
class DisplayTrainStations extends StatelessWidget {
final TrainData trainData;
const DisplayTrainStations({required this.trainData, super.key,});
const DisplayTrainStations({
required this.trainData,
super.key,
});
@override
Widget build(BuildContext context) {
@ -884,7 +928,8 @@ class DisplayTrainStations extends StatelessWidget {
onTap: () {
Navigator.of(context).pushNamed(
ViewStationPage.routeName,
arguments: ViewStationArguments(stationName: trainData.stations[index].name),
arguments: ViewStationArguments(
stationName: trainData.stations[index].name),
);
},
),

390
lib/pages/train_info_page/view_train/train_info_material_DisplayTrainStation.dart

@ -1,102 +1,178 @@
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:info_tren/components/train_id_text_span.dart';
import 'package:info_tren/models.dart';
import 'package:info_tren/components/badge/badge.dart';
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
import 'package:info_tren/providers.dart';
class DisplayTrainStation extends StatelessWidget {
final Station station;
final TrainDataStation station;
final void Function()? onTap;
const DisplayTrainStation({required this.station, this.onTap, super.key,});
const DisplayTrainStation({
required this.station,
this.onTap,
super.key,
});
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(2),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (station.notes.whereType<TrainDataNoteDepartsAs>().isNotEmpty)
Builder(
builder: (context) {
final note =
station.notes.whereType<TrainDataNoteDepartsAs>().first;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Trenul pleacă cu numărul '),
trainIdSpan(rank: note.rank, number: note.number),
],
),
),
);
},
),
Card(
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(2),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: Align(
alignment: Alignment.centerLeft,
child: Builder(
builder: (context) {
final departureStatus = station.departure?.status;
final arrivalStatus = station.arrival?.status;
int delay;
bool real;
if (departureStatus == null) {
delay = arrivalStatus?.delay ?? 0;
real = arrivalStatus?.real ?? false;
}
else if (arrivalStatus == null) {
delay = departureStatus.delay;
real = departureStatus.real;
}
else {
delay = departureStatus.delay;
real = departureStatus.real;
if (!real && arrivalStatus.real) {
delay = arrivalStatus.delay;
real = arrivalStatus.real;
Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
flex: 1,
child: Align(
alignment: Alignment.centerLeft,
child: Builder(builder: (context) {
final departureStatus = station.departure?.status;
final arrivalStatus = station.arrival?.status;
int delay;
bool real;
if (departureStatus == null) {
delay = arrivalStatus?.delay ?? 0;
real = arrivalStatus?.real ?? false;
} else if (arrivalStatus == null) {
delay = departureStatus.delay;
real = departureStatus.real;
} else {
delay = departureStatus.delay;
real = departureStatus.real;
if (!real && arrivalStatus.real) {
delay = arrivalStatus.delay;
real = arrivalStatus.real;
}
}
}
final isDelayed = delay > 0 && real == true;
final isOnTime = delay <= 0 && real == true;
const isNotScheduled = false;
return Badge(
text: station.km.toString(),
caption: 'km',
isNotScheduled: isNotScheduled,
isDelayed: isDelayed,
isOnTime: isOnTime,
);
}
final isDelayed = delay > 0 && real == true;
final isOnTime = delay <= 0 && real == true;
const isNotScheduled = false;
return Badge(
text: station.km.toString(),
caption: 'km',
isNotScheduled: isNotScheduled,
isDelayed: isDelayed,
isOnTime: isOnTime,
);
}),
),
),
),
Title(
station: station,
),
Expanded(
flex: 1,
child: (station.platform == null)
? Container()
: Align(
alignment: Alignment.centerRight,
child: Badge(
text: station.platform!,
caption: 'linia',
),
),
),
],
),
Title(
Time(
station: station,
),
Expanded(
flex: 1,
child: (station.platform == null)
? Container()
: Align(
alignment: Alignment.centerRight,
child: Badge(text: station.platform!, caption: 'linia',),
),
if (station.notes
.whereType<TrainDataNoteDetachingWagons>()
.isNotEmpty)
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteDetachingWagons>()
.first;
return Text(
'Trenul detașează vagoane către ${note.station}',
textAlign: TextAlign.center,
);
},
),
if (station.notes
.whereType<TrainDataNoteReceivingWagons>()
.isNotEmpty)
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteReceivingWagons>()
.first;
return Text(
'Trenul primește vagoane de la ${note.station}',
textAlign: TextAlign.center,
);
},
),
Delay(
station: station,
),
],
),
Time(
station: station,
),
Delay(
station: station,
),
],
),
),
),
),
if (station.notes
.whereType<TrainDataNoteTrainNumberChange>()
.isNotEmpty)
Builder(
builder: (context) {
final note = station.notes
.whereType<TrainDataNoteTrainNumberChange>()
.first;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Text.rich(
TextSpan(
children: [
const TextSpan(text: 'Trenul își schimbă numărul în '),
trainIdSpan(rank: note.rank, number: note.number),
],
),
),
);
},
),
],
);
}
}
class Title extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Title({
required this.station,
@ -105,20 +181,22 @@ class Title extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
return Text(
station.name,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: isSmallScreen(context) ? 18 : 22,
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w500 : FontWeight.w300,
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
),
fontSize: isSmallScreen(context) ? 18 : 22,
fontWeight: MediaQuery.of(context).boldText
? FontWeight.w500
: FontWeight.w300,
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
),
textAlign: TextAlign.center,
);
}
}
class Time extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Time({
required this.station,
@ -149,21 +227,35 @@ class Time extends StatelessWidget {
Text(
"",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: isSmallScreen(context) ? 18 : 22,
),
fontSize: isSmallScreen(context) ? 18 : 22,
),
),
Container(
width: 2,
),
ArrivalTime(
station: station,
),
Expanded(
child: Container(),
),
StopTime(
station: station,
),
Expanded(
child: Container(),
),
DepartureTime(
station: station,
),
Container(
width: 2,
),
Container(width: 2,),
ArrivalTime(station: station,),
Expanded(child: Container(),),
StopTime(station: station,),
Expanded(child: Container(),),
DepartureTime(station: station,),
Container(width: 2,),
Text(
"",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: isSmallScreen(context) ? 18 : 22,
),
fontSize: isSmallScreen(context) ? 18 : 22,
),
),
],
);
@ -171,7 +263,7 @@ class Time extends StatelessWidget {
}
class ArrivalTime extends ConsumerWidget {
final Station station;
final TrainDataStation station;
final bool finalStation;
const ArrivalTime({
@ -193,24 +285,29 @@ class ArrivalTime extends ConsumerWidget {
Text(
"",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: isSmallScreen(context) ? 18 : 22,
),
fontSize: isSmallScreen(context) ? 18 : 22,
),
),
Container(
width: 2,
),
Container(width: 2,),
const Text("sosire la "),
ArrivalTime(station: station,),
Expanded(child: Container(),),
ArrivalTime(
station: station,
),
Expanded(
child: Container(),
),
],
);
}
else {
} else {
final delay = station.arrival!.status?.delay ?? 0;
final time = tz.convertDateTime(station.arrival!.scheduleTime);
if (delay == 0) {
return Text("${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
}
else if (delay > 0) {
return Text(
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
} else if (delay > 0) {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -220,19 +317,18 @@ class ArrivalTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.red.shade300,
),
color: Colors.red.shade300,
),
),
],
);
}
else {
} else {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -242,14 +338,14 @@ class ArrivalTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.green.shade300,
),
color: Colors.green.shade300,
),
),
],
);
@ -259,7 +355,7 @@ class ArrivalTime extends ConsumerWidget {
}
class StopTime extends StatelessWidget {
final Station station;
final TrainDataStation station;
const StopTime({
required this.station,
@ -288,14 +384,12 @@ class StopTime extends StatelessWidget {
"1 ${minutes ? 'minut' : 'secundă'}",
textAlign: TextAlign.center,
);
}
else if (stopsForInt < 20) {
} else if (stopsForInt < 20) {
return Text(
"$stopsForInt ${minutes ? 'minute' : 'secunde'}",
textAlign: TextAlign.center,
);
}
else {
} else {
return Text(
"$stopsForInt de ${minutes ? 'minute' : 'secunde'}",
textAlign: TextAlign.center,
@ -309,7 +403,7 @@ class StopTime extends StatelessWidget {
}
class DepartureTime extends ConsumerWidget {
final Station station;
final TrainDataStation station;
final bool firstStation;
const DepartureTime({
@ -328,27 +422,32 @@ class DepartureTime extends ConsumerWidget {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(child: Container(),),
Expanded(
child: Container(),
),
const Text("plecare la "),
DepartureTime(station: station,),
Container(width: 2,),
DepartureTime(
station: station,
),
Container(
width: 2,
),
Text(
"",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: 22,
),
fontSize: 22,
),
),
],
);
}
else {
} else {
final delay = station.departure!.status?.delay ?? 0;
final time = tz.convertDateTime(station.departure!.scheduleTime);
if (delay == 0) {
return Text("${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
}
else if (delay > 0) {
return Text(
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
} else if (delay > 0) {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -358,19 +457,18 @@ class DepartureTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.red.shade300,
),
color: Colors.red.shade300,
),
),
],
);
}
else {
} else {
final oldDate = time;
final newDate = oldDate.add(Duration(minutes: delay));
@ -380,14 +478,14 @@ class DepartureTime extends ConsumerWidget {
Text(
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
decoration: TextDecoration.lineThrough,
),
decoration: TextDecoration.lineThrough,
),
),
Text(
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.green.shade300,
),
color: Colors.green.shade300,
),
),
],
);
@ -396,9 +494,8 @@ class DepartureTime extends ConsumerWidget {
}
}
class Delay extends StatelessWidget {
final Station station;
final TrainDataStation station;
const Delay({
required this.station,
@ -421,20 +518,19 @@ class Delay extends StatelessWidget {
return Text(
"$delay ${delay == 1 ? 'minut' : 'minute'} întârziere",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.red.shade300,
fontSize: 14,
fontStyle: FontStyle.italic,
),
color: Colors.red.shade300,
fontSize: 14,
fontStyle: FontStyle.italic,
),
);
}
else if (delay < 0) {
} else if (delay < 0) {
return Text(
"${-delay} ${delay == -1 ? 'minut' : 'minute'} mai devreme",
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.green.shade300,
fontSize: 14,
fontStyle: FontStyle.italic,
),
color: Colors.green.shade300,
fontSize: 14,
fontStyle: FontStyle.italic,
),
);
}

13
lib/providers.dart

@ -3,13 +3,17 @@ import 'dart:developer';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:info_tren/api/station_data.dart';
import 'package:info_tren/api/train_data.dart';
import 'package:info_tren/models.dart';
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
import 'package:info_tren/utils/default_ui_design.dart';
import 'package:info_tren/utils/iterable_extensions.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'providers.g.dart';
final sharedPreferencesProvider = Provider<SharedPreferences>(
(_) => throw UnimplementedError('Please override in ProviderScope'),
);
@ -76,8 +80,8 @@ final trainInfoArgumentsProvider = Provider<TrainInfoArguments>(
(_) => throw UnimplementedError('Please override in ProviderScope'),
);
final stationDataProvider = FutureProvider.family((ref, String stationName) async {
final data = await getStationData(stationName);
final stationDataProvider = FutureProvider.family((ref, ViewStationArguments args) async {
final data = await getStationData(args.stationName, args.date);
final timer = Timer(const Duration(minutes: 2), () {
ref.invalidateSelf();
@ -93,6 +97,9 @@ final viewStationArgumentsProvider = Provider<ViewStationArguments>(
);
final viewStationDataProvider = Provider((ref) {
final args = ref.watch(viewStationArgumentsProvider);
final data = ref.watch(stationDataProvider(args.stationName));
final data = ref.watch(stationDataProvider(args));
return data;
}, dependencies: [viewStationArgumentsProvider, stationDataProvider]);
@Riverpod(keepAlive: true)
Future<TrainData> trainInfo(TrainInfoRef ref, {required String trainNumber, DateTime? date}) => getTrain(trainNumber, date: date);

120
lib/providers.g.dart

@ -0,0 +1,120 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'providers.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$trainInfoHash() => r'd25aabc3ba656acf6497ec6831e11892178b22c9';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
typedef TrainInfoRef = FutureProviderRef<TrainData>;
/// See also [trainInfo].
@ProviderFor(trainInfo)
const trainInfoProvider = TrainInfoFamily();
/// See also [trainInfo].
class TrainInfoFamily extends Family<AsyncValue<TrainData>> {
/// See also [trainInfo].
const TrainInfoFamily();
/// See also [trainInfo].
TrainInfoProvider call({
required String trainNumber,
DateTime? date,
}) {
return TrainInfoProvider(
trainNumber: trainNumber,
date: date,
);
}
@override
TrainInfoProvider getProviderOverride(
covariant TrainInfoProvider provider,
) {
return call(
trainNumber: provider.trainNumber,
date: provider.date,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'trainInfoProvider';
}
/// See also [trainInfo].
class TrainInfoProvider extends FutureProvider<TrainData> {
/// See also [trainInfo].
TrainInfoProvider({
required this.trainNumber,
this.date,
}) : super.internal(
(ref) => trainInfo(
ref,
trainNumber: trainNumber,
date: date,
),
from: trainInfoProvider,
name: r'trainInfoProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$trainInfoHash,
dependencies: TrainInfoFamily._dependencies,
allTransitiveDependencies: TrainInfoFamily._allTransitiveDependencies,
);
final String trainNumber;
final DateTime? date;
@override
bool operator ==(Object other) {
return other is TrainInfoProvider &&
other.trainNumber == trainNumber &&
other.date == date;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, trainNumber.hashCode);
hash = _SystemHash.combine(hash, date.hashCode);
return _SystemHash.finish(hash);
}
}
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
Loading…
Cancel
Save