import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'api_handler.dart'; import 'transport_helper.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; //for testing on desktop void main() async { await dotenv.load(); const String dbName = "oeffimasterTransportDb"; databaseFactory = databaseFactoryFfi; // for debugging and desktop test DbHelper.initDb(dbName); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Oeffimaster', theme: ThemeData( colorScheme: .fromSeed(seedColor: Colors.yellow), ), home: const MyHomePage(title: 'Oeffimaster'), //this is what matters // routes: { // //'/': (context) => const MyHomePage(title: 'Oeffimaster'), // '/stations': (context) => const ChooseStationPage(), // }, ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { int _counter = 0; //String API_KEY = ApiHandler.accessID; String API_KEY = "no telly"; //Future> ?id; List stationList = []; String id = ''; void _incrementCounter() { setState(() { // This call to setState tells the Flutter framework that something has // changed in this State, which causes it to rerun the build method below // so that the display can reflect the updated values. If we changed // _counter without calling setState(), then the build method would not be // called again, and so nothing would appear to happen. _counter++; }); } // TODO :find a better way to show the list void showResult(Future> futureId) async { stationList = await futureId; id = stationList[0].id; setState(() {}); } @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // // The Flutter framework has been optimized to make rerunning build methods // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( //backgroundColor: Theme.of(context).colorScheme.inversePrimary, //backgroundColor: Colors.amber, // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: .center, children: [ const Text('You have pushed the button this many times:'), Text( '$_counter', style: Theme.of(context).textTheme.headlineMedium, ), Text('API key from ENV is $API_KEY'), MaterialButton( onPressed: () { showResult(ApiHandler.findStations('S Biesdorf')); }, child: Text('Search for \'S Biesdorf\''), ), Text(id), ElevatedButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => ChooseStationPage()), ); }, child: const Text('Start a route'), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } } class ChooseStationPage extends StatefulWidget { const ChooseStationPage({super.key}); @override State createState() => _ChooseStationPageState(); } class _ChooseStationPageState extends State { Station? _selectedStation; List stationList = []; void findNearbyStations() async { stationList = await ApiHandler.nearbyStations( // TODO: replace with location "52.55", "13.55", maxStations: 20, ); } void findStationsByName( String name, { int? resultnum, }) async { stationList = await ApiHandler.findStations(name); } void showResult(Future> futureId) async { stationList = await futureId; setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('RoutePicker')), body: Center( child: Column( children: [ ElevatedButton( onPressed: () { showResult(ApiHandler.findStations('S Biesdorf')); }, child: Text('Search for \'S Biesdorf\''), ), Expanded( child: SizedBox( height: 200, child: StationList( stationList: stationList, onTapped: _handleStationTapped, ), ), ), ], ), ), ); } void _handleStationTapped(Station station) { // setState(() { // _selectedStation = station; // }); Navigator.push( context, MaterialPageRoute( builder: (context) => ChooseDeparturePage(startStation: station), ), ); } } class StationList extends StatelessWidget { final List stationList; final ValueChanged onTapped; StationList({ super.key, required this.stationList, required this.onTapped, }); @override Widget build(BuildContext context) { return ListView( children: [ for (Station station in stationList) ListTile( title: Text(station.name), onTap: () => onTapped(station), ), ], ); } } class ChooseDeparturePage extends StatefulWidget { final Station startStation; final int? journeyId; const ChooseDeparturePage({ super.key, this.journeyId, required this.startStation, }); @override State createState() => _ChooseDeparturePageState(); } class _ChooseDeparturePageState extends State { List departureList = []; Journey? singleJourney; void loadDepartures(Station startStation) async { departureList = await ApiHandler.departures(startStation.id); setState(() {}); } void loadJourney(int journeyId) async { singleJourney = await Journey.dbGet(journeyId); Navigator.push( context, MaterialPageRoute( builder: (context) => JourneyDetailPage( singleJourney: singleJourney as Journey, ), ), ); } @override initState() { super.initState(); loadDepartures(widget.startStation); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( 'RoutePicker for ${widget.startStation.name} // ${widget.journeyId}', ), ), body: Center( child: Column( children: [ Expanded( child: SizedBox( height: 400, child: DepartureList( departureList: departureList, onTapped: _handleDepartureTapped, ), ), ), ElevatedButton( onPressed: () { if (widget.journeyId != null) { loadJourney(widget.journeyId as int); } }, child: const Text('Finish Route'), ), ], ), ), ); } void _handleDepartureTapped(Departure departure) { // setState(() { // _selectedDeparture = departure; // }); Navigator.push( context, MaterialPageRoute( builder: (context) => ChooseArrivalPage( departure: departure, journeyId: widget.journeyId, ), ), ); } } class DepartureList extends StatelessWidget { final List departureList; final ValueChanged onTapped; const DepartureList({ super.key, required this.departureList, required this.onTapped, }); @override Widget build(BuildContext context) { return ListView( children: [ for (Departure departure in departureList) ListTile( title: Text('${departure.vehicleName}: ${departure.direction}'), subtitle: Text(departure.departureTime.toString()), onTap: () => onTapped(departure), ), ], ); } } class ChooseArrivalPage extends StatefulWidget { final Departure departure; final int? journeyId; const ChooseArrivalPage({ super.key, this.journeyId, required this.departure, }); @override State createState() => _ChooseArrivalPageState(); } class _ChooseArrivalPageState extends State { List arrivalList = []; Departure? _selectedDeparture; void loadArrivals(String ref) async { arrivalList = await ApiHandler.tripDetail( ref, startStationId: widget.departure.stationId, ); setState(() {}); } @override initState() { super.initState(); loadArrivals(widget.departure.ref); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( 'Arrivals for ${widget.departure.vehicleName}// ${widget.journeyId}', ), ), body: Center( child: Column( children: [ Expanded( child: SizedBox( height: 400, child: ArrivalList( departure: widget.departure, arrivalList: arrivalList, onTapped: _handleArrivalTapped, ), ), ), ], ), ), ); } void _handleArrivalTapped(Departure departure, Departure arrival) async { // setState(() { // _selectedDeparture = departure; // }); departure.dbInsert; arrival.dbInsert; Segment newSegment = await Segment.fromDepartures(departure, arrival); Station startStation = await Station.dbGet(arrival.stationId); int journeyId; if (widget.journeyId == null) { Journey journey = await Journey.fromSegment(newSegment); journeyId = journey.id as int; } else { Segment segment = newSegment; Journey.dbAppendJourneySegment( widget.journeyId as int, segment.id as int, ); journeyId = widget.journeyId as int; } Navigator.push( context, MaterialPageRoute( builder: (context) => ChooseDeparturePage( startStation: startStation, journeyId: journeyId, ), ), ); } } class ArrivalList extends StatelessWidget { final Departure departure; final List arrivalList; final Function onTapped; const ArrivalList({ super.key, required this.departure, required this.arrivalList, required this.onTapped, }); @override Widget build(BuildContext context) { return ListView( children: [ for (Departure arrival in arrivalList) ListTile( title: Text(arrival.stationName), subtitle: Text(arrival.arrivalTime.toString()), onTap: () => onTapped(departure, arrival), ), ], ); } } class JourneyDetailPage extends StatefulWidget { final Journey singleJourney; const JourneyDetailPage({ super.key, required this.singleJourney, }); @override State createState() => _JourneyDetailPageState(); } class _JourneyDetailPageState extends State { Duration duration = Duration(minutes: 0); @override initState() { super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Connection Details \n$duration')), body: Center( child: SegmentList(journey: widget.singleJourney), ), ); } } class SegmentList extends StatelessWidget { final Journey journey; const SegmentList({ super.key, required this.journey, }); @override Widget build(BuildContext context) { return ListView( children: [ for (Segment seg in journey.segments) ListTile( title: Text(seg.start.direction), subtitle: Text(seg.start.departureTime.toString()), ), ], ); } } class JourneyOverviewPage extends StatefulWidget { const JourneyOverviewPage({super.key}); @override State createState() => _JourneyOverviewPageState(); } class _JourneyOverviewPageState extends State { List allJourneys = []; @override initState() async { super.initState(); // TODO: implement batch query to get a list (all) of journeys allJourneys = await Journey.dbGetAll(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: JourneyList(journeys: allJourneys), ), ); } } class JourneyList extends StatelessWidget { final List journeys; const JourneyList({ super.key, required this.journeys, }); @override Widget build(BuildContext context) { return ListView( children: [ for (Journey jour in journeys) ListTile(title: Text('${jour.startStation} to ${jour.endStation}')), ], ); } }