reworked page layout inheritence
This commit is contained in:
		@@ -1,72 +1,51 @@
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:anyway/modules/help_dialog.dart';
 | 
			
		||||
import 'package:anyway/pages/current_trip.dart';
 | 
			
		||||
import 'package:anyway/pages/settings.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:anyway/modules/help_dialog.dart';
 | 
			
		||||
import 'package:anyway/modules/trips_saved_list.dart';
 | 
			
		||||
import 'package:anyway/utils/load_trips.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/pages/new_trip_location.dart';
 | 
			
		||||
import 'package:anyway/pages/onboarding.dart';
 | 
			
		||||
import 'package:anyway/pages/current_trip.dart';
 | 
			
		||||
import 'package:anyway/pages/settings.dart';
 | 
			
		||||
import 'package:anyway/pages/new_trip_location.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// BasePage is the scaffold that holds a child page and a side drawer
 | 
			
		||||
// The side drawer is the main way to switch between pages
 | 
			
		||||
 | 
			
		||||
class BasePage extends StatefulWidget {
 | 
			
		||||
  final Widget mainScreen;
 | 
			
		||||
  final Widget title;
 | 
			
		||||
  final List<String> helpTexts;
 | 
			
		||||
 | 
			
		||||
  const BasePage({
 | 
			
		||||
    super.key,
 | 
			
		||||
    required this.mainScreen,
 | 
			
		||||
    this.title = const Text(APP_NAME),
 | 
			
		||||
    this.helpTexts = const [],
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<BasePage> createState() => _BasePageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _BasePageState extends State<BasePage> {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    savedTrips.loadTrips();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mixin ScaffoldLayout<T extends StatefulWidget> on State<T> {
 | 
			
		||||
  Widget mainScaffold(
 | 
			
		||||
    BuildContext context,
 | 
			
		||||
    {
 | 
			
		||||
      Widget child = const Text("emptiness"),
 | 
			
		||||
      Widget title = const Text(APP_NAME),
 | 
			
		||||
      List<String> helpTexts = const []
 | 
			
		||||
    }
 | 
			
		||||
  ) {
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      appBar: AppBar(
 | 
			
		||||
        title: widget.title,
 | 
			
		||||
        title: title,
 | 
			
		||||
        actions: [
 | 
			
		||||
          IconButton(
 | 
			
		||||
            icon: const Icon(Icons.help),
 | 
			
		||||
            tooltip: 'Help',
 | 
			
		||||
            onPressed: () {
 | 
			
		||||
              if (widget.helpTexts.isNotEmpty) {
 | 
			
		||||
                helpDialog(context, widget.helpTexts[0], widget.helpTexts[1]);
 | 
			
		||||
              if (helpTexts.isNotEmpty) {
 | 
			
		||||
                helpDialog(context, helpTexts[0], helpTexts[1]);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      body: Center(child: widget.mainScreen),
 | 
			
		||||
      body: Center(child: child),
 | 
			
		||||
      drawer: Drawer(
 | 
			
		||||
        child: Column(
 | 
			
		||||
          children: [
 | 
			
		||||
            Container(
 | 
			
		||||
              decoration: BoxDecoration(
 | 
			
		||||
              decoration: const BoxDecoration(
 | 
			
		||||
                gradient: APP_GRADIENT,
 | 
			
		||||
              ),
 | 
			
		||||
              height: 150,
 | 
			
		||||
              child: Center(
 | 
			
		||||
              child: const Center(
 | 
			
		||||
                child: Text(
 | 
			
		||||
                  APP_NAME,
 | 
			
		||||
                  style: TextStyle(
 | 
			
		||||
@@ -81,8 +60,7 @@ class _BasePageState extends State<BasePage> {
 | 
			
		||||
            ListTile(
 | 
			
		||||
              title: const Text('Your Trips'),
 | 
			
		||||
              leading: const Icon(Icons.map),
 | 
			
		||||
              // TODO: this is not working!
 | 
			
		||||
              selected: widget.mainScreen is TripPage,
 | 
			
		||||
              selected: widget is TripPage,
 | 
			
		||||
              onTap: () {},
 | 
			
		||||
              trailing: ElevatedButton(
 | 
			
		||||
                onPressed: () {
 | 
			
		||||
@@ -111,13 +89,12 @@ class _BasePageState extends State<BasePage> {
 | 
			
		||||
            const Divider(indent: 10, endIndent: 10),
 | 
			
		||||
            ListTile(
 | 
			
		||||
              title: const Text('How to use'),
 | 
			
		||||
              leading: Icon(Icons.help),
 | 
			
		||||
              // TODO: this is not working!
 | 
			
		||||
              selected: widget.mainScreen is OnboardingPage,
 | 
			
		||||
              leading: const Icon(Icons.help),
 | 
			
		||||
              selected: widget is OnboardingPage,
 | 
			
		||||
              onTap: () {
 | 
			
		||||
                Navigator.of(context).push(
 | 
			
		||||
                  MaterialPageRoute(
 | 
			
		||||
                    builder: (context) => OnboardingPage()
 | 
			
		||||
                    builder: (context) => const OnboardingPage()
 | 
			
		||||
                  )
 | 
			
		||||
                );
 | 
			
		||||
              },
 | 
			
		||||
@@ -127,8 +104,7 @@ class _BasePageState extends State<BasePage> {
 | 
			
		||||
            ListTile(
 | 
			
		||||
              title: const Text('Settings'),
 | 
			
		||||
              leading: const Icon(Icons.settings),
 | 
			
		||||
              // TODO: this is not working!
 | 
			
		||||
              selected: widget.mainScreen is SettingsPage,
 | 
			
		||||
              selected: widget is SettingsPage,
 | 
			
		||||
              onTap: () {
 | 
			
		||||
                Navigator.of(context).push(
 | 
			
		||||
                  MaterialPageRoute(
 | 
			
		||||
@@ -1,24 +1,27 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/utils/get_first_page.dart';
 | 
			
		||||
import 'package:anyway/utils/load_trips.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void main() => runApp(const App());
 | 
			
		||||
 | 
			
		||||
// Some global variables
 | 
			
		||||
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
 | 
			
		||||
final SavedTrips savedTrips = SavedTrips();
 | 
			
		||||
// the list of saved trips is then populated implicitly by getFirstPage()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class App extends StatelessWidget {
 | 
			
		||||
  const App({super.key});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return MaterialApp(
 | 
			
		||||
      title: APP_NAME,
 | 
			
		||||
      home: getFirstPage(),
 | 
			
		||||
      theme: APP_THEME,
 | 
			
		||||
      scaffoldMessengerKey: rootScaffoldMessengerKey
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  Widget build(BuildContext context) => MaterialApp(
 | 
			
		||||
    title: APP_NAME,
 | 
			
		||||
    home: getFirstPage(),
 | 
			
		||||
    theme: APP_THEME,
 | 
			
		||||
    scaffoldMessengerKey: rootScaffoldMessengerKey
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,9 @@
 | 
			
		||||
import 'dart:developer';
 | 
			
		||||
import 'package:anyway/modules/step_between_landmarks.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/modules/landmark_card.dart';
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:anyway/modules/step_between_landmarks.dart';
 | 
			
		||||
import 'package:anyway/modules/landmark_card.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Returns a list of widgets that represent the landmarks matching the given selector
 | 
			
		||||
@@ -35,4 +34,3 @@ List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector
 | 
			
		||||
 | 
			
		||||
  return children;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,29 +35,29 @@ class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicato
 | 
			
		||||
      // In the very center of the panel, show the greeter which tells the user that the trip is being generated
 | 
			
		||||
      Center(child: loadingText(widget.trip)),
 | 
			
		||||
      // As a gimmick, and a way to show that the app is still working, show a few loading dots
 | 
			
		||||
      Align(
 | 
			
		||||
      const Align(
 | 
			
		||||
        alignment: Alignment.bottomCenter,
 | 
			
		||||
        child: statusText(),
 | 
			
		||||
        child: StatusText(),
 | 
			
		||||
      )
 | 
			
		||||
    ],
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// automatically cycle through the greeter texts
 | 
			
		||||
class statusText extends StatefulWidget {
 | 
			
		||||
  const statusText({Key? key}) : super(key: key);
 | 
			
		||||
class StatusText extends StatefulWidget {
 | 
			
		||||
  const StatusText({Key? key}) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _statusTextState createState() => _statusTextState();
 | 
			
		||||
  _StatusTextState createState() => _StatusTextState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _statusTextState extends State<statusText> {
 | 
			
		||||
class _StatusTextState extends State<StatusText> {
 | 
			
		||||
  int statusIndex = 0;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    Future.delayed(Duration(seconds: 5), () {
 | 
			
		||||
    Future.delayed(const Duration(seconds: 5), () {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        statusIndex = (statusIndex + 1) % statusTexts.length;
 | 
			
		||||
      });
 | 
			
		||||
@@ -159,4 +159,3 @@ class _AnimatedGradientTextState extends State<AnimatedGradientText> with Single
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,14 @@
 | 
			
		||||
import 'dart:collection';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
			
		||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
 | 
			
		||||
import 'package:widget_to_marker/widget_to_marker.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/modules/landmark_map_marker.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
 | 
			
		||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
			
		||||
import 'package:widget_to_marker/widget_to_marker.dart';
 | 
			
		||||
import 'package:anyway/modules/landmark_map_marker.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CurrentTripMap extends StatefulWidget {
 | 
			
		||||
  final Trip? trip;
 | 
			
		||||
@@ -60,25 +61,29 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setMapMarkers() async {
 | 
			
		||||
    List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
 | 
			
		||||
    Set<Marker> markers = <Marker>{};
 | 
			
		||||
    Iterator<(int, Landmark)> it = (widget.trip?.landmarks.toList() ?? []).indexed.iterator;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < landmarks.length; i++) {
 | 
			
		||||
      Landmark landmark = landmarks[i];
 | 
			
		||||
    while (it.moveNext()) {
 | 
			
		||||
      int i = it.current.$1;
 | 
			
		||||
      Landmark landmark = it.current.$2;
 | 
			
		||||
 | 
			
		||||
      MarkerId markerId = MarkerId("${landmark.uuid} - ${landmark.visited}");
 | 
			
		||||
      List<double> location = landmark.location;
 | 
			
		||||
      Marker marker = Marker(
 | 
			
		||||
        markerId: MarkerId(landmark.uuid),
 | 
			
		||||
        position: LatLng(location[0], location[1]),
 | 
			
		||||
        icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
 | 
			
		||||
          logicalSize: const Size(150, 150),
 | 
			
		||||
          imageSize: const Size(150, 150),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      markers.add(marker);
 | 
			
		||||
      // only create a new marker, if there is no marker for this landmark
 | 
			
		||||
      if (!mapMarkers.any((Marker marker) => marker.markerId == markerId)) {
 | 
			
		||||
        Marker marker = Marker(
 | 
			
		||||
          markerId: markerId,
 | 
			
		||||
          position: LatLng(location[0], location[1]),
 | 
			
		||||
          icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
 | 
			
		||||
            logicalSize: const Size(150, 150),
 | 
			
		||||
            imageSize: const Size(150, 150),
 | 
			
		||||
          )
 | 
			
		||||
        );
 | 
			
		||||
        setState(() {
 | 
			
		||||
          mapMarkers.add(marker);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    setState(() {
 | 
			
		||||
      mapMarkers = markers;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setMapRoute() async {
 | 
			
		||||
@@ -98,8 +103,8 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
 | 
			
		||||
        Polyline stepLine = Polyline(
 | 
			
		||||
          polylineId: PolylineId('step-${landmark.uuid}'),
 | 
			
		||||
          points: step,
 | 
			
		||||
          color: landmark.visited ? Colors.grey : PRIMARY_COLOR,
 | 
			
		||||
          width: 5,
 | 
			
		||||
          color: landmark.visited || (landmark.next?.visited ?? false) ? Colors.grey : PRIMARY_COLOR,
 | 
			
		||||
          width: 5
 | 
			
		||||
        );
 | 
			
		||||
        polyLines.add(stepLine);
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/modules/current_trip_error_message.dart';
 | 
			
		||||
import 'package:anyway/modules/current_trip_loading_indicator.dart';
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/modules/current_trip_error_message.dart';
 | 
			
		||||
import 'package:anyway/modules/current_trip_loading_indicator.dart';
 | 
			
		||||
import 'package:anyway/modules/current_trip_summary.dart';
 | 
			
		||||
import 'package:anyway/modules/current_trip_save_button.dart';
 | 
			
		||||
import 'package:anyway/modules/current_trip_landmarks_list.dart';
 | 
			
		||||
@@ -74,20 +76,21 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
 | 
			
		||||
                  child: Column(
 | 
			
		||||
                    children: [
 | 
			
		||||
                      CurrentTripSummary(trip: widget.trip),
 | 
			
		||||
                      ExpansionTile(
 | 
			
		||||
                        leading: Icon(Icons.location_on),
 | 
			
		||||
                        title: Text('Visited Landmarks (tap to expand)'),
 | 
			
		||||
                        children: [
 | 
			
		||||
                          ...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
 | 
			
		||||
                        ],
 | 
			
		||||
                        visualDensity: VisualDensity.compact,
 | 
			
		||||
                        collapsedShape: RoundedRectangleBorder(
 | 
			
		||||
                          borderRadius: BorderRadius.circular(10),
 | 
			
		||||
                      if (widget.trip.landmarks.where((Landmark landmark) => landmark.visited).isNotEmpty)
 | 
			
		||||
                        ExpansionTile(
 | 
			
		||||
                          leading: const Icon(Icons.location_on),
 | 
			
		||||
                          title: const Text('Visited Landmarks (tap to expand)'),
 | 
			
		||||
                          children: [
 | 
			
		||||
                            ...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
 | 
			
		||||
                          ],
 | 
			
		||||
                          visualDensity: VisualDensity.compact,
 | 
			
		||||
                          collapsedShape: RoundedRectangleBorder(
 | 
			
		||||
                            borderRadius: BorderRadius.circular(10),
 | 
			
		||||
                          ),
 | 
			
		||||
                          shape: RoundedRectangleBorder(
 | 
			
		||||
                            borderRadius: BorderRadius.circular(10),
 | 
			
		||||
                          ),
 | 
			
		||||
                        ),
 | 
			
		||||
                        shape: RoundedRectangleBorder(
 | 
			
		||||
                          borderRadius: BorderRadius.circular(10),
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
@@ -108,4 +111,4 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}  
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:auto_size_text/auto_size_text.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:auto_size_text/auto_size_text.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class saveButton extends StatefulWidget {
 | 
			
		||||
@@ -52,4 +52,3 @@ class _saveButtonState extends State<saveButton> {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CurrentTripSummary extends StatefulWidget {
 | 
			
		||||
  final Trip trip;
 | 
			
		||||
  const CurrentTripSummary({
 | 
			
		||||
@@ -16,22 +17,22 @@ class _CurrentTripSummaryState extends State<CurrentTripSummary> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Padding(
 | 
			
		||||
      padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
 | 
			
		||||
      padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
 | 
			
		||||
      child: Row(
 | 
			
		||||
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
        children: [
 | 
			
		||||
          Row(
 | 
			
		||||
            children: [
 | 
			
		||||
              Icon(Icons.flag, size: 20),
 | 
			
		||||
              Padding(padding: EdgeInsets.only(right: 10)),
 | 
			
		||||
              Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge,),
 | 
			
		||||
              const Icon(Icons.flag, size: 20),
 | 
			
		||||
              const Padding(padding: EdgeInsets.only(right: 10)),
 | 
			
		||||
              Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge),
 | 
			
		||||
            ]
 | 
			
		||||
          ),
 | 
			
		||||
          Row(
 | 
			
		||||
            children: [
 | 
			
		||||
              Icon(Icons.hourglass_bottom_rounded, size: 20),
 | 
			
		||||
              Padding(padding: EdgeInsets.only(right: 10)),
 | 
			
		||||
              Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge,),
 | 
			
		||||
              const Icon(Icons.hourglass_bottom_rounded, size: 20),
 | 
			
		||||
              const Padding(padding: EdgeInsets.only(right: 10)),
 | 
			
		||||
              Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge),
 | 
			
		||||
            ]
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Future<void> helpDialog(BuildContext context, String title, String content) {
 | 
			
		||||
  return showDialog<void>(
 | 
			
		||||
    context: context,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher.dart';
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LandmarkCard extends StatefulWidget {
 | 
			
		||||
  final Landmark landmark;
 | 
			
		||||
  final Trip parentTrip;
 | 
			
		||||
@@ -23,20 +26,11 @@ class LandmarkCard extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
class _LandmarkCardState extends State<LandmarkCard> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    if (widget.landmark.type == typeStart || widget.landmark.type == typeFinish) {
 | 
			
		||||
      return TextButton.icon(
 | 
			
		||||
        onPressed: () {},
 | 
			
		||||
        icon: widget.landmark.type.icon,
 | 
			
		||||
        label: Text(widget.landmark.name),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  Widget build(BuildContext context) {      
 | 
			
		||||
    return Container(
 | 
			
		||||
      constraints: BoxConstraints(
 | 
			
		||||
        minHeight: 50,
 | 
			
		||||
        maxHeight: 200,
 | 
			
		||||
        // express the max height in terms text lines
 | 
			
		||||
        maxHeight: 7 * (Theme.of(context).textTheme.titleMedium!.fontSize! + 10),
 | 
			
		||||
      ),
 | 
			
		||||
      child: Card(
 | 
			
		||||
        shape: RoundedRectangleBorder(
 | 
			
		||||
@@ -79,23 +73,23 @@ class _LandmarkCardState extends State<LandmarkCard> {
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
 | 
			
		||||
                  Container(
 | 
			
		||||
                    color: PRIMARY_COLOR,
 | 
			
		||||
                    child: Center(
 | 
			
		||||
                      child: Padding(
 | 
			
		||||
                        padding: EdgeInsets.all(5),
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                          spacing: 5,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            Icon(widget.landmark.type.icon.icon, size: 16),
 | 
			
		||||
                            Text(widget.landmark.type.name, style: TextStyle(fontWeight: FontWeight.bold)),
 | 
			
		||||
                          ],
 | 
			
		||||
                  if (widget.landmark.type != typeStart && widget.landmark.type != typeFinish)
 | 
			
		||||
                    Container(
 | 
			
		||||
                      color: PRIMARY_COLOR,
 | 
			
		||||
                      child: Center(
 | 
			
		||||
                        child: Padding(
 | 
			
		||||
                          padding: EdgeInsets.all(5),
 | 
			
		||||
                          child: Row(
 | 
			
		||||
                            mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                            spacing: 5,
 | 
			
		||||
                            children: [
 | 
			
		||||
                              Icon(Icons.timer_outlined, size: 16),
 | 
			
		||||
                              Text("${widget.landmark.duration?.inMinutes} minutes"),
 | 
			
		||||
                            ],
 | 
			
		||||
                          )
 | 
			
		||||
                        )
 | 
			
		||||
                      )
 | 
			
		||||
                    ),
 | 
			
		||||
                  )
 | 
			
		||||
                      ),
 | 
			
		||||
                    )
 | 
			
		||||
                ],
 | 
			
		||||
              )
 | 
			
		||||
            ),
 | 
			
		||||
@@ -133,12 +127,6 @@ class _LandmarkCardState extends State<LandmarkCard> {
 | 
			
		||||
                        // show the type, the website, and the wikipedia link as buttons/labels in a row
 | 
			
		||||
                        children: [
 | 
			
		||||
                          doneToggleButton(),
 | 
			
		||||
                          // if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
 | 
			
		||||
                          //   TextButton.icon(
 | 
			
		||||
                          //     onPressed: () {},
 | 
			
		||||
                          //     icon: Icon(Icons.hourglass_bottom),
 | 
			
		||||
                          //     label: Text('${widget.landmark.duration!.inMinutes} minutes'),
 | 
			
		||||
                          //   ),
 | 
			
		||||
                          if (widget.landmark.websiteURL != null)
 | 
			
		||||
                            websiteButton(),
 | 
			
		||||
                          
 | 
			
		||||
@@ -172,33 +160,35 @@ class _LandmarkCardState extends State<LandmarkCard> {
 | 
			
		||||
      // open a browser with the website link
 | 
			
		||||
      await launchUrl(Uri.parse(widget.landmark.websiteURL!));
 | 
			
		||||
    },
 | 
			
		||||
    icon: Icon(Icons.link),
 | 
			
		||||
    label: Text('Website'),
 | 
			
		||||
    icon: const Icon(Icons.link),
 | 
			
		||||
    label: const Text('Website'),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Widget optionsButton () => PopupMenuButton(
 | 
			
		||||
    icon: Icon(Icons.settings),
 | 
			
		||||
    icon: const Icon(Icons.settings),
 | 
			
		||||
    style: TextButtonTheme.of(context).style,
 | 
			
		||||
    itemBuilder: (context) => [
 | 
			
		||||
      PopupMenuItem(
 | 
			
		||||
        child: ListTile(
 | 
			
		||||
          leading: Icon(Icons.delete),
 | 
			
		||||
          title: Text('Delete'),
 | 
			
		||||
          leading: const Icon(Icons.delete),
 | 
			
		||||
          title: const Text('Delete'),
 | 
			
		||||
          onTap: () async {
 | 
			
		||||
            widget.parentTrip.removeLandmark(widget.landmark);
 | 
			
		||||
            rootScaffoldMessengerKey.currentState!.showSnackBar(
 | 
			
		||||
              SnackBar(content: Text("We won't show ${widget.landmark.name} again"))
 | 
			
		||||
              SnackBar(content: Text("${widget.landmark.name} won't be shown again"))
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      PopupMenuItem(
 | 
			
		||||
        child: ListTile(
 | 
			
		||||
          leading: Icon(Icons.star),
 | 
			
		||||
          title: Text('Favorite'),
 | 
			
		||||
          leading: const Icon(Icons.star),
 | 
			
		||||
          title: const Text('Favorite'),
 | 
			
		||||
          onTap: () async {
 | 
			
		||||
            // delete the landmark
 | 
			
		||||
            // await deleteLandmark(widget.landmark);
 | 
			
		||||
            rootScaffoldMessengerKey.currentState!.showSnackBar(
 | 
			
		||||
              SnackBar(content: Text("Not implemented yet"))
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
 
 | 
			
		||||
@@ -46,11 +46,11 @@ class _NewTripButtonState extends State<NewTripButton> {
 | 
			
		||||
    UserPreferences preferences = widget.preferences;
 | 
			
		||||
    if (preferences.nature.value == 0 && preferences.shopping.value == 0 && preferences.sightseeing.value == 0){
 | 
			
		||||
      rootScaffoldMessengerKey.currentState!.showSnackBar(
 | 
			
		||||
        SnackBar(content: Text("Please specify at least one preference"))
 | 
			
		||||
        const SnackBar(content: Text("Please specify at least one preference"))
 | 
			
		||||
      );
 | 
			
		||||
    } else if (preferences.maxTime.value == 0){
 | 
			
		||||
      rootScaffoldMessengerKey.currentState!.showSnackBar(
 | 
			
		||||
        SnackBar(content: Text("Please choose a longer duration"))
 | 
			
		||||
        const SnackBar(content: Text("Please choose a longer duration"))
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      Trip trip = widget.trip;
 | 
			
		||||
@@ -63,4 +63,3 @@ class _NewTripButtonState extends State<NewTripButton> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
// A map that allows the user to select a location for a new trip.
 | 
			
		||||
import 'dart:developer';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
			
		||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
 | 
			
		||||
import 'package:widget_to_marker/widget_to_marker.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/modules/landmark_map_marker.dart';
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
 | 
			
		||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
			
		||||
import 'package:widget_to_marker/widget_to_marker.dart';
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:anyway/modules/landmark_map_marker.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NewTripMap extends StatefulWidget {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/structs/landmark.dart';
 | 
			
		||||
import 'package:anyway/modules/map_chooser.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class StepBetweenLandmarks extends StatefulWidget {
 | 
			
		||||
  final Landmark current;
 | 
			
		||||
  final Landmark next;
 | 
			
		||||
@@ -19,11 +21,15 @@ class StepBetweenLandmarks extends StatefulWidget {
 | 
			
		||||
class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    int time = widget.current.tripTime?.inMinutes ?? 0;
 | 
			
		||||
    int? time = widget.current.tripTime?.inMinutes;
 | 
			
		||||
    if (time != null && time < 1) {
 | 
			
		||||
      time = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return Container(
 | 
			
		||||
      margin: EdgeInsets.all(10),
 | 
			
		||||
      padding: EdgeInsets.all(10),
 | 
			
		||||
      decoration: BoxDecoration(
 | 
			
		||||
      margin: const EdgeInsets.all(10),
 | 
			
		||||
      padding: const EdgeInsets.all(10),
 | 
			
		||||
      decoration: const BoxDecoration(
 | 
			
		||||
        border: Border(
 | 
			
		||||
          left: BorderSide(width: 3.0, color: Colors.black),
 | 
			
		||||
        ),
 | 
			
		||||
@@ -32,21 +38,22 @@ class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
 | 
			
		||||
        children: [
 | 
			
		||||
          Column(
 | 
			
		||||
            children: [
 | 
			
		||||
              Icon(Icons.directions_walk),
 | 
			
		||||
              Text("$time min", style: TextStyle(fontSize: 10)),
 | 
			
		||||
              const Icon(Icons.directions_walk),
 | 
			
		||||
              Text(
 | 
			
		||||
                time == null ? "" : "About $time min",
 | 
			
		||||
                style: const TextStyle(fontSize: 10)
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
          Spacer(),
 | 
			
		||||
          ElevatedButton(
 | 
			
		||||
 | 
			
		||||
          const Spacer(),
 | 
			
		||||
 | 
			
		||||
          ElevatedButton.icon(
 | 
			
		||||
            onPressed: () async {
 | 
			
		||||
              showMapChooser(context, widget.current, widget.next);
 | 
			
		||||
            },
 | 
			
		||||
            child: Row(
 | 
			
		||||
              children: [
 | 
			
		||||
                Icon(Icons.directions),
 | 
			
		||||
                Text("Directions"),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
            icon: const Icon(Icons.directions),
 | 
			
		||||
            label: const Text("Directions"),
 | 
			
		||||
          )
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/pages/base_page.dart';
 | 
			
		||||
import 'package:anyway/layouts/scaffold.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:sliding_up_panel/sliding_up_panel.dart';
 | 
			
		||||
 | 
			
		||||
@@ -28,12 +28,13 @@ class TripPage extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _TripPageState extends State<TripPage> {
 | 
			
		||||
class _TripPageState extends State<TripPage> with ScaffoldLayout{
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return BasePage(
 | 
			
		||||
      mainScreen: SlidingUpPanel(
 | 
			
		||||
    return mainScaffold(
 | 
			
		||||
      context,
 | 
			
		||||
      child: SlidingUpPanel(
 | 
			
		||||
        // use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
 | 
			
		||||
        panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
 | 
			
		||||
        // using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
 | 
			
		||||
@@ -58,9 +59,13 @@ class _TripPageState extends State<TripPage> {
 | 
			
		||||
      title: FutureBuilder(
 | 
			
		||||
        future: widget.trip.cityName,
 | 
			
		||||
        builder: (context, snapshot) => Text(
 | 
			
		||||
          'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
 | 
			
		||||
          'Trip to ${snapshot.hasData ? snapshot.data! : "..."}',
 | 
			
		||||
        )
 | 
			
		||||
      ),
 | 
			
		||||
      helpTexts: [
 | 
			
		||||
        'Current trip',
 | 
			
		||||
        'You can see and edit your current trip here. Swipe up from the bottom to see a detailed view of the recommendations.'
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import 'package:anyway/layouts/scaffold.dart';
 | 
			
		||||
import 'package:anyway/modules/new_trip_options_button.dart';
 | 
			
		||||
import 'package:anyway/pages/base_page.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import "package:anyway/structs/trip.dart";
 | 
			
		||||
@@ -14,7 +14,7 @@ class NewTripPage extends StatefulWidget {
 | 
			
		||||
  _NewTripPageState createState() => _NewTripPageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _NewTripPageState extends State<NewTripPage> {
 | 
			
		||||
class _NewTripPageState extends State<NewTripPage> with ScaffoldLayout {
 | 
			
		||||
  final TextEditingController latController = TextEditingController();
 | 
			
		||||
  final TextEditingController lonController = TextEditingController();
 | 
			
		||||
  Trip trip = Trip();
 | 
			
		||||
@@ -23,8 +23,9 @@ class _NewTripPageState extends State<NewTripPage> {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    // floating search bar and map as a background
 | 
			
		||||
    return BasePage(
 | 
			
		||||
      mainScreen: Scaffold(
 | 
			
		||||
    return mainScaffold(
 | 
			
		||||
      context,
 | 
			
		||||
      child: Scaffold(
 | 
			
		||||
        body: Stack(
 | 
			
		||||
          children: [
 | 
			
		||||
            NewTripMap(trip),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import 'package:anyway/layouts/scaffold.dart';
 | 
			
		||||
import 'package:anyway/modules/new_trip_button.dart';
 | 
			
		||||
import 'package:anyway/pages/base_page.dart';
 | 
			
		||||
import 'package:anyway/structs/preferences.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:flutter/cupertino.dart';
 | 
			
		||||
@@ -15,13 +15,14 @@ class NewTripPreferencesPage extends StatefulWidget {
 | 
			
		||||
  _NewTripPreferencesPageState createState() => _NewTripPreferencesPageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
 | 
			
		||||
class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with ScaffoldLayout {
 | 
			
		||||
  UserPreferences preferences = UserPreferences();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return BasePage(
 | 
			
		||||
      mainScreen: Scaffold(
 | 
			
		||||
    return mainScaffold(
 | 
			
		||||
      context,
 | 
			
		||||
      child: Scaffold(
 | 
			
		||||
        body: ListView(
 | 
			
		||||
          children: [
 | 
			
		||||
            // Center(
 | 
			
		||||
@@ -41,23 +42,22 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
 | 
			
		||||
            //   )
 | 
			
		||||
            // ),
 | 
			
		||||
 | 
			
		||||
            Center(
 | 
			
		||||
              child: Padding(
 | 
			
		||||
              padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0),
 | 
			
		||||
                child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
 | 
			
		||||
              ),
 | 
			
		||||
          Center(
 | 
			
		||||
            child: Padding(
 | 
			
		||||
            padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0),
 | 
			
		||||
              child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
 | 
			
		||||
            Divider(indent: 25, endIndent: 25, height: 50),
 | 
			
		||||
          Divider(indent: 25, endIndent: 25, height: 50),
 | 
			
		||||
 | 
			
		||||
            durationPicker(preferences.maxTime),
 | 
			
		||||
          durationPicker(preferences.maxTime),
 | 
			
		||||
 | 
			
		||||
            preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]),
 | 
			
		||||
          ]
 | 
			
		||||
        ),
 | 
			
		||||
        floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
 | 
			
		||||
          preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]),
 | 
			
		||||
        ]
 | 
			
		||||
      ),
 | 
			
		||||
      floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
 | 
			
		||||
      ),
 | 
			
		||||
      
 | 
			
		||||
      title: FutureBuilder(
 | 
			
		||||
        future: widget.trip.cityName,
 | 
			
		||||
        builder: (context, snapshot) => Text(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import 'package:anyway/layouts/scaffold.dart';
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:anyway/pages/base_page.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:permission_handler/permission_handler.dart';
 | 
			
		||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
			
		||||
@@ -14,42 +14,41 @@ class SettingsPage extends StatefulWidget {
 | 
			
		||||
  _SettingsPageState createState() => _SettingsPageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _SettingsPageState extends State<SettingsPage> {
 | 
			
		||||
class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return BasePage(
 | 
			
		||||
      mainScreen: ListView(
 | 
			
		||||
        padding: EdgeInsets.all(15),
 | 
			
		||||
        children: [
 | 
			
		||||
          // First a round, centered image
 | 
			
		||||
          Center(
 | 
			
		||||
            child: CircleAvatar(
 | 
			
		||||
              radius: 75,
 | 
			
		||||
              child: Icon(Icons.settings, size: 100),
 | 
			
		||||
            )
 | 
			
		||||
          ),
 | 
			
		||||
          Center(
 | 
			
		||||
            child: Text('Global settings', style: TextStyle(fontSize: 24))
 | 
			
		||||
          ),
 | 
			
		||||
  Widget build (BuildContext context) => mainScaffold(
 | 
			
		||||
    context,
 | 
			
		||||
    child: ListView(
 | 
			
		||||
      padding: EdgeInsets.all(15),
 | 
			
		||||
      children: [
 | 
			
		||||
        // First a round, centered image
 | 
			
		||||
        Center(
 | 
			
		||||
          child: CircleAvatar(
 | 
			
		||||
            radius: 75,
 | 
			
		||||
            child: Icon(Icons.settings, size: 100),
 | 
			
		||||
          )
 | 
			
		||||
        ),
 | 
			
		||||
        Center(
 | 
			
		||||
          child: Text('Global settings', style: TextStyle(fontSize: 24))
 | 
			
		||||
        ),
 | 
			
		||||
 | 
			
		||||
          Divider(indent: 25, endIndent: 25, height: 50),
 | 
			
		||||
        Divider(indent: 25, endIndent: 25, height: 50),
 | 
			
		||||
 | 
			
		||||
          darkMode(),
 | 
			
		||||
          setLocationUsage(),
 | 
			
		||||
          setDebugMode(),
 | 
			
		||||
        darkMode(),
 | 
			
		||||
        setLocationUsage(),
 | 
			
		||||
        setDebugMode(),
 | 
			
		||||
 | 
			
		||||
          Divider(indent: 25, endIndent: 25, height: 50),
 | 
			
		||||
        Divider(indent: 25, endIndent: 25, height: 50),
 | 
			
		||||
 | 
			
		||||
          privacyInfo(),
 | 
			
		||||
        ]
 | 
			
		||||
      ),
 | 
			
		||||
      title: Text('Settings'),
 | 
			
		||||
      helpTexts: [
 | 
			
		||||
        'Settings',
 | 
			
		||||
        'Preferences set in this page are global and will affect the entire application.'
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
        privacyInfo(),
 | 
			
		||||
      ]
 | 
			
		||||
    ),
 | 
			
		||||
    title: Text('Settings'),
 | 
			
		||||
    helpTexts: [
 | 
			
		||||
      'Settings',
 | 
			
		||||
      'Preferences set in this page are global and will affect the entire application.'
 | 
			
		||||
    ],
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  Widget setDebugMode() {
 | 
			
		||||
    return Row(
 | 
			
		||||
 
 | 
			
		||||
@@ -70,10 +70,10 @@ final class Landmark extends LinkedListEntry<Landmark>{
 | 
			
		||||
      final websiteURL = json['website_url'] as String?;
 | 
			
		||||
      final imageURL = json['image_url'] as String?;
 | 
			
		||||
      final description = json['description'] as String?;
 | 
			
		||||
      var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
 | 
			
		||||
      final visited = json['visited'] ?? false as bool;
 | 
			
		||||
      var duration = Duration(minutes: json['duration']);
 | 
			
		||||
      final visited = json['visited'] ?? false;
 | 
			
		||||
      var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      return Landmark(
 | 
			
		||||
        uuid: uuid,
 | 
			
		||||
        name: name,
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,18 @@ class Trip with ChangeNotifier {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<int> landmarkPosition (Landmark landmark) async {
 | 
			
		||||
    int i = 0;
 | 
			
		||||
    for (Landmark l in landmarks) {
 | 
			
		||||
      if (l.uuid == landmark.uuid) {
 | 
			
		||||
        return i;
 | 
			
		||||
      } else if (l.type != typeStart && l.type != typeFinish) {
 | 
			
		||||
      i++;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Trip({
 | 
			
		||||
    this.uuid = 'pending',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +1,33 @@
 | 
			
		||||
import "dart:convert";
 | 
			
		||||
import "dart:developer";
 | 
			
		||||
import "package:anyway/utils/load_landmark_image.dart";
 | 
			
		||||
import 'package:dio/dio.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import "package:anyway/utils/load_landmark_image.dart";
 | 
			
		||||
import "package:anyway/structs/landmark.dart";
 | 
			
		||||
import "package:anyway/structs/trip.dart";
 | 
			
		||||
import "package:anyway/structs/preferences.dart";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Dio dio = Dio(
 | 
			
		||||
    BaseOptions(
 | 
			
		||||
      baseUrl: API_URL_BASE,
 | 
			
		||||
      connectTimeout: const Duration(seconds: 5),
 | 
			
		||||
      receiveTimeout: const Duration(seconds: 120),
 | 
			
		||||
      // also accept 500 errors, since we cannot rule out that the server is at fault. We still want to gracefully handle these errors
 | 
			
		||||
      validateStatus: (status) => status! <= 500,
 | 
			
		||||
      receiveDataWhenStatusError: true,
 | 
			
		||||
      // api is notoriously slow
 | 
			
		||||
      // headers: {
 | 
			
		||||
      //   HttpHeaders.userAgentHeader: 'dio',
 | 
			
		||||
      //   'api': '1.0.0',
 | 
			
		||||
      // },
 | 
			
		||||
      contentType: Headers.jsonContentType,
 | 
			
		||||
      responseType: ResponseType.json,
 | 
			
		||||
        
 | 
			
		||||
  BaseOptions(
 | 
			
		||||
    baseUrl: API_URL_BASE,
 | 
			
		||||
    connectTimeout: const Duration(seconds: 5),
 | 
			
		||||
    receiveTimeout: const Duration(seconds: 120),
 | 
			
		||||
    // also accept 500 errors, since we cannot rule out that the server is at fault. We still want to gracefully handle these errors
 | 
			
		||||
    validateStatus: (status) => status! <= 500,
 | 
			
		||||
    receiveDataWhenStatusError: true,
 | 
			
		||||
    // api is notoriously slow
 | 
			
		||||
    // headers: {
 | 
			
		||||
    //   HttpHeaders.userAgentHeader: 'dio',
 | 
			
		||||
    //   'api': '1.0.0',
 | 
			
		||||
    // },
 | 
			
		||||
    contentType: Headers.jsonContentType,
 | 
			
		||||
    responseType: ResponseType.json,    
 | 
			
		||||
  ),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fetchTrip(
 | 
			
		||||
  Trip trip,
 | 
			
		||||
  UserPreferences preferences,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
import 'package:anyway/pages/current_trip.dart';
 | 
			
		||||
import 'package:anyway/pages/onboarding.dart';
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:anyway/utils/load_trips.dart';
 | 
			
		||||
import 'package:anyway/main.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/structs/trip.dart';
 | 
			
		||||
import 'package:anyway/utils/load_trips.dart';
 | 
			
		||||
import 'package:anyway/pages/current_trip.dart';
 | 
			
		||||
import 'package:anyway/pages/onboarding.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Widget getFirstPage() {
 | 
			
		||||
  SavedTrips trips = SavedTrips();
 | 
			
		||||
  SavedTrips trips = savedTrips;
 | 
			
		||||
  trips.loadTrips();
 | 
			
		||||
 | 
			
		||||
  return ListenableBuilder(
 | 
			
		||||
@@ -15,7 +18,7 @@ Widget getFirstPage() {
 | 
			
		||||
      if (items.isNotEmpty) {
 | 
			
		||||
        return TripPage(trip: items[0]);
 | 
			
		||||
      } else {
 | 
			
		||||
        return OnboardingPage();
 | 
			
		||||
        return const OnboardingPage();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user