You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
7.5 KiB
247 lines
7.5 KiB
import 'package:flutter/material.dart'; |
|
|
|
import 'models/train_data.dart'; |
|
import 'train_info_display.dart'; |
|
|
|
void main() => runApp(MyApp()); |
|
|
|
class MyApp extends StatelessWidget { |
|
@override |
|
Widget build(BuildContext context) { |
|
return MaterialApp( |
|
title: 'Info Tren', |
|
theme: ThemeData( |
|
primarySwatch: Colors.blue, |
|
brightness: Brightness.dark, |
|
primaryColor: Colors.blue.shade600, |
|
accentColor: Colors.blue.shade700, |
|
), |
|
home: MainPageWrapper(), |
|
); |
|
} |
|
} |
|
|
|
class MainPageWrapper extends StatelessWidget { |
|
@override |
|
Widget build(BuildContext context) { |
|
return TrainDataSourceWidget( |
|
child: MainPage() |
|
); |
|
} |
|
} |
|
|
|
class MainPage extends StatefulWidget { |
|
@override |
|
_MainPageState createState() => _MainPageState(); |
|
} |
|
|
|
class _MainPageState extends State<MainPage> { |
|
final trainNumberController = TextEditingController(); |
|
bool showAlternate = false; |
|
|
|
bool get shouldTap { |
|
return trainNumberController.text.isNotEmpty; |
|
} |
|
|
|
onTap(BuildContext context) { |
|
FocusScope.of(context).requestFocus(FocusNode()); |
|
TrainDataSourceWidget.of(context).lookup(trainNumberController.text, showAlternate); |
|
} |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return Scaffold( |
|
appBar: AppBar( |
|
title: Text("Info Tren"), |
|
centerTitle: true, |
|
actions: <Widget>[ |
|
IconButton( |
|
icon: Icon(Icons.settings), |
|
onPressed: () { |
|
showModalBottomSheet(context: context, builder: (context) { |
|
return StatefulBuilder( |
|
builder: (context, ssSheet) => |
|
SafeArea( |
|
bottom: true, |
|
top: false, |
|
left: true, |
|
right: true, |
|
child: Column( |
|
mainAxisSize: MainAxisSize.min, |
|
children: <Widget>[ |
|
ListTile( |
|
title: Text( |
|
showAlternate |
|
? "Afișează rezultatul principal" |
|
: "Afișează rezultatul alternativ" |
|
), |
|
onTap: () { |
|
showAlternate = !showAlternate; |
|
setState(() {}); |
|
ssSheet(() {}); |
|
}, |
|
) |
|
], |
|
), |
|
), |
|
); |
|
}); |
|
}, |
|
) |
|
], |
|
), |
|
body: Column( |
|
children: <Widget>[ |
|
Row( |
|
children: <Widget>[ |
|
Expanded( |
|
child: Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: TextField( |
|
controller: trainNumberController, |
|
onChanged: (_) => setState(() => {}), |
|
autofocus: true, |
|
decoration: InputDecoration( |
|
labelText: "Numărul trenului", |
|
border: OutlineInputBorder(), |
|
hintText: "Scrieți doar numărul" |
|
), |
|
onSubmitted: (_) { |
|
if (shouldTap) { |
|
onTap(context); |
|
} |
|
}, |
|
keyboardType: TextInputType.numberWithOptions(), |
|
textInputAction: TextInputAction.search, |
|
), |
|
), |
|
), |
|
Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: RaisedButton( |
|
child: Text("Caută"), |
|
onPressed: (() { |
|
if (!shouldTap) return null; |
|
return () { |
|
onTap(context); |
|
}; |
|
})(), |
|
), |
|
) |
|
], |
|
), |
|
Text( |
|
showAlternate |
|
? "Se va afișa rezultatul alternativ\nla următoarea căutare" |
|
: "Se va afișa rezultatul principal\nla următoarea căutare", |
|
style: Theme.of(context).textTheme.caption.copyWith(fontStyle: FontStyle.italic), |
|
textAlign: TextAlign.center, |
|
), |
|
Divider( |
|
color: Theme.of(context).accentColor, |
|
height: 4, |
|
), |
|
Expanded( |
|
child: Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: TrainInfoDisplay(), |
|
), |
|
) |
|
], |
|
), |
|
); |
|
} |
|
} |
|
|
|
class TrainInfoDisplay extends StatelessWidget { |
|
@override |
|
Widget build(BuildContext context) { |
|
return StreamBuilder<TrainDataEvent>( |
|
stream: TrainDataSourceWidget.of(context).dataStream, |
|
builder: (context, snapshot) { |
|
if (snapshot.connectionState != ConnectionState.active) { |
|
return Container(); |
|
} |
|
|
|
if (snapshot.hasError) { |
|
final error = snapshot.error as TrainDataEvent; |
|
|
|
if (error.kind == TrainDataEventKind.NOT_FOUND) { |
|
return Center( |
|
child: Text( |
|
"Train number ${error.trainNumber}\nwas not found!", |
|
style: Theme.of(context).textTheme.headline, |
|
textAlign: TextAlign.center, |
|
) |
|
); |
|
} |
|
|
|
if (error.kind == TrainDataEventKind.TIMEOUT) { |
|
return Center( |
|
child: Column( |
|
mainAxisSize: MainAxisSize.min, |
|
children: <Widget>[ |
|
Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: Text( |
|
"The request has timed out!", |
|
style: Theme.of(context).textTheme.headline, |
|
textAlign: TextAlign.center, |
|
), |
|
), |
|
Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: RaisedButton( |
|
child: Text("Retry"), |
|
onPressed: () { |
|
TrainDataSourceWidget.of(context).lookup(error.trainNumber); |
|
}, |
|
), |
|
) |
|
], |
|
) |
|
); |
|
} |
|
|
|
if (error.kind == TrainDataEventKind.UNKNOWN_ERROR) { |
|
return Center( |
|
child: Column( |
|
mainAxisSize: MainAxisSize.min, |
|
children: <Widget>[ |
|
Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: Text("An unknown error with the status code ${error.errorStatusCode} has occured."), |
|
), |
|
Padding( |
|
padding: const EdgeInsets.all(8.0), |
|
child: RaisedButton( |
|
child: Text("Retry"), |
|
onPressed: () { |
|
TrainDataSourceWidget.of(context).lookup(error.trainNumber); |
|
}, |
|
), |
|
) |
|
], |
|
), |
|
); |
|
} |
|
} |
|
|
|
if (snapshot.hasData) { |
|
if (snapshot.data.kind == TrainDataEventKind.LOADING) { |
|
return Center( |
|
child: CircularProgressIndicator(), |
|
); |
|
} |
|
|
|
if (snapshot.data.kind == TrainDataEventKind.GOT_DATA) { |
|
return TrainInfoDisplayData(snapshot.data.trainData); |
|
} |
|
} |
|
|
|
return Placeholder(); |
|
}, |
|
); |
|
} |
|
} |
|
|
|
|