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
|
||||
Transitioned to Material 3.
|
||||
Redesigned main page on Material.
|
||||
|
|
|
@ -5,6 +5,6 @@ import 'package:info_tren/api/common.dart';
|
|||
import 'package:info_tren/models/station_data.dart';
|
||||
|
||||
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));
|
||||
}
|
|
@ -6,8 +6,8 @@ part 'station_data.g.dart';
|
|||
class StationData {
|
||||
final String date;
|
||||
final String stationName;
|
||||
final List<StationArrival>? arrivals;
|
||||
final List<StationDeparture>? departures;
|
||||
final List<StationArrDep>? arrivals;
|
||||
final List<StationArrDep>? departures;
|
||||
|
||||
const StationData({required this.date, required this.stationName, required this.arrivals, required this.departures});
|
||||
|
||||
|
@ -16,53 +16,40 @@ class StationData {
|
|||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class StationArrival {
|
||||
class StationArrDep {
|
||||
final int? stoppingTime;
|
||||
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);
|
||||
Map<String, dynamic> toJson() => _$StationArrivalToJson(this);
|
||||
factory StationArrDep.fromJson(Map<String, dynamic> json) => _$StationArrDepFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$StationArrDepToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class StationDeparture {
|
||||
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 {
|
||||
class StationTrain {
|
||||
final String rank;
|
||||
final String number;
|
||||
final String operator;
|
||||
final String origin;
|
||||
final String terminus;
|
||||
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);
|
||||
Map<String, dynamic> toJson() => _$StationTrainArrToJson(this);
|
||||
factory StationTrain.fromJson(Map<String, dynamic> json) => _$StationTrainFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$StationTrainToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class StationTrainDep {
|
||||
final String rank;
|
||||
final String number;
|
||||
final String operator;
|
||||
final String destination;
|
||||
final List<String>? route;
|
||||
class StationStatus {
|
||||
final int delay;
|
||||
final bool real;
|
||||
final String? platform;
|
||||
|
||||
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);
|
||||
Map<String, dynamic> toJson() => _$StationTrainDepToJson(this);
|
||||
factory StationStatus.fromJson(Map<String, dynamic> json) => _$StationStatusFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$StationStatusToJson(this);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ StationData _$StationDataFromJson(Map<String, dynamic> json) => StationData(
|
|||
date: json['date'] as String,
|
||||
stationName: json['stationName'] as String,
|
||||
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(),
|
||||
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(),
|
||||
);
|
||||
|
||||
|
@ -25,68 +25,50 @@ Map<String, dynamic> _$StationDataToJson(StationData instance) =>
|
|||
'departures': instance.departures,
|
||||
};
|
||||
|
||||
StationArrival _$StationArrivalFromJson(Map<String, dynamic> json) =>
|
||||
StationArrival(
|
||||
StationArrDep _$StationArrDepFromJson(Map<String, dynamic> json) =>
|
||||
StationArrDep(
|
||||
stoppingTime: json['stoppingTime'] as int?,
|
||||
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>{
|
||||
'stoppingTime': instance.stoppingTime,
|
||||
'time': instance.time.toIso8601String(),
|
||||
'train': instance.train,
|
||||
'status': instance.status,
|
||||
};
|
||||
|
||||
StationDeparture _$StationDepartureFromJson(Map<String, dynamic> json) =>
|
||||
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(
|
||||
StationTrain _$StationTrainFromJson(Map<String, dynamic> json) => StationTrain(
|
||||
rank: json['rank'] as String,
|
||||
number: json['number'] as String,
|
||||
operator: json['operator'] as String,
|
||||
origin: json['origin'] as String,
|
||||
terminus: json['terminus'] as String,
|
||||
route:
|
||||
(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>{
|
||||
'rank': instance.rank,
|
||||
'number': instance.number,
|
||||
'operator': instance.operator,
|
||||
'origin': instance.origin,
|
||||
'terminus': instance.terminus,
|
||||
'route': instance.route,
|
||||
};
|
||||
|
||||
StationTrainDep _$StationTrainDepFromJson(Map<String, dynamic> json) =>
|
||||
StationTrainDep(
|
||||
rank: json['rank'] as String,
|
||||
number: json['number'] as String,
|
||||
operator: json['operator'] as String,
|
||||
destination: json['destination'] as String,
|
||||
route:
|
||||
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
StationStatus _$StationStatusFromJson(Map<String, dynamic> json) =>
|
||||
StationStatus(
|
||||
delay: json['delay'] as int,
|
||||
real: json['real'] as bool,
|
||||
platform: json['platform'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$StationTrainDepToJson(StationTrainDep instance) =>
|
||||
Map<String, dynamic> _$StationStatusToJson(StationStatus instance) =>
|
||||
<String, dynamic>{
|
||||
'rank': instance.rank,
|
||||
'number': instance.number,
|
||||
'operator': instance.operator,
|
||||
'destination': instance.destination,
|
||||
'route': instance.route,
|
||||
'delay': instance.delay,
|
||||
'real': instance.real,
|
||||
'platform': instance.platform,
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ class ViewStationPage extends StatefulWidget {
|
|||
|
||||
abstract class ViewStationPageState extends State<ViewStationPage> {
|
||||
static const arrivals = 'Sosiri';
|
||||
static const departures = 'Pleacări';
|
||||
static const departures = 'Plecări';
|
||||
static const loadingText = 'Se încarcă...';
|
||||
static const arrivesFrom = 'Sosește 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 buildStationArrivalItem(BuildContext context, StationArrival item);
|
||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item);
|
||||
Widget buildStationArrivalItem(BuildContext context, StationArrDep item);
|
||||
Widget buildStationDepartureItem(BuildContext context, StationArrDep item);
|
||||
|
||||
void onTabChange(int index) {
|
||||
setState(() {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:info_tren/components/loading/loading.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/models/station_data.dart';
|
||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||
|
@ -53,7 +52,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) {
|
||||
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||
return GestureDetector(
|
||||
onTap: () => onTrainTapped(item.train.number),
|
||||
child: CupertinoFormRow(
|
||||
|
@ -77,7 +76,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
|||
children: [
|
||||
TextSpan(text: ViewStationPageState.arrivesFrom),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: item.train.origin),
|
||||
TextSpan(text: item.train.terminus),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -86,7 +85,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) {
|
||||
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||
return GestureDetector(
|
||||
onTap: () => onTrainTapped(item.train.number),
|
||||
child: CupertinoFormRow(
|
||||
|
@ -110,7 +109,7 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
|||
children: [
|
||||
TextSpan(text: ViewStationPageState.departsTo),
|
||||
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:info_tren/components/badge.dart';
|
||||
import 'package:info_tren/components/loading/loading.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/pages/station_arrdep_page/view_station/view_station.dart';
|
||||
|
||||
|
@ -48,64 +50,240 @@ class ViewStationPageStateMaterial extends ViewStationPageState {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) {
|
||||
return ListTile(
|
||||
leading: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: item.train.rank,
|
||||
style: TextStyle(
|
||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
||||
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||
return InkWell(
|
||||
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(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: item.train.rank,
|
||||
style: TextStyle(
|
||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
||||
),
|
||||
),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: item.train.number,),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0 ? ViewStationPageState.arrivedFrom : ViewStationPageState.arrivesFrom),
|
||||
TextSpan(text: ' '),
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: item.time.compareTo(DateTime.now()) < 0 ? ViewStationPageState.arrivedFrom : ViewStationPageState.arrivesFrom),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: item.train.origin),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () => onTrainTapped(item.train.number),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) {
|
||||
return ListTile(
|
||||
leading: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: item.train.rank,
|
||||
style: TextStyle(
|
||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
||||
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||
return InkWell(
|
||||
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(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: item.train.rank,
|
||||
style: TextStyle(
|
||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
||||
),
|
||||
),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: item.train.number,),
|
||||
],
|
||||
),
|
||||
),
|
||||
subtitle: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0 ? ViewStationPageState.departedTo : ViewStationPageState.departsTo),
|
||||
TextSpan(text: ' '),
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: item.time.compareTo(DateTime.now()) < 0 ? ViewStationPageState.departedTo : ViewStationPageState.departsTo),
|
||||
TextSpan(text: ' '),
|
||||
TextSpan(text: item.train.destination),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () => onTrainTapped(item.train.number),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 2.7.6
|
||||
version: 2.7.7
|
||||
|
||||
environment:
|
||||
sdk: ">=2.15.0 <3.0.0"
|
||||
|
|
Loading…
Add table
Reference in a new issue