>>(context);
27 | final geoService = GeoLocatorService();
28 | final markerService = MarkerService();
29 | return Scaffold(
30 | appBar: AppBar(
31 | backgroundColor: Constants.secColor,
32 | title: Text('Add a Parking Spot'),
33 | ),
34 | body: GoogleMap(
35 | initialCameraPosition: CameraPosition(
36 | target:
37 | LatLng(currentPosition.latitude, currentPosition.longitude),
38 | zoom: 16.0),
39 | zoomGesturesEnabled: true,
40 | markers: Set.from(myMarker),
41 | mapType: MapType.hybrid,
42 | onTap: _handleTap,
43 | ),
44 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
45 | floatingActionButton: FloatingActionButton(
46 | child: Icon(Icons.add_location_rounded),
47 | backgroundColor: Constants.secColor,
48 | onPressed: () {
49 | Navigator.push(
50 | context,
51 | MaterialPageRoute(
52 | builder: (context) =>
53 | AddForm(tappedpoint: abc, address: address),
54 | ));
55 | },
56 | ));
57 | }
58 |
59 | _handleTap(LatLng tappedPoint) {
60 | print(tappedPoint);
61 | setState(() {
62 | abc = tappedPoint;
63 | print(abc);
64 | getUserLocation();
65 | myMarker = [];
66 | myMarker.add(Marker(
67 | markerId: MarkerId(tappedPoint.toString()),
68 | position: tappedPoint,
69 | draggable: true,
70 | onDragEnd: (dragEndPosition) {
71 | print(dragEndPosition);
72 | }));
73 | });
74 | }
75 |
76 | double lat, long;
77 | String address = "No address selected";
78 |
79 | void getUserLocation() async {
80 | print("yoo");
81 | print(abc.latitude);
82 | lat = abc.latitude;
83 | long = abc.longitude;
84 | final coordinates = new Coordinates(lat, long);
85 | var addresses =
86 | await Geocoder.local.findAddressesFromCoordinates(coordinates);
87 | var first = addresses.first;
88 | setState(() {
89 | address = first.addressLine;
90 | });
91 | print(
92 | ' ${first.locality}, ${first.adminArea},${first.subLocality}, ${first.subAdminArea},${first.addressLine}, ${first.featureName},${first.thoroughfare}, ${first.subThoroughfare}');
93 | // return first.addressLine;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/parking_locator/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: parking_locator
2 | description: A new Flutter project.
3 |
4 | # The following line prevents the package from being accidentally published to
5 | # pub.dev using `pub publish`. This is preferred for private packages.
6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 |
8 | # The following defines the version and build number for your application.
9 | # A version number is three numbers separated by dots, like 1.2.43
10 | # followed by an optional build number separated by a +.
11 | # Both the version and the builder number may be overridden in flutter
12 | # build by specifying --build-name and --build-number, respectively.
13 | # In Android, build-name is used as versionName while build-number used as versionCode.
14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
16 | # Read more about iOS versioning at
17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
18 | version: 1.0.0+1
19 |
20 | environment:
21 | sdk: ">=2.7.0 <3.0.0"
22 |
23 | dependencies:
24 | flutter:
25 | sdk: flutter
26 |
27 | # The following adds the Cupertino Icons font to your application.
28 | # Use with the CupertinoIcons class for iOS style icons.
29 | cupertino_icons: ^1.0.2
30 | google_maps_flutter: ^2.0.2
31 | geolocator: ^7.0.1
32 | provider: ^5.0.0
33 | url_launcher: ^6.0.3
34 | http: ^0.13.1
35 | flutter_rating_bar: ^4.0.0
36 | geocoder: ^0.2.0
37 | form_field_validator: ^1.0.1
38 | date_format: ^2.0.2
39 | intl: ^0.17.0
40 | flutter_datetime_picker: ^1.5.0
41 | google_fonts: ^2.0.0
42 | loading_animations: ^2.2.0
43 | lottie: ^1.0.1
44 |
45 |
46 |
47 |
48 | dev_dependencies:
49 | flutter_test:
50 | sdk: flutter
51 |
52 | # For information on the generic Dart part of this file, see the
53 | # following page: https://dart.dev/tools/pub/pubspec
54 |
55 | # The following section is specific to Flutter.
56 | flutter:
57 |
58 | # The following line ensures that the Material Icons font is
59 | # included with your application, so that you can use the icons in
60 | # the material Icons class.
61 | uses-material-design: true
62 |
63 | # To add assets to your application, add an assets section, like this:
64 | assets:
65 | - assets/parking-icon.png
66 |
67 |
68 | # An image asset can refer to one or more resolution-specific "variants", see
69 | # https://flutter.dev/assets-and-images/#resolution-aware.
70 |
71 | # For details regarding adding assets from package dependencies, see
72 | # https://flutter.dev/assets-and-images/#from-packages
73 |
74 | # To add custom fonts to your application, add a fonts section here,
75 | # in this "flutter" section. Each entry in this list should have a
76 | # "family" key with the font family name, and a "fonts" key with a
77 | # list giving the asset and other descriptors for the font. For
78 | # example:
79 | # fonts:
80 | # - family: Schyler
81 | # fonts:
82 | # - asset: fonts/Schyler-Regular.ttf
83 | # - asset: fonts/Schyler-Italic.ttf
84 | # style: italic
85 | # - family: Trajan Pro
86 | # fonts:
87 | # - asset: fonts/TrajanPro.ttf
88 | # - asset: fonts/TrajanPro_Bold.ttf
89 | # weight: 700
90 | #
91 | # For details regarding fonts from package dependencies,
92 | # see https://flutter.dev/custom-fonts/#from-packages
93 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [](https://flutter.dev/docs)
7 | []( "Firestore")
8 | [](https://nodejs.org/en/)
9 | [](https://code.visualstudio.com/ "Visual Studio Code")
10 |
11 |
12 |
13 |
14 |
15 |
16 | Park ME
17 |
18 | ## Description ##
19 |
20 |
21 | On any given working day approximately 40% of the roads in urban India are taken up for just parking the cars !!!
22 | The global average of time spent looking for a parking spot is 20 minutes,If we could somehow minimize this time it could save people a lot of time daily.
23 | We have developed a mobile app that can help people find parking spots around their current location easily and on-demand
24 | .A simple hassle-free process that involves pulling up into the parking spot and engaging it at the click of a button.
25 | We incorporate the use of a image recognition model that automatically detects whether the parking spot is empty or full
26 |
27 | For more details-
28 |
29 | Youtube link
30 |
31 |
32 |
33 |
34 | ------------------------------------------
35 | ## Features ##
36 | - Easily find empty parking spots nearby.
37 | - Get directions to the parking spot of your choice.
38 | - Host your own parking space and get paid for it.
39 | - Easy check-in to the spot after pulling in.
40 | - Be charged on hourly basis for the use of the parking space.
41 | - User authentication.
42 |
43 |
44 | ------------------------------------------
45 | ## Demo ##
46 | Sign Up/Sign In
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | ------------------------------------------
77 |
78 | ## How To Use
79 | #### Software Requirements
80 | VSCode or Android Studio
81 |
82 | ## Installation
83 | Install the dependencies by running:
84 | ```html
85 | npm install
86 | ```
87 | ```html
88 | flutter pub get
89 | ```
90 |
91 |
92 | #### Run using Command Prompt
93 | ```html
94 | node start
95 | ```
96 |
97 | ```html
98 | flutter run
99 | ```
100 |
101 | ---
102 | ### Tech stack
103 |
104 | `Frontend` : Flutter
105 | `Backend` : Nodejs
106 | `Database` : MongoDB
107 |
108 | ------------------------------------------
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | !
117 |
--------------------------------------------------------------------------------
/parking_locator/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/confirm_booking.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:parking_locator/services/dbservice.dart';
3 | import 'package:parking_locator/widgets/drawer.dart';
4 |
5 | import 'package:parking_locator/constants.dart';
6 |
7 | class ConfirmBooking extends StatefulWidget {
8 | final String carImage;
9 | final String bookingId;
10 | final String slotID;
11 |
12 | ConfirmBooking({this.slotID, this.carImage, this.bookingId});
13 | @override
14 | _ConfirmBookingState createState() => _ConfirmBookingState();
15 | }
16 |
17 | class _ConfirmBookingState extends State {
18 | @override
19 | Widget build(BuildContext context) {
20 | var height = MediaQuery.of(context).size.height;
21 | var width = MediaQuery.of(context).size.width;
22 | DbBookingMethods _dbmethod = DbBookingMethods();
23 | void _submit() async {
24 | var obj = await _dbmethod.confirmBook(widget.slotID, widget.bookingId);
25 | print(obj);
26 | if (obj["status"] == "SUCCESS") {
27 | Navigator.of(context).pushNamed('/my_booking');
28 | // Navigator.push(
29 | // context,
30 | // MaterialPageRoute(
31 | // builder: (context) => ConfirmBooking(obj["carImage"])),
32 | // );
33 | }
34 | }
35 |
36 | return Scaffold(
37 | appBar: AppBar(
38 | backgroundColor: Constants.secColor,
39 | title: Text("ParkMe"),
40 |
41 | ),
42 |
43 | body: Center(
44 | child: Container(
45 | child: Card(
46 | elevation: 10.0,
47 | shape: RoundedRectangleBorder(
48 | borderRadius: BorderRadius.all(
49 | Radius.circular(25),
50 | ),
51 | // side: BorderSide(width: 1, color: Colors.green),
52 | ),
53 | margin: EdgeInsets.all(10),
54 | child: Column(
55 | crossAxisAlignment: CrossAxisAlignment.stretch,
56 | children: [
57 | ClipRRect(
58 | borderRadius: BorderRadius.all(Radius.circular(10)),
59 | child: Image.network(
60 | widget.carImage,
61 | height: height * 0.65,
62 | width: width * 0.7,
63 | fit: BoxFit.cover,
64 | ),
65 | ),
66 | SizedBox(
67 | height: height * 0.05,
68 | ),
69 | Center(
70 | child: ElevatedButton(
71 | style: ElevatedButton.styleFrom(
72 | shape: new RoundedRectangleBorder(
73 | borderRadius: new BorderRadius.circular(20.0),
74 | ),
75 | //primary: kMainColor
76 | ),
77 | onPressed: () {
78 | _submit();
79 | },
80 | child: Padding(
81 | padding: const EdgeInsets.all(18.0),
82 | child: Text(
83 | 'Confirm Booking',
84 | style: TextStyle(
85 | fontSize: 18, color: Colors.white),
86 | ),
87 | ),
88 | ),
89 | ),
90 | ])))));
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/parking-locator-car-detector-model/static/js/index.js:
--------------------------------------------------------------------------------
1 | $(".upload").click(function (e) {
2 | $("#uploader").click();
3 | });
4 |
5 | var uploadedFiles = [];
6 | var cameraStream = null;
7 |
8 | $("#uploader").change(function (event) {
9 | const files = event.target.files;
10 | if (files && files.length > 0 && FileReader) {
11 | const file = event.target.files[0];
12 | var fr = new FileReader();
13 | fr.onload = function () {
14 | uploadedFiles = [file];
15 | $(".fileDisplay img").prop("src", fr.result);
16 | $(".fileDisplay h3").hide();
17 | $(".iscar h1").text("");
18 | $(".predict").removeAttr("disabled");
19 | };
20 | fr.readAsDataURL(file);
21 | }
22 | });
23 |
24 | $(".predict").click(function (e) {
25 | console.log("here");
26 | var fd = new FormData();
27 | var dataURI = snapshot.firstChild.getAttribute("src");
28 | var imageData = dataURItoBlob(dataURI);
29 | fd.append("files[]", imageData, "myImage");
30 | $(".predict").text("loading");
31 | $(".predict").prop("disabled", "true");
32 | $.ajax({
33 | method: "POST",
34 | data: fd,
35 | processData: false,
36 | contentType: false,
37 | cache: false,
38 | url: "/predict/",
39 | success: function (data) {
40 | console.log($(this));
41 | const res = data[0];
42 | $(".predict").text("Predict");
43 | $(".predict").removeAttr("disabled");
44 | $(".iscar h1").text(
45 | res.isCar ? `Car Present. (${res.confidence * 100}%)` : `No car Present. (${100 - res.confidence * 100}%)`
46 | );
47 | },
48 | });
49 | });
50 | var camera = document.getElementById("camera");
51 |
52 | window.addEventListener(
53 | "load",
54 | function () {
55 | var constraints = { video: true };
56 |
57 | function success(stream) {
58 | cameraStream = stream;
59 | camera.srcObject = stream;
60 | var playPromise = camera.play();
61 | if (playPromise !== undefined) {
62 | playPromise
63 | .then(function () {
64 | setInterval(function () {
65 | captureSnapshot();
66 | }, 1000);
67 | })
68 | .catch(function (error) {
69 | console.error(error);
70 | });
71 | }
72 | }
73 |
74 | function failure(error) {
75 | alert(JSON.stringify(error));
76 | }
77 |
78 | if (navigator.getUserMedia) navigator.getUserMedia(constraints, success, failure);
79 | else alert("Your browser does not support getUserMedia()");
80 | },
81 | false
82 | );
83 | function sendToServer() {
84 | var fd = new FormData();
85 | var dataURI = snapshot.firstChild.getAttribute("src");
86 | var imageData = dataURItoBlob(dataURI);
87 | fd.append("files[]", imageData, "myImage");
88 |
89 | $.ajax({
90 | method: "POST",
91 | data: fd,
92 | processData: false,
93 | contentType: false,
94 | cache: false,
95 | url: "/predict/",
96 | success: function (data) {
97 | console.log($(this));
98 | const res = data[0];
99 |
100 | $(".iscar h1").text(
101 | res.isCar ? `Car Present. (${res.confidence * 100}%)` : `No car Present. (${100 - res.confidence * 100}%)`
102 | );
103 | },
104 | });
105 | }
106 |
107 | var capture = document.getElementById("capture");
108 |
109 | function captureSnapshot() {
110 | if (null != cameraStream) {
111 | var ctx = capture.getContext("2d");
112 | var img = new Image();
113 |
114 | ctx.drawImage(camera, 0, 0, capture.width, capture.height);
115 |
116 | img.src = capture.toDataURL("image/png");
117 | img.width = 240;
118 |
119 | snapshot.innerHTML = "";
120 |
121 | snapshot.appendChild(img);
122 | sendToServer();
123 | }
124 | }
125 |
126 | function dataURItoBlob(dataURI) {
127 | var byteString = atob(dataURI.split(",")[1]);
128 | var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
129 |
130 | var buffer = new ArrayBuffer(byteString.length);
131 | var data = new DataView(buffer);
132 |
133 | for (var i = 0; i < byteString.length; i++) {
134 | data.setUint8(i, byteString.charCodeAt(i));
135 | }
136 |
137 | return new Blob([buffer], { type: mimeString });
138 | }
139 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/authentication/auth2.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_fonts/google_fonts.dart';
3 | import 'package:parking_locator/screens/authentication/login.dart';
4 | import 'package:parking_locator/screens/authentication/login_option.dart';
5 | import 'package:parking_locator/screens/authentication/signup.dart';
6 | import 'package:parking_locator/screens/authentication/signup_option.dart';
7 | import 'package:parking_locator/constants.dart';
8 |
9 |
10 | class HomePage extends StatefulWidget {
11 | @override
12 | _HomePageState createState() => _HomePageState();
13 | }
14 |
15 | class _HomePageState extends State {
16 |
17 | bool login = true;
18 | static const mainColor = Constants.mainColor;
19 | static const secColor = Constants.secColor;
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return Scaffold(
24 | backgroundColor: secColor,//Color(0xFF1C1C1C),
25 | body: SingleChildScrollView(
26 | child: Column(
27 | crossAxisAlignment: CrossAxisAlignment.stretch,
28 | mainAxisAlignment: MainAxisAlignment.center,
29 | children: [
30 |
31 | GestureDetector(
32 | onTap: () {
33 | setState(() {
34 | login = true;
35 | });
36 | },
37 | child: AnimatedContainer(
38 | duration: Duration(milliseconds: 500),
39 | curve: Curves.ease,
40 | height: login ? MediaQuery.of(context).size.height * 0.6 : MediaQuery.of(context).size.height * 0.4,
41 | child: CustomPaint(
42 | painter: CurvePainter(login),
43 | child: Container(
44 | padding: EdgeInsets.only(bottom: login ? 0 : 55),
45 | child: Center(
46 | child: SingleChildScrollView(
47 | child: Padding(
48 | padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
49 | child: login
50 | ? Login()
51 | : LoginOption(),
52 | ),
53 | ),
54 | ),
55 | ),
56 | ),
57 | ),
58 | ),
59 |
60 | GestureDetector(
61 | onTap: () {
62 | setState(() {
63 | login = false;
64 | });
65 | },
66 | child: AnimatedContainer(
67 | duration: Duration(milliseconds: 500),
68 | curve: Curves.ease,
69 | height: login ? MediaQuery.of(context).size.height * 0.4 : MediaQuery.of(context).size.height * 0.6,
70 | child: Container(
71 | color: Colors.transparent,
72 | padding: EdgeInsets.only(top: login ? 55 : 0),
73 | child: Center(
74 | child: SingleChildScrollView(
75 | child: Padding(
76 | padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
77 | child: !login
78 | ? SignUp()
79 | : SignUpOption(),
80 | ),
81 | ),
82 | )
83 | ),
84 | ),
85 | ),
86 |
87 | ],
88 | ),
89 | ),
90 | );
91 | }
92 | }
93 |
94 | class CurvePainter extends CustomPainter {
95 | static const mainColor = Constants.mainColor;
96 | static const secColor = Constants.secColor;
97 | static const backgroundColor = Constants.mainColor;
98 | bool outterCurve;
99 |
100 | CurvePainter(this.outterCurve);
101 |
102 | @override
103 | void paint(Canvas canvas, Size size) {
104 | var paint = Paint();
105 | paint.color = mainColor;
106 | paint.style = PaintingStyle.fill;
107 |
108 | Path path = Path();
109 | path.moveTo(0, 0);
110 | path.lineTo(0, size.height);
111 | path.quadraticBezierTo(size.width * 0.5, outterCurve ? size.height + 110 : size.height - 110, size.width, size.height);
112 | path.lineTo(size.width, 0);
113 | path.close();
114 |
115 | canvas.drawPath(path, paint);
116 | }
117 |
118 | @override
119 | bool shouldRepaint(CustomPainter oldDelegate) => false;
120 | }
--------------------------------------------------------------------------------
/parking-locator-backend/src/routes/booking.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const ParkingLocations = require("../database/models/parkingLocations");
3 | const ParkingHistory = require("../database/models/ParkingHistory");
4 | const moment = require("moment");
5 | const getDistanceFromLatLonInKm = require("../helpers/mapDistance");
6 | const router = express.Router();
7 | const {TIME_FORMAT}=require('../config');
8 |
9 | router.get("/", async (req, res) => {
10 | res.send("booking service");
11 | });
12 |
13 | router.post("/checkin", async (req, res) => {
14 | console.log(req.body);
15 | console.log(req.user);
16 | const { userID } = req.user;
17 | const { spotID, lat, long,isEmpty } = req.body;
18 |
19 | const imageIfFull = "https://martolex-book-images.s3.ap-south-1.amazonaws.com/car-1.jpeg";
20 | try {
21 | console.log("lets tryy");
22 | const parkingSpot = await ParkingLocations.findOne({ slotID: spotID });
23 | if (parkingSpot) {
24 | console.log(parkingSpot);
25 | if (parkingSpot.isEmpty) {
26 | const parkingLocation = parkingSpot.Location.coordinates;
27 | const distance = getDistanceFromLatLonInKm(parkingLocation[0], parkingLocation[1], lat, long);
28 | if (distance < 100) {
29 | if (isEmpty === "false") {
30 | const parkingHistory = await ParkingHistory.create({ userID, slotID: spotID });
31 | res.json({ STATUS: "SUCCESS", carImage: imageIfFull, bookingID: parkingHistory._id });
32 | } else {
33 | res.json({ status: "FAILED", message: "NO car is present in the slot" });
34 | }
35 | } else {
36 | res.json({ status: "FAILED", message: "You are too far away from the parking" });
37 | }
38 | } else {
39 | res.json({ status: "FAILED", message: "Slot is not empty" });
40 | }
41 | } else {
42 | res.json({ status: "FAILED", message: "Slot not found" });
43 | }
44 |
45 | } catch (error) {
46 | res.status(500).send({ message: error.message, errorType: error.name });
47 | }
48 | });
49 |
50 | router.post("/bookPrior", async (req, res) => {
51 | try {
52 | const { spotID, startTime, duration } = req.body;
53 | console.log(startTime);
54 | const { userID } = req.user;
55 | const parkingSpot = await ParkingLocations.findOne({ slotID: spotID });
56 | if (parkingSpot) {
57 | const startTimeObj = moment(startTime,TIME_FORMAT);
58 | const endTime = startTimeObj.clone().add(duration, "hours");
59 | const startTimeMinutesSinceDayStart = startTimeObj.diff(startTimeObj.clone().startOf("day"), "minutes");
60 | console.log(parkingSpot.activeHours.start, startTimeMinutesSinceDayStart,);
61 | if (
62 | parkingSpot.activeHours.start <= startTimeMinutesSinceDayStart &&
63 | parkingSpot.activeHours.end > startTimeMinutesSinceDayStart + 60 * duration
64 | ) {
65 | const booking = await ParkingHistory.create({
66 | userID,
67 | slotID: spotID,
68 | advancedBooking: true,
69 | estimatedStartTime: startTimeObj.toDate(),
70 | estimatedEndTime: endTime.toDate(),
71 | isConfirmed: true,
72 | });
73 | res.json({ status: "SUCCESS", bookingDetails: booking });
74 | } else {
75 | res.json({ status: "FAILED", message: "cannot book for this time duration." });
76 | }
77 | } else {
78 | res.json({ status: "FAILED", message: "Slot not found" });
79 | }
80 | } catch (err) {
81 | res.status(500).send({ message: err.message, errorType: err.name });
82 | }
83 | });
84 |
85 | router.post("/checkin/verify", async (req, res) => {
86 | const { userID } = req.user;
87 | const { spotID, bookingID } = req.body;
88 | try {
89 | const booking = await ParkingHistory.findOne({ slotID: spotID, userID, _id: bookingID });
90 | if (booking) {
91 | booking.isConfirmed = true;
92 | booking.startTime = new Date();
93 | await booking.save();
94 | await ParkingLocations.findOneAndUpdate({ spotID }, { $set: { isEmpty: false } });
95 | res.json({ status: "SUCCESS", bookingDetails: booking });
96 | } else {
97 | res.json({ status: "FAILED", message: "invali details" });
98 | }
99 | } catch (error) {
100 | res.status(500).send({ message: error.message, errorType: error.name });
101 | }
102 | });
103 |
104 | router.post("/checkout", async (req, res) => {
105 | const { userID } = req.user;
106 | const { spotID } = req.body;
107 | try {
108 | const booking = await ParkingHistory.findOne({
109 | userID,
110 | slotID: spotID,
111 | isConfirmed: true,
112 | endTime: { $exists: false },
113 | duration: { $exists: false },
114 | });
115 |
116 | if (booking) {
117 | booking.endTime = new Date();
118 | booking.duration = Math.max(1, moment().diff(booking.startTime, "hours"));
119 | await booking.save();
120 | await ParkingLocations.findOneAndUpdate({ spotID }, { $set: { isEmpty: true } });
121 | res.json({ status: "SUCCESS", message: "checked Out", billedPeriod: booking.duration });
122 | } else {
123 | res.json({ status: "FAILED", message: "no such booking" });
124 | }
125 | } catch (error) {
126 | res.status(500).send({ message: error.message, errorType: error.name });
127 | }
128 | });
129 |
130 | module.exports = router;
131 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/mySpots.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:parking_locator/services/dbservice.dart';
3 | import 'package:parking_locator/screens/slotdetails.dart';
4 | import 'package:parking_locator/constants.dart';
5 |
6 |
7 | class MySpots extends StatefulWidget {
8 | @override
9 | _MySpotsState createState() => _MySpotsState();
10 | }
11 |
12 | class _MySpotsState extends State {
13 | final db_methods = DbMethods();
14 | List spots;
15 |
16 | void getspots() async {
17 | List spots1;
18 | spots1 = await db_methods.mySpots();
19 | setState(() {
20 | spots = spots1;
21 | });
22 | }
23 |
24 | @override
25 | void initState() {
26 | getspots();
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | final height = MediaQuery.of(context).size.height;
32 | final width = MediaQuery.of(context).size.width;
33 | return Scaffold(
34 | appBar: AppBar(
35 | backgroundColor: Constants.secColor,
36 | title: Text('My Parking Spots'),
37 | ),
38 | body: Column(
39 | children: [
40 | // Text(spots[1]['address']),
41 | Expanded(
42 | child: (spots != null)
43 | ? ListView.builder(
44 | itemCount: spots.length,
45 | itemBuilder: (context, index) {
46 | return Container(
47 | child: Card(
48 | shape: RoundedRectangleBorder(
49 | borderRadius: BorderRadius.circular(15.0),
50 | ),
51 | color: Colors.white,
52 | elevation: 7,
53 | child: InkWell(
54 | borderRadius: BorderRadius.circular(15.0),
55 | onTap: () {
56 | Navigator.push(
57 | context,
58 | MaterialPageRoute(
59 | builder: (context) => SlotDetails(
60 | spotID: spots[index]['slotID']),
61 | ),
62 | );
63 | },
64 | child: Container(
65 | child: Column(
66 | children: [
67 | // Column(
68 | // crossAxisAlignment: CrossAxisAlignment.start,
69 | // children: [
70 | // Text(spots[index]['address']),
71 | // Text("Start time: " +
72 | // spots[index]['activeHours']['start']),
73 | // Text("End time: " +
74 | // spots[index]['activeHours']['end']),
75 | // Row(
76 | // children: [
77 | // Text("Parking Type: " +
78 | // spots[index]['parkingType']),
79 | // SizedBox(
80 | // width: width * 2 / 5,
81 | // ),
82 | // Text("Charges: " +
83 | // (spots[index]['chargesPerHour'])
84 | // .toString()),
85 | // ],
86 | // ),
87 | // ],
88 | // )
89 | ListTile(
90 | isThreeLine: true,
91 | title: Text(spots[index]['address']),
92 | subtitle: Text("Start time: " +
93 | spots[index]['activeHours']
94 | ['start'] +
95 | "\nEnd time: " +
96 | spots[index]['activeHours']['end'] +
97 | "\nParking Type: " +
98 | spots[index]['parkingType'] +
99 | " Charges: " +
100 | (spots[index]['chargesPerHour'])
101 | .toString()),
102 | )
103 | ],
104 | ),
105 | )),
106 | ),
107 | );
108 | })
109 | : Center(
110 | child: Text('No Parking Spot Found'),
111 | )),
112 | ],
113 | ),
114 | );
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/authentication/signup.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:parking_locator/services/auth_service.dart';
3 | import 'package:parking_locator/widgets/form_input.dart';
4 |
5 | import 'package:parking_locator/constants.dart';
6 |
7 |
8 |
9 | class SignUp extends StatefulWidget {
10 | @override
11 | _SignUpState createState() => _SignUpState();
12 | }
13 |
14 | class _SignUpState extends State {
15 | static const mainColor = Constants.mainColor;
16 | static const secColor = Constants.secColor;
17 | static const backgroundColor = Constants.mainColor;
18 | AuthMethods _authMethods = AuthMethods();
19 |
20 | Future _alertDialogBuilder(String error) async {
21 | return showDialog(
22 | context: context,
23 | barrierDismissible: false,
24 | builder: (context) {
25 | return AlertDialog(
26 | title: Text("Error"),
27 | content: Container(
28 | child: Text(error),
29 | ),
30 | actions: [
31 | FlatButton(
32 | child: Text("Close Dialog"),
33 | onPressed: () {
34 | Navigator.pop(context);
35 | },
36 | )
37 | ],
38 | );
39 | });
40 | }
41 |
42 | Future createUser() async {
43 |
44 |
45 | // Call the user's CollectionReference to add a new user
46 | await _authMethods.signup(_registerName,_registerEmail,_registerPhone,_registerPassword)
47 | .then((value) => Navigator.pushReplacementNamed(context, '/search'))
48 | .catchError((error) => print("Failed to add user: $error"));
49 | return "xyz";
50 | }
51 |
52 | void _submitForm() async {
53 | setState(() {
54 | _registerFormLoading = true;
55 | });
56 |
57 | String _createAccountFeedback = await createUser();
58 |
59 | if (_createAccountFeedback != null) {
60 | _alertDialogBuilder(_createAccountFeedback);
61 |
62 | setState(() {
63 | _registerFormLoading = false;
64 | });
65 | } else {
66 | Navigator.pop(context);
67 | }
68 | }
69 |
70 | bool _registerFormLoading = false;
71 | String _registerEmail = "";
72 | String _registerName = "";
73 | String _registerPassword = "";
74 | String _registerPhone = "";
75 |
76 |
77 |
78 | @override
79 | Widget build(BuildContext context) {
80 | return Column(
81 | crossAxisAlignment: CrossAxisAlignment.stretch,
82 | mainAxisAlignment: MainAxisAlignment.center,
83 | children: [
84 | Text(
85 | "Sign up with",
86 | style: TextStyle(
87 | fontSize: 16,
88 | color: mainColor,
89 | height: 2,
90 | ),
91 | ),
92 | Text(
93 | "ParkMe",
94 | style: TextStyle(
95 | fontSize: 36,
96 | fontWeight: FontWeight.bold,
97 | color: mainColor,
98 | letterSpacing: 2,
99 | height: 1,
100 | ),
101 | ),
102 | SizedBox(
103 | height: 16,
104 | ),
105 | Input(str:"Name",
106 | onChanged: (value) {
107 | _registerName = value;
108 | },
109 | type:TextInputType.text,
110 | isPassword: false,
111 | ),
112 | SizedBox(
113 | height: 16,
114 | ),
115 | Input(str:"Email",
116 | onChanged: (value) {
117 | _registerEmail = value;
118 | },
119 | type:TextInputType.text,
120 | isPassword: false,
121 | ),
122 | SizedBox(
123 | height: 16,
124 | ),
125 | Input(str:"Phone",
126 | onChanged: (value) {
127 | _registerPhone = value;
128 | },
129 | type:TextInputType.phone,
130 | isPassword: false,
131 | ),
132 | SizedBox(
133 | height: 16,
134 | ),
135 | Input(str:"Password",
136 | onChanged: (value) {
137 | _registerPassword = value;
138 | },
139 | type:TextInputType.visiblePassword,
140 | isPassword: true,
141 | ),
142 | SizedBox(
143 | height: 16,
144 | ),
145 | InkWell(
146 | child: Container(
147 |
148 | height: 40,
149 | decoration: BoxDecoration(
150 | color: mainColor,
151 | borderRadius: BorderRadius.all(
152 | Radius.circular(25),
153 | ),
154 | boxShadow: [
155 | BoxShadow(
156 | color: mainColor,
157 | spreadRadius: 3,
158 | blurRadius: 3,
159 | offset: Offset(0, 3),
160 | ),
161 | ],
162 | ),
163 | child: Center(
164 | child: Text(
165 | "SIGN UP",
166 | style: TextStyle(
167 | fontSize: 24,
168 | fontWeight: FontWeight.bold,
169 | color: secColor,
170 | ),
171 | ),
172 | ),
173 | ),
174 | onTap: () {
175 | _submitForm();
176 | },
177 | //isLoading: _registerFormLoading,
178 | ),
179 | SizedBox(
180 | height: 24,
181 | ),
182 | ],
183 | );
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/parking-locator-backend/src/routes/user.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const ParkingHistory = require("../database/models/ParkingHistory");
3 | const ParkingLocations = require("../database/models/parkingLocations");
4 | const moment = require("moment");
5 | const { TIME_FORMAT } = require("../config");
6 |
7 | const router = express.Router();
8 |
9 | router.get("/", (req, res) => {
10 | res.send("user service");
11 | });
12 |
13 | router.post("/myParking", async (req, res) => {
14 | try {
15 | const { lat, long, startTime, endTime, address, parkingType, chargesPerHour } = req.body;
16 | const { userID } = req.user;
17 | const startTimeObj = moment(startTime, TIME_FORMAT);
18 | console.log(req.body);
19 | const endTimeObj = moment(endTime, TIME_FORMAT);
20 | console.log(endTime);
21 | const startOfDay = moment().startOf("day");
22 | console.log(address);
23 | const parking = await ParkingLocations.create({
24 | userID,
25 | Location: { type: "Point", coordinates: [lat, long] },
26 | activeHours: {
27 | start: startTimeObj.diff(startOfDay, "minutes"),
28 | end: endTimeObj.diff(startOfDay, "minutes"),
29 | },
30 | address,
31 | parkingType,
32 | chargesPerHour,
33 | });
34 |
35 | res.json({ status: "SUCCESS", parking });
36 | } catch (error) {
37 | res.status(500).send({ message: error.message, errorType: error.name });
38 | }
39 | });
40 |
41 | router.post("/myParking/:spotID/setActiveHours", async (req, res) => {
42 | const { userID } = req.user;
43 | const { spotID } = req.params;
44 | const { startTime, endTime } = req.body;
45 | console.log(spotID, userID);
46 | try {
47 | const parking = await ParkingLocations.findOne({ slotID: spotID, userID });
48 | if (parking) {
49 | const startTimeObj = moment(startTime, TIME_FORMAT);
50 | const endTimeObj = moment(endTime, TIME_FORMAT);
51 | if (startTimeObj.isAfter(endTimeObj)) {
52 | res.json({ status: "FAILED", message: "invalid start and end times" });
53 | return;
54 | }
55 | const isCurrentTimeSlot = moment().isBetween(startTimeObj, endTimeObj);
56 | if (parking.isEmpty || !isCurrentTimeSlot) {
57 | const startOfDay = moment().startOf("day");
58 | parking.activeHours = {
59 | start: startTimeObj.diff(startOfDay, "minutes"),
60 | end: endTimeObj.diff(startOfDay, "minutes"),
61 | };
62 | await parking.save();
63 | res.json({ status: "SUCCESS", parking });
64 | } else {
65 | res.json({ status: "FAILED", message: "Cannot modify at the moment" });
66 | }
67 | } else {
68 | res.json({ status: "FAILED", message: "parking not found" });
69 | }
70 | } catch (error) {
71 | res.status(500).send({ message: error.message, errorType: error.name });
72 | }
73 | });
74 |
75 | router.get("/myParking", async (req, res) => {
76 | try {
77 | const { userID } = req.user;
78 | const parkings = await ParkingLocations.find({ userID });
79 | const parkingsRes = parkings.map((parking) => {
80 | const startTime = moment().startOf("day").add(parking.activeHours.start, "minutes").format(TIME_FORMAT);
81 | const endTime = moment().startOf("day").add(parking.activeHours.end, "minutes").format(TIME_FORMAT);
82 | const parkingJSON = parking.toJSON();
83 | return { ...parkingJSON, activeHours: { start: startTime, end: endTime } };
84 | });
85 | res.json({ status: "SUCCESS", parkings: parkingsRes });
86 | } catch (error) {
87 | res.status(500).send({ message: error.message, errorType: error.name });
88 | }
89 | });
90 |
91 | router.get("/myParking/bookings", async (req, res) => {
92 | try {
93 | const { spotID } = req.query;
94 | const bookings = await ParkingHistory.aggregate([
95 | { $match: { slotID: spotID, isConfirmed: true } },
96 | { $lookup: { from: "users", localField: "userID", foreignField: "userID", as: "user" } },
97 | { $unwind: { path: "$user" } },
98 | { $project: { "user.password": 0, "user.mobile": 0, "user.walletBalance": 0 } },
99 | ]);
100 | if (bookings) {
101 | res.json({ status: "SUCCESS", bookings });
102 | } else {
103 | res.json({ status: "NOTFOUND", message: "Could not find the requested slot" });
104 | }
105 | } catch (error) {
106 | res.status(500).send({ message: error.message, errorType: error.name });
107 | }
108 | });
109 |
110 | router.get("/myParking/:spotID", async (req, res) => {
111 | try {
112 | const { spotID } = req.params;
113 | const { userID } = req.user;
114 | let parking = await ParkingLocations.findOne({ slotID: spotID, userID });
115 | if (parking) {
116 | parking = parking.toJSON();
117 |
118 | parking.activeHours.start = moment().startOf("day").add(parking.activeHours.start, "minutes").format(TIME_FORMAT);
119 | parking.activeHours.end = moment().startOf("day").add(parking.activeHours.end, "minutes").format(TIME_FORMAT);
120 | res.json({ status: "SUCCESS", parking });
121 | } else {
122 | res.json({ status: "NOTFOUND", message: "Could not find the requested spot" });
123 | }
124 | } catch (error) {
125 | res.status(500).send({ message: error.message, errorType: error.name });
126 | }
127 | });
128 |
129 | router.delete("/myParking", async (req, res) => {
130 | const { userID } = req.user;
131 | const { spotID } = req.body;
132 | try {
133 | const parking = await ParkingLocations.findOne({ userID, slotID: spotID });
134 | if (parking) {
135 | await ParkingLocations.findOneAndDelete({ userID, slotID: spotID });
136 | res.json({ status: "SUCCESS", message: "deleted" });
137 | } else {
138 | res.json({ status: "NOTFOUND", message: "Could not find the requested spot" });
139 | }
140 | } catch (error) {
141 | res.status(500).send({ message: error.message, errorType: error.name });
142 | }
143 | });
144 |
145 | router.get("/bookings", async (req, res) => {
146 | const { userID } = req.user;
147 | console.log(userID);
148 | try {
149 | const bookings = await ParkingHistory.aggregate([
150 | { $match: { userID } },
151 | {
152 | $lookup: {
153 | from: "parkinglocations",
154 | localField: "slotID",
155 | foreignField: "slotID",
156 | as: "parkingLocation",
157 | },
158 | },
159 | {
160 | $unwind: {
161 | path: "$parkingLocation",
162 | },
163 | },
164 | ]);
165 | res.json({ status: "SUCCESS", bookings });
166 | } catch (error) {
167 | res.status(500).send({ message: error.message, errorType: error.name });
168 | }
169 | });
170 |
171 | router.get("/bookings/active", async (req, res) => {
172 | const { userID } = req.user;
173 | try {
174 | const bookings = await ParkingHistory.find({ userID,endTime:undefined });
175 | res.json({ status: "SUCCESS", bookings });
176 | } catch (error) {
177 | res.status(500).send({ message: error.message, errorType: error.name });
178 | }
179 | });
180 |
181 | module.exports = router;
182 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/authentication/login.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:parking_locator/services/auth_service.dart';
3 | import 'package:parking_locator/constants.dart';
4 |
5 |
6 | // import 'package:firebase_auth/firebase_auth.dart';
7 | class Login extends StatefulWidget {
8 | @override
9 | _LoginState createState() => _LoginState();
10 | }
11 |
12 | class _LoginState extends State {
13 | static const mainColor = Constants.mainColor;
14 | static const secColor = Constants.secColor;
15 | static const backgroundColor = Constants.mainColor;
16 |
17 | final TextEditingController _controller = TextEditingController();
18 | Future _alertDialogBuilder(String error) async {
19 | return showDialog(
20 | context: context,
21 | barrierDismissible: false,
22 | builder: (context) {
23 | return AlertDialog(
24 | title: Text("Error"),
25 | content: Container(
26 | child: Text(error),
27 | ),
28 | actions: [
29 | FlatButton(
30 | child: Text("Close Dialog"),
31 | onPressed: () {
32 | Navigator.pop(context);
33 | },
34 | )
35 | ],
36 | );
37 | });
38 | }
39 | AuthMethods _authMethods = AuthMethods();
40 |
41 | Future _loginAccount() async {
42 | // Call the user's CollectionReference to add a new user
43 | await _authMethods
44 | .signin(
45 | _loginEmail, _loginPassword)
46 | .then((value) => Navigator.pushReplacementNamed(context, '/search'))
47 | .catchError((error) => print("Failed to add user: $error"));
48 | return "Icorrect Password!";
49 | }
50 |
51 | void _submitForm() async {
52 | setState(() {
53 | _loginFormLoading = true;
54 | });
55 |
56 | String _loginFeedback = await _loginAccount();
57 |
58 | if (_loginFeedback != null) {
59 | _alertDialogBuilder(_loginFeedback);
60 |
61 | setState(() {
62 | print("hi");
63 | _loginFormLoading = false;
64 | });
65 | } else {
66 | Navigator.pop(context);
67 | }
68 | }
69 |
70 | bool _loginFormLoading = false;
71 | String _loginEmail = "";
72 | String _loginPassword = "";
73 |
74 | FocusNode _passwordFocusNode;
75 |
76 | @override
77 | void initState() {
78 | _passwordFocusNode = FocusNode();
79 | super.initState();
80 | }
81 |
82 | @override
83 | void dispose() {
84 | _passwordFocusNode.dispose();
85 | super.dispose();
86 | }
87 |
88 | @override
89 | Widget build(BuildContext context) {
90 | return Column(
91 | crossAxisAlignment: CrossAxisAlignment.stretch,
92 | mainAxisAlignment: MainAxisAlignment.center,
93 | children: [
94 | Text(
95 | "Welcome to",
96 | style: TextStyle(
97 | fontSize: 16,
98 | color: secColor,
99 | height: 2,
100 | ),
101 | ),
102 | Text(
103 | "ParkMe",
104 | style: TextStyle(
105 | fontSize: 36,
106 | fontWeight: FontWeight.bold,
107 | color: secColor,
108 | letterSpacing: 2,
109 | height: 1,
110 | ),
111 | ),
112 | SizedBox(
113 | height: 10.0,
114 | ),
115 | Text(
116 | "Please login to continue",
117 | style: TextStyle(
118 | fontSize: 16,
119 | color: Color(0xFF1C1C1C),
120 | height: 1,
121 | ),
122 | ),
123 | SizedBox(
124 | height: 16,
125 | ),
126 | TextField(
127 | onChanged: (value) {
128 | _loginEmail = value;
129 | },
130 | onSubmitted: (value) {
131 | _passwordFocusNode.requestFocus();
132 | },
133 | textInputAction: TextInputAction.next,
134 | // controller: _controller,
135 | decoration: InputDecoration(
136 | hintText: 'Email / Username',
137 | hintStyle: TextStyle(
138 | fontSize: 16,
139 | color: secColor,
140 | fontWeight: FontWeight.bold,
141 | ),
142 | border: OutlineInputBorder(
143 | borderRadius: BorderRadius.circular(25),
144 | borderSide: BorderSide(
145 | width: 0,
146 | style: BorderStyle.none,
147 | ),
148 | ),
149 | filled: true,
150 | fillColor: Colors.black12,
151 | contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 0),
152 | ),
153 | ),
154 | SizedBox(
155 | height: 16,
156 | ),
157 | TextField(
158 | obscureText: true,
159 | onChanged: (value) {
160 | _loginPassword = value;
161 | },
162 | focusNode: _passwordFocusNode,
163 | //isPasswordField: true,
164 | onSubmitted: (value) {
165 | _submitForm();
166 | },
167 | decoration: InputDecoration(
168 | hintText: 'Password',
169 | hintStyle: TextStyle(
170 | fontSize: 16,
171 | color: secColor,
172 | fontWeight: FontWeight.bold,
173 | ),
174 | border: OutlineInputBorder(
175 | borderRadius: BorderRadius.circular(25),
176 | borderSide: BorderSide(
177 | width: 0,
178 | style: BorderStyle.none,
179 | ),
180 | ),
181 | filled: true,
182 | fillColor: Colors.black12,
183 | contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 0),
184 | ),
185 | ),
186 | SizedBox(
187 | height: 24,
188 | ),
189 | InkWell(
190 | child: Container(
191 | height: 40,
192 | decoration: BoxDecoration(
193 | color: secColor,
194 | borderRadius: BorderRadius.all(
195 | Radius.circular(25),
196 | ),
197 | boxShadow: [
198 | BoxShadow(
199 | color: Color(0xFF041E42).withOpacity(0.2),
200 | spreadRadius: 3,
201 | blurRadius: 4,
202 | offset: Offset(0, 3),
203 | ),
204 | ],
205 | ),
206 | child: Center(
207 | child: Text(
208 | "LOGIN",
209 | style: TextStyle(
210 | fontSize: 24,
211 | fontWeight: FontWeight.bold,
212 | color: mainColor,
213 | ),
214 | ),
215 | ),
216 | ),
217 | onTap: () {
218 | _submitForm();
219 | //HomePage();
220 | },
221 | ),
222 | SizedBox(
223 | height: 16,
224 | ),
225 | ],
226 | );
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/search.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:google_maps_flutter/google_maps_flutter.dart';
3 | import 'package:parking_locator/screens/placeDetails.dart';
4 | import 'package:parking_locator/services/geolocator_service.dart';
5 | // import 'package:parking_locator/services/dbservice.dart';
6 | // import 'package:parking_locator/screens/confirm_booking.dart';
7 | import 'package:parking_locator/services/marker_service.dart';
8 | import 'package:parking_locator/widgets/drawer.dart';
9 | import 'package:parking_locator/constants.dart';
10 |
11 |
12 |
13 | import 'package:provider/provider.dart';
14 | import 'package:geolocator/geolocator.dart';
15 | import 'package:url_launcher/url_launcher.dart';
16 | import '../models/place.dart';
17 |
18 | class Search extends StatelessWidget {
19 | @override
20 | Widget build(BuildContext context) {
21 | final currentPosition = Provider.of(context);
22 | final placesProvider = Provider.of>>(context);
23 | final geoService = GeoLocatorService();
24 | final markerService = MarkerService();
25 |
26 | return FutureProvider(
27 | create: (context) => placesProvider,
28 | child: Scaffold(
29 | appBar: AppBar(
30 | backgroundColor: Constants.secColor,
31 | title: Text("ParkMe"),
32 | ),
33 | drawer: NavDrawer(),
34 | body: (currentPosition != null)
35 | ? Consumer>(
36 | builder: (_, places, __) {
37 | var markers = (places != null)
38 | ? markerService.getMarkers(places)
39 | : List();
40 | return (places != null)
41 | ? Column(
42 | children: [
43 | Container(
44 | height: MediaQuery.of(context).size.height / 2,
45 | width: MediaQuery.of(context).size.width,
46 | child: GoogleMap(
47 | initialCameraPosition: CameraPosition(
48 | target: LatLng(currentPosition.latitude,
49 | currentPosition.longitude),
50 | zoom: 16.0),
51 | zoomGesturesEnabled: true,
52 | markers: Set.of(markers),
53 | ),
54 | ),
55 | SizedBox(
56 | height: 10.0,
57 | ),
58 | Expanded(
59 | child:Container(
60 | color: Constants.mainColor,
61 | child: (places.length > 0)
62 | ? ListView.builder(
63 | itemCount: places.length,
64 | itemBuilder: (context, index) {
65 | return FutureProvider(
66 | initialData: Container(),
67 | create: (context) =>
68 | geoService.getDistance(
69 | currentPosition.latitude,
70 | currentPosition.longitude,
71 | places[index].lat,
72 | places[index].long,
73 | ),
74 | child: GestureDetector(
75 | onTap: () {
76 | Navigator.push(
77 | context,
78 | MaterialPageRoute(
79 | builder: (context) =>
80 | PlaceDetails(
81 | spotId:
82 | places[index].slotID,
83 | ),
84 | ));
85 | },
86 | child: Card(
87 |
88 | child: ListTile(
89 | title:
90 | Text(places[index].address,style: TextStyle(color:Constants.secColor),),
91 | subtitle: Column(
92 | crossAxisAlignment:
93 | CrossAxisAlignment.start,
94 | children: [
95 | SizedBox(
96 | height: 3.0,
97 | ),
98 | SizedBox(
99 | height: 5.0,
100 | ),
101 | ],
102 | ),
103 | trailing: IconButton(
104 | icon: Icon(Icons.directions),
105 | color: Theme.of(context)
106 | .primaryColor,
107 | onPressed: () {
108 | _launchMapsUrl(
109 | places[index].lat,
110 | places[index].long);
111 | },
112 | ),
113 | ),
114 | ),
115 | ),
116 | );
117 | })
118 | : Center(
119 | child: Text('No Parking Found Nearby'),
120 | ),
121 | )
122 | )
123 | ],
124 | )
125 | : Center(child: CircularProgressIndicator());
126 | },
127 | )
128 | : Center(
129 | child: CircularProgressIndicator(),
130 | ),
131 | ),
132 | );
133 | }
134 |
135 | void _launchMapsUrl(double lat, double lng) async {
136 | final url = 'https://www.google.com/maps/search/?api=1&query=$lat,$lng';
137 | if (await canLaunch(url)) {
138 | await launch(url);
139 | } else {
140 | throw 'Could not launch $url';
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/userHistory.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:parking_locator/services/dbservice.dart';
3 | import 'package:parking_locator/constants.dart';
4 | import 'package:parking_locator/widgets/drawer.dart';
5 |
6 | class MyHistory extends StatefulWidget {
7 | @override
8 | _MyHistoryState createState() => _MyHistoryState();
9 | }
10 |
11 | class _MyHistoryState extends State {
12 | final db_methods = DbMethods();
13 | final db2_methods = DbBookingMethods();
14 |
15 | List history;
16 |
17 | void gethistory() async {
18 | List result;
19 | result = await db_methods.userHistory();
20 | setState(() {
21 | history = result;
22 | print("My History ");
23 | print(history);
24 | });
25 | }
26 |
27 | void _checkout(id) {
28 | db2_methods.checkout(id);
29 | }
30 |
31 | @override
32 | void initState() {
33 | gethistory();
34 | // db_methods.userHistory();
35 | }
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | final height = MediaQuery.of(context).size.height;
40 | final width = MediaQuery.of(context).size.width;
41 | return Scaffold(
42 | appBar: AppBar(
43 | backgroundColor: Constants.secColor,
44 | title: Text('My Bookings'),
45 | ),
46 | drawer:NavDrawer(),
47 | body: Column(
48 | children: [
49 | // Text(spots[1]['address']),
50 | Expanded(
51 | child: (history != null)
52 | ? ListView.builder(
53 | itemCount: history.length,
54 | itemBuilder: (context, index) {
55 | return Container(
56 | child: Card(
57 | shape: RoundedRectangleBorder(
58 | borderRadius: BorderRadius.circular(15.0),
59 | ),
60 | color: Colors.white,
61 | elevation: 7,
62 | child: Column(
63 | children: [
64 | GestureDetector(
65 | onTap: () {
66 | _checkout(history[index]['slotID']);
67 | },
68 | child: Container(
69 | child:
70 |
71 | // Column(
72 | // crossAxisAlignment: CrossAxisAlignment.start,
73 | // children: [
74 | // Text(history[index]['address']),
75 | // Text("Start time: " +
76 | // history[index]['activeHours']['start']),
77 | // Text("End time: " +
78 | // history[index]['activeHours']['end']),
79 | // Row(
80 | // children: [
81 | // Text("Parking Type: " +
82 | // history[index]['parkingType']),
83 | // SizedBox(
84 | // width: width * 2 / 5,
85 | // ),
86 | // Text("Charges: " +
87 | // (history[index]['chargesPerHour'])
88 | // .toString()),
89 | // ],
90 | // ),
91 | // ],
92 | // )
93 | // ,
94 | (history[index]['startTime'] ==
95 | null)
96 | ? ListTile(
97 | // isThreeLine: true,
98 | subtitle: Text(
99 | "Parking Type: " +
100 | history[index]
101 | [
102 | 'parkingLocation']
103 | [
104 | 'parkingType']),
105 | title: Text(
106 | // "Start time: " +
107 | // history[index][
108 | // 'startTime']
109 | // .toString() +
110 | "\nParking Address: " +
111 | history[index][
112 | 'parkingLocation']
113 | ['address'] +
114 | "\nCharges per hour: " +
115 | history[index][
116 | 'parkingLocation']
117 | [
118 | 'chargesPerHour']
119 | .toString()
120 | // " Charges: " +
121 | // (history[index]['parkingLocation']['chargesPerHour'])
122 | // .toString()
123 | ),
124 | )
125 | : ListTile(
126 | // isThreeLine: true,
127 | subtitle: Text(
128 | "Parking Type: " +
129 | history[index]
130 | [
131 | 'parkingLocation']
132 | [
133 | 'parkingType']),
134 | title: Text(
135 | // "Estimated Start time: " +
136 | // history[index][
137 | // 'estimatedStartTime']
138 | // .toString() +
139 | "\nParking Address: " +
140 | history[index][
141 | 'parkingLocation']
142 | ['address'] +
143 | "\nCharges per hour: " +
144 | history[index][
145 | 'parkingLocation']
146 | [
147 | 'chargesPerHour']
148 | .toString()
149 | // " Charges: " +
150 | // (history[index]['parkingLocation']['chargesPerHour'])
151 | // .toString()
152 | ),
153 | )))
154 | ],
155 | ),
156 | ),
157 | );
158 | })
159 | : Center(
160 | child: Text('No Parking History Found'),
161 | )),
162 | ],
163 | ),
164 | );
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/parking_locator/lib/services/dbservice.dart:
--------------------------------------------------------------------------------
1 | import 'package:http/http.dart' as http;
2 | import 'dart:io';
3 | import 'dart:convert' as convert;
4 | import 'package:parking_locator/models/place.dart';
5 |
6 | class DbMethods {
7 | addSpot(lat, long, startTime, endTime, address, type, cost) async {
8 | String token =
9 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
10 | // try {
11 | var url = Uri.parse('http://127.0.0.1:5000/user/myParking');
12 | print(url);
13 | var obj = {
14 | "lat": lat,
15 | "long": long,
16 | "startTime": startTime,
17 | "endTime": endTime,
18 | "address": address,
19 | "parkingType": type,
20 | "chargesPerHour": cost
21 | };
22 | print(obj);
23 |
24 | var res = await http.post(
25 | url,
26 | body: convert.json.encode({
27 | "lat": lat,
28 | "long": long,
29 | "startTime": startTime,
30 | "endTime": endTime,
31 | "address": address,
32 | "parkingType": type,
33 | "chargesPerHour": cost
34 | }),
35 | headers: {
36 | "authorization": token,
37 | "Content-Type": "application/json",
38 | },
39 | );
40 |
41 | print(res.statusCode);
42 | print(res.body);
43 | var jsonRes = convert.jsonDecode(res.body);
44 | print(jsonRes);
45 | return jsonRes;
46 | }
47 | // addSpot(lat, long, startTime, endTime, address, type) async {
48 | // print("imhere");
49 | // print("end" + endTime);
50 | // print("type" + type);
51 | // String token =
52 | // "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
53 | // // try {
54 | // var url = Uri.parse('http://127.0.0.1:5000/user/myParking');
55 | // print(url);
56 | // var res = await http.post(
57 | // url,
58 | // body: convert.json.encode({
59 | // "lat": lat,
60 | // "long": long,
61 | // "startTime": startTime,
62 | // "endTime": endTime,
63 | // "address": address,
64 | // "parkingType": type,
65 | // "chargesPerHour": 100
66 | // }),
67 | // headers: {
68 | // "authorization": token,
69 | // "Content-Type": "application/json",
70 | // },
71 | // );
72 |
73 | // print(res.statusCode);
74 | // print(res.body);
75 | // if (res.statusCode == 200) {
76 | // print("Spot added");
77 | // } else {
78 | // throw Exception('Failed to create album.');
79 | // }
80 | // }
81 |
82 | mySpots() async {
83 | String token =
84 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
85 | // try {
86 | var url = Uri.parse('http://127.0.0.1:5000/user/myParking');
87 | print(url);
88 | var res = await http.get(
89 | url,
90 | headers: {
91 | "authorization": token,
92 | "Content-Type": "application/json",
93 | },
94 | );
95 | var json = convert.jsonDecode(res.body);
96 | print("hi");
97 | print(json);
98 |
99 | var jsonResults = json['parkings'];
100 | print(jsonResults);
101 | return jsonResults;
102 | }
103 |
104 | spotDetail(String spotID) async {
105 | String token =
106 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
107 | // try {
108 | var url = Uri.parse(
109 | 'http://127.0.0.1:5000/user/myParking/bookings/?spotID=$spotID');
110 | print(url);
111 | var res = await http.get(
112 | url,
113 | headers: {
114 | "authorization": token,
115 | "Content-Type": "application/json",
116 | },
117 | );
118 | var json = convert.jsonDecode(res.body);
119 | print("hi");
120 | print(json);
121 |
122 | var jsonResults = json['bookings'];
123 | print(jsonResults);
124 | return jsonResults;
125 | }
126 |
127 | bookingDetails(String spotID, startTime, endTime) async {
128 | String token =
129 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
130 | // try {
131 | var url = Uri.parse(
132 | 'http://127.0.0.1:5000/user/myParking/$spotID/setActiveHours');
133 | print(url);
134 | var res = await http.post(
135 | url,
136 | body: convert.json.encode({
137 | "startTime": startTime,
138 | "endTime": endTime,
139 | }),
140 | headers: {
141 | "authorization": token,
142 | "Content-Type": "application/json",
143 | },
144 | );
145 | print(res.statusCode);
146 | print(res.body);
147 | if (res.statusCode == 200) {
148 | print("Spot added");
149 | } else {
150 | throw Exception('Failed to create album.2');
151 | }
152 | }
153 |
154 | userHistory() async {
155 | String token =
156 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
157 | // try {
158 | var url = Uri.parse('http://127.0.0.1:5000/user/bookings');
159 | print(url);
160 | var res = await http.get(
161 | url,
162 | headers: {
163 | "authorization": token,
164 | "Content-Type": "application/json",
165 | },
166 | );
167 | var json = convert.jsonDecode(res.body);
168 | print("hi");
169 | print(json);
170 |
171 | var jsonResults = json['bookings'];
172 | print(jsonResults);
173 | return jsonResults;
174 | }
175 |
176 | //get details of a parkspot
177 | Future getPlaceDetails(String spotId) async {
178 | var url = Uri.parse('http://127.0.0.1:5000/parking/$spotId');
179 | print(url);
180 | String token =
181 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
182 | var response = await http.get(
183 | url,
184 | headers: {
185 | "authorization": token,
186 | "Content-Type": "application/json",
187 | },
188 | );
189 | var jsonResults = convert.jsonDecode(response.body);
190 | print(jsonResults['parking']);
191 | return jsonResults['parking'];
192 | }
193 | }
194 |
195 | class DbBookingMethods {
196 | onSubmit(spotid, lat, long, canBook) async {
197 | print("imhere");
198 |
199 | String token =
200 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
201 | // try {
202 | var url = Uri.parse('http://127.0.0.1:5000/booking/checkin');
203 | print(url);
204 | var res = await http.post(
205 | url,
206 | body: convert.json.encode({
207 | "spotID": spotid,
208 | "lat": lat,
209 | "long": long,
210 | "isEmpty": canBook,
211 | }),
212 | headers: {
213 | "authorization": token,
214 | "Content-Type": "application/json",
215 | },
216 | );
217 |
218 | print(res.statusCode);
219 | print(res.body);
220 | if (res.statusCode == 200) {
221 | print("Spot added");
222 | var status = res.body;
223 | var json = convert.jsonDecode(res.body);
224 | print(json);
225 | return json;
226 | } else {
227 | throw Exception('Failed to see booking.');
228 | }
229 | }
230 |
231 | PriorBook(spotid, startTime, duration) async {
232 | print("imhere");
233 |
234 | String token =
235 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
236 | // try {
237 | var url = Uri.parse('http://127.0.0.1:5000/booking/bookPrior');
238 | print(url);
239 | var res = await http.post(
240 | url,
241 | body: convert.json.encode({
242 | "spotID": spotid,
243 | "startTime": startTime,
244 | "duration": duration,
245 | }),
246 | headers: {
247 | "authorization": token,
248 | "Content-Type": "application/json",
249 | },
250 | );
251 |
252 | print(res.statusCode);
253 | print(res.body);
254 | if (res.statusCode == 200) {
255 | print("Spot added");
256 | var status = res.body;
257 | var json = convert.jsonDecode(res.body);
258 | print(json);
259 | return json;
260 | } else {
261 | throw Exception('Failed to see booking.');
262 | }
263 | }
264 |
265 | confirmBook(spotid, bookingid) async {
266 | print("imhere");
267 | print(spotid);
268 | print(bookingid);
269 |
270 | String token =
271 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
272 | // try {
273 | var url = Uri.parse('http://127.0.0.1:5000/booking/checkin/verify');
274 | print(url);
275 | var res = await http.post(
276 | url,
277 | body: convert.json.encode({"spotID": spotid, "bookingID": bookingid}),
278 | headers: {
279 | "authorization": token,
280 | "Content-Type": "application/json",
281 | },
282 | );
283 |
284 | print(res.statusCode);
285 | print(res.body);
286 | var json = convert.jsonDecode(res.body);
287 | print(json);
288 |
289 | if (res.statusCode == 200) {
290 | print("Confirm booking");
291 | } else {
292 | throw Exception('Failed confirm booking.');
293 | }
294 | return json;
295 | }
296 |
297 | checkout(spotid) async {
298 | print("imhere");
299 |
300 | String token =
301 | "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3YWxsZXRCYWxhbmNlIjoxMDAsIl9pZCI6IjYwNjZmYTZkYTQxY2JmMmEwOGY2YTY0NiIsIm5hbWUiOiJIaXJhbCIsImVtYWlsIjoiaGlyYWxAZ21haWwuY29tIiwibW9iaWxlIjoiMTIzNDU2Nzg5MCIsInVzZXJJRCI6IjE4NWNhZGQyLWI2Y2YtNGM4MC05MGZjLTc3M2Q5NTg3MGRhYiIsIl9fdiI6MCwiaWF0IjoxNjE3NDUzNjE5fQ.czhfN16oe57qpS8wt_CNt3giA2f5FFOvKjhD46IPnbU";
302 | // try {
303 | var url = Uri.parse('http://127.0.0.1:5000/booking/checkout');
304 | print(url);
305 | var res = await http.post(
306 | url,
307 | body: convert.json.encode({"spotID": spotid}),
308 | headers: {
309 | "authorization": token,
310 | "Content-Type": "application/json",
311 | },
312 | );
313 | print(res.statusCode);
314 | print(res.body);
315 | if (res.statusCode == 200) {
316 | print("Checkout!!");
317 | } else {
318 | throw Exception('Failed confirm booking.');
319 | }
320 | }
321 | }
322 |
--------------------------------------------------------------------------------
/parking_locator/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "3.1.2"
11 | async:
12 | dependency: transitive
13 | description:
14 | name: async
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "2.5.0"
18 | boolean_selector:
19 | dependency: transitive
20 | description:
21 | name: boolean_selector
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.1.0"
25 | characters:
26 | dependency: transitive
27 | description:
28 | name: characters
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.1.0"
32 | charcode:
33 | dependency: transitive
34 | description:
35 | name: charcode
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "1.2.0"
39 | clock:
40 | dependency: transitive
41 | description:
42 | name: clock
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.1.0"
46 | collection:
47 | dependency: transitive
48 | description:
49 | name: collection
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.15.0"
53 | crypto:
54 | dependency: transitive
55 | description:
56 | name: crypto
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "3.0.1"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "1.0.2"
67 | date_format:
68 | dependency: "direct main"
69 | description:
70 | name: date_format
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "2.0.2"
74 | fake_async:
75 | dependency: transitive
76 | description:
77 | name: fake_async
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "1.2.0"
81 | ffi:
82 | dependency: transitive
83 | description:
84 | name: ffi
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "1.0.0"
88 | file:
89 | dependency: transitive
90 | description:
91 | name: file
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "6.1.0"
95 | flutter:
96 | dependency: "direct main"
97 | description: flutter
98 | source: sdk
99 | version: "0.0.0"
100 | flutter_datetime_picker:
101 | dependency: "direct main"
102 | description:
103 | name: flutter_datetime_picker
104 | url: "https://pub.dartlang.org"
105 | source: hosted
106 | version: "1.5.0"
107 | flutter_plugin_android_lifecycle:
108 | dependency: transitive
109 | description:
110 | name: flutter_plugin_android_lifecycle
111 | url: "https://pub.dartlang.org"
112 | source: hosted
113 | version: "2.0.1"
114 | flutter_rating_bar:
115 | dependency: "direct main"
116 | description:
117 | name: flutter_rating_bar
118 | url: "https://pub.dartlang.org"
119 | source: hosted
120 | version: "4.0.0"
121 | flutter_test:
122 | dependency: "direct dev"
123 | description: flutter
124 | source: sdk
125 | version: "0.0.0"
126 | flutter_web_plugins:
127 | dependency: transitive
128 | description: flutter
129 | source: sdk
130 | version: "0.0.0"
131 | form_field_validator:
132 | dependency: "direct main"
133 | description:
134 | name: form_field_validator
135 | url: "https://pub.dartlang.org"
136 | source: hosted
137 | version: "1.1.0"
138 | geocoder:
139 | dependency: "direct main"
140 | description:
141 | name: geocoder
142 | url: "https://pub.dartlang.org"
143 | source: hosted
144 | version: "0.2.1"
145 | geolocator:
146 | dependency: "direct main"
147 | description:
148 | name: geolocator
149 | url: "https://pub.dartlang.org"
150 | source: hosted
151 | version: "7.0.1"
152 | geolocator_platform_interface:
153 | dependency: transitive
154 | description:
155 | name: geolocator_platform_interface
156 | url: "https://pub.dartlang.org"
157 | source: hosted
158 | version: "2.0.0"
159 | geolocator_web:
160 | dependency: transitive
161 | description:
162 | name: geolocator_web
163 | url: "https://pub.dartlang.org"
164 | source: hosted
165 | version: "2.0.3"
166 | google_fonts:
167 | dependency: "direct main"
168 | description:
169 | name: google_fonts
170 | url: "https://pub.dartlang.org"
171 | source: hosted
172 | version: "2.0.0"
173 | google_maps_flutter:
174 | dependency: "direct main"
175 | description:
176 | name: google_maps_flutter
177 | url: "https://pub.dartlang.org"
178 | source: hosted
179 | version: "2.0.2"
180 | google_maps_flutter_platform_interface:
181 | dependency: transitive
182 | description:
183 | name: google_maps_flutter_platform_interface
184 | url: "https://pub.dartlang.org"
185 | source: hosted
186 | version: "2.0.4"
187 | http:
188 | dependency: "direct main"
189 | description:
190 | name: http
191 | url: "https://pub.dartlang.org"
192 | source: hosted
193 | version: "0.13.1"
194 | http_parser:
195 | dependency: transitive
196 | description:
197 | name: http_parser
198 | url: "https://pub.dartlang.org"
199 | source: hosted
200 | version: "4.0.0"
201 | intl:
202 | dependency: "direct main"
203 | description:
204 | name: intl
205 | url: "https://pub.dartlang.org"
206 | source: hosted
207 | version: "0.17.0"
208 | js:
209 | dependency: transitive
210 | description:
211 | name: js
212 | url: "https://pub.dartlang.org"
213 | source: hosted
214 | version: "0.6.3"
215 | loading_animations:
216 | dependency: "direct main"
217 | description:
218 | name: loading_animations
219 | url: "https://pub.dartlang.org"
220 | source: hosted
221 | version: "2.2.0"
222 | logging:
223 | dependency: transitive
224 | description:
225 | name: logging
226 | url: "https://pub.dartlang.org"
227 | source: hosted
228 | version: "1.0.1"
229 | lottie:
230 | dependency: "direct main"
231 | description:
232 | name: lottie
233 | url: "https://pub.dartlang.org"
234 | source: hosted
235 | version: "1.0.1"
236 | matcher:
237 | dependency: transitive
238 | description:
239 | name: matcher
240 | url: "https://pub.dartlang.org"
241 | source: hosted
242 | version: "0.12.10"
243 | meta:
244 | dependency: transitive
245 | description:
246 | name: meta
247 | url: "https://pub.dartlang.org"
248 | source: hosted
249 | version: "1.3.0"
250 | nested:
251 | dependency: transitive
252 | description:
253 | name: nested
254 | url: "https://pub.dartlang.org"
255 | source: hosted
256 | version: "1.0.0"
257 | path:
258 | dependency: transitive
259 | description:
260 | name: path
261 | url: "https://pub.dartlang.org"
262 | source: hosted
263 | version: "1.8.0"
264 | path_provider:
265 | dependency: transitive
266 | description:
267 | name: path_provider
268 | url: "https://pub.dartlang.org"
269 | source: hosted
270 | version: "2.0.1"
271 | path_provider_linux:
272 | dependency: transitive
273 | description:
274 | name: path_provider_linux
275 | url: "https://pub.dartlang.org"
276 | source: hosted
277 | version: "2.0.0"
278 | path_provider_macos:
279 | dependency: transitive
280 | description:
281 | name: path_provider_macos
282 | url: "https://pub.dartlang.org"
283 | source: hosted
284 | version: "2.0.0"
285 | path_provider_platform_interface:
286 | dependency: transitive
287 | description:
288 | name: path_provider_platform_interface
289 | url: "https://pub.dartlang.org"
290 | source: hosted
291 | version: "2.0.1"
292 | path_provider_windows:
293 | dependency: transitive
294 | description:
295 | name: path_provider_windows
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "2.0.0"
299 | pedantic:
300 | dependency: transitive
301 | description:
302 | name: pedantic
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "1.11.0"
306 | platform:
307 | dependency: transitive
308 | description:
309 | name: platform
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "3.0.0"
313 | plugin_platform_interface:
314 | dependency: transitive
315 | description:
316 | name: plugin_platform_interface
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "2.0.0"
320 | process:
321 | dependency: transitive
322 | description:
323 | name: process
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "4.2.1"
327 | provider:
328 | dependency: "direct main"
329 | description:
330 | name: provider
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "5.0.0"
334 | sky_engine:
335 | dependency: transitive
336 | description: flutter
337 | source: sdk
338 | version: "0.0.99"
339 | source_span:
340 | dependency: transitive
341 | description:
342 | name: source_span
343 | url: "https://pub.dartlang.org"
344 | source: hosted
345 | version: "1.8.0"
346 | stack_trace:
347 | dependency: transitive
348 | description:
349 | name: stack_trace
350 | url: "https://pub.dartlang.org"
351 | source: hosted
352 | version: "1.10.0"
353 | stream_channel:
354 | dependency: transitive
355 | description:
356 | name: stream_channel
357 | url: "https://pub.dartlang.org"
358 | source: hosted
359 | version: "2.1.0"
360 | stream_transform:
361 | dependency: transitive
362 | description:
363 | name: stream_transform
364 | url: "https://pub.dartlang.org"
365 | source: hosted
366 | version: "2.0.0"
367 | string_scanner:
368 | dependency: transitive
369 | description:
370 | name: string_scanner
371 | url: "https://pub.dartlang.org"
372 | source: hosted
373 | version: "1.1.0"
374 | term_glyph:
375 | dependency: transitive
376 | description:
377 | name: term_glyph
378 | url: "https://pub.dartlang.org"
379 | source: hosted
380 | version: "1.2.0"
381 | test_api:
382 | dependency: transitive
383 | description:
384 | name: test_api
385 | url: "https://pub.dartlang.org"
386 | source: hosted
387 | version: "0.2.19"
388 | typed_data:
389 | dependency: transitive
390 | description:
391 | name: typed_data
392 | url: "https://pub.dartlang.org"
393 | source: hosted
394 | version: "1.3.0"
395 | url_launcher:
396 | dependency: "direct main"
397 | description:
398 | name: url_launcher
399 | url: "https://pub.dartlang.org"
400 | source: hosted
401 | version: "6.0.3"
402 | url_launcher_linux:
403 | dependency: transitive
404 | description:
405 | name: url_launcher_linux
406 | url: "https://pub.dartlang.org"
407 | source: hosted
408 | version: "2.0.0"
409 | url_launcher_macos:
410 | dependency: transitive
411 | description:
412 | name: url_launcher_macos
413 | url: "https://pub.dartlang.org"
414 | source: hosted
415 | version: "2.0.0"
416 | url_launcher_platform_interface:
417 | dependency: transitive
418 | description:
419 | name: url_launcher_platform_interface
420 | url: "https://pub.dartlang.org"
421 | source: hosted
422 | version: "2.0.2"
423 | url_launcher_web:
424 | dependency: transitive
425 | description:
426 | name: url_launcher_web
427 | url: "https://pub.dartlang.org"
428 | source: hosted
429 | version: "2.0.0"
430 | url_launcher_windows:
431 | dependency: transitive
432 | description:
433 | name: url_launcher_windows
434 | url: "https://pub.dartlang.org"
435 | source: hosted
436 | version: "2.0.0"
437 | vector_math:
438 | dependency: transitive
439 | description:
440 | name: vector_math
441 | url: "https://pub.dartlang.org"
442 | source: hosted
443 | version: "2.1.0"
444 | win32:
445 | dependency: transitive
446 | description:
447 | name: win32
448 | url: "https://pub.dartlang.org"
449 | source: hosted
450 | version: "2.0.5"
451 | xdg_directories:
452 | dependency: transitive
453 | description:
454 | name: xdg_directories
455 | url: "https://pub.dartlang.org"
456 | source: hosted
457 | version: "0.2.0"
458 | sdks:
459 | dart: ">=2.12.0 <3.0.0"
460 | flutter: ">=1.22.0"
461 |
--------------------------------------------------------------------------------
/parking_locator/lib/screens/slotdetails.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:parking_locator/services/dbservice.dart';
3 | import 'package:intl/intl.dart';
4 | import 'package:date_format/date_format.dart';
5 | import 'package:parking_locator/constants.dart';
6 |
7 |
8 |
9 | const headingColor = Color(0xFF002140);
10 |
11 | class SlotDetails extends StatefulWidget {
12 | final String spotID;
13 | SlotDetails({this.spotID});
14 | @override
15 | _SlotDetailsState createState() => _SlotDetailsState();
16 | }
17 |
18 | class _SlotDetailsState extends State {
19 | final db_methods = DbMethods();
20 | GlobalKey _formKey = GlobalKey();
21 | TextEditingController _timeControllerFrom = TextEditingController();
22 | TextEditingController _timeControllerTo = TextEditingController();
23 | List spotbooking;
24 | double _height;
25 | double _width;
26 | String _setFromTime, _setToTime;
27 | String _hour, _minute, _time;
28 | TimeOfDay startTime, endTime;
29 | bool _formLoading = false;
30 | TimeOfDay selectedFromTime = TimeOfDay(hour: 00, minute: 00);
31 | TimeOfDay selectedToTime = TimeOfDay(hour: 00, minute: 00);
32 |
33 | Future _selectTime(BuildContext context, int a) async {
34 | final TimeOfDay picked = await showTimePicker(
35 | context: context,
36 | initialTime: selectedFromTime,
37 | );
38 | if (picked != null)
39 | setState(() {
40 | if (a == 0) {
41 | selectedFromTime = picked;
42 | _timeControllerFrom.text = formatDate(
43 | DateTime(
44 | 2019, 08, 1, selectedFromTime.hour, selectedFromTime.minute),
45 | [hh, ':', nn, " ", am]).toString();
46 | } else {
47 | selectedToTime = picked;
48 | _timeControllerTo.text = formatDate(
49 | DateTime(2019, 08, 1, selectedToTime.hour, selectedToTime.minute),
50 | [hh, ':', nn, " ", am]).toString();
51 | }
52 | });
53 | }
54 |
55 | String formatTimeOfDay(TimeOfDay tod) {
56 | final now = new DateTime.now();
57 | final dt = DateTime(now.year, now.month, now.day, tod.hour, tod.minute);
58 | final format = DateFormat('HH:mm:ss');
59 | // print(format.format(dt));
60 | return format.format(dt);
61 | }
62 |
63 | @override
64 | void initState() {
65 | getbookings();
66 | _timeControllerFrom.text = formatDate(
67 | DateTime(2019, 08, 1, DateTime.now().hour, DateTime.now().minute),
68 | [hh, ':', nn, " ", am]).toString();
69 | _timeControllerTo.text = formatDate(
70 | DateTime(2019, 08, 1, DateTime.now().hour, DateTime.now().minute),
71 | [hh, ':', nn, " ", am]).toString();
72 | super.initState();
73 | }
74 |
75 | Future _alertDialogBuilder(String error) async {
76 | return showDialog(
77 | context: context,
78 | barrierDismissible: false,
79 | builder: (context) {
80 | return AlertDialog(
81 | title: Text("Error"),
82 | content: Container(
83 | child: Text(error),
84 | ),
85 | actions: [
86 | FlatButton(
87 | child: Text("Close Dialog"),
88 | onPressed: () {
89 | Navigator.pop(context);
90 | },
91 | )
92 | ],
93 | );
94 | });
95 | }
96 |
97 | Future add() async {
98 | print(startTime);
99 | print(endTime);
100 | var start = formatTimeOfDay(startTime).toString();
101 | var end = formatTimeOfDay(endTime).toString();
102 | print("end" + end);
103 | // toTime: formatTimeOfDay(selectedToTime).toString(),
104 | await db_methods
105 | .bookingDetails(widget.spotID, start, end)
106 | .then((obj) => print("Changed the timings of the parking spot"))
107 | .catchError((error) =>
108 | print("Failed to change the timings of the parking spot: $error"));
109 | return "Successfully updated";
110 | }
111 |
112 | void _submit() async {
113 | setState(() {
114 | _formLoading = true;
115 | });
116 |
117 | startTime = selectedFromTime;
118 | endTime = selectedToTime;
119 | print(startTime);
120 | print(endTime);
121 | String _addSpotFeedback = await add();
122 | if (_addSpotFeedback != null) {
123 | _alertDialogBuilder(_addSpotFeedback);
124 |
125 | setState(() {
126 | _formLoading = false;
127 | });
128 | } else {
129 | Navigator.pop(context);
130 | }
131 | }
132 |
133 | void getbookings() async {
134 | List result;
135 | result = await db_methods.spotDetail(widget.spotID);
136 | setState(() {
137 | spotbooking = result;
138 | });
139 | print("hi");
140 | print(spotbooking);
141 | }
142 |
143 | // @override
144 | // void initState() {
145 | // getbookings();
146 | // // db_methods.spotDetail(widget.spotID);
147 | // }
148 |
149 | @override
150 | Widget build(BuildContext context) {
151 | _height = MediaQuery.of(context).size.height;
152 | _width = MediaQuery.of(context).size.width;
153 | return Scaffold(
154 | appBar: AppBar(
155 | backgroundColor: Constants.secColor,
156 | title: Text('Slot details'),
157 | ),
158 | body: Column(
159 | children: [
160 | Form(
161 | key: _formKey,
162 | child: Column(
163 | children: [
164 | Text("Edits the spot's timings:"),
165 | Row(
166 | mainAxisAlignment: MainAxisAlignment.spaceEvenly,
167 | children: [
168 | InkWell(
169 | onTap: () {
170 | _selectTime(context, 0);
171 | },
172 | child: Container(
173 | // padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
174 | width: _width / 2.4,
175 | height: _height / 10,
176 | alignment: Alignment.center,
177 | child: TextFormField(
178 | // style: TextStyle(fontSize: 40),
179 | textAlign: TextAlign.center,
180 | onSaved: (String val) {
181 | _setFromTime = val;
182 | },
183 | enabled: false,
184 | keyboardType: TextInputType.text,
185 | controller: _timeControllerFrom,
186 | decoration: InputDecoration(
187 | contentPadding: EdgeInsets.all(5),
188 | prefixIcon: Icon(
189 | Icons.alarm,
190 | color:Constants.secColor,
191 | ),
192 | enabledBorder: const OutlineInputBorder(
193 | borderSide: const BorderSide(
194 | color:Constants.secColor, width: 1.0),
195 | ),
196 | border: OutlineInputBorder(
197 | // borderRadius: new BorderRadius.circular(20.0),
198 | borderSide: BorderSide(color:Constants.secColor),
199 | ),
200 | focusedBorder: new OutlineInputBorder(
201 | // borderRadius: new BorderRadius.circular(20.0),
202 | borderSide: BorderSide(color:Constants.secColor),
203 | ),
204 | labelStyle: new TextStyle(
205 | color: headingColor, fontSize: 15),
206 | labelText: "From time",
207 | )),
208 | ),
209 | ),
210 | InkWell(
211 | onTap: () {
212 | _selectTime(context, 1);
213 | },
214 | child: Container(
215 | width: _width / 2.4,
216 | height: _height / 10,
217 | alignment: Alignment.center,
218 | child: TextFormField(
219 | textAlign: TextAlign.center,
220 | onSaved: (String val) {
221 | _setToTime = val;
222 | },
223 | enabled: false,
224 | keyboardType: TextInputType.text,
225 | controller: _timeControllerTo,
226 | decoration: InputDecoration(
227 | contentPadding: EdgeInsets.all(5),
228 | prefixIcon: Icon(
229 | Icons.alarm,
230 | color:Constants.secColor,
231 | ),
232 | enabledBorder: const OutlineInputBorder(
233 | borderSide: const BorderSide(
234 | color:Constants.secColor, width: 1.0),
235 | ),
236 | border: OutlineInputBorder(
237 | // borderRadius: new BorderRadius.circular(20.0),
238 | borderSide: BorderSide(color:Constants.secColor),
239 | ),
240 | focusedBorder: new OutlineInputBorder(
241 | // borderRadius: new BorderRadius.circular(20.0),
242 | borderSide: BorderSide(color:Constants.secColor),
243 | ),
244 | labelStyle: new TextStyle(
245 | color: headingColor, fontSize: 15),
246 | labelText: "To time",
247 | )),
248 | ),
249 | ),
250 | ],
251 | ),
252 | Center(
253 | child: ElevatedButton(
254 | style: ElevatedButton.styleFrom(
255 | shape: new RoundedRectangleBorder(
256 | borderRadius: new BorderRadius.circular(20.0),
257 | ),
258 | //primary:Constants.secColor
259 | ),
260 | onPressed: () {
261 | if (_formKey.currentState.validate()) {
262 | // If the form is valid, display a Snackbar.
263 | ScaffoldMessenger.of(context).showSnackBar(
264 | SnackBar(content: Text('Processing Data')));
265 | _submit();
266 | }
267 | },
268 | child: Text(
269 | 'Submit',
270 | style: TextStyle(fontSize: 16.9, color: Colors.white),
271 | ),
272 | // textColor: Colors.white70,
273 | ))
274 | ],
275 | )),
276 | SizedBox(height:5.0),
277 | Text("Slot's booking details"),
278 | SizedBox(height:10.0),
279 | Expanded(
280 | child: (spotbooking != null)
281 | ? ListView.builder(
282 | itemCount: spotbooking.length,
283 | itemBuilder: (context, index) {
284 | return Container(
285 | //color:Constants.mainColor,
286 | child: Card(
287 | shape: RoundedRectangleBorder(
288 | borderRadius: BorderRadius.circular(15.0),
289 | ),
290 | color: Constants.secColor.withOpacity(0.7),
291 | elevation: 7,
292 | child: InkWell(
293 | borderRadius: BorderRadius.circular(15.0),
294 | onTap: () {
295 | Navigator.push(
296 | context,
297 | MaterialPageRoute(
298 | builder: (context) => SlotDetails(
299 | spotID: spotbooking[index]['slotID']),
300 | ),
301 | );
302 | },
303 | child: Container(
304 | child: Column(
305 | children: [
306 | // Column(
307 | // crossAxisAlignment: CrossAxisAlignment.start,
308 | // children: [
309 | // Text(spots[index]['address']),
310 | // Text("Start time: " +
311 | // spots[index]['activeHours']['start']),
312 | // Text("End time: " +
313 | // spots[index]['activeHours']['end']),
314 | // Row(
315 | // children: [
316 | // Text("Parking Type: " +
317 | // spots[index]['parkingType']),
318 | // SizedBox(
319 | // width: width * 2 / 5,
320 | // ),
321 | // Text("Charges: " +
322 | // (spots[index]['chargesPerHour'])
323 | // .toString()),
324 | // ],
325 | // ),
326 | // ],
327 | // )
328 | ListTile(
329 | isThreeLine: true,
330 | title: Text(
331 | spotbooking[index]['user']['name'],style: TextStyle(color:Colors.white),),
332 | subtitle: Text("User email id: " +
333 | spotbooking[index]['user']
334 | ['email'],style: TextStyle(color:Colors.white),),
335 | )
336 | ],
337 | ),
338 | )),
339 | ),
340 | );
341 | })
342 | : Center(
343 | child: Text('No Slot Bookings Found'),
344 | )),
345 | ],
346 | ),
347 | );
348 | }
349 | }
--------------------------------------------------------------------------------