frontend groundwork
This commit is contained in:
		@@ -1,9 +1,10 @@
 | 
			
		||||
import 'dart:collection';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter/material.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:the_widget_marker/the_widget_marker.dart';
 | 
			
		||||
 | 
			
		||||
class MapWidget extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
@@ -25,6 +26,7 @@ class _MapWidgetState extends State<MapWidget> {
 | 
			
		||||
    zoom: 11.0,
 | 
			
		||||
  );
 | 
			
		||||
  Set<Marker> markers = <Marker>{};
 | 
			
		||||
  final GlobalKey globalKey = GlobalKey();
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  void _onMapCreated(GoogleMapController controller) async {
 | 
			
		||||
@@ -49,28 +51,81 @@ class _MapWidgetState extends State<MapWidget> {
 | 
			
		||||
    Trip? trip = await widget.trip;
 | 
			
		||||
    LinkedList<Landmark>? landmarks = trip?.landmarks;
 | 
			
		||||
    if (landmarks != null){
 | 
			
		||||
      setState(() {
 | 
			
		||||
        for (Landmark landmark in landmarks) {
 | 
			
		||||
          markers.add(Marker(
 | 
			
		||||
            markerId: MarkerId(landmark.name),
 | 
			
		||||
            position: LatLng(landmark.location[0], landmark.location[1]),
 | 
			
		||||
            infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name),
 | 
			
		||||
          ));
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      for (Landmark landmark in landmarks) {
 | 
			
		||||
        markers.add(Marker(
 | 
			
		||||
          markerId: MarkerId(landmark.name),
 | 
			
		||||
          position: LatLng(landmark.location[0], landmark.location[1]),
 | 
			
		||||
          // infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name),
 | 
			
		||||
          icon: await MarkerIcon.widgetToIcon(globalKey),
 | 
			
		||||
        ));
 | 
			
		||||
      }
 | 
			
		||||
      setState(() {});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return GoogleMap(
 | 
			
		||||
      onMapCreated: _onMapCreated,
 | 
			
		||||
      initialCameraPosition: _cameraPosition,
 | 
			
		||||
      onCameraIdle: _onCameraIdle,
 | 
			
		||||
      // onLongPress: ,
 | 
			
		||||
      markers: markers,
 | 
			
		||||
      cloudMapId: '41c21ac9b81dbfd8',
 | 
			
		||||
    return Stack(
 | 
			
		||||
      children: [
 | 
			
		||||
        MyMarker(globalKey),
 | 
			
		||||
 | 
			
		||||
        GoogleMap(
 | 
			
		||||
              onMapCreated: _onMapCreated,
 | 
			
		||||
              initialCameraPosition: _cameraPosition,
 | 
			
		||||
              onCameraIdle: _onCameraIdle,
 | 
			
		||||
              // onLongPress: ,
 | 
			
		||||
              markers: markers,
 | 
			
		||||
              cloudMapId: '41c21ac9b81dbfd8',
 | 
			
		||||
            )
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MyMarker extends StatelessWidget {
 | 
			
		||||
  // declare a global key and get it trough Constructor
 | 
			
		||||
 | 
			
		||||
  MyMarker(this.globalKeyMyWidget);
 | 
			
		||||
  final GlobalKey globalKeyMyWidget;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    // This returns an outlined circle, with an icon corresponding to the landmark type
 | 
			
		||||
    // As a small dot, the number of the landmark is displayed in the top right
 | 
			
		||||
    return RepaintBoundary(
 | 
			
		||||
      key: globalKeyMyWidget,
 | 
			
		||||
      child: Stack(
 | 
			
		||||
        children: [
 | 
			
		||||
          Container(
 | 
			
		||||
            width: 75,
 | 
			
		||||
            height: 75,
 | 
			
		||||
            decoration: BoxDecoration(
 | 
			
		||||
              gradient: LinearGradient(
 | 
			
		||||
                begin: Alignment.topLeft,
 | 
			
		||||
                end: Alignment.bottomRight,
 | 
			
		||||
                colors: [Colors.red, Colors.yellow]
 | 
			
		||||
              ),
 | 
			
		||||
              shape: BoxShape.circle,
 | 
			
		||||
              border: Border.all(color: Colors.black, width: 5),
 | 
			
		||||
            ),
 | 
			
		||||
            child: Icon(Icons.location_on, color: Colors.black, size: 50),
 | 
			
		||||
          ),
 | 
			
		||||
          Positioned(
 | 
			
		||||
            top: 0,
 | 
			
		||||
            right: 0,
 | 
			
		||||
            child: Container(
 | 
			
		||||
              padding: EdgeInsets.all(5),
 | 
			
		||||
              decoration: BoxDecoration(
 | 
			
		||||
                color: Theme.of(context).primaryColor,
 | 
			
		||||
                shape: BoxShape.circle,
 | 
			
		||||
              ),
 | 
			
		||||
              child: Text('1', style: TextStyle(color: Colors.white, fontSize: 20)),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,11 @@
 | 
			
		||||
 | 
			
		||||
import 'package:anyway/layout.dart';
 | 
			
		||||
import 'package:anyway/structs/preferences.dart';
 | 
			
		||||
import 'package:anyway/utils/fetch_trip.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import "package:anyway/structs/trip.dart";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NewTripPage extends StatefulWidget {
 | 
			
		||||
  const NewTripPage({Key? key}) : super(key: key);
 | 
			
		||||
@@ -9,22 +15,71 @@ class NewTripPage extends StatefulWidget {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _NewTripPageState extends State<NewTripPage> {
 | 
			
		||||
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
 | 
			
		||||
  final TextEditingController latController = TextEditingController();
 | 
			
		||||
  final TextEditingController lonController = TextEditingController();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      appBar: AppBar(
 | 
			
		||||
        title: const Text('New Trip'),
 | 
			
		||||
      ),
 | 
			
		||||
      body: Center(
 | 
			
		||||
        child: Column(
 | 
			
		||||
          mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
          children: <Widget>[
 | 
			
		||||
            const Text(
 | 
			
		||||
              'Create a new trip',
 | 
			
		||||
      body: Form(
 | 
			
		||||
        key: _formKey,
 | 
			
		||||
        child: 
 | 
			
		||||
          Padding(
 | 
			
		||||
            padding: const EdgeInsets.all(15.0),
 | 
			
		||||
            child: Column(
 | 
			
		||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
              
 | 
			
		||||
              children: <Widget>[
 | 
			
		||||
                TextFormField(
 | 
			
		||||
                  decoration: const InputDecoration(hintText: 'Lat'),
 | 
			
		||||
                  controller: latController,
 | 
			
		||||
                  validator: (String? value) {
 | 
			
		||||
                    if (value == null || value.isEmpty || double.tryParse(value) == null){
 | 
			
		||||
                      return 'Please enter a floating point number';
 | 
			
		||||
                    }
 | 
			
		||||
                    return null;
 | 
			
		||||
                  },
 | 
			
		||||
                ),
 | 
			
		||||
                TextFormField(
 | 
			
		||||
                  decoration: const InputDecoration(hintText: 'Lon'),
 | 
			
		||||
                  controller: lonController,
 | 
			
		||||
 | 
			
		||||
                  validator: (String? value) {
 | 
			
		||||
                    if (value == null || value.isEmpty || double.tryParse(value) == null){
 | 
			
		||||
                      return 'Please enter a floating point number';
 | 
			
		||||
                    }
 | 
			
		||||
                    return null;
 | 
			
		||||
                  },
 | 
			
		||||
                ),
 | 
			
		||||
                Divider(height: 15, color: Colors.transparent),
 | 
			
		||||
                ElevatedButton(
 | 
			
		||||
                  onPressed: () {
 | 
			
		||||
                    if (_formKey.currentState!.validate()) {
 | 
			
		||||
                      List<double> startPoint = [
 | 
			
		||||
                        double.parse(latController.text),
 | 
			
		||||
                        double.parse(lonController.text)
 | 
			
		||||
                      ];
 | 
			
		||||
                      UserPreferences preferences = UserPreferences();
 | 
			
		||||
                      preferences.load();
 | 
			
		||||
                      Future<Trip> trip = fetchTrip(startPoint, preferences);
 | 
			
		||||
                        Navigator.of(context).push(
 | 
			
		||||
                          MaterialPageRoute(
 | 
			
		||||
                            builder: (context) => BasePage(mainScreen: "map", trip: trip)
 | 
			
		||||
                          )
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                  },
 | 
			
		||||
                  child: const Text('Create trip'),
 | 
			
		||||
                ),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
          )
 | 
			
		||||
        
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
import "package:anyway/structs/landmark.dart";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Route {
 | 
			
		||||
  final String name;
 | 
			
		||||
  final Duration duration;
 | 
			
		||||
  final List<Landmark> landmarks;
 | 
			
		||||
 | 
			
		||||
  Route({
 | 
			
		||||
    required this.name,
 | 
			
		||||
    required this.duration,
 | 
			
		||||
    required this.landmarks
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
import "package:anyway/structs/landmark.dart";
 | 
			
		||||
import "package:anyway/structs/linked_landmarks.dart";
 | 
			
		||||
import 'package:dio/dio.dart';
 | 
			
		||||
 | 
			
		||||
final dio = Dio();
 | 
			
		||||
 | 
			
		||||
// Future<List<Landmark>> fetchLandmarks() async {
 | 
			
		||||
//   // final response = await http
 | 
			
		||||
//   //     .get(Uri.parse('https://nav.kluster.moll.re/v1/destination/1'));
 | 
			
		||||
 | 
			
		||||
//   // if (response.statusCode == 200) {
 | 
			
		||||
//     // If the server did return a 200 OK response,
 | 
			
		||||
//     // then parse the JSON.
 | 
			
		||||
//     List<Landmark> landmarks = [
 | 
			
		||||
//       // 48°51′29.6″N 2°17′40.2″E
 | 
			
		||||
//       Landmark(
 | 
			
		||||
//         name: "Eiffel Tower",
 | 
			
		||||
//         location: [48.51296, 2.17402],
 | 
			
		||||
//         type: LandmarkType(name: "Tower"),
 | 
			
		||||
//         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg"
 | 
			
		||||
//         ),
 | 
			
		||||
//       Landmark(
 | 
			
		||||
//         name: "Notre Dame Cathedral",
 | 
			
		||||
//         location: [48.8530, 2.3498],
 | 
			
		||||
//         type: LandmarkType(name: "Monument"),
 | 
			
		||||
//         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Notre-Dame_de_Paris%2C_4_October_2017.jpg/440px-Notre-Dame_de_Paris%2C_4_October_2017.jpg"
 | 
			
		||||
//         ),
 | 
			
		||||
//       Landmark(
 | 
			
		||||
//         name: "Louvre palace",
 | 
			
		||||
//         location: [48.8606, 2.3376],
 | 
			
		||||
//         type: LandmarkType(name: "Museum"),
 | 
			
		||||
//         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg"
 | 
			
		||||
//         ),
 | 
			
		||||
//       Landmark(
 | 
			
		||||
//         name: "Pont-des-arts",
 | 
			
		||||
//         location: [48.5130, 2.2015],
 | 
			
		||||
//         type: LandmarkType(name: "Bridge"),
 | 
			
		||||
//         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg/560px-Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg"),
 | 
			
		||||
//       Landmark(
 | 
			
		||||
//         name: "Panthéon",
 | 
			
		||||
//         location: [48.5046, 2.2046],
 | 
			
		||||
//         type: LandmarkType(name: "Monument"),
 | 
			
		||||
//         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG"
 | 
			
		||||
//         ),
 | 
			
		||||
//     ];
 | 
			
		||||
//     // sleep 10 seconds
 | 
			
		||||
//     await Future.delayed(Duration(seconds: 5));
 | 
			
		||||
//     return landmarks;
 | 
			
		||||
//   // } else {
 | 
			
		||||
//   //   // If the server did not return a 200 OK response,
 | 
			
		||||
//   //   // then throw an exception.
 | 
			
		||||
//   //   throw Exception('Failed to load destination');
 | 
			
		||||
//   // }
 | 
			
		||||
// }
 | 
			
		||||
							
								
								
									
										45
									
								
								frontend/lib/utils/fetch_trip.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								frontend/lib/utils/fetch_trip.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
import 'package:dio/dio.dart';
 | 
			
		||||
import 'package:anyway/constants.dart';
 | 
			
		||||
import "package:anyway/structs/landmark.dart";
 | 
			
		||||
import "package:anyway/structs/trip.dart";
 | 
			
		||||
import "package:anyway/structs/preferences.dart";
 | 
			
		||||
 | 
			
		||||
import "package:anyway/structs/linked_landmarks.dart";
 | 
			
		||||
 | 
			
		||||
Dio dio = Dio(
 | 
			
		||||
    BaseOptions(
 | 
			
		||||
      baseUrl: API_URL_BASE,
 | 
			
		||||
      connectTimeout: const Duration(seconds: 5),
 | 
			
		||||
      receiveTimeout: const Duration(seconds: 60),
 | 
			
		||||
      // api is notoriously slow
 | 
			
		||||
      // headers: {
 | 
			
		||||
      //   HttpHeaders.userAgentHeader: 'dio',
 | 
			
		||||
      //   'api': '1.0.0',
 | 
			
		||||
      // },
 | 
			
		||||
      contentType: Headers.jsonContentType,
 | 
			
		||||
      responseType: ResponseType.json,
 | 
			
		||||
  ),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
Future<Trip> fetchTrip(
 | 
			
		||||
  List<double> startPoint,
 | 
			
		||||
  UserPreferences preferences,
 | 
			
		||||
) async {
 | 
			
		||||
  final response = await dio.post(
 | 
			
		||||
    "/trip/new",
 | 
			
		||||
    data: {
 | 
			
		||||
      // 'preferences': preferences.toJson(),
 | 
			
		||||
      'start': [48,2.3]
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  // handle errors
 | 
			
		||||
  if (response.statusCode != 200) {
 | 
			
		||||
    throw Exception('Failed to load trip');
 | 
			
		||||
  }
 | 
			
		||||
  if (response.data["error"] != null) {
 | 
			
		||||
    throw Exception(response.data["error"]);
 | 
			
		||||
  }
 | 
			
		||||
  return Trip.fromJson(response.data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user