import 'package:flutter/cupertino.dart'; import 'package:info_tren/models/train_data.dart'; import 'package:info_tren/train_info_page/train_info.dart'; import 'package:info_tren/train_info_page/train_info_animation_helpers.dart'; import 'package:info_tren/train_info_page/train_info_constants.dart'; import 'package:info_tren/utils/stream_list.dart'; class TrainInfoCupertino extends StatefulWidget { final int trainNumber; TrainInfoCupertino({@required this.trainNumber}); @override _TrainInfoCupertinoState createState() => _TrainInfoCupertinoState(); } class _TrainInfoCupertinoState extends State with TrainInfoMixin { @override void initState() { super.initState(); title = widget.trainNumber.toString(); showTrainData = false; requestedData = false; } @override void didChangeDependencies() { super.didChangeDependencies(); if (!requestedData) { requestedData = true; TrainDataWebViewAdapter.of(context).loadTrain(widget.trainNumber).then((value) { setState(() { lookupResult = value; }); if (lookupResult == TrainLookupResult.NOT_FOUND) { Future.delayed(Duration(seconds: 5), () { Navigator.of(context).pop(); }); } else if (lookupResult == TrainLookupResult.FOUND) { Future.delayed(Duration(seconds: 1, milliseconds: 500), () { setState(() { showTrainData = true; }); }); } }); } } @override Widget build(BuildContext context) { if (!showTrainData) { return _TrainDataCupertinoBefore( title: title, lookupResult: lookupResult, ); } else { return _TrainDataCupertinoAfter( title: title, ); } } } class _TrainDataCupertinoBefore extends StatefulWidget { final String title; final TrainLookupResult lookupResult; _TrainDataCupertinoBefore({ @required this.title, @required this.lookupResult, }); @override __TrainDataCupertinoBeforeState createState() => __TrainDataCupertinoBeforeState(); } class __TrainDataCupertinoBeforeState extends State<_TrainDataCupertinoBefore> { @override Widget build(BuildContext context) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(widget.title ?? ""), ), child: SafeArea( child: StreamBuilder( stream: TrainDataWebViewAdapter.of(context).progressStream, builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return Container(); case ConnectionState.waiting: return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ CupertinoActivityIndicator(), Text( "Conectare...", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 18, fontWeight: FontWeight.bold, ), ), ], ), ); case ConnectionState.active: break; case ConnectionState.done: Navigator.of(context).pop(); return Container(); } return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ ProgressReportDisplayEntry( key: ValueKey(1), completed: 1 <= snapshot.data.current, waitingText: "Se crează WebView", completedText: "WebView a fost creat", ), ProgressReportDisplayEntry( key: ValueKey(2), completed: 2 <= snapshot.data.current, waitingText: "Se încarcă pagina Informatica Feroviară", completedText: "Pagina Informatica Feroviară a fost încărcată", ), ProgressReportDisplayEntry( key: ValueKey(3), completed: 3 <= snapshot.data.current, waitingText: "Se încarcă informațiile despre tren", completedText: "Informațiile despre tren au fost încărcate", ), if (widget.lookupResult != null) ...[ Container(height: 20,), SizedBox( width: double.infinity, child: AnimatedBackground( animationDuration: Duration(milliseconds: 250), initialColor: CupertinoTheme.of(context).scaffoldBackgroundColor, backgroundColor: widget.lookupResult == TrainLookupResult.FOUND ? BACKGROUND_GREEN : BACKGROUND_RED, child: Center( child: Row( children: [ Expanded(child: Container(),), if (widget.lookupResult == TrainLookupResult.FOUND) Padding( padding: const EdgeInsets.fromLTRB(8, 8, 0, 8), child: Center( child: CupertinoActivityIndicator() ), ), Padding( padding: const EdgeInsets.all(8.0), child: Text( widget.lookupResult == TrainLookupResult.FOUND ? "Trenul a fost găsit" : widget.lookupResult == TrainLookupResult.NOT_FOUND ? "Trenul nu a fost găsit" : "A apărut o eroare în căutarea trenului", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 20), ), ), Expanded(child: Container(),), ], ), ), ), ), ], ], ), ); } ), ), ); } } class _TrainDataCupertinoAfter extends StatefulWidget { final String title; _TrainDataCupertinoAfter({ @required this.title, }); @override __TrainDataCupertinoAfterState createState() => __TrainDataCupertinoAfterState(); } class __TrainDataCupertinoAfterState extends State<_TrainDataCupertinoAfter> { @override Widget build(BuildContext context) { return FutureBuilder( future: TrainDataWebViewAdapter.of(context).trainData(onInvalidation: () { Navigator.of(context).pop(); }), builder: (context, snapshot) { if (!snapshot.hasData) { return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: Text(widget.title ?? ""), ), child: SafeArea( child: Center( child: CupertinoActivityIndicator(), ), ), ); } return CupertinoPageScaffold( navigationBar: CupertinoNavigationBar( middle: FutureBuilder>( future: Future.wait([ snapshot.data.rang, snapshot.data.trainNumber ]), builder: (context, snapshot) { if (snapshot.hasData) { return Text("Informații despre ${snapshot.data[0]} ${snapshot.data[1]}"); } else { return Text(widget.title ?? ""); } }, ), ), child: SafeArea( top: false, bottom: false, child: Builder( builder: (context) { final topPadding = MediaQuery.of(context).padding.top; return CustomScrollView( slivers: [ SliverToBoxAdapter( child: Padding( padding: EdgeInsets.only( top: topPadding, ), child: Container(), ), ), DisplayTrainID(trainData: snapshot.data,), DisplayTrainOperator(trainData: snapshot.data,), DisplayTrainRoute(trainData: snapshot.data,), DisplayTrainDeparture(trainData: snapshot.data,), SliverToBoxAdapter( child: CupertinoDivider( color: FOREGROUND_WHITE, ), ), DisplayTrainLastInfo(trainData: snapshot.data,), SliverToBoxAdapter( child: CupertinoDivider(), ), SliverToBoxAdapter( child: IntrinsicHeight( child: Row( children: [ Expanded( child: DisplayTrainNextStop(trainData: snapshot.data,), ), SizedBox( height: double.infinity, child: CupertinoVerticalDivider(), ), Expanded( child: DisplayTrainDestination(trainData: snapshot.data,), ) ], ), ), ), SliverToBoxAdapter( child: CupertinoDivider(), ), SliverToBoxAdapter( child: IntrinsicHeight( child: Row( children: [ Expanded( child: DisplayTrainRouteDuration(trainData: snapshot.data,), ), SizedBox( height: double.infinity, child: CupertinoVerticalDivider(), ), Expanded( child: DisplayTrainRouteDistance(trainData: snapshot.data,), ) ], ), ), ), SliverToBoxAdapter( child: CupertinoDivider( color: FOREGROUND_WHITE, ), ), DisplayTrainStations( trainData: snapshot.data, pageLoadFuture: TrainDataWebViewAdapter.of(context).nextLoadFuture, ), SliverToBoxAdapter( child: Container( height: MediaQuery.of(context).viewPadding.bottom, ), ), ], ); } ), ), ); }, ); // return CupertinoPageScaffold( // navigationBar: CupertinoNavigationBar( // middle: Text(title ?? ""), // ), // child: SafeArea( // bottom: false, // child: FutureBuilder( // future: TrainDataWebViewAdapter.of(context).trainData(onInvalidation: () { // Navigator.of(context).pop(); // }), // builder: (context, snapshot) { // if (!snapshot.hasData) { // return Center( // child: CupertinoActivityIndicator(), // ); // } // try { // Future.wait([ // snapshot.data.rang, // snapshot.data.trainNumber // ]).then((values) { // setState(() { // title = "Informații despre ${values[0]} ${values[1]}"; // }); // }); // return CustomScrollView( // slivers: [ // DisplayTrainID(data: snapshot.data,), // DisplayTrainOperator(data: snapshot.data,), // DisplayTrainRoute(data: snapshot.data,), // DisplayTrainDeparture(data: snapshot.data,), // SliverToBoxAdapter( // child: CupertinoDivider( // color: FOREGROUND_WHITE, // ), // ), // DisplayTrainLastInfo(data: snapshot.data,), // SliverToBoxAdapter( // child: CupertinoDivider(), // ), // SliverToBoxAdapter( // child: IntrinsicHeight( // child: Row( // children: [ // Expanded( // child: DisplayTrainNextStop(data: snapshot.data,), // ), // SizedBox( // height: double.infinity, // child: CupertinoVerticalDivider(), // ), // Expanded( // child: DisplayTrainDestination(data: snapshot.data,), // ) // ], // ), // ), // ), // SliverToBoxAdapter( // child: CupertinoDivider(), // ), // SliverToBoxAdapter( // child: IntrinsicHeight( // child: Row( // children: [ // Expanded( // child: DisplayTrainRouteDuration(data: snapshot.data,), // ), // SizedBox( // height: double.infinity, // child: CupertinoVerticalDivider(), // ), // Expanded( // child: DisplayTrainRouteDistance(data: snapshot.data,), // ) // ], // ), // ), // ), // SliverToBoxAdapter( // child: CupertinoDivider( // color: FOREGROUND_WHITE, // ), // ), // DisplayTrainStations( // data: snapshot.data, // pageLoadFuture: TrainDataWebViewAdapter.of(context).nextLoadFuture, // ), // ], // ); // } // on OnDemandInvalidatedException { // Navigator.of(context).pop(); // print("Got OnDemandInvalidatedException!"); // return Container(); // } // }, // ), // ), // ); } } class DisplayTrainID extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainID({@required this.trainData}); @override Widget build(BuildContext context) { return SliverToBoxAdapter( child: FutureDisplay( future: Future.wait([ trainData.rang, trainData.trainNumber ]), builder: (context, datas) { return Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Text( "${datas[0]} ${datas[1]}", style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle, ), ), ); }, ), ); } } class DisplayTrainRoute extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainRoute({@required this.trainData}); @override Widget build(BuildContext context) { return SliverToBoxAdapter( child: FutureDisplay( future: Future.wait([trainData.route.from, trainData.route.to]), builder: (context, routePieces) { return Row( children: [ Center( child: Padding( padding: const EdgeInsets.all(4), child: Text( routePieces[0], style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 16, ), ), ), ), Expanded(child: Container(),), Center(child: Text("-")), Expanded(child: Container(),), Center( child: Padding( padding: const EdgeInsets.all(4), child: Text( routePieces[1], style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 16, ), textAlign: TextAlign.right, ), ), ), ], ); }, ), ); } } class DisplayTrainOperator extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainOperator({@required this.trainData}); @override Widget build(BuildContext context) { return SliverToBoxAdapter( child: FutureDisplay( future: trainData.operator, builder: (context, operator) { return Center( child: Text( operator, style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 14, fontStyle: FontStyle.italic, ), ), ); }, ), ); } } class DisplayTrainDeparture extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainDeparture({@required this.trainData}); @override Widget build(BuildContext context) { return SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(2), child: FutureDisplay( future: trainData.departureDate, builder: (context, dataPlecare) { return Text( "Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontStyle: FontStyle.italic, fontWeight: FontWeight.w200, ), textAlign: TextAlign.center, ); }, ), ), ); } } class DisplayTrainLastInfo extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainLastInfo({@required this.trainData}); @override Widget build(BuildContext context) { return SliverToBoxAdapter( child: Column( mainAxisSize: MainAxisSize.min, children: [ Center( child: Padding( padding: const EdgeInsets.all(2), child: Text( "Ultima informație", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), ), Row( children: [ Padding( padding: const EdgeInsets.all(4), child: FutureDisplay( future: trainData.lastInfo.station, builder: (context, station) { return Text( station, style: CupertinoTheme.of(context).textTheme.textStyle, textAlign: TextAlign.left, ); }, ), ), Expanded(child: Container(),), Padding( padding: const EdgeInsets.all(4), child: FutureDisplay( future: trainData.lastInfo.event, builder: (context, event) { return Text( event, style: CupertinoTheme.of(context).textTheme.textStyle, textAlign: TextAlign.right, ); }, ), ), ], ), FutureDisplay( future: trainData.lastInfo.dateAndTime, builder: (context, dt) { return Text( "Raportat în ${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year.toString().padLeft(4, '0')}, la ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}", textAlign: TextAlign.center, ); }, ), FutureBuilder( initialData: 0, future: trainData.lastInfo.delay, builder: (context, snapshot) { if (snapshot.data == 0) { return Container(); } if (snapshot.data > 0) { return Text( "${snapshot.data} minute întârziere", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 14, color: Color.fromRGBO(200, 30, 15, 1), ), ); } else { return Text( "${-snapshot.data} minute mai devreme", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 12, color: Color.fromRGBO(15, 200, 15, 1), ), ); } }, ) ], ), ); } } class DisplayTrainNextStop extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainNextStop({@required this.trainData}); @override Widget build(BuildContext context) { return FutureBuilder( future: trainData.nextStop.stationName, builder: (context, snapshot) { if (!snapshot.hasData) return Container(); return Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(4), child: Text( "Următoarea oprire", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 20, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), ), CupertinoDivider( color: Color.fromRGBO(15, 15, 15, 1), ), FutureDisplay( future: trainData.nextStop.stationName, builder: (context, station) { return Padding( padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), child: Text( station, style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 18, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), ); }, ), FutureDisplay( future: trainData.nextStop.arrival, builder: (context, arrival) { const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"]; return Column( mainAxisSize: MainAxisSize.min, children: [ Text( "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 14, ), textAlign: TextAlign.center, ), Text( "la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 14, ), textAlign: TextAlign.center, ), ], ); }, ) ], ); } ); } } class DisplayTrainDestination extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainDestination({@required this.trainData}); @override Widget build(BuildContext context) { return FutureBuilder( future: trainData.destination.stationName, builder: (context, snapshot) { if (!snapshot.hasData) return Container(); return Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(4), child: Text( "Destinația", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 20, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), ), CupertinoDivider( color: Color.fromRGBO(15, 15, 15, 1), ), FutureDisplay( future: trainData.destination.stationName, builder: (context, station) { return Padding( padding: const EdgeInsets.fromLTRB(4, 0, 4, 0), child: Text( station, style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 18, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), ); }, ), FutureDisplay( future: trainData.destination.arrival, builder: (context, arrival) { const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"]; return Column( mainAxisSize: MainAxisSize.min, children: [ Text( "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 14, ), textAlign: TextAlign.center, ), Text( "la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 14, ), textAlign: TextAlign.center, ), ], ); }, ) ], ); } ); } } class DisplayTrainRouteDistance extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainRouteDistance({@required this.trainData}); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ Text( "Distanța rutei", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 18, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), FutureDisplay( future: trainData.routeDistance, builder: (context, distance) { return Text( "$distance km", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 16, ), textAlign: TextAlign.center, ); }, ), ], ); } } class DisplayTrainRouteDuration extends StatelessWidget { final OnDemandTrainData trainData; DisplayTrainRouteDuration({@required this.trainData}); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ Text( "Durata rutei", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 18, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), FutureDisplay( future: trainData.routeDuration, builder: (context, duration) { var durationString = StringBuffer(); bool firstWritten = false; if (duration.inDays > 0) { firstWritten = true; if (duration.inDays == 1) durationString.write("1 zi"); else durationString.write("${duration.inDays} zile"); duration -= Duration(days: duration.inDays); } if (duration.inHours > 0) { if (firstWritten) { durationString.write(", "); } firstWritten = true; if (duration.inHours == 1) durationString.write("1 oră"); else durationString.write("${duration.inHours} ore"); duration -= Duration(hours: duration.inHours); } if (duration.inMinutes > 0) { if (firstWritten) { durationString.write(", "); } firstWritten = true; if (duration.inMinutes == 1) durationString.write("1 minut"); else durationString.write("${duration.inMinutes} minute"); duration -= Duration(minutes: duration.inMinutes); } return Text( durationString.toString(), style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 16, ), textAlign: TextAlign.center, ); }, ), ], ); } } class DisplayTrainStations extends StatelessWidget { final OnDemandTrainData trainData; final Future pageLoadFuture; DisplayTrainStations({@required this.trainData, @required this.pageLoadFuture}); @override Widget build(BuildContext context) { return StreamBuilder>( stream: listifyStream(trainData.stations(pageLoadFuture: pageLoadFuture)), builder: (context, snapshot) { if (!snapshot.hasData) { return SliverToBoxAdapter( child: Container(), ); } return SliverList( delegate: SliverChildBuilderDelegate( (context, index) { if (index.isOdd) { return CupertinoDivider(); } else { final itemIndex = index ~/ 2; return IndexedSemantics( child: DisplayTrainStation( station: snapshot.data[itemIndex], ), index: itemIndex, ); } }, childCount: snapshot.data.length * 2 - 1, addSemanticIndexes: false, ), ); }, ); } } class DisplayTrainStation extends StatelessWidget { final OnDemandStation station; DisplayTrainStation({@required this.station}); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( mainAxisSize: MainAxisSize.max, children: [ Padding( padding: const EdgeInsets.all(8), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), border: Border.all( width: 2, color: FOREGROUND_WHITE, ), // color: CupertinoColors.activeOrange, ), width: 48, height: 48, child: Column( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: Center( child: FutureDisplay( future: station.km, builder: (context, value) { return Text( value.toString(), style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 18, fontWeight: FontWeight.w100, ), textAlign: TextAlign.center, ); }, ), ), ), Text( "km", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 10), ), ], ), ), ), Expanded( child: FutureDisplay>( future: Future.wait([ station.stationName, station.observations ]), builder: (context, items) { return Text( items[0], style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 22, fontWeight: FontWeight.w100, fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal, ), textAlign: TextAlign.center, ); }, ) ) ], ), FutureDisplay>( future: Future.wait([ station.arrivalTime, station.stopsFor, station.departureTime ]), builder: (context, items) { if (items[0].isEmpty) { // Plecare return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded(child: Container(),), Text("plecare la ${items[2]}"), Container(width: 2,), Text( "→", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 22, ), ), ], ); } if (items[2].isEmpty) { // Sosire return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "→", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 22, ), ), Container(width: 2,), Text("sosire la ${items[0]}"), Expanded(child: Container(),), ], ); } return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "→", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 22, ), ), Container(width: 2,), Text(items[0]), Expanded(child: Container(),), Column( mainAxisSize: MainAxisSize.min, children: [ Builder( builder: (context) { if (items[1].isEmpty || items[1] == "0") { return Container(); } if (items[1] == "1") { return Text( "staționează pentru\n1 minut", textAlign: TextAlign.center, ); } return Text( "staționează pentru\n${items[1]} minute", textAlign: TextAlign.center, ); } ), FutureBuilder( future: station.observations, builder: (context, snapshot) { if (snapshot.data == "ONI") { return Text( "oprire ne-itinerarică", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontStyle: FontStyle.italic, ), textAlign: TextAlign.center, ); } return Container(); }, ) ], ), Expanded(child: Container(),), Text(items[2]), Container(width: 2,), Text( "→", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( fontSize: 22, ), ), ], ); }, ), FutureDisplay( future: station.delay, builder: (context, delay) { if (delay == 0) return Container(); else if (delay > 0) { return Text( "$delay minute întârziere", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( color: CupertinoColors.destructiveRed, fontSize: 12, fontStyle: FontStyle.italic, ), ); } else if (delay < 0) { return Text( "${-delay} minute mai devreme", style: CupertinoTheme.of(context).textTheme.textStyle.copyWith( color: CupertinoColors.activeGreen, fontSize: 12, fontStyle: FontStyle.italic, ), ); } return Container(); }, ) ], ); } } class CupertinoDivider extends StatelessWidget { final Color color; CupertinoDivider({Key key, Color color}): color = color ?? FOREGROUND_DARK_GREY, super(key: key); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ Container( height: 1, ), Container( height: 1, decoration: BoxDecoration( color: color, ), ), Container( height: 1, ), ], ); } } class CupertinoVerticalDivider extends StatelessWidget { final Color color; CupertinoVerticalDivider({Key key, Color color}): color = color ?? FOREGROUND_DARK_GREY, super(key: key); @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 1, ), Container( width: 1, decoration: BoxDecoration( color: color, ), ), Container( width: 1, ), ], ); } }