Dan Cojocaru
3 years ago
19 changed files with 741 additions and 9 deletions
@ -0,0 +1 @@
|
||||
const authority = 'scraper.infotren.dcdevelop.xyz'; |
@ -0,0 +1,10 @@
|
||||
import 'dart:convert'; |
||||
|
||||
import 'package:http/http.dart' as http; |
||||
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')); |
||||
return StationData.fromJson(jsonDecode(response.body)); |
||||
} |
@ -0,0 +1,11 @@
|
||||
import 'dart:convert'; |
||||
|
||||
import 'package:http/http.dart' as http; |
||||
import 'package:info_tren/api/common.dart'; |
||||
import 'package:info_tren/models/stations_result.dart'; |
||||
|
||||
Future<List<StationsResult>> get stations async { |
||||
final result = await http.get(Uri.https(authority, 'v2/stations')); |
||||
final data = jsonDecode(result.body) as List<dynamic>; |
||||
return data.map((e) => StationsResult.fromJson(e)).toList(growable: false,); |
||||
} |
@ -1,9 +1,8 @@
|
||||
import 'package:http/http.dart' as http; |
||||
import 'package:info_tren/api/common.dart'; |
||||
import 'package:info_tren/models/train_data.dart'; |
||||
|
||||
const AUTHORITY = 'scraper.infotren.dcdevelop.xyz'; |
||||
|
||||
Future<TrainData> getTrain(String trainNumber) async { |
||||
final response = await http.get(Uri.https(AUTHORITY, 'v2/train/$trainNumber')); |
||||
final response = await http.get(Uri.https(authority, 'v2/train/$trainNumber')); |
||||
return trainDataFromJson(response.body); |
||||
} |
@ -0,0 +1,43 @@
|
||||
import 'package:flutter/cupertino.dart'; |
||||
|
||||
class CupertinoListTile extends StatelessWidget { |
||||
final Widget? leading; |
||||
final Widget? title; |
||||
final Widget? subtitle; |
||||
final Widget? trailing; |
||||
|
||||
const CupertinoListTile({ Key? key, this.leading, this.title, this.subtitle, this.trailing, }) : super(key: key); |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return Row( |
||||
mainAxisSize: MainAxisSize.max, |
||||
children: [ |
||||
if (leading != null) |
||||
leading!, |
||||
Expanded( |
||||
child: Column( |
||||
mainAxisSize: MainAxisSize.min, |
||||
children: [ |
||||
if (title != null) |
||||
title!, |
||||
if (subtitle != null) |
||||
CupertinoTheme( |
||||
child: subtitle!, |
||||
data: CupertinoTheme.of(context).copyWith( |
||||
textTheme: CupertinoTextThemeData( |
||||
textStyle: TextStyle( |
||||
fontSize: CupertinoTheme.of(context).textTheme.textStyle.fontSize! - 2, |
||||
) |
||||
) |
||||
), |
||||
), |
||||
], |
||||
), |
||||
), |
||||
if (trailing != null) |
||||
trailing!, |
||||
], |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,68 @@
|
||||
import 'package:json_annotation/json_annotation.dart'; |
||||
|
||||
part 'station_data.g.dart'; |
||||
|
||||
@JsonSerializable() |
||||
class StationData { |
||||
final String date; |
||||
final String stationName; |
||||
final List<StationArrival>? arrivals; |
||||
final List<StationDeparture>? departures; |
||||
|
||||
const StationData({required this.date, required this.stationName, required this.arrivals, required this.departures}); |
||||
|
||||
factory StationData.fromJson(Map<String, dynamic> json) => _$StationDataFromJson(json); |
||||
Map<String, dynamic> toJson() => _$StationDataToJson(this); |
||||
} |
||||
|
||||
@JsonSerializable() |
||||
class StationArrival { |
||||
final int? stoppingTime; |
||||
final DateTime time; |
||||
final StationTrainArr train; |
||||
|
||||
const StationArrival({required this.stoppingTime, required this.time, required this.train,}); |
||||
|
||||
factory StationArrival.fromJson(Map<String, dynamic> json) => _$StationArrivalFromJson(json); |
||||
Map<String, dynamic> toJson() => _$StationArrivalToJson(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 { |
||||
final String rank; |
||||
final String number; |
||||
final String operator; |
||||
final String origin; |
||||
final List<String>? route; |
||||
|
||||
StationTrainArr({required this.rank, required this.number, required this.operator, required this.origin, this.route,}); |
||||
|
||||
factory StationTrainArr.fromJson(Map<String, dynamic> json) => _$StationTrainArrFromJson(json); |
||||
Map<String, dynamic> toJson() => _$StationTrainArrToJson(this); |
||||
} |
||||
|
||||
@JsonSerializable() |
||||
class StationTrainDep { |
||||
final String rank; |
||||
final String number; |
||||
final String operator; |
||||
final String destination; |
||||
final List<String>? route; |
||||
|
||||
StationTrainDep({required this.rank, required this.number, required this.operator, required this.destination, this.route,}); |
||||
|
||||
factory StationTrainDep.fromJson(Map<String, dynamic> json) => _$StationTrainDepFromJson(json); |
||||
Map<String, dynamic> toJson() => _$StationTrainDepToJson(this); |
||||
} |
@ -0,0 +1,92 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
||||
part of 'station_data.dart'; |
||||
|
||||
// ************************************************************************** |
||||
// JsonSerializableGenerator |
||||
// ************************************************************************** |
||||
|
||||
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>)) |
||||
.toList(), |
||||
departures: (json['departures'] as List<dynamic>?) |
||||
?.map((e) => StationDeparture.fromJson(e as Map<String, dynamic>)) |
||||
.toList(), |
||||
); |
||||
|
||||
Map<String, dynamic> _$StationDataToJson(StationData instance) => |
||||
<String, dynamic>{ |
||||
'date': instance.date, |
||||
'stationName': instance.stationName, |
||||
'arrivals': instance.arrivals, |
||||
'departures': instance.departures, |
||||
}; |
||||
|
||||
StationArrival _$StationArrivalFromJson(Map<String, dynamic> json) => |
||||
StationArrival( |
||||
stoppingTime: json['stoppingTime'] as int?, |
||||
time: DateTime.parse(json['time'] as String), |
||||
train: StationTrainArr.fromJson(json['train'] as Map<String, dynamic>), |
||||
); |
||||
|
||||
Map<String, dynamic> _$StationArrivalToJson(StationArrival instance) => |
||||
<String, dynamic>{ |
||||
'stoppingTime': instance.stoppingTime, |
||||
'time': instance.time.toIso8601String(), |
||||
'train': instance.train, |
||||
}; |
||||
|
||||
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( |
||||
rank: json['rank'] as String, |
||||
number: json['number'] as String, |
||||
operator: json['operator'] as String, |
||||
origin: json['origin'] as String, |
||||
route: |
||||
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(), |
||||
); |
||||
|
||||
Map<String, dynamic> _$StationTrainArrToJson(StationTrainArr instance) => |
||||
<String, dynamic>{ |
||||
'rank': instance.rank, |
||||
'number': instance.number, |
||||
'operator': instance.operator, |
||||
'origin': instance.origin, |
||||
'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(), |
||||
); |
||||
|
||||
Map<String, dynamic> _$StationTrainDepToJson(StationTrainDep instance) => |
||||
<String, dynamic>{ |
||||
'rank': instance.rank, |
||||
'number': instance.number, |
||||
'operator': instance.operator, |
||||
'destination': instance.destination, |
||||
'route': instance.route, |
||||
}; |
@ -0,0 +1,14 @@
|
||||
import 'package:json_annotation/json_annotation.dart'; |
||||
|
||||
part 'stations_result.g.dart'; |
||||
|
||||
@JsonSerializable() |
||||
class StationsResult { |
||||
final String name; |
||||
final List<String>? stoppedAtBy; |
||||
|
||||
const StationsResult({required this.name, this.stoppedAtBy}); |
||||
|
||||
factory StationsResult.fromJson(Map<String, dynamic> json) => _$StationsResultFromJson(json); |
||||
Map<String, dynamic> toJson() => _$StationsResultToJson(this); |
||||
} |
@ -0,0 +1,21 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND |
||||
|
||||
part of 'stations_result.dart'; |
||||
|
||||
// ************************************************************************** |
||||
// JsonSerializableGenerator |
||||
// ************************************************************************** |
||||
|
||||
StationsResult _$StationsResultFromJson(Map<String, dynamic> json) => |
||||
StationsResult( |
||||
name: json['name'] as String, |
||||
stoppedAtBy: (json['stoppedAtBy'] as List<dynamic>?) |
||||
?.map((e) => e as String) |
||||
.toList(), |
||||
); |
||||
|
||||
Map<String, dynamic> _$StationsResultToJson(StationsResult instance) => |
||||
<String, dynamic>{ |
||||
'name': instance.name, |
||||
'stoppedAtBy': instance.stoppedAtBy, |
||||
}; |
@ -1,9 +1,53 @@
|
||||
import 'package:flutter/cupertino.dart'; |
||||
import 'package:info_tren/components/cupertino_divider.dart'; |
||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart'; |
||||
|
||||
class SelectStationPageStateCupertino extends SelectStationPageState { |
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return Container(); |
||||
return CupertinoPageScaffold( |
||||
navigationBar: CupertinoNavigationBar( |
||||
middle: Text(SelectStationPageState.pageTitle), |
||||
), |
||||
child: SafeArea( |
||||
bottom: false, |
||||
child: Column( |
||||
mainAxisSize: MainAxisSize.max, |
||||
children: [ |
||||
Padding( |
||||
padding: const EdgeInsets.all(4), |
||||
child: CupertinoTextField( |
||||
controller: textEditingController, |
||||
autofocus: true, |
||||
placeholder: SelectStationPageState.textFieldLabel, |
||||
textInputAction: TextInputAction.search, |
||||
onChanged: onTextChanged, |
||||
), |
||||
), |
||||
Expanded( |
||||
child: ListView.builder( |
||||
itemBuilder: (context, index) { |
||||
return Column( |
||||
mainAxisSize: MainAxisSize.min, |
||||
crossAxisAlignment: CrossAxisAlignment.stretch, |
||||
children: [ |
||||
GestureDetector( |
||||
child: Padding( |
||||
padding: const EdgeInsets.all(8.0), |
||||
child: Text(filteredStations[index]), |
||||
), |
||||
onTap: () => onSuggestionSelected(filteredStations[index]), |
||||
), |
||||
CupertinoDivider(), |
||||
], |
||||
); |
||||
}, |
||||
itemCount: filteredStations.length, |
||||
), |
||||
), |
||||
], |
||||
), |
||||
), |
||||
); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,89 @@
|
||||
import 'package:flutter/widgets.dart'; |
||||
import 'package:info_tren/api/station_data.dart'; |
||||
import 'package:info_tren/components/refresh_future_builder.dart'; |
||||
import 'package:info_tren/models/station_data.dart'; |
||||
import 'package:info_tren/models/ui_design.dart'; |
||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_cupertino.dart'; |
||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_material.dart'; |
||||
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart'; |
||||
import 'package:info_tren/utils/default_ui_design.dart'; |
||||
|
||||
class ViewStationPage extends StatefulWidget { |
||||
final UiDesign? uiDesign; |
||||
final String stationName; |
||||
|
||||
const ViewStationPage({ Key? key, required this.stationName, this.uiDesign }) : super(key: key); |
||||
|
||||
static String routeName = '/stationArrDep/viewStation'; |
||||
|
||||
@override |
||||
ViewStationPageState createState() { |
||||
final uiDesign = this.uiDesign ?? defaultUiDesign; |
||||
switch (uiDesign) { |
||||
case UiDesign.MATERIAL: |
||||
return ViewStationPageStateMaterial(); |
||||
case UiDesign.CUPERTINO: |
||||
return ViewStationPageStateCupertino(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
abstract class ViewStationPageState extends State<ViewStationPage> { |
||||
static const arrivals = 'Sosiri'; |
||||
static const departures = 'Pleacări'; |
||||
static const loadingText = 'Se încarcă...'; |
||||
static const arrivesFrom = 'Sosește de la'; |
||||
static const departsTo = 'Pleacă către'; |
||||
|
||||
ViewStationPageTab tab = ViewStationPageTab.departures; |
||||
late String stationName; |
||||
late Future<StationData> Function() futureCreator; |
||||
|
||||
@override |
||||
void initState() { |
||||
initData(); |
||||
super.initState(); |
||||
} |
||||
|
||||
@override |
||||
void didChangeDependencies() { |
||||
if (stationName != widget.stationName) { |
||||
setState(() { |
||||
initData(); |
||||
}); |
||||
} |
||||
super.didChangeDependencies(); |
||||
} |
||||
|
||||
void initData() { |
||||
stationName = widget.stationName; |
||||
futureCreator = () => getStationData(stationName); |
||||
} |
||||
|
||||
Widget buildContent(BuildContext context, Future Function() refresh, RefreshFutureBuilderSnapshot<StationData> snapshot); |
||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item); |
||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item); |
||||
|
||||
void onTabChange(int index) { |
||||
setState(() { |
||||
tab = ViewStationPageTab.values[index]; |
||||
}); |
||||
} |
||||
|
||||
void onTrainTapped(String trainNumber) { |
||||
Navigator.of(context).pushNamed(TrainInfo.routeName, arguments: trainNumber); |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return RefreshFutureBuilder( |
||||
futureCreator: futureCreator, |
||||
builder: buildContent, |
||||
); |
||||
} |
||||
} |
||||
|
||||
enum ViewStationPageTab { |
||||
arrivals, |
||||
departures, |
||||
} |
@ -0,0 +1,120 @@
|
||||
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'; |
||||
|
||||
class ViewStationPageStateCupertino extends ViewStationPageState { |
||||
@override |
||||
Widget buildContent(BuildContext context, Future Function() refresh, RefreshFutureBuilderSnapshot<StationData> snapshot) { |
||||
return CupertinoPageScaffold( |
||||
navigationBar: CupertinoNavigationBar( |
||||
middle: Text(snapshot.hasData ? snapshot.data!.stationName : stationName), |
||||
), |
||||
child: snapshot.hasData ? CupertinoTabScaffold( |
||||
tabBar: CupertinoTabBar( |
||||
items: [ |
||||
BottomNavigationBarItem( |
||||
icon: Icon(CupertinoIcons.arrow_down), |
||||
label: ViewStationPageState.arrivals, |
||||
), |
||||
BottomNavigationBarItem( |
||||
icon: Icon(CupertinoIcons.arrow_up), |
||||
label: ViewStationPageState.departures, |
||||
), |
||||
], |
||||
onTap: onTabChange, |
||||
currentIndex: tab.index, |
||||
), |
||||
tabBuilder: (context, index) { |
||||
final topPadding = MediaQuery.of(context).padding.top; |
||||
return NestedScrollView( |
||||
headerSliverBuilder: (context, _) { |
||||
return [SliverPersistentHeaderPadding(maxHeight: topPadding)]; |
||||
}, |
||||
body: CustomScrollView( |
||||
slivers: [ |
||||
SliverList( |
||||
delegate: SliverChildBuilderDelegate( |
||||
(context, index) { |
||||
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]); |
||||
}, |
||||
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0, |
||||
), |
||||
), |
||||
], |
||||
), |
||||
); |
||||
}, |
||||
) : snapshot.state == RefreshFutureBuilderState.waiting ? Loading(text: ViewStationPageState.loadingText, uiDesign: widget.uiDesign,) : Container(), |
||||
); |
||||
} |
||||
|
||||
@override |
||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) { |
||||
return GestureDetector( |
||||
onTap: () => onTrainTapped(item.train.number), |
||||
child: CupertinoFormRow( |
||||
child: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'), |
||||
prefix: 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,), |
||||
], |
||||
), |
||||
), |
||||
helper: Text.rich( |
||||
TextSpan( |
||||
children: [ |
||||
TextSpan(text: ViewStationPageState.arrivesFrom), |
||||
TextSpan(text: ' '), |
||||
TextSpan(text: item.train.origin), |
||||
], |
||||
), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
|
||||
@override |
||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) { |
||||
return GestureDetector( |
||||
onTap: () => onTrainTapped(item.train.number), |
||||
child: CupertinoFormRow( |
||||
child: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'), |
||||
prefix: 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,), |
||||
], |
||||
), |
||||
), |
||||
helper: Text.rich( |
||||
TextSpan( |
||||
children: [ |
||||
TextSpan(text: ViewStationPageState.departsTo), |
||||
TextSpan(text: ' '), |
||||
TextSpan(text: item.train.destination), |
||||
], |
||||
), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.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'; |
||||
|
||||
class ViewStationPageStateMaterial extends ViewStationPageState { |
||||
@override |
||||
Widget buildContent(BuildContext context, Future Function() refresh, RefreshFutureBuilderSnapshot<StationData> snapshot) { |
||||
return Scaffold( |
||||
appBar: AppBar( |
||||
title: Text(snapshot.hasData ? snapshot.data!.stationName : stationName), |
||||
centerTitle: true, |
||||
), |
||||
body: snapshot.state == RefreshFutureBuilderState.waiting ? Loading(text: ViewStationPageState.loadingText, uiDesign: widget.uiDesign,) : CustomScrollView( |
||||
slivers: [ |
||||
SliverToBoxAdapter(child: SafeArea(child: Container(), left: false, bottom: false, right: false,),), |
||||
SliverList( |
||||
delegate: SliverChildBuilderDelegate( |
||||
(context, index) { |
||||
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]); |
||||
}, |
||||
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0, |
||||
), |
||||
), |
||||
], |
||||
), |
||||
bottomNavigationBar: snapshot.hasData ? BottomNavigationBar( |
||||
items: [ |
||||
BottomNavigationBarItem( |
||||
icon: Icon(Icons.arrow_downward), |
||||
label: ViewStationPageState.arrivals, |
||||
), |
||||
BottomNavigationBarItem( |
||||
icon: Icon(Icons.arrow_upward), |
||||
label: ViewStationPageState.departures, |
||||
), |
||||
], |
||||
currentIndex: tab.index, |
||||
onTap: onTabChange, |
||||
) : null, |
||||
); |
||||
} |
||||
|
||||
@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, |
||||
), |
||||
), |
||||
TextSpan(text: ' '), |
||||
TextSpan(text: item.train.number,), |
||||
], |
||||
), |
||||
), |
||||
subtitle: Text.rich( |
||||
TextSpan( |
||||
children: [ |
||||
TextSpan(text: 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, |
||||
), |
||||
), |
||||
TextSpan(text: ' '), |
||||
TextSpan(text: item.train.number,), |
||||
], |
||||
), |
||||
), |
||||
subtitle: Text.rich( |
||||
TextSpan( |
||||
children: [ |
||||
TextSpan(text: ViewStationPageState.departsTo), |
||||
TextSpan(text: ' '), |
||||
TextSpan(text: item.train.destination), |
||||
], |
||||
), |
||||
), |
||||
onTap: () => onTrainTapped(item.train.number), |
||||
); |
||||
} |
||||
} |
Loading…
Reference in new issue