diff --git a/.gitignore b/.gitignore index 9393f7a..8d91972 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ linux/ macos/ plugins/ *.env +newbuild.sh # IntelliJ related *.iml @@ -55,4 +56,5 @@ heresdk-explore-flutter-4.13.0.0.3315.tar.gz /android/app/google-services.json firebase_rules.txt lib/firebase_options.dart -ios/firebase_app_id_file.json \ No newline at end of file +ios/firebase_app_id_file.json +/book ambulance \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..fa862c6 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,42 @@ +/* Requires the Docker Pipeline plugin */ +pipeline { + agent { + docker { + image 'am271/flutter-apk-builder:heresdk' + } + } + stages { + stage('extract-sdk') { + steps { + sh ''' + sudo chown $UID:$GID -R $(pwd) + mkdir -p plugins/here_sdk + tar xzf /home/developer/heresdk-explore-flutter.tar.gz -C plugins/here_sdk + ''' + } + } + stage('build') { + environment { + CREDS = credentials('navigation-credentials') + FIREBASE_CREDS = credentials('navigation-firebase-options') + } + steps { + sh ''' + cat ${CREDS} > credentials.env + cat ${FIREBASE_CREDS} > lib/firebase_options.dart + flutter pub get + flutter build apk --debug + ''' + } + } + stage('upload-apk') { + environment { + APITOKEN = credentials('navigation-api-token') + NGROK_URL = credentials('navigation-ngrok-url') + } + steps { + sh 'newbuild.sh' + } + } + } +} diff --git a/assets/ambulance.png b/assets/ambulance.png new file mode 100644 index 0000000..4efe331 Binary files /dev/null and b/assets/ambulance.png differ diff --git a/lib/ambulance_form.dart b/lib/ambulance_form.dart index daedbf6..c90c920 100644 --- a/lib/ambulance_form.dart +++ b/lib/ambulance_form.dart @@ -1,22 +1,23 @@ import 'dart:convert'; +import 'package:AmbiNav/app_screen_ui.dart'; +import 'package:AmbiNav/grid.dart'; +import 'package:AmbiNav/main.dart'; +import 'package:AmbiNav/map_functions.dart'; import 'package:AmbiNav/services.dart'; -import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:crypto/crypto.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hive_flutter/adapters.dart'; // User defined ambulance form widget class AmbulanceForm extends StatefulWidget { + Services sobj; + AmbulanceForm({super.key, required this.sobj}); @override AmbulanceFormState createState() { return AmbulanceFormState(); } - - String generateFormHash(String name, String age, String hospital) { - var bytes = utf8.encode(name + age + hospital); - var hash = sha256.convert(bytes); - return hash.toString(); - } } // The form state class @@ -24,10 +25,18 @@ class AmbulanceFormState extends State { // a global key to validate form and identify widget final _formKey = GlobalKey(); final appTitle = 'Book an Ambulance'; + // final AppScreen aobj = AppScreen(); TextEditingController patient_name = TextEditingController(); TextEditingController age = TextEditingController(); TextEditingController preferred_hosp = TextEditingController(); String? gender; + + String generateFormHash(String name, String age, String hospital) { + var bytes = utf8.encode(name + age + hospital); + var hash = sha256.convert(bytes); + return hash.toString(); + } + @override Widget build(BuildContext context) { return MaterialApp( @@ -90,32 +99,49 @@ class AmbulanceFormState extends State { child: new ElevatedButton( child: const Text("Submit"), onPressed: () async { - Services.ref = - FirebaseDatabase.instance.ref("Bookings"); - //call to hashing function - String hashvalue = AmbulanceForm().generateFormHash( - patient_name.text, age.text, preferred_hosp.text); - Services.ref.update({ - hashvalue: { - "patient_name": patient_name.text, - "age": age.text, - "preferred_hospital": preferred_hosp.text, - "gender": gender, - "user_location": { - "lat": Services.userLocation.latitude, - "lon": Services.userLocation.longitude, - } - } - }); + _book(); + //listen to firebase to plot path on user side // ref.set({ // "patient_name": patient_name.text, // "age": age.text, // "preferred_hospital": preferred_hosp.text // }); + widget.sobj.goToUserLoc(); + MapServices.mapController.camera.zoomTo(20); + while (MapServices.mapController.camera.boundingBox == + null) {} + print("Grid is to be drawn after submit!"); + Grid grid = Grid(); + grid.isBooking = true; + Fluttertoast.showToast(msg: "Grid is shown"); + Navigator.pop(context); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: ((context) => AppScreen( + sobj: sobj, + grid: grid, + )))); + // Fluttertoast.showToast(msg: "hahahah"); + // grid.getGrid(true); }, )) ], ), ))); } + + void _book() async { + var box = await Hive.openBox('booking'); + // GeoCoordinates userLoc = await MapServices().getCurrentLoc(); + + String hashvalue = + generateFormHash(patient_name.text, age.text, preferred_hosp.text); + + box.put('name', patient_name.text); + box.put('age', age.text); + box.put('preferred_hosp', preferred_hosp.text); + box.put('gender', gender!); + box.put('lat', sobj.userLocation!.latitude); + box.put('lon', sobj.userLocation!.longitude); + box.put('hash', hashvalue); + } } diff --git a/lib/app_screen_res.dart b/lib/app_screen_res.dart index 44c5de7..9230771 100644 --- a/lib/app_screen_res.dart +++ b/lib/app_screen_res.dart @@ -1,47 +1,43 @@ -import 'dart:convert'; - +import 'package:AmbiNav/ambulance_form.dart'; +import 'package:AmbiNav/app_screen_ui.dart'; +import 'package:AmbiNav/grid.dart'; +import 'package:AmbiNav/listeners.dart'; +import 'package:AmbiNav/login.dart'; +import 'package:AmbiNav/map_functions.dart'; import 'package:AmbiNav/navig_notif_overlay_ui.dart'; -import 'package:AmbiNav/routing.dart'; +import 'package:AmbiNav/search.dart'; import 'package:AmbiNav/search_overlay_ui.dart'; -import 'package:AmbiNav/starter.dart'; -import 'package:firebase_database/firebase_database.dart'; +import 'package:AmbiNav/services.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:here_sdk/core.dart'; -import 'package:here_sdk/core.errors.dart'; -import 'services.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'ambulance_form.dart'; -class MapScreenRes { - static void goToUserLoc() async { - // Code to move the camera to user's current location - // LocationData ld = await Services.locationData.first; - Services.mapController.camera.lookAtPoint(Services.userLocation); +class AppScreenRes { + late var setStateOverlay; + late var bookingSetStateOverlay; + late SearchWidget searchWidget; + late Search seobj; + Grid grid = Grid(); + late var context; + + void setContext(var context) { + this.context = context; } - static List getActionButtonList() { - List actionButtonList = []; - if (Services.usertype == 'user') { - actionButtonList.add(Padding( - padding: const EdgeInsets.only(right: 15.0), - child: IconButton( - icon: Icon(Icons.search), - onPressed: (() => Services.setStateOverlay( - () => SearchWidget.toggleVisibility()))))); - } else if (Services.usertype == 'driver') { - actionButtonList.add(Padding( - padding: const EdgeInsets.only(right: 15.0), - child: IconButton( - icon: Icon(Icons.navigation), - onPressed: (() => Services.setStateOverlay( - () => NavigationNotif.toggleVisibility()))))); + Widget? chooseOverlayWidget(Services sobj) { + if (sobj.usertype == 'user') { + return SearchWidget( + seobj: seobj, + ); + } else if (sobj.usertype == 'driver' || sobj.usertype == 'police') { + return NavigationNotif( + sobj: sobj, + appScreenRes: this, + ); } - - return actionButtonList; + return null; } - static List getDrawerOptions(BuildContext context) { + List getDrawerOptions(BuildContext context, Services sobj) { List drawerButtonList = []; drawerButtonList.add(GestureDetector( child: ListTile( @@ -49,101 +45,75 @@ class MapScreenRes { leading: Icon(Icons.logout_rounded), ), onTap: () async { - SharedPreferences logindata = await SharedPreferences.getInstance(); - logindata.setBool('login', true); - logindata.setString('username', ""); - logindata.setString('usertype', ""); - Services.usertype = ""; + sobj.logout(); Navigator.pushReplacement( - context, MaterialPageRoute(builder: ((context) => loginpg()))); + context, + MaterialPageRoute( + builder: ((context) => loginpg( + sobj: sobj, + )))); }, )); - if (Services.usertype == 'user') { + if (sobj.usertype == 'user') { drawerButtonList.add(GestureDetector( child: ListTile( title: const Text('Book an ambulance'), leading: Icon(Icons.edit_note_rounded), ), - onTap: () => Navigator.push( - context, MaterialPageRoute(builder: (context) => AmbulanceForm())), + onTap: () { + AppScreen.scaffoldKey.currentState!.closeDrawer(); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AmbulanceForm( + sobj: sobj, + ))); + }, )); } return drawerButtonList; } - static void listenToBookings() async { - DatabaseReference ref = FirebaseDatabase.instance.ref("Bookings"); - Services.listen = ref.onChildAdded.listen((event) { - Services.formDetails = event.snapshot; - Services.setStateOverlay(() => NavigationNotif.toggleVisibility()); - }); - } - - static void search() async { - // Code to implement search functionality - } - - static Widget? chooseOverlayWidget() { - if (Services.usertype == 'user') { - return SearchWidget(); - } else if (Services.usertype == 'driver') { - return NavigationNotif(); - } - return null; - } - - static _parse(String dataString) { - // print(dataString); - - // Remove the square brackets at the beginning and end of the string - dataString = dataString.substring(1, dataString.length - 1); - - // Split the string into separate coordinate objects - List coordinateStrings = dataString.split("}, {"); - - // Loop through each coordinate object string and extract the latitude and longitude - List coordinates = []; - for (String coordinateString in coordinateStrings) { - // Remove the curly braces at the beginning and end of the coordinate string - coordinateString = - coordinateString.replaceAll("{", "").replaceAll("}", ""); - - // Split the coordinate string into separate latitude and longitude values - List values = coordinateString.split(", "); - - // Extract the latitude and longitude values and add them to the list of coordinates - double lon = double.parse(values[0].split(": ")[1]); - double lat = double.parse(values[1].split(": ")[1]); - coordinates.add(GeoCoordinates(lat, lon)); - } - print("Length: " + coordinates.length.toString()); - GeoPolyline geoPolyline; - try { - geoPolyline = GeoPolyline(coordinates); - return geoPolyline; - } catch (e) { - // Thrown when less than two vertices. - print("Oh shit!"); - print(e); - return null; + List getActionButtonList(Services sobj) { + seobj = Search(context, sobj); + searchWidget = SearchWidget(seobj: seobj); + List actionButtonList = []; + actionButtonList.add(Padding( + padding: const EdgeInsets.only(right: 15.0), + child: IconButton( + icon: Icon(Icons.grid_on), + onPressed: ((() async { + double zoom; + if (grid.isDisplayed) { + grid.removeGrid(); + } else { + zoom = + MapServices.mapController.camera.state.zoomLevel.toDouble(); + if (zoom >= 19) + grid.getGrid(); + else + Fluttertoast.showToast(msg: "Zoom in more to see grid!"); + } + }))))); + if (sobj.usertype == 'user') { + actionButtonList.add(Padding( + padding: const EdgeInsets.only(right: 15.0), + child: IconButton( + icon: Icon(Icons.search), + onPressed: (() => this + .setStateOverlay(() => searchWidget.toggleVisibility()))))); + } else if (sobj.usertype == 'driver') { + actionButtonList.add(Padding( + padding: const EdgeInsets.only(right: 15.0), + child: IconButton( + icon: Icon(Icons.navigation), + onPressed: (() { + if (Services.listen != null) { + FireListener(sobj).listenToBookings(this); + } + })))); } - } - static void listenToRequest() async { - DatabaseReference ref = FirebaseDatabase.instance.ref("Drivers"); - Routing rt = Routing(); - rt.initRoutingEngine(); - ref.onChildChanged.listen((event) { - DataSnapshot d = event.snapshot; - for (var i in d.children) { - // Fluttertoast.showToast(msg: i.value.toString()); - // print(i.value.toString()); - // print(i.value.runtimeType.toString()); - if (i.value.runtimeType == List) { - rt.showRouteOnMap(_parse(i.value.toString())); - } - // rt.showRouteOnMap(_parse(i.value.toString())); - } - }); + return actionButtonList; } } diff --git a/lib/app_screen_ui.dart b/lib/app_screen_ui.dart index 5b20e5a..af4565d 100644 --- a/lib/app_screen_ui.dart +++ b/lib/app_screen_ui.dart @@ -1,81 +1,110 @@ +// import 'package:AmbiNav/grid.dart'; +import 'package:AmbiNav/app_screen_res.dart'; +import 'package:AmbiNav/booking_map_ui.dart'; +import 'package:AmbiNav/end_destination_ui.dart'; +import 'package:AmbiNav/grid.dart'; +import 'package:AmbiNav/listeners.dart'; +import 'package:AmbiNav/map.dart'; import 'package:AmbiNav/marker_details_ui.dart'; -import 'package:AmbiNav/search_res.dart'; +import 'package:AmbiNav/search.dart'; import 'package:AmbiNav/services.dart'; import 'package:flutter/material.dart'; -import 'app_screen_res.dart'; -import 'map.dart'; class AppScreen extends StatefulWidget { - AppScreen({super.key}); + Grid? grid = null; + final Services sobj; + Search?obj; + AppScreen({super.key, required this.sobj, this.grid}); + static final scaffoldKey = GlobalKey(); @override State createState() => _AppScreenState(); } class _AppScreenState extends State { + AppScreenRes appScreenRes = AppScreenRes(); + @override void initState() { super.initState(); - Services.mapContext = this.context; - if(Services.usertype=="driver") { - MapScreenRes.listenToBookings(); - } - if(Services.usertype=="user") { - MapScreenRes.listenToRequest(); + appScreenRes.setContext(context); + if (widget.grid != null) { + widget.grid!.getGrid(); + } else { + if (widget.sobj.usertype == 'driver') { + FireListener(widget.sobj).listenToBookings(appScreenRes); + } else if (widget.sobj.usertype == 'police') { + FireListener(widget.sobj).listenToAll(); + } } } //used to reference setState() for search widget (setState is copied to this variable in StatefulBuilder) - var setStateOverlay; + // var setStateOverlay; + // var bookingSetStateOverlay; var setStateMarkerDetailsCard; @override Widget build(BuildContext context) { - final scaffoldKey = GlobalKey(); return Scaffold( - key: scaffoldKey, - drawer: Drawer( - child: SafeArea( - child: Column( - children: MapScreenRes.getDrawerOptions(context) - ), - ), - ), + key: AppScreen.scaffoldKey, appBar: AppBar( title: Text("Navigation"), leading: IconButton( //hamburger icon icon: Icon(Icons.menu), onPressed: () { - if (scaffoldKey.currentState!.isDrawerOpen) { - scaffoldKey.currentState!.closeDrawer(); + if (AppScreen.scaffoldKey.currentState!.isDrawerOpen) { + AppScreen.scaffoldKey.currentState!.closeDrawer(); } else { - scaffoldKey.currentState!.openDrawer(); + AppScreen.scaffoldKey.currentState!.openDrawer(); } }, ), - actions: MapScreenRes.getActionButtonList()), + actions: appScreenRes.getActionButtonList(widget.sobj)), body: Stack( children: [ // MapWidget - MapWidget(), + MapWidget(sobj: widget.sobj), //here the stateful builder is used to render search widget of search.dart (a card element to enter destination) //it renders without redrawing the entire screen //if the below lines are not included , map will be redrawn every time the search button is toggled StatefulBuilder(builder: ((context, setState) { - Services.setStateOverlay = setState; - return MapScreenRes.chooseOverlayWidget()!; + appScreenRes.setStateOverlay = setState; + return appScreenRes.chooseOverlayWidget(widget.sobj)!; })), StatefulBuilder(builder: ((context, setState) { - SearchRes.setStateMarkerDetailsCard = setState; + appScreenRes.bookingSetStateOverlay = setState; + return BookingWidget( + grid: widget.grid, + isVisible: (widget.grid != null) ? true : false); + })), + + StatefulBuilder( + builder: (BuildContext context, setState) { + Services.endDestinationSetSateOverlay = setState; + return EndDes( + sbj: widget.sobj); + }, + ), + + StatefulBuilder(builder: ((context, setState) { + Search.setStateMarkerDetailsCard = setState; return DisplayMarkerInfo(); })), ], + ), + drawer: Drawer( + child: SafeArea( + child: Column(children: appScreenRes.getDrawerOptions(context, widget.sobj)), + ), ), floatingActionButton: FloatingActionButton( //this button moves the camera to user's current location - recenter button - onPressed: (MapScreenRes.goToUserLoc), + onPressed: () async { + widget.sobj.goToUserLoc(); + }, child: const Icon( Icons.add_location_alt_outlined, color: Colors.white, diff --git a/lib/booking_map_ui.dart b/lib/booking_map_ui.dart new file mode 100644 index 0000000..2bf7dce --- /dev/null +++ b/lib/booking_map_ui.dart @@ -0,0 +1,73 @@ +import 'package:AmbiNav/grid.dart'; +import 'package:flutter/material.dart'; + +class BookingWidget extends StatefulWidget { + Grid? grid; + bool isVisible; + BookingWidget({super.key, this.grid, required this.isVisible}); + + //function to toggle visibility of search overlay (essentially a card element to enter destination) + void toggleVisibility() { + isVisible = !isVisible; + } + + @override + State createState() => _BookingWidgetState(); +} + +class _BookingWidgetState extends State { + TextStyle style = TextStyle(fontSize: 16, color: Colors.white); + + @override + Widget build(BuildContext context) { + return Visibility( + child: Container( + margin: EdgeInsets.all(30), + height: 70, + decoration: BoxDecoration( + boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 2)], + color: Colors.blue.shade400, + borderRadius: BorderRadius.all(Radius.circular(13))), + child: Padding( + padding: EdgeInsets.all(15), + child: Row( + children: [ + Text("Proceed to Book?", style: style), + Container( + width: 70, + ), + VerticalDivider( + width: 30, + thickness: 1.2, + ), + GestureDetector( + child: Text('Yes', style: style), + onTap: () { + if (widget.grid != null) { + widget.grid!.sobj.bookAmbulance(); + setState((() => widget.toggleVisibility())); + widget.grid!.isBooking = false; + widget.grid!.removeGrid(); + } + }, + ), + VerticalDivider( + width: 30, + thickness: 1.2, + ), + GestureDetector( + child: Text('No', style: style), + onTap: () { + setState((() => widget.toggleVisibility())); + widget.grid!.removeGrid(); + widget.grid!.isBooking = false; + widget.grid = null; + }, + ), // Text here + ], + ), + )), + visible: widget.isVisible, + ); + } +} \ No newline at end of file diff --git a/lib/countdown_timer.dart b/lib/countdown_timer.dart index 152006b..46cd7aa 100644 --- a/lib/countdown_timer.dart +++ b/lib/countdown_timer.dart @@ -1,9 +1,14 @@ import 'dart:math'; +import 'package:AmbiNav/app_screen_res.dart'; import 'package:AmbiNav/navig_notif_overlay_ui.dart'; import 'package:AmbiNav/services.dart'; import 'package:flutter/material.dart'; class CountDownTimer extends StatefulWidget { + final AppScreenRes appScreenRes; + + const CountDownTimer({super.key, required this.appScreenRes}); + @override _CountDownTimerState createState() => _CountDownTimerState(); } @@ -27,8 +32,8 @@ class _CountDownTimerState extends State controller.reverse(from: 1.0); controller.addStatusListener((status) { if (status == AnimationStatus.dismissed) { - Services.setStateOverlay(() { - NavigationNotif.toggleVisibility(); + widget.appScreenRes.setStateOverlay(() { + NavigationNotif.toggleVisibility(null, ''); }); } }); @@ -98,4 +103,4 @@ class CustomTimerPainter extends CustomPainter { color != old.color || backgroundColor != old.backgroundColor; } -} +} \ No newline at end of file diff --git a/lib/driver_details.dart b/lib/driver_details.dart index 0d82a75..66adbaf 100644 --- a/lib/driver_details.dart +++ b/lib/driver_details.dart @@ -1,15 +1,14 @@ import 'package:AmbiNav/app_screen_ui.dart'; +import 'package:AmbiNav/main.dart'; import 'package:AmbiNav/services.dart'; -import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'starter.dart'; +import 'login.dart'; import 'package:shared_preferences/shared_preferences.dart'; class AmbiDriverDetails extends StatefulWidget { - AmbiDriverDetails({super.key}); - + final Services sobj; + AmbiDriverDetails({super.key, required this.sobj}); @override State createState() => _AmbiDriverDetailsState(); } @@ -108,17 +107,18 @@ class _AmbiDriverDetailsState extends State { if (username != '' && code != '') { logindata.setBool('login', false); - logindata.setString('username', username); logindata.setString('usertype', 'driver'); - Services.usertype = 'driver'; - Services.username = username; - Fluttertoast.showToast(msg: username); + sobj.setCred('username', username); + sobj.setCred('usertype', 'driver'); + sobj.username = username; + sobj.usertype = 'driver'; Navigator.pop(context); Navigator.pushReplacement( context, MaterialPageRoute( - builder: (context) => AppScreen())); + builder: (context) => + AppScreen(sobj: widget.sobj))); } }, child: Container( @@ -155,9 +155,11 @@ class _AmbiDriverDetailsState extends State { Container( child: GestureDetector( onTap: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: ((context) => loginpg()))); + Navigator.of(context) + .pushReplacement(MaterialPageRoute( + builder: ((context) => loginpg( + sobj: widget.sobj, + )))); }, child: Text( ' Click here', diff --git a/lib/end_destination_ui.dart b/lib/end_destination_ui.dart new file mode 100644 index 0000000..1df6472 --- /dev/null +++ b/lib/end_destination_ui.dart @@ -0,0 +1,37 @@ +import 'package:AmbiNav/routing.dart'; +import 'package:AmbiNav/services.dart'; +import 'package:flutter/material.dart'; + +class EndDes extends StatefulWidget { + static bool isVisible = false; + Services sbj; + static late Routing rt ; + EndDes({super.key, required this.sbj}); + + @override + State createState() => _EndDesState(); +} + +class _EndDesState extends State { + @override + Widget build(BuildContext context) { + return Visibility( + child: ElevatedButton( + onPressed: () { + EndDes.rt.removeRoute(); + setState(() { + EndDes.isVisible = false; + }); + }, + + // style: ButtonStyle(elevation: MaterialStateProperty(12.0 )), + style: ElevatedButton.styleFrom( + elevation: 12.0, + textStyle: const TextStyle(color: Colors.white), + backgroundColor: Colors.blue[400]), + child: const Text('End trip'), + ), + visible: EndDes.isVisible, + ); + } +} diff --git a/lib/grid.dart b/lib/grid.dart new file mode 100644 index 0000000..55a35d7 --- /dev/null +++ b/lib/grid.dart @@ -0,0 +1,187 @@ +import 'dart:convert'; +import 'package:AmbiNav/map_functions.dart'; +import 'package:AmbiNav/routing.dart'; +import 'package:AmbiNav/services.dart'; +import 'package:AmbiNav/starter.dart'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:here_sdk/core.dart'; +import 'package:here_sdk/gestures.dart'; +import 'package:here_sdk/mapview.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:what3words/what3words.dart'; +import 'package:http/http.dart' as http; + +class Grid { + var _api; + List lines = []; + Services sobj = Services(); + static GeoCoordinates? target = null; + static bool marked = false; + static MapPolyline? addSquare = null; + static Routing obj = Routing(); + static MapPolyline? currentSquare = null; + static MapPolyline? prevSquare = null; + static GeoCoordinates source = GeoCoordinates(12.916734, 77.673736); + static bool choose2Squares = false; + bool isDisplayed = false; + bool isBooking = false; + + Grid() { + Services _sobj = Services(); + _api = What3WordsV3(Starter().getSecret('what3words.api.key')!); + print("Initialized W3W"); + } + + void _convertGrid(List grid) { + List coordinates = []; + double widthInPixels = 2; + + print(grid.length); + + for (Line element in grid) { + coordinates.add(GeoCoordinates(element.start.lat, element.start.lng)); + coordinates.add(GeoCoordinates(element.end.lat, element.end.lng)); + MapPolyline polyline = MapPolyline(GeoPolyline(coordinates), + widthInPixels, Color.fromARGB(255, 49, 214, 203)); + lines.add(polyline); + + coordinates.clear(); + } + } + + void _showGrid() { + for (MapPolyline polyline in lines) { + MapServices.mapController.mapScene.addMapPolyline(polyline); + } + isDisplayed = true; + } + + Future removeGrid() async { + for (MapPolyline element in lines) { + print('removing!'); + MapServices.mapController.mapScene.removeMapPolyline(element); + } + // Services.mapController.mapScene.removeMapPolyline(polyline); + lines.clear(); + isDisplayed = false; + MapServices.mapController.gestures.tapListener = null; + if(currentSquare != null) MapServices.mapController.mapScene.removeMapPolyline(currentSquare!); + } + + static List _getOtherCorners( + double swLat, double swLng, double neLat, double neLng) { + List> otherCorners = List.generate(4, (_) => [0.0, 0.0]); + + double width = neLng - swLng; + double height = neLat - swLat; + + otherCorners[0][0] = swLat; + otherCorners[0][1] = swLng; + + otherCorners[1][0] = swLat; + otherCorners[1][1] = swLng + width; + + otherCorners[2][0] = swLat + height; + otherCorners[2][1] = swLng + width; + + otherCorners[3][0] = swLat + height; + otherCorners[3][1] = swLng; + + List coords = []; + for (List pair in otherCorners) { + coords.add(GeoCoordinates(pair[0], pair[1])); + } + coords.add(coords.first); + + return coords; + } + + bool markerState() { + if (marked) { + return false; + } else { + return true; + } + } + + Future getGrid() async { + GeoCoordinates NEC = + MapServices.mapController.camera.boundingBox!.northEastCorner; + GeoCoordinates SWC = + MapServices.mapController.camera.boundingBox!.southWestCorner; + GridSectionRequestBuilder gsrb = GridSectionRequestBuilder( + _api, + Coordinates(NEC.latitude, NEC.longitude), + Coordinates(SWC.latitude, SWC.longitude)); + Response grid; + grid = await gsrb.execute(); + print("Request successful grid2"); + + if (grid.isSuccessful()) { + _convertGrid(grid.data()!.lines); + _showGrid(); + } else { + print(grid.error()!.message); + } + + // lat and long when screen is tapped + MapServices.mapController.gestures.tapListener = + TapListener((Point2D touchPoint) async { + GeoCoordinates geoCoordinates = + MapServices.mapController.viewToGeoCoordinates(touchPoint)!; + marked = markerState(); + print('Tap at: ' + + geoCoordinates.latitude.toString() + + '\n' + + geoCoordinates.longitude.toString()); + // Fluttertoast.showToast(msg: 'Tap at: '+ geoCoordinates.latitude.toString()+'\n' +geoCoordinates.longitude.toString()); + var url = Uri.https('api.what3words.com', 'v3/convert-to-3wa', { + 'key': Starter().getSecret('what3words.api.key')!, + 'coordinates': geoCoordinates.latitude.toString() + + ',' + + geoCoordinates.longitude.toString(), + }); + + var response = await http.get(url); + + Map parsed = + jsonDecode(response.body).cast(); + + if (parsed.containsKey('words')) { + print('3word request successful'); + Fluttertoast.showToast(msg: parsed['words']); + print(parsed['words']); + if (isBooking) { + var box = Hive.openBox('booking'); + box.then((value_) { + value_.put('lat', geoCoordinates.latitude); + value_.put('lon', geoCoordinates.longitude); + }); + } + } + + List coords = _getOtherCorners( + parsed['square']['southwest']['lat'], + parsed['square']['southwest']['lng'], + parsed['square']['northeast']['lat'], + parsed['square']['northeast']['lng']); + + if (!marked) { + // Fluttertoast.showToast(msg: "removing the marker"); + MapServices.mapController.mapScene.removeMapPolyline(currentSquare!); + currentSquare = null; + marked = markerState(); + } + currentSquare = MapPolyline(GeoPolyline(coords), 5, Colors.red.shade700); + target = + GeoCoordinates(geoCoordinates.latitude, geoCoordinates.longitude); + // Fluttertoast.showToast(msg: "redd marker!"); + + if (currentSquare != null) { + MapServices.mapController.mapScene.removeMapPolyline(currentSquare!); + } + MapServices.mapController.mapScene.addMapPolyline(currentSquare!); + }); + } +} diff --git a/lib/listeners.dart b/lib/listeners.dart new file mode 100644 index 0000000..d793a29 --- /dev/null +++ b/lib/listeners.dart @@ -0,0 +1,177 @@ +import 'dart:math'; +import 'package:AmbiNav/app_screen_res.dart'; +import 'package:AmbiNav/map_functions.dart'; +import 'package:AmbiNav/navig_notif_overlay_ui.dart'; +import 'package:AmbiNav/routing.dart'; +import 'package:AmbiNav/services.dart'; +import 'package:firebase_database/firebase_database.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:here_sdk/core.dart'; +import 'package:here_sdk/mapview.dart'; +import 'package:hive_flutter/adapters.dart'; +import 'dart:math' as math; + +class FireListener { + late Services sobj; + List hashes = []; + Routing rt = Routing(); + + FireListener(Services sobj) { + this.sobj = sobj; + } + + void listenToBookings(AppScreenRes appScreenRes) async { + DatabaseReference ref = FirebaseDatabase.instance.ref('Bookings'); + Services.listen = ref.onChildAdded.listen((event) async { + double lat = double.parse( + event.snapshot.child('user_location/lat').value.toString()); + double long = double.parse( + event.snapshot.child('user_location/lon').value.toString()); + appScreenRes.setStateOverlay(() { + NavigationNotif.toggleVisibility( + GeoCoordinates(lat, long), event.snapshot.key.toString()); + }); + }); + } + + void listenToAcceptance() async { + var box = await Hive.openBox('booking'); + String hash = box.get('hash'); + listenToAmbLoc(); + // Fluttertoast.showToast(msg: "Hash is " + hash); + DatabaseReference ref = FirebaseDatabase.instance.ref('Bookings/' + hash); + ref.onChildAdded.listen((event) async { + Object? data = event.snapshot.value; + // Fluttertoast.showToast(msg: data.toString()); + if (data.runtimeType.toString() != 'String') { + List d = data as List; + _convertToPolyline(d); + } + }); + } + + _convertToPolyline(List l) { + List newlist = []; + l.forEach((element) { + newlist.add(GeoCoordinates(element['lat'], element['lon'])); + }); + rt.initRoutingEngine(sobj); + rt.showRouteOnMap(GeoPolyline(newlist)); + // Fluttertoast.showToast(msg: "LIGHT"); + } + + //this function is on the user's side + void listenToAmbLoc() async { + var box = await Hive.openBox('booking'); + String hash = box.get('hash'); + double userlat = box.get('lat'); + double userlon = box.get('lon'); + double lat = 0, long = 0; + bool flag = false; + bool once = true; + DatabaseReference ref = + FirebaseDatabase.instance.ref('Bookings/' + hash + '/ambulance_loc'); + ref.onChildChanged.listen((event) { + // Fluttertoast.showToast(msg: "This is " + event.snapshot.value.toString()); + if (event.snapshot.key == 'lat') { + lat = double.parse(event.snapshot.value.toString()); + } else if (event.snapshot.key == 'lon') { + long = double.parse(event.snapshot.value.toString()); + flag = true; + } + if (flag) { + // Fluttertoast.showToast( + // msg: "You are at " + lat.toString() + ", " + long.toString()); + sobj.updateAmbLoc(GeoCoordinates(lat, long)); + flag = false; + if (once) { + midPoint(lat, long).then((value) { + MapServices.mapController.camera.lookAtPointWithMeasure( + value, + MapMeasure(MapMeasureKind.distance, + distance(lat, long, userlat, userlon))); + }); + once = false; + } + //check if the ambulance has arrived + double d = distance(lat, long, userlat, userlon); + DatabaseReference ref1 = FirebaseDatabase.instance.ref('Bookings/' + hash); + if (d < 300) { + //code the part to end trip + Fluttertoast.showToast(msg: "Ambulance in vicinity"); + ref1.update({"Reached":"True"}); + Services.endDestinationSetSateOverlay((){ + rt.removeRoute(); + }); + } + } + }); + } + + Future midPoint(double lat1_, double lon1_) async { + var box = await Hive.openBox('booking'); + double lat2 = degreesToRadians(box.get('lat')); + double lon2 = degreesToRadians(box.get('lon')); + + double lat1 = degreesToRadians(lat1_); + double lon1 = degreesToRadians(lon1_); + + double bx = cos(lat2) * cos(lon2 - lon1); + double by = cos(lat2) * sin(lon2 - lon1); + + double midLat = atan2(sin(lat1) + sin(lat2), + sqrt((cos(lat1) + bx) * (cos(lat1) + bx) + by * by)); + double midLon = lon1 + atan2(by, cos(lat1) + bx); + + return GeoCoordinates(radiansToDegrees(midLat), radiansToDegrees(midLon)); + } + + double degreesToRadians(double degrees) { + return degrees * pi / 180.0; + } + + double radiansToDegrees(double radians) { + return radians * 180.0 / pi; + } + + double distance(double lat1, double lon1, double lat2, double lon2) { + double r = 6371; // radius of the Earth in km + double phi1 = math.pi * lat1 / 180; + double phi2 = math.pi * lat2 / 180; + double delta_phi = math.pi * (lat2 - lat1) / 180; + double delta_lambda = math.pi * (lon2 - lon1) / 180; + double a = math.sin(delta_phi / 2) * math.sin(delta_phi / 2) + + math.cos(phi1) * + math.cos(phi2) * + math.sin(delta_lambda / 2) * + math.sin(delta_lambda / 2); + double c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)); + double d = r * c * 1000; // distance in km + return d; + } + + void listenToAll() { + DatabaseReference ref = FirebaseDatabase.instance.ref('Bookings'); + ref.onChildChanged.listen((event) async { + if (event.snapshot.hasChild('ambulance_loc')) { + double lat = double.parse( + event.snapshot.child('ambulance_loc/lat').value.toString()); + double lon = double.parse( + event.snapshot.child('ambulance_loc/lon').value.toString()); + sobj.updateAmbLoc(GeoCoordinates(lat, lon)); + } + if (event.snapshot.hasChild('route')) { + Object? data = event.snapshot.child('route').value; + // Fluttertoast.showToast(msg: data.toString()); + if (data.runtimeType.toString() != 'String' && + !hashes.contains(event.snapshot.key.toString())) { + // Fluttertoast.showToast(msg: event.snapshot.key.toString()); + List d = data as List; + _convertToPolyline(d); + hashes.add(event.snapshot.key.toString()); + // Fluttertoast.showToast(msg: hashes.length.toString()); + } + } + }); + } +} diff --git a/lib/login.dart b/lib/login.dart new file mode 100644 index 0000000..2ffcab7 --- /dev/null +++ b/lib/login.dart @@ -0,0 +1,156 @@ +import 'package:AmbiNav/services.dart'; +import 'package:flutter/material.dart'; +import 'user_details.dart'; +import 'driver_details.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:bordered_text/bordered_text.dart'; + +String finalAmbulanceCode = ""; + +class loginpg extends StatefulWidget { + final Services sobj; + const loginpg({super.key, required this.sobj}); + + @override + State createState() => _loginpgState(); +} + +class _loginpgState extends State { + @override + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage("images/ambiBg.jpg"), fit: BoxFit.cover)), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.center, + end: Alignment.bottomCenter, + colors: [ + Color.fromARGB(221, 24, 24, 24), + Color.fromARGB(221, 0, 0, 0) + ])), + child: Scaffold( + backgroundColor: Colors.transparent, + body: SafeArea( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircleAvatar( + radius: 92.0, + backgroundColor: Color.fromARGB(255, 255, 255, 255), + child: CircleAvatar( + backgroundColor: Color.fromARGB(255, 5, 5, 5), + backgroundImage: AssetImage('images/ambi2.png'), + radius: 90.0, + ), + ), + SizedBox( + height: 20.0, + ), + BorderedText( + strokeWidth: 4, + strokeColor: Color.fromARGB(255, 251, 251, 251), + child: Text("AMBINAV", + style: GoogleFonts.montserrat( + fontSize: 40, + color: Colors.green, + fontWeight: FontWeight.bold, + letterSpacing: 2.5, + )), + ), + SizedBox( + height: 20.0, + ), + BorderedText( + strokeWidth: 0.8, + strokeColor: Color.fromARGB(255, 0, 0, 0), + child: Text("Choose your role", + style: GoogleFonts.rokkitt( + fontSize: 21, + color: Colors.green, + fontWeight: FontWeight.bold, + letterSpacing: 1, + )), + ), + SizedBox( + height: 40.0, + width: 260.0, + child: Divider( + color: Color.fromARGB(255, 243, 249, 251), + thickness: 1.6, + ), + ), + Card( + borderOnForeground: true, + color: Colors.grey[200], + elevation: 8.0, + shadowColor: Color.fromARGB(255, 255, 255, 255), + child: InkWell( + splashColor: + Color.fromARGB(255, 25, 143, 96).withAlpha(30), + onTap: () { + debugPrint('Card tapped.'); + // Connect to map + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AmbiDriverDetails(sobj: widget.sobj,))); + }, + child: const SizedBox( + width: 200, + height: 50, + child: Center( + child: Text( + 'Ambulance Driver', + style: TextStyle( + letterSpacing: 0.7, + fontSize: 16, + ), + ), + ), + ), + ), + ), + SizedBox( + height: 15.0, + ), + Card( + color: Colors.grey[200], + elevation: 8.0, + shadowColor: Color.fromARGB(255, 247, 248, 247), + child: InkWell( + splashColor: + Color.fromARGB(255, 72, 202, 21).withAlpha(30), + onTap: () { + debugPrint('Card tapped.'); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => userDetails(sobj: widget.sobj,))); + // Connect to map + }, + child: const SizedBox( + width: 200, + height: 50, + child: Center( + child: Text('User Driver', + style: TextStyle( + letterSpacing: 0.7, + fontSize: 16, + ))), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 9158468..63d2195 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,88 +1,50 @@ +import 'package:AmbiNav/app_screen_ui.dart'; +import 'package:AmbiNav/firebase_options.dart'; +import 'package:AmbiNav/login.dart'; import 'package:AmbiNav/services.dart'; +import 'package:AmbiNav/starter.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'firebase_options.dart'; import 'package:flutter/material.dart'; -import 'app_screen_ui.dart'; -import 'package:here_sdk/core.engine.dart'; -import 'package:here_sdk/core.dart'; -import 'package:here_sdk/core.errors.dart'; //for handling InstantiationException while initializing sdk -import 'starter.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -Future _initializeHERESDK() async { - // Needs to be called before accessing SDKOptions to load necessary libraries. - SdkContext.init(IsolateOrigin.main); +Starter starter = Starter(); +Services sobj = Services(); - // Set your credentials for the HERE SDK. - String accessKeyId = Services.getSecret("here.access.key.id")!; - String accessKeySecret = Services.getSecret("here.access.key.secret")!; - SDKOptions sdkOptions = - SDKOptions.withAccessKeySecret(accessKeyId, accessKeySecret); - - try { - await SDKNativeEngine.makeSharedInstance(sdkOptions); - } on InstantiationException { - throw Exception("Failed to initialize the HERE SDK."); - } -} - -void alreadyLoggedin() { +void login() { SharedPreferences.getInstance().then((value) { bool newuser = (value.getBool('login') ?? true); - if (newuser == false) { - Services.usertype = value.getString('usertype')!; - Services.username = value.getString('username')!; + // Services.usertype = value.getString('usertype')!; + sobj.usertype = value.getString('usertype')!; + sobj.username = value.getString('username')!; + starter.loadHiveBox(value.getString('username')!, value.getString('usertype')!); runApp(MaterialApp( debugShowCheckedModeBanner: false, - home: AppScreen(), + home: AppScreen( + sobj: sobj, + ), )); } else { runApp(MaterialApp( debugShowCheckedModeBanner: false, - home: loginpg(), + home: loginpg( + sobj: sobj, + ), )); } }); } -void checkLoginStatus() { - FirebaseAuth.instance.idTokenChanges().listen((User? user) { - if (user == null) { - Fluttertoast.showToast(msg: "User is currently signed out!"); - } else { - Fluttertoast.showToast(msg: "User is signed in!"); - } - }); -} - void main() async { WidgetsFlutterBinding.ensureInitialized(); - await Services.loadCreds(); - await _initializeHERESDK(); // initialise the HERE SDK - await Services.getPermissions(); // wait for permissions - await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); - checkLoginStatus(); - try { - final userCredential = await FirebaseAuth.instance.signInAnonymously(); - print("Signed in with temporary account."); - Fluttertoast.showToast(msg: userCredential.user!.uid); - } on FirebaseAuthException catch (e) { - switch (e.code) { - case "operation-not-allowed": - print("Anonymous auth hasn't been enabled for this project."); - break; - default: - print("Unknown error."); - } - } - checkLoginStatus(); - alreadyLoggedin(); // check if user is already logged in - Services.setLoc(); // start streaming the location -} + await starter.loadCreds(); + await starter.initializeHERESDK(); + await starter.getPermissions(); + await starter.firebaseLogin(); + + login(); +} \ No newline at end of file diff --git a/lib/map.dart b/lib/map.dart index b6cba26..b8c877a 100644 --- a/lib/map.dart +++ b/lib/map.dart @@ -1,10 +1,15 @@ // Code for map widget +import 'package:AmbiNav/main.dart'; +import 'package:AmbiNav/map_functions.dart'; import 'package:flutter/material.dart'; import 'package:here_sdk/core.dart'; import 'package:here_sdk/mapview.dart'; import 'services.dart'; +// import 'main.dart' as mm; class MapWidget extends StatelessWidget { + MapWidget({required Services sobj}); + @override Widget build(BuildContext context) { return HereMap(onMapCreated: _onMapCreated); @@ -17,37 +22,39 @@ class MapWidget extends StatelessWidget { print('Map scene not loaded. MapError: ${error.toString()}'); return; } - + MapServices.mapController = hereMapController; const double distanceToEarthInMeters = 4000; MapMeasure mapMeasureZoom = MapMeasure(MapMeasureKind.distance, distanceToEarthInMeters); - hereMapController.camera - .lookAtPointWithMeasure(Services.userLocation, mapMeasureZoom); + MapServices().getCurrentLoc().then((value) { + hereMapController.camera.lookAtPointWithMeasure(value, mapMeasureZoom); + _addLocationIndicator( + value, LocationIndicatorIndicatorStyle.navigation); + }); }); - - Services.mapController = hereMapController; - _addLocationIndicator( - Services.userLocation, LocationIndicatorIndicatorStyle.navigation); } void _addLocationIndicator(GeoCoordinates geoCoordinates, - LocationIndicatorIndicatorStyle indicatorStyle) { - Services.locationIndicator.locationIndicatorStyle = indicatorStyle; + LocationIndicatorIndicatorStyle indicatorStyle) async { + // mm.sobj.locationIndicator.locationIndicatorStyle = indicatorStyle; + MapServices.locationIndicator = LocationIndicator(); + MapServices.locationIndicator.locationIndicatorStyle = indicatorStyle; // A LocationIndicator is intended to mark the user's current location, // including a bearing direction. // For testing purposes, we create a Location object. Usually, you may want to get this from // a GPS sensor instead. - Location location = Location.withCoordinates(Services.userLocation); + Location location = Location.withCoordinates(GeoCoordinates(12.9716, 77.5946)); location.horizontalAccuracyInMeters = 1.0; // location.time = DateTime.now(); // // location.bearingInDegrees = _getRandom(0, 360); - Services.locationIndicator.updateLocation(location); - + // mm.sobj.locationIndicator.updateLocation(location); + MapServices.locationIndicator.updateLocation(location); + sobj.streamLoc(); // A LocationIndicator listens to the lifecycle of the map view, // therefore, for example, it will get destroyed when the map view gets destroyed. - Services.mapController.addLifecycleListener(Services.locationIndicator); + MapServices.mapController.addLifecycleListener(MapServices.locationIndicator); } } diff --git a/lib/map_functions.dart b/lib/map_functions.dart new file mode 100644 index 0000000..fbb3827 --- /dev/null +++ b/lib/map_functions.dart @@ -0,0 +1,33 @@ +import 'package:here_sdk/gestures.dart'; +import 'package:here_sdk/mapview.dart'; +import 'package:location/location.dart'; +import 'package:here_sdk/core.dart' as here_core; + +class MapServices { + static late HereMapController mapController; + + static late LocationIndicator locationIndicator; + + void setTapGestureHandler(TapListener listener) { + MapServices.mapController.gestures.tapListener = listener; + } + + void clearMapMarkers(List mapMarkerList) { + mapMarkerList.forEach((mapMarker) { + MapServices.mapController.mapScene.removeMapMarker(mapMarker); + }); + mapMarkerList.clear(); + } + + void clearMapPolylines(List mapPolylines) { + for (var mapPolyline in mapPolylines) { + MapServices.mapController.mapScene.removeMapPolyline(mapPolyline); + } + mapPolylines.clear(); + } + + Future getCurrentLoc() async { + LocationData temp = await Location().getLocation(); + return here_core.GeoCoordinates(temp.latitude!, temp.longitude!); + } +} diff --git a/lib/marker_details_ui.dart b/lib/marker_details_ui.dart index 3d7f6dd..4c22234 100644 --- a/lib/marker_details_ui.dart +++ b/lib/marker_details_ui.dart @@ -1,14 +1,25 @@ -import 'package:AmbiNav/search_res.dart'; +import 'package:AmbiNav/search.dart'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; class DisplayMarkerInfo extends StatefulWidget { static bool isVisible = false; + static bool addInfo = false; DisplayMarkerInfo({super.key}); + static void toggleVisisbility() { isVisible = !isVisible; } + static addressInfo(addInfo) { + if (addInfo) { + addInfo = false; + } else { + addInfo = true; + } + } + @override State createState() => _DisplayMarkerInfoState(); } @@ -17,15 +28,52 @@ class _DisplayMarkerInfoState extends State { @override Widget build(BuildContext context) { return Visibility( - child: Align( - alignment: Alignment.bottomCenter, - child: Container( - height: 100, - child: ListTile( - title: Text(SearchRes.place), - subtitle: Text(SearchRes.vicinity), - )), - ), + child: Container( + height: 180, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(30.0), + topLeft: Radius.circular(30.0)), + color: Color.fromARGB(255, 159, 211, 214), + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Align( + // alignment: Alignment.bottomCenter, + child: Container( + height: 80, + child: ListTile( + title: Text(Search.place), + subtitle: Text(Search.vicinity), + )), + ), + ElevatedButton( + child: const Text('Close BottomSheet'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + ), + ), + // child: Center( + + // child: Scaffold.of(context).showBottomSheet( + // shape: const RoundedRectangleBorder( + // borderRadius: BorderRadius.only( + // topLeft: Radius.circular(30.0), + // topRight: Radius.circular(30.0), + // ), + // ), + // (BuildContext context) { + // return + // }, + // );, + visible: DisplayMarkerInfo.isVisible, ); } diff --git a/lib/navig_notif_overlay_ui.dart b/lib/navig_notif_overlay_ui.dart index a68c338..2c24fd2 100644 --- a/lib/navig_notif_overlay_ui.dart +++ b/lib/navig_notif_overlay_ui.dart @@ -1,17 +1,32 @@ + + +import 'package:AmbiNav/app_screen_res.dart'; import 'package:AmbiNav/countdown_timer.dart'; +import 'package:AmbiNav/end_destination_ui.dart'; import 'package:AmbiNav/routing.dart'; import 'package:AmbiNav/services.dart'; +import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:here_sdk/core.dart'; class NavigationNotif extends StatefulWidget { - const NavigationNotif({super.key}); + final AppScreenRes appScreenRes; + static late GeoCoordinates patientLoc; + static late String hashvalue; + final Services sobj; + + NavigationNotif({super.key, required this.appScreenRes, required this.sobj}); static bool isVisible = false; @override State createState() => _NavigationNotifState(); - static void toggleVisibility() { + static void toggleVisibility(GeoCoordinates? patientLoc, String hash) { + if (patientLoc != null) { + NavigationNotif.patientLoc = patientLoc; + hashvalue = hash; + } isVisible = !isVisible; } } @@ -22,7 +37,7 @@ class _NavigationNotifState extends State { @override void initState() { super.initState(); - rt.initRoutingEngine(); + rt.initRoutingEngine(widget.sobj); } @override @@ -30,20 +45,40 @@ class _NavigationNotifState extends State { return Visibility( child: GestureDetector( onTap: () async { - GeoCoordinates patientLoc = GeoCoordinates( - double.parse(Services.formDetails - .child('user_location/lat') - .value - .toString()), - double.parse(Services.formDetails - .child('user_location/lon') - .value - .toString())); - rt.addRoute(Services.userLocation, patientLoc); - //after the formhas been accepted by the driver , stop listening to other forms + // GeoCoordinates patientLoc = GeoCoordinates( + // double.parse(sobj.formDetails + // .child('user_location/lat') + // .value + // .toString()), + // double.parse(sobj.formDetails + // .child('user_location/lon') + // .value + // .toString())); + widget.sobj.currentLocRef = FirebaseDatabase.instance.ref( + 'Bookings/' + NavigationNotif.hashvalue + '/ambulance_loc'); + widget.sobj.isBooking = true; + rt.addRoute(NavigationNotif.patientLoc); + // //after the formhas been accepted by the driver , stop listening to other forms Services.listen.cancel(); + DatabaseReference ref1 = FirebaseDatabase.instance + .ref('Bookings/' + NavigationNotif.hashvalue); + // print((ref1.get()).runtimeType.toString()); + // var flag = await ref1.get(); + // print(flag.value); + // Fluttertoast.showToast(msg: "Printing flag"); + // Fluttertoast.showToast(msg: flag.value.toString()); + ref1.onChildAdded.listen((event) { + if (event.snapshot.key.toString() == "Reached") { + Services.endDestinationSetSateOverlay(() { + EndDes.isVisible = true; + EndDes.rt = this.rt; + }); + } + }); }, - child: CountDownTimer()), + child: CountDownTimer( + appScreenRes: widget.appScreenRes, + )), visible: NavigationNotif.isVisible, ); } diff --git a/lib/routing.dart b/lib/routing.dart index 43b3a78..38d808c 100644 --- a/lib/routing.dart +++ b/lib/routing.dart @@ -1,21 +1,29 @@ +import 'package:AmbiNav/map_functions.dart'; +import 'package:AmbiNav/navig_notif_overlay_ui.dart'; import 'package:AmbiNav/services.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:here_sdk/core.dart'; import 'package:here_sdk/core.errors.dart'; import 'package:here_sdk/mapview.dart'; import 'package:here_sdk/routing.dart' as here; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:http/http.dart' as http; class Routing { late here.RoutingEngine _routingEngine; List _mapPolylines = []; - - DatabaseReference ref = FirebaseDatabase.instance.ref('Drivers/' + Services.username); + late Services sobj; + + late DatabaseReference ref; + // DatabaseReference ref = FirebaseDatabase.instance.ref('results'); - void initRoutingEngine() { + void initRoutingEngine(Services sobj) { try { _routingEngine = here.RoutingEngine(); + this.sobj = sobj; } on InstantiationException { throw ("Initialization of RoutingEngine failed."); } @@ -43,35 +51,81 @@ class Routing { _formatTime(estimatedTravelTimeInSeconds) + ', Length: ' + _formatLength(lengthInMeters); + // ref.update({"0": routeDetails}); + Hive.openBox("marker").then((box) { + box.put('eta', estimatedTravelTimeInSeconds); + } ); + Fluttertoast.showToast(msg: routeDetails); } + + showRouteOnMap(GeoPolyline routeGeoPolyline) { // Show route as polyline. double widthInPixels = 20; MapPolyline routeMapPolyline = MapPolyline( routeGeoPolyline, widthInPixels, Color.fromARGB(160, 0, 144, 138)); - Services.mapController.mapScene.addMapPolyline(routeMapPolyline); + MapServices.mapController.mapScene.addMapPolyline(routeMapPolyline); _mapPolylines.add(routeMapPolyline); } - + Future getRoute( + String lat1, String lon1, String lat2, String lon2) async { + await dotenv.load(fileName: "credentials.env"); + + final response = await http.get(Uri.parse('http://' + + dotenv.env["ip"]! + + ':5566/?lat1=' + + lat1 + + '&lon1=' + + lon1 + + '&lat2=' + + lat2 + + '&lon2=' + + lon2)); + if (response.statusCode == 200) { + // If the server did return a 200 OK response, + // then parse the JSON. + // return Album.fromJson(jsonDecode(response.body)); + print("Successful api call"); + return response.body; + } else { + // If the server did not return a 200 OK response, + // then throw an exception. + Fluttertoast.showToast(msg: 'Failed to get response'); + throw Exception('Failed to load album'); + } + } - Future addRoute(startGeoCoordinates, destinationGeoCoordinates) async { - var startWaypoint = here.Waypoint.withDefaults(startGeoCoordinates); + void removeRoute() async { + _mapPolylines.forEach((MapPolyline element) { + MapServices.mapController.mapScene.removeMapPolyline(element); + }); + } + + Future addRoute(destinationGeoCoordinates) async { + // GeoCoordinates startGeoCoordinates = await MapServices().getCurrentLoc(); + var startWaypoint = here.Waypoint.withDefaults(sobj.userLocation!); var destinationWaypoint = here.Waypoint.withDefaults(destinationGeoCoordinates); List waypoints = [startWaypoint, destinationWaypoint]; + if (_mapPolylines.isNotEmpty) this.removeRoute(); + _routingEngine.calculateCarRoute(waypoints, here.CarOptions(), (here.RoutingError? routingError, List? routeList) async { if (routingError == null) { + // String? usertype = await sobj.getCred('usertype'); + String usertype = sobj.usertype; // When error is null, then the list guaranteed to be not null. here.Route route = routeList!.first; _showRouteDetails(route); + showRouteOnMap(route.geometry); - if (Services.usertype == 'driver') { + // Fluttertoast.showToast(msg: usertype.toString()); + if (usertype == 'driver') { _broadcastRoute(route); } } else { @@ -81,20 +135,17 @@ class Routing { }); } - void clearMap() { - for (var mapPolyline in _mapPolylines) { - Services.mapController.mapScene.removeMapPolyline(mapPolyline); - } - _mapPolylines.clear(); - } - //add route to database void _broadcastRoute(here.Route route) { List route_ = []; + ref = + FirebaseDatabase.instance.ref('Bookings/' + NavigationNotif.hashvalue); for (var element in route.geometry.vertices) { route_.add({"lat": element.latitude, "lon": element.longitude}); } - ref.update({'route' : route_}); - Services.pathToBeShared = route_; + ref.update({'route': route_}); + var box = Hive.openBox('routes'); + box.then((value) => value.put('route', route_)); + Fluttertoast.showToast(msg: "User will now see your route"); } } diff --git a/lib/search_res.dart b/lib/search.dart similarity index 63% rename from lib/search_res.dart rename to lib/search.dart index 2a8d793..e775422 100644 --- a/lib/search_res.dart +++ b/lib/search.dart @@ -1,7 +1,10 @@ +import 'package:AmbiNav/app_screen_ui.dart'; +import 'package:AmbiNav/map_functions.dart'; import 'package:AmbiNav/marker_details_ui.dart'; import 'package:AmbiNav/routing.dart'; import 'package:AmbiNav/search_result_metadata.dart'; import 'package:AmbiNav/services.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:here_sdk/core.errors.dart'; //for handling search instantiation Exception @@ -9,14 +12,23 @@ import 'package:here_sdk/gestures.dart'; import 'package:here_sdk/mapview.dart'; import 'package:here_sdk/core.dart' as core; import 'package:here_sdk/search.dart'; -import 'package:intl/intl.dart'; -class SearchRes { +class Search { MapImage? _poiMapImage; - List _mapMarkerList = []; + List mapMarkerList = []; static var setStateMarkerDetailsCard; static String place = ""; + static String oldVicinity = ""; static String vicinity = ""; + static var context; + late PersistentBottomSheetController controller; + Routing obj = Routing(); + late Services sobj; + + Search(var ctx, Services sobj) { + context = ctx; + this.sobj = sobj; + } Future _loadFileAsUint8List(String fileName) async { // The path refers to the assets directory as specified in pubspec.yaml. @@ -33,8 +45,8 @@ class SearchRes { } MapMarker mapMarker = MapMarker(geoCoordinates, _poiMapImage!); - Services.mapController.mapScene.addMapMarker(mapMarker); - _mapMarkerList.add(mapMarker); + MapServices.mapController.mapScene.addMapMarker(mapMarker); + mapMarkerList.add(mapMarker); return mapMarker; } @@ -48,7 +60,7 @@ class SearchRes { void search(String queryString) async { // Code to implement search functionality //clear map markers before every search - _clearMap(); + MapServices().clearMapMarkers(mapMarkerList); //instantiate search engine late SearchEngine _searchEngine; try { @@ -57,14 +69,12 @@ class SearchRes { throw Exception("Initialization of SearchEngine failed."); } - _setTapGestureHandler(); - SearchOptions searchOptions = SearchOptions(); searchOptions.languageCode = core.LanguageCode.enUs; searchOptions.maxItems = 30; //build the search query - TextQueryArea queryArea = TextQueryArea.withCenter(Services.userLocation); + TextQueryArea queryArea = TextQueryArea.withCenter(sobj.userLocation!); TextQuery query = TextQuery.withArea(queryString, queryArea); // _searchEngine.searchByText(query, searchOptions, (p0, p1) { }); @@ -97,8 +107,9 @@ class SearchRes { } void _pickMapMarker(core.Point2D touchPoint) { + obj.initRoutingEngine(sobj); double radiusInPixel = 2; - Services.mapController.pickMapItems(touchPoint, radiusInPixel, + MapServices.mapController.pickMapItems(touchPoint, radiusInPixel, (pickMapItemsResult) async { if (pickMapItemsResult == null) { // Pick operation failed. @@ -124,13 +135,18 @@ class SearchRes { place = searchResultMetadata.searchResult.title; vicinity = searchResultMetadata.searchResult.address.addressText; - Routing obj = Routing(); - obj.initRoutingEngine(); - await obj.addRoute(Services.userLocation, searchResultMetadata.searchResult.geoCoordinates); - - setStateMarkerDetailsCard((){ - DisplayMarkerInfo.isVisible = true; - }); + if (vicinity == oldVicinity) { + oldVicinity = ''; + obj.removeRoute(); + } else { + await obj + .addRoute(searchResultMetadata.searchResult.geoCoordinates!); + } + // setStateMarkerDetailsCard(() { + // DisplayMarkerInfo.isVisible = true; + // }); + markerInfo(); + oldVicinity = vicinity; return; } } @@ -140,17 +156,50 @@ class SearchRes { }); } - void _setTapGestureHandler() { - Services.mapController.gestures.tapListener = - TapListener((core.Point2D touchPoint) { - _pickMapMarker(touchPoint); - }); + void markerInfo() { + controller = AppScreen.scaffoldKey.currentState!.showBottomSheet( + (BuildContext context) { + return Container( + height: 180, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topRight: Radius.circular(25.0), + topLeft: Radius.circular(25.0)), + color: Color.fromARGB(255, 0, 145, 197), + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Align( + // alignment: Alignment.bottomCenter, + child: Container( + height: 80, + child: ListTile( + title: Text(Search.place, style: TextStyle(color: Colors.white, fontSize: 16),), + subtitle: Text(Search.vicinity, style: TextStyle(color: Colors.white)), + )), + ), + ElevatedButton( + child: const Text('Directions'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + ), + ); + }, + ); + controller.closed.then((value) {obj.removeRoute(); oldVicinity = '';}); } - void _clearMap() { - _mapMarkerList.forEach((mapMarker) { - Services.mapController.mapScene.removeMapMarker(mapMarker); + void setTapGestureHandler() { + TapListener listener = TapListener((core.Point2D touchPoint) { + _pickMapMarker(touchPoint); }); - _mapMarkerList.clear(); + MapServices().setTapGestureHandler(listener); } } diff --git a/lib/search_overlay_ui.dart b/lib/search_overlay_ui.dart index 26bf3d3..bf55f88 100644 --- a/lib/search_overlay_ui.dart +++ b/lib/search_overlay_ui.dart @@ -1,13 +1,20 @@ -import 'package:AmbiNav/search_res.dart'; +import 'package:AmbiNav/map_functions.dart'; +import 'package:AmbiNav/search.dart'; import 'package:flutter/material.dart'; class SearchWidget extends StatefulWidget { - const SearchWidget({super.key}); + Search seobj; + SearchWidget({super.key, required this.seobj}); static bool isVisible = false; //function to toggle visibility of search overlay (essentially a card element to enter destination) - static void toggleVisibility() { + void toggleVisibility() { isVisible = !isVisible; + if (isVisible == true) { + seobj.setTapGestureHandler(); + } else { + MapServices().clearMapMarkers(seobj.mapMarkerList); + } } @override @@ -15,9 +22,6 @@ class SearchWidget extends StatefulWidget { } class _SearchWidgetState extends State { - - SearchRes search = SearchRes(); - @override Widget build(BuildContext context) { return Visibility( @@ -32,12 +36,10 @@ class _SearchWidgetState extends State { border: OutlineInputBorder(), hintText: 'Enter destination', ), - onSubmitted: ( - (value) { - search.search(value); - SearchWidget.toggleVisibility(); - } - ), + onSubmitted: ((value) { + widget.seobj.search(value); + // SearchWidget.toggleVisibility(); + }), ), ], ), diff --git a/lib/services.dart b/lib/services.dart index 99e33f5..8e1d6ef 100644 --- a/lib/services.dart +++ b/lib/services.dart @@ -1,92 +1,137 @@ -import 'dart:async'; - +import 'package:AmbiNav/listeners.dart'; +import 'package:AmbiNav/map_functions.dart'; +import 'package:AmbiNav/routing.dart'; import 'package:firebase_database/firebase_database.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:here_sdk/core.dart' as core; +import 'package:flutter/services.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:here_sdk/mapview.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:here_sdk/core.dart' as core; import 'package:location/location.dart'; class Services { - static late HereMapController mapController; - //used to reference setState() for search widget (setState is copied to this variable in StatefulBuilder) - static late var setStateOverlay; - static late String usertype; - static late String username; - static late BuildContext mapContext; - static late core.GeoCoordinates userLocation; // user's location - static LocationIndicator locationIndicator = LocationIndicator(); - static DatabaseReference ref = FirebaseDatabase.instance.ref('routes'); - //this current_loc is used for driver's current location - //NOTE: not setting this in All Drivers key of rtdb because this has to be used by IoT device - //and the IoT device is slow in handling nested data - static DatabaseReference currentLocRef = FirebaseDatabase.instance.ref('current_loc/' + username); - //a field to note which driver has accepted which patient and to broadcast route i.e pathToBeShared field - static late DatabaseReference driverProfiles; - //a listen flag for ambulance driver to not listen to bookings once a patient has been accepted - //after the trip is complete , resubscribe to bookings listener - static late StreamSubscription listen; - static late DataSnapshot formDetails; - static bool flag = false; - static late List pathToBeShared; + late String username; + late String usertype; + MapMarker? ambulance = null; + // LocationIndicator? ambulance; + DatabaseReference? currentLocRef = null; + bool isBooking = false; + core.GeoCoordinates? userLocation = null; + late Routing? ambroute; + static late var endDestinationSetSateOverlay; - static Future loadCreds() async { - //loading the .env file - await dotenv.load(fileName: "credentials.env"); + static var listen = null; + + Future getCred(String key) { + var box = Hive.openBox('creds'); + box.then((value) { + return value.get(key); + }); + return Future.value(null); } - static String? getSecret(String key) { - return dotenv.env[key]; - //here.access.key.id + void setCred(String key, String value) { + var box = Hive.openBox('creds'); + box.then((value_) { + value_.put(key, value); + }); + } + + void logout() async { + Hive.deleteBoxFromDisk('creds'); + SharedPreferences login = await SharedPreferences.getInstance(); + login.setBool('login', true); + } + + void bookAmbulance() async { + DatabaseReference ref = FirebaseDatabase.instance.ref("Bookings"); + var box = await Hive.openBox('booking'); + //call to hashing function + Fluttertoast.showToast(msg: "Booking Successful!"); + ref.update({ + box.get('hash'): { + "patient_name": box.get('name'), + "age": box.get('age'), + "preferred_hospital": box.get('preferred_hosp'), + "gender": box.get('gender'), + "user_location": { + "lat": box.get('lat'), + "lon": box.get('lon'), + } + } + }); + FireListener(this).listenToAcceptance(); } - static void setLoc() async { + void streamLoc() async { Location location = await Location(); - location.changeSettings(accuracy: LocationAccuracy.high,interval: 5000,distanceFilter: 1); + location.changeSettings( + accuracy: LocationAccuracy.high, interval: 1000, distanceFilter: 1); location.onLocationChanged.listen((LocationData currentLocation) { userLocation = core.GeoCoordinates( currentLocation.latitude!, currentLocation.longitude!); - flag = true; - core.Location cameraLoc_ = core.Location.withCoordinates(userLocation); + core.Location cameraLoc_ = core.Location.withCoordinates(userLocation!); cameraLoc_.bearingInDegrees = currentLocation .heading; // Degrees of the horizontal direction the user is facing - print("degrees"+cameraLoc_.bearingInDegrees.toString()); - locationIndicator.updateLocation(cameraLoc_); + print("degrees" + cameraLoc_.bearingInDegrees.toString()); + MapServices.locationIndicator.updateLocation(cameraLoc_); - if (usertype == 'driver') { + if (this.usertype == 'driver') { // broadcast the location if the ambulance driver is using the app _broadcastLoc(); } }); } - static void _broadcastLoc() async { - currentLocRef - .set({'lat': userLocation.latitude, 'lon': userLocation.longitude}); + void _broadcastLoc() async { + if (currentLocRef != null) { + if (isBooking == true) { + currentLocRef!.set( + {'lat': userLocation!.latitude, 'lon': userLocation!.longitude}); + } + } } - static Future getPermissions() async { - Location location = Location(); + void goToUserLoc() async { + MapServices.mapController.camera.lookAtPoint(userLocation!); + } - bool _serviceEnabled; - PermissionStatus _permissionGranted; + //prepaing ambulance map marker - _serviceEnabled = await location.serviceEnabled(); - if (!_serviceEnabled) { - _serviceEnabled = await location.requestService(); - if (!_serviceEnabled) { - return; - } + Future _loadFileAsUint8List(String fileName) async { + // The path refers to the assets directory as specified in pubspec.yaml. + ByteData fileData = await rootBundle.load('assets/' + fileName); + return Uint8List.view(fileData.buffer); + } + + Future _addAmbMapMarker(core.GeoCoordinates geoCoordinates) async { + MapImage? _ambImage; + // Reuse existing MapImage for new map markers. + if (_ambImage == null) { + Uint8List imagePixelData = await _loadFileAsUint8List('ambulance.png'); + _ambImage = + MapImage.withPixelDataAndImageFormat(imagePixelData, ImageFormat.png); } - _permissionGranted = await location.hasPermission(); - if (_permissionGranted == PermissionStatus.denied) { - _permissionGranted = await location.requestPermission(); - if (_permissionGranted != PermissionStatus.granted) { - return; - } + MapMarker mapMarker = MapMarker(geoCoordinates, _ambImage); + // later ,to clear map marker add all map markers to the same list + // _mapMarkerList.add(mapMarker); + return mapMarker; + } + + void updateAmbLoc(core.GeoCoordinates loc) { + // if (ambulance == null) { + // ambulance = LocationIndicator(); + // // MapServices.mapController.addLifecycleListener(ambulance!); + // } + // ambulance!.updateLocation(core.Location.withCoordinates(loc)); + if (ambulance != null) { + MapServices.mapController.mapScene.removeMapMarker(ambulance!); } - LocationData temp = await location.getLocation(); - Services.userLocation = core.GeoCoordinates(temp.latitude!,temp.longitude!); + _addAmbMapMarker(loc).then((value) { + ambulance = value; + MapServices.mapController.mapScene.addMapMarker(value); + }); } } diff --git a/lib/starter.dart b/lib/starter.dart index 0625685..7dd0ba7 100644 --- a/lib/starter.dart +++ b/lib/starter.dart @@ -1,154 +1,87 @@ -import 'package:flutter/material.dart'; -import 'driver_details.dart'; -import 'user_details.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:bordered_text/bordered_text.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:here_sdk/core.dart' as here_core; +import 'package:here_sdk/core.engine.dart'; +import 'package:here_sdk/core.errors.dart'; +import 'package:location/location.dart'; +import 'package:hive_flutter/hive_flutter.dart'; -String finalAmbulanceCode = ""; +class Starter { + Future loadCreds() async { + //loading the .env file + await Hive.initFlutter(); + await dotenv.load(fileName: "credentials.env"); + } + + String? getSecret(String key) { + return dotenv.env[key]; + //here.access.key.id + } -class loginpg extends StatefulWidget { - const loginpg({super.key}); + Future initializeHERESDK() async { + // Needs to be called before accessing SDKOptions to load necessary libraries. + here_core.SdkContext.init(here_core.IsolateOrigin.main); - @override - State createState() => _loginpgState(); -} + // Clear the cache occupied by a previous instance. + await SDKNativeEngine.sharedInstance?.dispose(); + + // Set your credentials for the HERE SDK. + String accessKeyId = this.getSecret("here.access.key.id")!; + String accessKeySecret = this.getSecret("here.access.key.secret")!; + SDKOptions sdkOptions = + SDKOptions.withAccessKeySecret(accessKeyId, accessKeySecret); + + try { + await SDKNativeEngine.makeSharedInstance(sdkOptions); + } on InstantiationException { + throw Exception("Failed to initialize the HERE SDK."); + } + } + + Future firebaseLogin() async { + try { + final userCredential = await FirebaseAuth.instance.signInAnonymously(); + print("Signed in with temporary account."); + // Fluttertoast.showToast(msg: userCredential.user!.uid); + } on FirebaseAuthException catch (e) { + switch (e.code) { + case "operation-not-allowed": + print("Anonymous auth hasn't been enabled for this project."); + break; + default: + print("Unknown error."); + } + } + } + + Future getPermissions() async { + Location location = Location(); + + bool _serviceEnabled; + PermissionStatus _permissionGranted; + + _serviceEnabled = await location.serviceEnabled(); + if (!_serviceEnabled) { + _serviceEnabled = await location.requestService(); + if (!_serviceEnabled) { + return; + } + } + + _permissionGranted = await location.hasPermission(); + if (_permissionGranted == PermissionStatus.denied) { + _permissionGranted = await location.requestPermission(); + if (_permissionGranted != PermissionStatus.granted) { + return; + } + } + // LocationData temp = await location.getLocation(); + // userLocation = core.GeoCoordinates(temp.latitude!, temp.longitude!); + } -class _loginpgState extends State { - @override - @override - Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage("images/ambiBg.jpg"), fit: BoxFit.cover)), - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.center, - end: Alignment.bottomCenter, - colors: [ - Color.fromARGB(221, 24, 24, 24), - Color.fromARGB(221, 0, 0, 0) - ])), - child: Scaffold( - backgroundColor: Colors.transparent, - body: SafeArea( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircleAvatar( - radius: 92.0, - backgroundColor: Color.fromARGB(255, 255, 255, 255), - child: CircleAvatar( - backgroundColor: Color.fromARGB(255, 5, 5, 5), - backgroundImage: AssetImage('images/ambi2.png'), - radius: 90.0, - ), - ), - SizedBox( - height: 20.0, - ), - BorderedText( - strokeWidth: 4, - strokeColor: Color.fromARGB(255, 251, 251, 251), - child: Text("AMBINAV", - style: GoogleFonts.montserrat( - fontSize: 40, - color: Colors.green, - fontWeight: FontWeight.bold, - letterSpacing: 2.5, - )), - ), - SizedBox( - height: 20.0, - ), - BorderedText( - strokeWidth: 0.8, - strokeColor: Color.fromARGB(255, 0, 0, 0), - child: Text("Choose your role", - style: GoogleFonts.rokkitt( - fontSize: 21, - color: Colors.green, - fontWeight: FontWeight.bold, - letterSpacing: 1, - )), - ), - SizedBox( - height: 40.0, - width: 260.0, - child: Divider( - color: Color.fromARGB(255, 243, 249, 251), - thickness: 1.6, - ), - ), - Card( - borderOnForeground: true, - color: Colors.grey[200], - elevation: 8.0, - shadowColor: Color.fromARGB(255, 255, 255, 255), - child: InkWell( - splashColor: - Color.fromARGB(255, 25, 143, 96).withAlpha(30), - onTap: () { - debugPrint('Card tapped.'); - // Connect to map - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AmbiDriverDetails())); - }, - child: const SizedBox( - width: 200, - height: 50, - child: Center( - child: Text( - 'Ambulance Driver', - style: TextStyle( - letterSpacing: 0.7, - fontSize: 16, - ), - ), - ), - ), - ), - ), - SizedBox( - height: 15.0, - ), - Card( - color: Colors.grey[200], - elevation: 8.0, - shadowColor: Color.fromARGB(255, 247, 248, 247), - child: InkWell( - splashColor: - Color.fromARGB(255, 72, 202, 21).withAlpha(30), - onTap: () { - debugPrint('Card tapped.'); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => userDetails())); - // Connect to map - }, - child: const SizedBox( - width: 200, - height: 50, - child: Center( - child: Text('User Driver', - style: TextStyle( - letterSpacing: 0.7, - fontSize: 16, - ))), - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); + void loadHiveBox(String username, String usertype) async { + var box = await Hive.openBox('creds'); + box.put('username', username); + box.put('usertype', usertype); } } diff --git a/lib/user_details.dart b/lib/user_details.dart index 01bfa0d..2edb321 100644 --- a/lib/user_details.dart +++ b/lib/user_details.dart @@ -1,13 +1,16 @@ import 'package:AmbiNav/app_screen_ui.dart'; +import 'package:AmbiNav/main.dart'; import 'package:AmbiNav/services.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'starter.dart'; +import 'login.dart'; import 'package:shared_preferences/shared_preferences.dart'; +// import 'main.dart' as mm; class userDetails extends StatefulWidget { - const userDetails({super.key}); + final Services sobj; + const userDetails({super.key, required this.sobj}); @override State createState() => _userDetailsState(); @@ -105,16 +108,28 @@ class _userDetailsState extends State { if (username != '' && code != '') { logindata.setBool('login', false); - logindata.setString('username', username); - logindata.setString('usertype', 'user'); - Services.usertype = 'user'; - Fluttertoast.showToast(msg: username); + sobj.setCred('username', username); + sobj.username = username; + if (codeController.text == 'pol1234') { + logindata.setString('usertype', 'police'); + sobj.setCred('usertype', 'police'); + sobj.usertype = 'police'; + Fluttertoast.showToast( + msg: + "You are now logged in as a traffic authority!"); + } else { + logindata.setString('usertype', 'user'); + sobj.setCred('usertype', 'user'); + sobj.usertype = 'user'; + } Navigator.pop(context); Navigator.pushReplacement( context, MaterialPageRoute( - builder: (context) => AppScreen())); + builder: (context) => AppScreen( + sobj: widget.sobj, + ))); } }, child: Container( @@ -151,9 +166,11 @@ class _userDetailsState extends State { Container( child: GestureDetector( onTap: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: ((context) => loginpg()))); + Navigator.of(context) + .pushReplacement(MaterialPageRoute( + builder: ((context) => loginpg( + sobj: widget.sobj, + )))); }, child: Text( ' Click here', diff --git a/pubspec.lock b/pubspec.lock index b8de8a1..f017f2f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,7 +7,7 @@ packages: name: _flutterfire_internals url: "https://pub.dartlang.org" source: hosted - version: "1.0.12" + version: "1.0.15" async: dependency: transitive description: @@ -36,6 +36,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" + chopper: + dependency: transitive + description: + name: chopper + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.6" clock: dependency: transitive description: @@ -91,63 +98,63 @@ packages: name: firebase_auth url: "https://pub.dartlang.org" source: hosted - version: "4.2.2" + version: "4.2.8" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "6.11.7" + version: "6.11.10" firebase_auth_web: dependency: transitive description: name: firebase_auth_web url: "https://pub.dartlang.org" source: hosted - version: "5.2.2" + version: "5.2.7" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.6.1" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.5.2" + version: "4.5.3" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.1" firebase_database: dependency: "direct main" description: name: firebase_database url: "https://pub.dartlang.org" source: hosted - version: "10.0.9" + version: "10.0.13" firebase_database_platform_interface: dependency: transitive description: name: firebase_database_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "0.2.2+17" + version: "0.2.2+20" firebase_database_web: dependency: transitive description: name: firebase_database_web url: "https://pub.dartlang.org" source: hosted - version: "0.2.1+19" + version: "0.2.1+22" flutter: dependency: "direct main" description: flutter @@ -176,14 +183,14 @@ packages: name: fluttertoast url: "https://pub.dartlang.org" source: hosted - version: "8.1.2" + version: "8.2.1" google_fonts: dependency: "direct main" description: name: google_fonts url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "4.0.3" here_sdk: dependency: "direct main" description: @@ -191,8 +198,22 @@ packages: relative: true source: path version: "4.13.0" + hive: + dependency: "direct main" + description: + name: hive + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" + hive_flutter: + dependency: "direct main" + description: + name: hive_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" http: - dependency: transitive + dependency: "direct main" description: name: http url: "https://pub.dartlang.org" @@ -211,7 +232,7 @@ packages: name: intl url: "https://pub.dartlang.org" source: hosted - version: "0.18.0" + version: "0.17.0" js: dependency: transitive description: @@ -240,6 +261,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" matcher: dependency: transitive description: @@ -275,6 +303,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.0" + os_detect: + dependency: transitive + description: + name: os_detect + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" path: dependency: transitive description: @@ -288,7 +323,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" path_provider_android: dependency: transitive description: @@ -296,27 +331,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.22" - path_provider_ios: + path_provider_foundation: dependency: transitive description: - name: path_provider_ios + name: path_provider_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.1.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" + version: "2.1.8" path_provider_platform_interface: dependency: transitive description: @@ -358,35 +386,28 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.15" + version: "2.0.17" shared_preferences_android: dependency: transitive description: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.14" - shared_preferences_ios: + version: "2.0.15" + shared_preferences_foundation: dependency: transitive description: - name: shared_preferences_ios + name: shared_preferences_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" + version: "2.1.3" shared_preferences_platform_interface: dependency: transitive description: @@ -407,7 +428,7 @@ packages: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" sky_engine: dependency: transitive description: flutter @@ -469,6 +490,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + what3words: + dependency: "direct main" + description: + name: what3words + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" win32: dependency: transitive description: @@ -482,7 +510,7 @@ packages: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0+2" + version: "1.0.0" sdks: dart: ">=2.18.4 <3.0.0" flutter: ">=3.3.2" diff --git a/pubspec.yaml b/pubspec.yaml index ff66646..83480bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,10 @@ dependencies: firebase_core: ^2.4.1 firebase_database: ^10.0.9 firebase_auth: ^4.2.2 + http: ^0.13.5 + hive: ^2.2.3 + hive_flutter: ^1.1.0 + what3words: ^3.1.0 dev_dependencies: flutter_test: diff --git a/release-notes.txt b/release-notes.txt index 4c48ac0..8e572f1 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -1 +1,2 @@ -Now the form response event is listened to , and the details can be seen on the console when a form is submitted \ No newline at end of file +what3words grid can now be displayed and removed using a toggle button. +Ambulance booking grid is fixed. Booking is done when the first booking is done. \ No newline at end of file