Improve departures/arrivals page
Show badge for platform Show time deviations (delays, arriving early) Move to API v3
This commit is contained in:
parent
7fcbdc18bd
commit
3c68cf7164
9 changed files with 289 additions and 137 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
v2.7.7
|
||||||
|
Improved departures/arrivals page:
|
||||||
|
- badge for platform (due to limitations in data, platform in only known when a train arrives/departs)
|
||||||
|
- time deviations shown (delays or arriving early)
|
||||||
|
Moved to API v3 for station data.
|
||||||
|
|
||||||
v2.7.6
|
v2.7.6
|
||||||
Transitioned to Material 3.
|
Transitioned to Material 3.
|
||||||
Redesigned main page on Material.
|
Redesigned main page on Material.
|
||||||
|
|
|
@ -5,6 +5,6 @@ import 'package:info_tren/api/common.dart';
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/models/station_data.dart';
|
||||||
|
|
||||||
Future<StationData> getStationData(String stationName) async {
|
Future<StationData> getStationData(String stationName) async {
|
||||||
final response = await http.get(Uri.https(authority, 'v2/station/$stationName'));
|
final response = await http.get(Uri.https(authority, 'v3/stations/$stationName'));
|
||||||
return StationData.fromJson(jsonDecode(response.body));
|
return StationData.fromJson(jsonDecode(response.body));
|
||||||
}
|
}
|
|
@ -6,8 +6,8 @@ part 'station_data.g.dart';
|
||||||
class StationData {
|
class StationData {
|
||||||
final String date;
|
final String date;
|
||||||
final String stationName;
|
final String stationName;
|
||||||
final List<StationArrival>? arrivals;
|
final List<StationArrDep>? arrivals;
|
||||||
final List<StationDeparture>? departures;
|
final List<StationArrDep>? departures;
|
||||||
|
|
||||||
const StationData({required this.date, required this.stationName, required this.arrivals, required this.departures});
|
const StationData({required this.date, required this.stationName, required this.arrivals, required this.departures});
|
||||||
|
|
||||||
|
@ -16,53 +16,40 @@ class StationData {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class StationArrival {
|
class StationArrDep {
|
||||||
final int? stoppingTime;
|
final int? stoppingTime;
|
||||||
final DateTime time;
|
final DateTime time;
|
||||||
final StationTrainArr train;
|
final StationTrain train;
|
||||||
|
final StationStatus status;
|
||||||
|
|
||||||
const StationArrival({required this.stoppingTime, required this.time, required this.train,});
|
const StationArrDep({required this.stoppingTime, required this.time, required this.train, required this.status,});
|
||||||
|
|
||||||
factory StationArrival.fromJson(Map<String, dynamic> json) => _$StationArrivalFromJson(json);
|
factory StationArrDep.fromJson(Map<String, dynamic> json) => _$StationArrDepFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$StationArrivalToJson(this);
|
Map<String, dynamic> toJson() => _$StationArrDepToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class StationDeparture {
|
class StationTrain {
|
||||||
final int? stoppingTime;
|
|
||||||
final DateTime time;
|
|
||||||
final StationTrainDep train;
|
|
||||||
|
|
||||||
const StationDeparture({required this.stoppingTime, required this.time, required this.train,});
|
|
||||||
|
|
||||||
factory StationDeparture.fromJson(Map<String, dynamic> json) => _$StationDepartureFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$StationDepartureToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class StationTrainArr {
|
|
||||||
final String rank;
|
final String rank;
|
||||||
final String number;
|
final String number;
|
||||||
final String operator;
|
final String operator;
|
||||||
final String origin;
|
final String terminus;
|
||||||
final List<String>? route;
|
final List<String>? route;
|
||||||
|
|
||||||
StationTrainArr({required this.rank, required this.number, required this.operator, required this.origin, this.route,});
|
StationTrain({required this.rank, required this.number, required this.operator, required this.terminus, this.route,});
|
||||||
|
|
||||||
factory StationTrainArr.fromJson(Map<String, dynamic> json) => _$StationTrainArrFromJson(json);
|
factory StationTrain.fromJson(Map<String, dynamic> json) => _$StationTrainFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$StationTrainArrToJson(this);
|
Map<String, dynamic> toJson() => _$StationTrainToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class StationTrainDep {
|
class StationStatus {
|
||||||
final String rank;
|
final int delay;
|
||||||
final String number;
|
final bool real;
|
||||||
final String operator;
|
final String? platform;
|
||||||
final String destination;
|
|
||||||
final List<String>? route;
|
|
||||||
|
|
||||||
StationTrainDep({required this.rank, required this.number, required this.operator, required this.destination, this.route,});
|
StationStatus({required this.delay, required this.real, required this.platform});
|
||||||
|
|
||||||
factory StationTrainDep.fromJson(Map<String, dynamic> json) => _$StationTrainDepFromJson(json);
|
factory StationStatus.fromJson(Map<String, dynamic> json) => _$StationStatusFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$StationTrainDepToJson(this);
|
Map<String, dynamic> toJson() => _$StationStatusToJson(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@ StationData _$StationDataFromJson(Map<String, dynamic> json) => StationData(
|
||||||
date: json['date'] as String,
|
date: json['date'] as String,
|
||||||
stationName: json['stationName'] as String,
|
stationName: json['stationName'] as String,
|
||||||
arrivals: (json['arrivals'] as List<dynamic>?)
|
arrivals: (json['arrivals'] as List<dynamic>?)
|
||||||
?.map((e) => StationArrival.fromJson(e as Map<String, dynamic>))
|
?.map((e) => StationArrDep.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
departures: (json['departures'] as List<dynamic>?)
|
departures: (json['departures'] as List<dynamic>?)
|
||||||
?.map((e) => StationDeparture.fromJson(e as Map<String, dynamic>))
|
?.map((e) => StationArrDep.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -25,68 +25,50 @@ Map<String, dynamic> _$StationDataToJson(StationData instance) =>
|
||||||
'departures': instance.departures,
|
'departures': instance.departures,
|
||||||
};
|
};
|
||||||
|
|
||||||
StationArrival _$StationArrivalFromJson(Map<String, dynamic> json) =>
|
StationArrDep _$StationArrDepFromJson(Map<String, dynamic> json) =>
|
||||||
StationArrival(
|
StationArrDep(
|
||||||
stoppingTime: json['stoppingTime'] as int?,
|
stoppingTime: json['stoppingTime'] as int?,
|
||||||
time: DateTime.parse(json['time'] as String),
|
time: DateTime.parse(json['time'] as String),
|
||||||
train: StationTrainArr.fromJson(json['train'] as Map<String, dynamic>),
|
train: StationTrain.fromJson(json['train'] as Map<String, dynamic>),
|
||||||
|
status: StationStatus.fromJson(json['status'] as Map<String, dynamic>),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$StationArrivalToJson(StationArrival instance) =>
|
Map<String, dynamic> _$StationArrDepToJson(StationArrDep instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'stoppingTime': instance.stoppingTime,
|
'stoppingTime': instance.stoppingTime,
|
||||||
'time': instance.time.toIso8601String(),
|
'time': instance.time.toIso8601String(),
|
||||||
'train': instance.train,
|
'train': instance.train,
|
||||||
|
'status': instance.status,
|
||||||
};
|
};
|
||||||
|
|
||||||
StationDeparture _$StationDepartureFromJson(Map<String, dynamic> json) =>
|
StationTrain _$StationTrainFromJson(Map<String, dynamic> json) => StationTrain(
|
||||||
StationDeparture(
|
|
||||||
stoppingTime: json['stoppingTime'] as int?,
|
|
||||||
time: DateTime.parse(json['time'] as String),
|
|
||||||
train: StationTrainDep.fromJson(json['train'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StationDepartureToJson(StationDeparture instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'stoppingTime': instance.stoppingTime,
|
|
||||||
'time': instance.time.toIso8601String(),
|
|
||||||
'train': instance.train,
|
|
||||||
};
|
|
||||||
|
|
||||||
StationTrainArr _$StationTrainArrFromJson(Map<String, dynamic> json) =>
|
|
||||||
StationTrainArr(
|
|
||||||
rank: json['rank'] as String,
|
rank: json['rank'] as String,
|
||||||
number: json['number'] as String,
|
number: json['number'] as String,
|
||||||
operator: json['operator'] as String,
|
operator: json['operator'] as String,
|
||||||
origin: json['origin'] as String,
|
terminus: json['terminus'] as String,
|
||||||
route:
|
route:
|
||||||
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$StationTrainArrToJson(StationTrainArr instance) =>
|
Map<String, dynamic> _$StationTrainToJson(StationTrain instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'rank': instance.rank,
|
'rank': instance.rank,
|
||||||
'number': instance.number,
|
'number': instance.number,
|
||||||
'operator': instance.operator,
|
'operator': instance.operator,
|
||||||
'origin': instance.origin,
|
'terminus': instance.terminus,
|
||||||
'route': instance.route,
|
'route': instance.route,
|
||||||
};
|
};
|
||||||
|
|
||||||
StationTrainDep _$StationTrainDepFromJson(Map<String, dynamic> json) =>
|
StationStatus _$StationStatusFromJson(Map<String, dynamic> json) =>
|
||||||
StationTrainDep(
|
StationStatus(
|
||||||
rank: json['rank'] as String,
|
delay: json['delay'] as int,
|
||||||
number: json['number'] as String,
|
real: json['real'] as bool,
|
||||||
operator: json['operator'] as String,
|
platform: json['platform'] as String?,
|
||||||
destination: json['destination'] as String,
|
|
||||||
route:
|
|
||||||
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$StationTrainDepToJson(StationTrainDep instance) =>
|
Map<String, dynamic> _$StationStatusToJson(StationStatus instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'rank': instance.rank,
|
'delay': instance.delay,
|
||||||
'number': instance.number,
|
'real': instance.real,
|
||||||
'operator': instance.operator,
|
'platform': instance.platform,
|
||||||
'destination': instance.destination,
|
|
||||||
'route': instance.route,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ViewStationPage extends StatefulWidget {
|
||||||
|
|
||||||
abstract class ViewStationPageState extends State<ViewStationPage> {
|
abstract class ViewStationPageState extends State<ViewStationPage> {
|
||||||
static const arrivals = 'Sosiri';
|
static const arrivals = 'Sosiri';
|
||||||
static const departures = 'Pleacări';
|
static const departures = 'Plecări';
|
||||||
static const loadingText = 'Se încarcă...';
|
static const loadingText = 'Se încarcă...';
|
||||||
static const arrivesFrom = 'Sosește de la';
|
static const arrivesFrom = 'Sosește de la';
|
||||||
static const arrivedFrom = 'A sosit de la';
|
static const arrivedFrom = 'A sosit de la';
|
||||||
|
@ -63,8 +63,8 @@ abstract class ViewStationPageState extends State<ViewStationPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function() newFutureBuilder) _, RefreshFutureBuilderSnapshot<StationData> snapshot);
|
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function() newFutureBuilder) _, RefreshFutureBuilderSnapshot<StationData> snapshot);
|
||||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item);
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item);
|
||||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item);
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item);
|
||||||
|
|
||||||
void onTabChange(int index) {
|
void onTabChange(int index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:info_tren/components/sliver_persistent_header_padding.dart';
|
import 'package:info_tren/components/sliver_persistent_header_padding.dart';
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/models/station_data.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
@ -53,7 +52,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) {
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
onTap: () => onTrainTapped(item.train.number),
|
||||||
child: CupertinoFormRow(
|
child: CupertinoFormRow(
|
||||||
|
@ -77,7 +76,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: ViewStationPageState.arrivesFrom),
|
TextSpan(text: ViewStationPageState.arrivesFrom),
|
||||||
TextSpan(text: ' '),
|
TextSpan(text: ' '),
|
||||||
TextSpan(text: item.train.origin),
|
TextSpan(text: item.train.terminus),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -86,7 +85,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) {
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
onTap: () => onTrainTapped(item.train.number),
|
||||||
child: CupertinoFormRow(
|
child: CupertinoFormRow(
|
||||||
|
@ -110,7 +109,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: ViewStationPageState.departsTo),
|
TextSpan(text: ViewStationPageState.departsTo),
|
||||||
TextSpan(text: ' '),
|
TextSpan(text: ' '),
|
||||||
TextSpan(text: item.train.destination),
|
TextSpan(text: item.train.terminus),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:ui';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/components/badge.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/models/station_data.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
|
||||||
|
@ -48,9 +50,53 @@ class ViewStationPageStateMaterial extends ViewStationPageState {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) {
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||||
return ListTile(
|
return InkWell(
|
||||||
leading: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
onTap: () => onTrainTapped(item.train.number),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
decoration: item.status.delay != 0 ? TextDecoration.lineThrough : null,
|
||||||
|
fontSize: item.status.delay != 0 ? 12 : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.delay != 0) Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final newTime = item.time.add(Duration(minutes: item.status.delay));
|
||||||
|
final delay = item.status.delay > 0;
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
'${newTime.toLocal().hour.toString().padLeft(2, '0')}:${newTime.toLocal().minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
color: delay ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: ListTile(
|
||||||
|
isThreeLine: item.status.delay != 0,
|
||||||
title: Text.rich(
|
title: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
|
@ -68,20 +114,108 @@ class ViewStationPageStateMaterial extends ViewStationPageState {
|
||||||
subtitle: Text.rich(
|
subtitle: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: item.time.compareTo(DateTime.now()) < 0 ? ViewStationPageState.arrivedFrom : ViewStationPageState.arrivesFrom),
|
TextSpan(text: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0 ? ViewStationPageState.arrivedFrom : ViewStationPageState.arrivesFrom),
|
||||||
TextSpan(text: ' '),
|
TextSpan(text: ' '),
|
||||||
TextSpan(text: item.train.origin),
|
TextSpan(text: item.train.terminus),
|
||||||
|
if (item.status.delay != 0) ...[
|
||||||
|
TextSpan(text: '\n'),
|
||||||
|
if (item.status.delay.abs() >= 60) ...[
|
||||||
|
TextSpan(text: (item.status.delay.abs() ~/ 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() >= 120 ? ' ore' : ' oră'),
|
||||||
|
if (item.status.delay.abs() % 60 != 0)
|
||||||
|
TextSpan(text: ' și '),
|
||||||
|
],
|
||||||
|
TextSpan(text: (item.status.delay.abs() % 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() > 1 ? ' minute' : ' minut'),
|
||||||
|
TextSpan(text: ' '),
|
||||||
|
if (item.status.delay > 0)
|
||||||
|
TextSpan(
|
||||||
|
text: 'întârziere',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
TextSpan(
|
||||||
|
text: 'mai devreme',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.platform != null)
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: MaterialBadge(
|
||||||
|
text: item.status.platform!,
|
||||||
|
caption: 'Linia',
|
||||||
|
isOnTime: item.status.real && item.status.delay <= 0,
|
||||||
|
isDelayed: item.status.real && item.status.delay > 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) {
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||||
return ListTile(
|
return InkWell(
|
||||||
leading: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
onTap: () => onTrainTapped(item.train.number),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
decoration: item.status.delay != 0 ? TextDecoration.lineThrough : null,
|
||||||
|
fontSize: item.status.delay != 0 ? 12 : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.delay != 0) Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final newTime = item.time.add(Duration(minutes: item.status.delay));
|
||||||
|
final delay = item.status.delay > 0;
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
'${newTime.toLocal().hour.toString().padLeft(2, '0')}:${newTime.toLocal().minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
color: delay ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: ListTile(
|
||||||
|
isThreeLine: item.status.delay != 0,
|
||||||
title: Text.rich(
|
title: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
|
@ -99,13 +233,57 @@ class ViewStationPageStateMaterial extends ViewStationPageState {
|
||||||
subtitle: Text.rich(
|
subtitle: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: item.time.compareTo(DateTime.now()) < 0 ? ViewStationPageState.departedTo : ViewStationPageState.departsTo),
|
TextSpan(text: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0 ? ViewStationPageState.departedTo : ViewStationPageState.departsTo),
|
||||||
TextSpan(text: ' '),
|
TextSpan(text: ' '),
|
||||||
TextSpan(text: item.train.destination),
|
TextSpan(text: item.train.terminus),
|
||||||
|
if (item.status.delay != 0) ...[
|
||||||
|
TextSpan(text: '\n'),
|
||||||
|
if (item.status.delay.abs() >= 60) ...[
|
||||||
|
TextSpan(text: (item.status.delay.abs() ~/ 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() >= 120 ? ' ore' : ' oră'),
|
||||||
|
if (item.status.delay.abs() % 60 != 0)
|
||||||
|
TextSpan(text: ' și '),
|
||||||
|
],
|
||||||
|
TextSpan(text: (item.status.delay.abs() % 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() > 1 ? ' minute' : ' minut'),
|
||||||
|
TextSpan(text: ' '),
|
||||||
|
if (item.status.delay > 0)
|
||||||
|
TextSpan(
|
||||||
|
text: 'întârziere',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
TextSpan(
|
||||||
|
text: 'mai devreme',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.platform != null)
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: MaterialBadge(
|
||||||
|
text: item.status.platform!,
|
||||||
|
caption: 'Linia',
|
||||||
|
isOnTime: item.status.real && item.status.delay <= 0,
|
||||||
|
isDelayed: item.status.real && item.status.delay > 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ description: O aplicație de vizualizare a datelor puse la dispoziție de Inform
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 2.7.6
|
version: 2.7.7
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.15.0 <3.0.0"
|
sdk: ">=2.15.0 <3.0.0"
|
||||||
|
|
Loading…
Add table
Reference in a new issue