247 lines
7.5 KiB
Dart
247 lines
7.5 KiB
Dart
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();
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|