summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitreview5
-rw-r--r--License.md201
-rw-r--r--assets/car2.pngbin0 -> 25120 bytes
-rw-r--r--lib/config.dart129
-rw-r--r--lib/homepage.dart191
-rw-r--r--lib/kuksa/class-provider.dart39
-rw-r--r--lib/kuksa/class.dart52
-rw-r--r--lib/kuksa/config.dart47
-rw-r--r--lib/kuksa/intial-connection.dart43
-rw-r--r--lib/kuksa/onBoarding.dart64
-rw-r--r--lib/kuksa/paths.dart11
-rw-r--r--lib/kuksa/vehicle-methods.dart148
-rw-r--r--lib/main.dart29
-rw-r--r--lib/map/Show-route.dart152
-rw-r--r--lib/map/bottom-card.dart55
-rw-r--r--lib/map/map-response.dart65
-rw-r--r--lib/map/turnNavigation.dart231
-rw-r--r--lib/mapbox.dart293
-rw-r--r--lib/provider.dart95
-rw-r--r--lib/search.dart69
-rw-r--r--pubspec.yaml96
21 files changed, 2015 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..11fc1dd
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.automotivelinux.org
+port=29418
+project=apps/flutter-navigation
+defaultbranch=master
diff --git a/License.md b/License.md
new file mode 100644
index 0000000..a0b7d15
--- /dev/null
+++ b/License.md
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [2022] [Hritik Chouhan]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/assets/car2.png b/assets/car2.png
new file mode 100644
index 0000000..5b5af09
--- /dev/null
+++ b/assets/car2.png
Binary files differ
diff --git a/lib/config.dart b/lib/config.dart
new file mode 100644
index 0000000..cda553b
--- /dev/null
+++ b/lib/config.dart
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:flutter_navigation/kuksa/intial-connection.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:yaml/yaml.dart';
+
+
+class GetConfig extends ConsumerStatefulWidget {
+ const GetConfig({Key? key, required this.client}) : super(key: key);
+ final HttpClient client;
+
+ @override
+ ConsumerState<GetConfig> createState() => _GetConfigState();
+}
+
+class _GetConfigState extends ConsumerState<GetConfig> {
+ @override
+ void initState() {
+ super.initState();
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+ final configStateProvider = ref.read(ConfigStateprovider.notifier);
+
+ String configFilePath = '/etc/xdg/AGL/nav_config.yaml';
+ String mapboxFilePath = '/etc/default/mapboxkey';
+
+ String keyContent = "";
+
+ final mapboxKeyFile = File(mapboxFilePath);
+
+ final configFile = File(configFilePath);
+ configFile.readAsString().then((content) {
+ final dynamic yamlMap = loadYaml(content);
+ configStateProvider.update(
+ hostname: yamlMap['hostname'],
+ port: yamlMap['port'],
+ kuksaAuthToken: yamlMap['kuskaAuthToken'],
+ );
+ });
+ mapboxKeyFile.readAsString().then((content) {
+ keyContent = content.split(':')[1].trim();
+ if (keyContent.isNotEmpty && keyContent != 'YOU_NEED_TO_SET_IT_IN_LOCAL_CONF') {
+ configStateProvider.update(mapboxAccessToken: keyContent);
+ } else {
+ print("WARNING: Mapbox API Key not found !");
+ }
+ });
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final config = ref.watch(ConfigStateprovider);
+ if (config.hostname == "" ||
+ config.port == 0 ||
+ config.kuksaAuthToken == "" ||
+ config.mapboxAccessToken == "") {
+ return Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: const [
+ Text("ERROR",
+ style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
+ Text(
+ "Something Wrong with config file! Check config.yaml file and restart"),
+ ],
+ )),
+ );
+ }
+ return InitialScreen(client: widget.client);
+ }
+}
+
+class Config {
+ Config({
+ required this.hostname,
+ required this.port,
+ required this.kuksaAuthToken,
+ required this.mapboxAccessToken,
+
+ });
+ final String hostname;
+ final int port;
+ final String kuksaAuthToken;
+ final String mapboxAccessToken;
+
+ Config copywith({
+ String? hostname,
+ int? port,
+ String? kuksaAuthToken,
+ String? mapboxAccessToken,
+ }) =>
+ Config(
+ hostname: hostname ?? this.hostname,
+ port: port ?? this.port,
+ kuksaAuthToken: kuksaAuthToken ?? this.kuksaAuthToken,
+ mapboxAccessToken: mapboxAccessToken ?? this.mapboxAccessToken,
+ );
+}
+
+final ConfigStateprovider =
+StateNotifierProvider<ConfigStateNotifier, Config>(
+ (ref) => ConfigStateNotifier());
+
+class ConfigStateNotifier extends StateNotifier<Config> {
+ ConfigStateNotifier() : super(_initialValue);
+ static final Config _initialValue = Config(
+ hostname: "",
+ port: 0,
+ kuksaAuthToken: "",
+ mapboxAccessToken: "",
+ );
+ void update({
+ String? hostname,
+ int? port,
+ String? kuksaAuthToken,
+ String? mapboxAccessToken,
+ }) {
+ state = state.copywith(
+ hostname: hostname,
+ port: port,
+ kuksaAuthToken: kuksaAuthToken,
+ mapboxAccessToken: mapboxAccessToken,
+ );
+ }
+}
diff --git a/lib/homepage.dart b/lib/homepage.dart
new file mode 100644
index 0000000..4933741
--- /dev/null
+++ b/lib/homepage.dart
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: Apache-2.0
+
+
+import 'package:flutter/material.dart';
+import 'package:flutter_map/flutter_map.dart';
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_navigation/kuksa/class-provider.dart';
+import 'package:flutter_navigation/kuksa/class.dart';
+import 'package:flutter_navigation/map/map-response.dart';
+import 'package:flutter_navigation/provider.dart';
+import 'package:flutter_navigation/search.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:latlong2/latlong.dart';
+
+
+import 'map/Show-route.dart';
+
+class MyHomePage extends ConsumerStatefulWidget {
+ const MyHomePage({Key? key, required this.title}) : super(key: key);
+
+
+ final String title;
+
+ @override
+ ConsumerState<MyHomePage> createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends ConsumerState<MyHomePage> {
+
+
+ late MapController mapController;
+ TextEditingController _destinationController = TextEditingController();
+
+
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+ mapController = MapController();
+ }
+
+ String ConvertToTime(num duration){
+ int hour = (duration/3600).toInt();
+ int min = (duration%3600).toInt() ;
+ min = (min/60).toInt();
+ String mini = min.toString();
+ String Hour = hour.toString();
+ String time = "$Hour hr $mini min";
+
+ return time;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+
+ VehicleSignal vehicleSignal = ref.watch(vehicleSignalProvider);
+ LatLng center = LatLng(vehicleSignal.currentLatitude, vehicleSignal.currentLongitude);
+
+ _destinationController.text = ref.watch(DestinationAdressProvider);
+ final config = ref.read(ConfigStateprovider);
+
+
+
+ return Scaffold(
+
+ body: Stack(
+ children: [
+
+ FlutterMap(
+ mapController: mapController,
+ options: MapOptions(
+ center: center,
+ minZoom: 12,
+ zoom: 12,
+
+ maxZoom: 25.0,
+ keepAlive: true,
+ ),
+ layers: [
+
+ TileLayerOptions(
+ urlTemplate: "https://api.mapbox.com/styles/v1/hritik3961/cl7hxzrrf002t15o2j2yh14lm/tiles/256/{z}/{x}/{y}@2x?access_token=${config.mapboxAccessToken}",
+ additionalOptions: {
+ "access_token": config.mapboxAccessToken,
+
+ },
+ ),
+ MarkerLayerOptions(
+ rotate: true,
+ markers: [
+ Marker(
+ point: center,
+ width: 70,
+ height: 70,
+ builder: (context) =>
+ const Icon(
+
+ Icons.location_pin,
+ size: 40,
+ color: Colors.red,
+ )
+
+ ),
+ ],
+ ),
+
+ ],
+ ),
+ Container(
+ padding: EdgeInsets.all(8),
+
+ alignment: Alignment.topLeft,
+ child: TextFormField(
+
+ controller: _destinationController,
+ decoration: InputDecoration(
+ filled: true,
+ fillColor: Colors.white,
+ border: OutlineInputBorder(),
+ icon: Icon(Icons.location_pin,color: Colors.black,),
+ hintText: "Choose your destination",
+
+
+ ),
+
+ onTap: (){
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => SearchPage(iscurrent: false),
+ ),
+ );
+ },
+ ),
+ ),
+ ],
+ ),
+ floatingActionButton: FloatingActionButton.extended(
+ onPressed: () async{
+
+
+ LatLng current = LatLng(vehicleSignal.currentLatitude, vehicleSignal.currentLongitude);
+ LatLng destination = LatLng(vehicleSignal.destinationLatitude,vehicleSignal.destinationLongitude);
+
+ if(destination != LatLng(0,0)){
+
+ Map RouteResponse = await getDirectionsAPIResponse(current,destination,ref);
+
+ if(RouteResponse.isNotEmpty){
+ List RouteCoordinates = RouteResponse['geometry']['coordinates'];
+ List<LatLng> polyline =[];
+
+ for(int i =0; i<RouteCoordinates.length ;i++){
+ polyline.add(LatLng((RouteCoordinates[i][1]).toDouble(),(RouteCoordinates[i][0]).toDouble()));
+
+ }
+ ref.read(polylineprovider.notifier).update(polyline);
+ Map response = await getAdress(current,ref);
+ String curradress = response['features'][0]['place_name'];
+ num duration = RouteResponse['duration'];
+ String time = ConvertToTime(duration);
+
+
+ double distanc = ((RouteResponse['distance']).toDouble());
+ int distance = (distanc/1000).toInt();
+
+
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (_) =>
+ NavigationHome( polyLine: polyline, CurrAddress: curradress,Duration: time,Distance: distance,)));
+
+ }
+
+
+
+ }
+
+
+ },
+ label: const Text('Show Route'),
+ backgroundColor: Colors.purple,
+ icon: const Icon(Icons.drive_eta_rounded),
+ ),
+
+
+ );
+ }
+}
diff --git a/lib/kuksa/class-provider.dart b/lib/kuksa/class-provider.dart
new file mode 100644
index 0000000..1169f6c
--- /dev/null
+++ b/lib/kuksa/class-provider.dart
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import 'class.dart';
+
+final vehicleSignalProvider =
+StateNotifierProvider<VehicleSignalNotifier, VehicleSignal>(
+ (ref) => VehicleSignalNotifier(),
+);
+
+class VehicleSignalNotifier extends StateNotifier<VehicleSignal> {
+ VehicleSignalNotifier() : super(_initialValue);
+ static final VehicleSignal _initialValue = VehicleSignal(
+
+ currentLatitude: 31.706964,
+ currentLongitude: 76.933138,
+
+ destinationLatitude: 0,
+ destinationLongitude: 0,
+ );
+ void update({
+
+ double? currentLatitude,
+ double? currentLongitude,
+
+ double? destinationLatitude,
+ double? destinationLongitude,
+ }) {
+ state = state.copyWith(
+
+ currentLatitude: currentLatitude,
+ currentLongitude: currentLongitude,
+
+ destinationLatitude: destinationLatitude,
+ destinationLongitude: destinationLongitude,
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/kuksa/class.dart b/lib/kuksa/class.dart
new file mode 100644
index 0000000..2d64ac9
--- /dev/null
+++ b/lib/kuksa/class.dart
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: Apache-2.0
+
+class VehicleSignal {
+ VehicleSignal({
+
+ required this.currentLatitude,
+ required this.currentLongitude,
+
+ required this.destinationLatitude,
+ required this.destinationLongitude,
+ });
+
+
+ final double currentLongitude;
+ final double currentLatitude;
+ final double destinationLongitude;
+ final double destinationLatitude;
+
+
+ VehicleSignal copyWith({
+
+ double? currentLongitude,
+ double? currentLatitude,
+
+ double? destinationLongitude,
+ double? destinationLatitude,
+ }) {
+ return VehicleSignal(
+
+ currentLatitude: currentLatitude ?? this.currentLatitude,
+ currentLongitude: currentLongitude ?? this.currentLongitude,
+
+ destinationLatitude: destinationLatitude ?? this.destinationLatitude,
+ destinationLongitude: destinationLongitude ?? this.destinationLongitude,
+ );
+ }
+}
+
+class info{
+ info({required this.Duration, required this.Distance, required this.instruction});
+
+ final num Duration;
+ final num Distance;
+ final String instruction;
+
+ info copywith({num? Duration , num? Distance, String? instruction}){
+ return info(Duration: Duration ?? this.Duration,
+ Distance: Distance ?? this.Distance,
+ instruction: instruction ?? this.instruction);
+
+ }
+} \ No newline at end of file
diff --git a/lib/kuksa/config.dart b/lib/kuksa/config.dart
new file mode 100644
index 0000000..5fb6965
--- /dev/null
+++ b/lib/kuksa/config.dart
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:http/http.dart' as http;
+
+
+// class VehicleSignalConfig {
+// static String authTokenPath = "cert/all_read_write.json.token";
+// static String hostname = "localhost";
+// static int port = 8090;
+// static String uri = "ws://${hostname}:${port}";
+// static String s_uri = "wss://${hostname}:${port}";
+// static String authToken =
+// "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJrdWtzYS52YWwiLCJpc3MiOiJFY2xpcHNlIEtVS1NBIERldiIsImFkbWluIjp0cnVlLCJtb2RpZnlUcmVlIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTc2NzIyNTU5OSwia3Vrc2EtdnNzIjp7IioiOiJydyJ9fQ.p2cnFGH16QoQ14l6ljPVKggFXZKmD-vrw8G6Vs6DvAokjsUG8FHh-F53cMsE-GDjyZH_1_CrlDCnbGlqjsFbgAylqA7IAJWp9_N6dL5p8DHZTwlZ4IV8L1CtCALs7XVqvcQKHCCzB63Y8PgVDCAqpQSRb79JPVD4pZwkBKpOknfEY5y9wfbswZiRKdgz7o61_oFnd-yywpse-23HD6v0htThVF1SuGL1PuvGJ8p334nt9bpkZO3gaTh1xVD_uJMwHzbuBCF33_f-I5QMZO6bVooXqGfe1zvl3nDrPEjq1aPulvtP8RgREYEqE6b2hB8jouTiC_WpE3qrdMw9sfWGFbm04qC-2Zjoa1yYSXoxmYd0SnliSYHAad9aXoEmFENezQV-of7sc-NX1-2nAXRAEhaqh0IRuJwB4_sG7SvQmnanwkz-sBYxKqkoFpOsZ6hblgPDOPYY2NAsZlYkjvAL2mpiInrsmY_GzGsfwPeAx31iozImX75rao8rm-XucAmCIkRlpBz6MYKCjQgyRz3UtZCJ2DYF4lKqTjphEAgclbYZ7KiCuTn9HualwtEmVzHHFneHMKl7KnRQk-9wjgiyQ5nlsVpCCblg6JKr9of4utuPO3cBvbjhB4_ueQ40cpWVOICcOLS7_w0i3pCq1ZKDEMrYDJfz87r2sU9kw1zeFQk";
+// }
+
+final sockConnectprovider = FutureProvider.family<WebSocket, HttpClient>(
+ (ref, client) => connect(client,ref));
+
+
+
+// load certificates and set context and returns http client
+Future<HttpClient> initializeClient() async {
+
+
+ SecurityContext ctx = SecurityContext.defaultContext;
+
+ HttpClient client = HttpClient(context: ctx)
+ ..findProxy = null
+ ..badCertificateCallback = (cert, host, port) {
+ return true;
+ };
+ return client;
+}
+
+
+
+Future<WebSocket> connect(HttpClient client, ref) async {
+ final config = ref.read(ConfigStateprovider);
+ WebSocket socket = await WebSocket.connect(
+ "wss://${config.hostname}:${config.port}",
+ customClient: client);
+ return socket;
+}
diff --git a/lib/kuksa/intial-connection.dart b/lib/kuksa/intial-connection.dart
new file mode 100644
index 0000000..53879d9
--- /dev/null
+++ b/lib/kuksa/intial-connection.dart
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import 'config.dart';
+import 'onBoarding.dart';
+
+
+class InitialScreen extends ConsumerWidget {
+ InitialScreen({Key? key, required this.client}) : super(key: key);
+ final HttpClient client;
+ late WebSocket socket;
+
+ @override
+ Widget build(BuildContext context, ref) {
+
+ final sockConnect = ref.watch(sockConnectprovider(client));
+
+
+ return sockConnect.when(
+ data: (socket) {
+
+ this.socket = socket;
+ this.socket.pingInterval = const Duration(seconds: 2);
+ return OnBoardingPage(client: client, socket: this.socket);
+ },
+ error: (e, stk) {
+ print(e);
+ ref.refresh(sockConnectprovider(client));
+ return const Scaffold(
+ backgroundColor: Colors.black,
+ body: Center(child: Text('error',style: TextStyle(color: Colors.white),)),
+ );
+ },
+ loading: () => const Scaffold(
+ backgroundColor: Colors.black,
+ body: Center(child: Text('loading',style: TextStyle(color: Colors.white))),
+ ),
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/kuksa/onBoarding.dart b/lib/kuksa/onBoarding.dart
new file mode 100644
index 0000000..84c85bd
--- /dev/null
+++ b/lib/kuksa/onBoarding.dart
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_navigation/homepage.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_navigation/kuksa/vehicle-methods.dart';
+
+import 'config.dart';
+
+
+class OnBoardingPage extends ConsumerStatefulWidget {
+ const OnBoardingPage({Key? key, required this.client, required this.socket})
+ : super(key: key);
+ final WebSocket socket;
+ final HttpClient client;
+
+ @override
+ ConsumerState<OnBoardingPage> createState() => _OnBoardingPageState();
+}
+
+class _OnBoardingPageState extends ConsumerState<OnBoardingPage> {
+ late Timer _timer;
+
+
+ @override
+ void initState() {
+
+ super.initState();
+ VISS.init(widget.socket,ref);
+ _timer = Timer.periodic(const Duration(seconds: 2), (timer) {
+ // print(widget.socket.readyState);
+ if (widget.socket.readyState == 3) {
+ ref.refresh(sockConnectprovider(widget.client));
+ }
+ });
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+ widget.socket.listen(
+ (data) {
+ VISS.parseData(ref, data);
+ // print(data);
+ },
+ onError: (e, stk) {
+ print(e.toString());
+ ref.refresh(sockConnectprovider(widget.client));
+ },
+ );
+ });
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ _timer.cancel();
+ widget.socket.close(786887, "Connection lost with server!");
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return MyHomePage(title: 'navigation',);
+ }
+} \ No newline at end of file
diff --git a/lib/kuksa/paths.dart b/lib/kuksa/paths.dart
new file mode 100644
index 0000000..df22644
--- /dev/null
+++ b/lib/kuksa/paths.dart
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: Apache-2.0
+
+class VSPath {
+
+ static const String vehicleCurrentLatitude = "Vehicle.CurrentLocation.Latitude";
+ static const String vehicleCurrentLongitude = "Vehicle.CurrentLocation.Longitude";
+ static const String vehicleDestinationLatitude = "Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Latitude";
+ static const String vehicleDestinationLongitude = "Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Longitude";
+
+
+} \ No newline at end of file
diff --git a/lib/kuksa/vehicle-methods.dart b/lib/kuksa/vehicle-methods.dart
new file mode 100644
index 0000000..dbbdc3b
--- /dev/null
+++ b/lib/kuksa/vehicle-methods.dart
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:convert';
+import 'dart:io';
+
+
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_navigation/kuksa/paths.dart';
+
+import 'class-provider.dart';
+
+class VISS {
+ static const requestId = "test-id";
+ static void init(WebSocket socket, WidgetRef ref) {
+ authorize(socket,ref);
+ subscribe(socket,ref, VSPath.vehicleCurrentLatitude);
+ subscribe(socket,ref, VSPath.vehicleCurrentLongitude);
+ subscribe(socket,ref, VSPath.vehicleDestinationLatitude);
+ subscribe(socket,ref, VSPath.vehicleDestinationLongitude);
+
+ }
+
+ static void update(WebSocket socket,WidgetRef ref) {
+ get(socket,ref, VSPath.vehicleCurrentLatitude);
+ get(socket,ref, VSPath.vehicleCurrentLongitude);
+ get(socket, ref,VSPath.vehicleDestinationLatitude);
+ get(socket,ref, VSPath.vehicleDestinationLongitude);
+
+
+
+ }
+
+ static void authorize(WebSocket socket,WidgetRef ref) {
+ final config = ref.read(ConfigStateprovider);
+ Map<String, dynamic> map = {
+ "action": "authorize",
+ "tokens": config.kuksaAuthToken,
+ "requestId": requestId
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static void get(WebSocket socket, WidgetRef ref,String path) {
+ final config = ref.read(ConfigStateprovider);
+
+ Map<String, dynamic> map = {
+ "action": "get",
+ "tokens": config.kuksaAuthToken,
+ "path": path,
+ "requestId": requestId
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static void set(WebSocket socket, WidgetRef ref,String path, String value) {
+ final config = ref.read(ConfigStateprovider);
+
+ Map<String, dynamic> map = {
+ "action": "set",
+ "tokens": config.kuksaAuthToken,
+ "path": path,
+ "requestId": requestId,
+ "value": value
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static void subscribe(WebSocket socket,WidgetRef ref, String path) {
+ final config = ref.read(ConfigStateprovider);
+
+ Map<String, dynamic> map = {
+ "action": "subscribe",
+ "tokens": config.kuksaAuthToken,
+ "path": path,
+ "requestId": requestId
+ };
+ socket.add(jsonEncode(map));
+ }
+
+ static String? numToGear(int? number) {
+ switch (number) {
+ case -1:
+ return 'R';
+ case 0:
+ return 'N';
+ case 126:
+ return 'P';
+ case 127:
+ return 'D';
+ default:
+ return null;
+ }
+ }
+
+ static void parseData(WidgetRef ref, String data) {
+ final vehicleSignal = ref.read(vehicleSignalProvider.notifier);
+ Map<String, dynamic> dataMap = jsonDecode(data);
+ if (dataMap["action"] == "subscription" || dataMap["action"] == "get") {
+ if (dataMap.containsKey("data")) {
+ if ((dataMap["data"] as Map<String, dynamic>).containsKey("dp") &&
+ (dataMap["data"] as Map<String, dynamic>).containsKey("path")) {
+ String path = dataMap["data"]["path"];
+ Map<String, dynamic> dp = dataMap["data"]["dp"];
+ if (dp.containsKey("value")) {
+ if (dp["value"] != "---") {
+ switch (path) {
+
+
+ case VSPath.vehicleCurrentLatitude:
+ vehicleSignal.update(
+ currentLatitude: double.parse(dp["value"]));
+ break;
+ case VSPath.vehicleCurrentLongitude:
+ vehicleSignal.update(
+ currentLongitude: double.parse(dp["value"]));
+ break;
+ case VSPath.vehicleDestinationLatitude:
+ vehicleSignal.update(
+ destinationLatitude: double.parse(dp["value"]));
+ break;
+ case VSPath.vehicleDestinationLongitude:
+ vehicleSignal.update(
+ destinationLongitude: double.parse(dp["value"]));
+ break;
+
+ default:
+ print("$path Not Available yet!");
+ }
+ } else {
+ print("ERROR:Value not available yet! Set Value of $path");
+ }
+ } else {
+ print("ERROR:'value': Key not found!");
+ }
+ } else if ((!dataMap["data"] as Map<String, dynamic>)
+ .containsKey("path")) {
+ print("ERROR:'path':key not found !");
+ } else if ((dataMap["data"] as Map<String, dynamic>)
+ .containsKey("dp")) {
+ print("ERROR:'dp':key not found !");
+ }
+ } else {
+ print("ERROR:'data':key not found!");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..8300961
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+
+import 'kuksa/config.dart';
+
+
+
+Future<void> main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ HttpClient client = await initializeClient();
+
+
+ runApp(
+ ProviderScope(
+ child: MaterialApp(
+ home: GetConfig(client: client),
+ ),
+ ),
+ );
+}
+
+
+
diff --git a/lib/map/Show-route.dart b/lib/map/Show-route.dart
new file mode 100644
index 0000000..6bb9987
--- /dev/null
+++ b/lib/map/Show-route.dart
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: Apache-2.0
+
+
+import 'package:flutter/material.dart';
+import 'package:flutter_map/flutter_map.dart';
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:latlong2/latlong.dart';
+import 'package:flutter_navigation/kuksa/class-provider.dart';
+import 'package:flutter_navigation/kuksa/class.dart';
+import 'package:flutter_navigation/map/bottom-card.dart';
+import 'package:flutter_navigation/map/turnNavigation.dart';
+
+class NavigationHome extends ConsumerWidget {
+ final List<LatLng> polyLine;
+ String CurrAddress;
+ String Duration;
+ num Distance;
+
+ NavigationHome({
+ Key? key,
+ required this.polyLine,
+ required this.CurrAddress,
+ required this.Duration,
+ required this.Distance,
+
+ }) : super(key: key);
+
+
+
+ double tempangle = 0;
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+
+ final config = ref.read(ConfigStateprovider);
+
+
+
+ MapController mapController = MapController();
+ VehicleSignal vehicleSignal = ref.watch(vehicleSignalProvider);
+ LatLng currPos = LatLng(vehicleSignal.currentLatitude, vehicleSignal.currentLongitude);
+ LatLng destiPos = LatLng(vehicleSignal.destinationLatitude, vehicleSignal.destinationLongitude);
+
+ return Scaffold(
+
+
+ body: Stack(
+ children: [
+ FlutterMap(
+ mapController: mapController,
+ options: MapOptions(
+
+ center: currPos,
+ minZoom: 1,
+ zoom: 8,
+
+ maxZoom: 22.0,
+ keepAlive: true,
+ ),
+ layers: [
+
+ TileLayerOptions(
+ urlTemplate: "https://api.mapbox.com/styles/v1/hritik3961/cl7j225qm001w14o4xeiqtv36/tiles/256/{z}/{x}/{y}@2x?access_token=${config.mapboxAccessToken}",
+ additionalOptions: {
+ "access_token": config.mapboxAccessToken,
+ },
+ ),
+ if (polyLine.isNotEmpty)
+ PolylineLayerOptions(
+ polylineCulling: false,
+ polylines: [
+
+ Polyline(
+ color : Colors.blue,
+ strokeWidth: 6,
+
+ points: polyLine,
+ ),
+
+ ],
+ ),
+ MarkerLayerOptions(
+ rotate: true,
+ markers: [
+ Marker(
+ point: currPos,
+ width: 70,
+ height: 70,
+ builder: (context) =>
+ const Icon(
+
+ Icons.location_pin,
+ size: 50,
+ color: Colors.red,
+ )
+
+ ),
+ ],
+ ),
+ MarkerLayerOptions(
+ rotate: true,
+ markers: [
+ Marker(
+ point: destiPos,
+ width: 70,
+ height: 70,
+ builder: (context) =>
+ const Icon(
+
+ Icons.location_pin,
+ size: 50,
+ color: Colors.green,
+ )
+
+ ),
+ ],
+ ),
+
+ ],
+ ),
+ Container(
+ alignment: Alignment.topLeft,
+ child :IconButton(
+ icon: Icon(Icons.arrow_back, color: Colors.white,),
+ onPressed: (){
+ Navigator.pop(context);
+ },
+ )
+ ),
+ bottomDetailCard(context,ref,Distance.toString(),Duration.toString(),CurrAddress),
+ ],
+ ),
+
+ floatingActionButton: FloatingActionButton.extended(
+ backgroundColor: Colors.black,
+ onPressed: () async{
+
+
+
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (_) =>
+ TurnNavigation()));
+
+ },
+ label: const Text('lets go'),
+ icon: const Icon(Icons.drive_eta_rounded),
+ ),
+ );
+ }
+} \ No newline at end of file
diff --git a/lib/map/bottom-card.dart b/lib/map/bottom-card.dart
new file mode 100644
index 0000000..0dc2c34
--- /dev/null
+++ b/lib/map/bottom-card.dart
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter/material.dart';
+
+import 'package:flutter_navigation/kuksa/class-provider.dart';
+import 'package:flutter_navigation/kuksa/class.dart';
+import 'package:flutter_navigation/provider.dart';
+
+Widget bottomDetailCard(
+ BuildContext context, ref,String distance, String dropOffTime,String CurrAdd) {
+ VehicleSignal vehicleSignal = ref.watch(vehicleSignalProvider);
+ String destiadd = ref.read(DestinationAdressProvider);
+
+ return Container(
+ alignment: Alignment.bottomLeft,
+
+ child: SizedBox(
+
+ width: MediaQuery.of(context).size.width,
+ child: Card(
+
+ clipBehavior: Clip.antiAlias,
+ child: Padding(
+ padding: const EdgeInsets.all(15),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text('$CurrAdd ➡ $destiadd',
+ style: Theme.of(context)
+ .textTheme
+ .titleMedium
+ ?.copyWith(color: Colors.indigo)),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 10),
+ child: ListTile(
+ tileColor: Colors.grey[200],
+ leading: const Image(
+ image: AssetImage('assets/car2.png'),
+ height: 50,
+ width: 50),
+ title: const Text('Happy Journey',
+ style: TextStyle(
+ fontSize: 18, fontWeight: FontWeight.bold)),
+ subtitle: Text('$distance km $dropOffTime',style: TextStyle(color: Colors.black),),
+
+ ),
+ ),
+
+ ]),
+ ),
+ ),
+ ),
+ );
+} \ No newline at end of file
diff --git a/lib/map/map-response.dart b/lib/map/map-response.dart
new file mode 100644
index 0000000..cfc50c2
--- /dev/null
+++ b/lib/map/map-response.dart
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:convert';
+
+import 'package:dio/dio.dart';
+import 'package:flutter_navigation/config.dart';
+
+import 'package:http/http.dart' as http;
+import 'package:latlong2/latlong.dart';
+
+
+
+String baseUrl = 'https://api.mapbox.com/directions/v5/mapbox';
+String navType = 'driving';
+
+Dio _dio = Dio();
+
+Future getdrivingRouteUsingMapbox(LatLng source, LatLng destination,ref) async {
+ final config = ref.read(ConfigStateprovider);
+
+ String url =
+ '$baseUrl/$navType/${source.longitude},${source.latitude};${destination.longitude},${destination.latitude}?alternatives=true&continue_straight=true&geometries=geojson&language=en&overview=full&steps=true&access_token=${config.mapboxAccessToken}';
+ try {
+ _dio.options.contentType = Headers.jsonContentType;
+ final responseData = await _dio.get(url);
+ return responseData.data;
+ } catch (e) {
+ print(e);
+ }
+}
+
+Future<Map> getDirectionsAPIResponse(LatLng currentLatLng,LatLng destiLatLng,ref) async {
+
+ final response = await getdrivingRouteUsingMapbox(currentLatLng, destiLatLng,ref);
+
+ if(response != null){
+ Map geometry = response['routes'][0]['geometry'];
+ num duration = response['routes'][0]['duration'];
+ num distance = response['routes'][0]['distance'];
+ Map legs = response['routes'][0]['legs'][0];
+
+ Map modifiedResponse = {
+ "geometry": geometry,
+ "duration": duration,
+ "distance": distance,
+ "legs" : legs,
+ };
+ return modifiedResponse;
+
+ }
+ else{
+ Map map = {};
+ return map;
+ }
+
+}
+
+Future<Map> getAdress(LatLng pos,ref) async{
+ final config = ref.read(ConfigStateprovider);
+
+ var url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/${pos.longitude},${pos.latitude}.json?&access_token=${config.mapboxAccessToken}';
+ http.Response response = await http.get(Uri.parse(url));
+ Map data = json.decode(response.body);
+ return data;
+} \ No newline at end of file
diff --git a/lib/map/turnNavigation.dart b/lib/map/turnNavigation.dart
new file mode 100644
index 0000000..6370e44
--- /dev/null
+++ b/lib/map/turnNavigation.dart
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:async';
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_map/flutter_map.dart';
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:latlong2/latlong.dart';
+import 'package:flutter_navigation/kuksa/class-provider.dart';
+import 'package:flutter_navigation/kuksa/class.dart';
+import 'package:flutter_navigation/provider.dart';
+
+import 'map-response.dart';
+
+class TurnNavigation extends ConsumerStatefulWidget {
+ TurnNavigation({Key? key,}) : super(key: key);
+
+ @override
+ ConsumerState<TurnNavigation> createState() => _TurnNavigationState();
+}
+
+class _TurnNavigationState extends ConsumerState<TurnNavigation> {
+
+ late Timer timer;
+ late MapController mapController;
+ List<LatLng> polyLine = [];
+
+ String ConvertToTime(num duration){
+ int hour = (duration/3600).toInt();
+ int min = (duration%3600).toInt() ;
+ min = (min/60).toInt();
+ String mini = min.toString();
+ String Hour = hour.toString();
+ String time = "$Hour hr $mini min";
+
+ return time;
+ }
+
+
+
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+ mapController = MapController();
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+
+ timer = Timer.periodic(Duration(seconds: 7), (timer) async{
+ VehicleSignal vehicleSignal = ref.read(vehicleSignalProvider);
+
+ LatLng current = LatLng(vehicleSignal.currentLatitude, vehicleSignal.currentLongitude);
+ mapController.move(current, 18);
+ LatLng destination = LatLng(vehicleSignal.destinationLatitude,vehicleSignal.destinationLongitude);
+
+ Map RouteResponse = await getDirectionsAPIResponse(current,destination,ref);
+
+
+ if(RouteResponse.isNotEmpty){
+
+ List RouteCoordinates = RouteResponse['geometry']['coordinates'];
+
+ Map steps = RouteResponse['legs']['steps'][0];
+
+ ref.read(Infoprovider.notifier).update(Duration: RouteResponse['duration'],
+ Distance: RouteResponse['distance'], instruction: steps['maneuver']['instruction']);
+ List<LatLng> currpolyline =[];
+ for(int i =0; i<RouteCoordinates.length ;i++){
+ currpolyline.add(LatLng((RouteCoordinates[i][1]).toDouble(),(RouteCoordinates[i][0]).toDouble()));
+
+ }
+ ref.read(polylineprovider.notifier).update(currpolyline);
+ double rotationDegree = 0;
+ int n = currpolyline.length;
+ if (currpolyline.isNotEmpty && n > 1) {
+ rotationDegree = calcAngle(
+ currpolyline[0], currpolyline[1]);
+
+ rotationDegree = (rotationDegree.isNaN) ? 0 : rotationDegree;
+ }
+
+ mapController.rotate(-1 * rotationDegree);
+
+
+ }
+
+
+ });
+
+ });
+ }
+
+ void dispose(){
+
+ super.dispose();
+ timer.cancel();
+
+ }
+
+ double tempangle = 0;
+ double calcAngle(LatLng a, LatLng b) {
+ List<double> newA = convertCoord(a);
+ List<double> newB = convertCoord(b);
+ double slope = (newB[1] - newA[1]) / (newB[0] - newA[0]);
+
+ return ((atan(slope) * 180) / pi);
+ }
+
+ List<double> convertCoord(LatLng coord) {
+ double oldLat = coord.latitude;
+ double oldLong = coord.longitude;
+ double newLong = (oldLong * 20037508.34 / 180);
+ double newlat =
+ (log(tan((90 + oldLat) * pi / 360)) / (pi / 180)) * (20037508.34 / 180);
+ return [newlat, newLong];
+ }
+ @override
+ Widget build(BuildContext context) {
+
+
+
+
+ VehicleSignal vehicleSignal = ref.watch(vehicleSignalProvider);
+ LatLng currPos = LatLng(vehicleSignal.currentLatitude, vehicleSignal.currentLongitude);
+ polyLine = ref.watch(polylineprovider);
+ info routeinfo = ref.watch(Infoprovider);
+ final config = ref.read(ConfigStateprovider);
+
+
+ return Scaffold(
+ body: Stack(
+ children: [
+ FlutterMap(
+ mapController: mapController,
+ options: MapOptions(
+
+ center: currPos,
+ minZoom: 1,
+ zoom: 12,
+
+ maxZoom: 30.0,
+ keepAlive: true,
+ ),
+ layers: [
+
+ TileLayerOptions(
+ urlTemplate: "https://api.mapbox.com/styles/v1/hritik3961/cl7hxzrrf002t15o2j2yh14lm/tiles/256/{z}/{x}/{y}@2x?access_token=${config.mapboxAccessToken}",
+ additionalOptions: {
+ "access_token": config.mapboxAccessToken,
+ },
+ ),
+ if (polyLine.isNotEmpty)
+ PolylineLayerOptions(
+ polylineCulling: false,
+ polylines: [
+
+ Polyline(
+ strokeWidth: 3,
+ points: polyLine,
+ color: Colors.purple,
+ ),
+
+ ],
+ ),
+ MarkerLayerOptions(
+ rotate: true,
+ markers: [
+ Marker(
+ point: currPos,
+ width: 70,
+ height: 70,
+ builder: (context) =>
+ const Icon(
+ Icons.circle,
+ size: 40,
+ color: Colors.green,
+
+ )
+
+
+ ),
+ ],
+ ),
+
+ ],
+ ),
+ Container(
+ alignment: Alignment.bottomCenter,
+
+ child: Card(
+
+ color: Colors.black54,
+ elevation: 5,
+ child: ListTile(
+ leading: Icon(Icons.drive_eta_rounded,color: Colors.greenAccent,),
+ title: Text(routeinfo.instruction,style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),),
+ subtitle: Text('Remaining Distance : ${(routeinfo.Distance/1000).toInt().toString()} KM',style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),),
+ trailing: Text('Remaining Time : ${ConvertToTime(routeinfo.Duration)}',style: TextStyle(
+ color: Colors.white,
+ fontWeight: FontWeight.bold,
+ ),),
+
+ ),
+
+ ),
+ ),
+ Container(
+ alignment: Alignment.topLeft,
+ child :IconButton(
+ icon: Icon(Icons.arrow_back),
+ onPressed: (){
+ Navigator.pop(context);
+ },
+ )
+ ),
+ ],
+ ),
+ );
+
+ }
+}
+
+
diff --git a/lib/mapbox.dart b/lib/mapbox.dart
new file mode 100644
index 0000000..f7bf91e
--- /dev/null
+++ b/lib/mapbox.dart
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:mapbox_search/mapbox_search.dart';
+
+class MapBoxPlaceSearchWidget extends StatefulWidget {
+ MapBoxPlaceSearchWidget({
+ required this.apiKey,
+ required this.onSelected,
+ // this.onSearch,
+ this.fontSize,
+ this.searchHint = 'Search',
+ required this.context,
+ this.height,
+ this.popOnSelect = false,
+ this.location,
+ this.country,
+ });
+
+ /// True if there is different search screen and you want to pop screen on select
+ final bool popOnSelect;
+
+ ///To get the height of the page
+ final BuildContext context;
+
+ /// Height of whole search widget
+ final double? height;
+
+ /// API Key of the MapBox.
+ final String apiKey;
+
+ /// The callback that is called when one Place is selected by the user.
+ final void Function(MapBoxPlace place) onSelected;
+
+ /// The callback that is called when the user taps on the search icon.
+ // final void Function(MapBoxPlaces place) onSearch;
+
+ /// The point around which you wish to retrieve place information.
+ final Location? location;
+
+ ///Limits the search to the given country
+ ///
+ /// Check the full list of [supported countries](https://docs.mapbox.com/api/search/) for the MapBox API
+ final String? country;
+
+ ///Search Hint Localization
+ final String? searchHint;
+
+ ///Font Size
+ final String? fontSize;
+
+ @override
+ _MapBoxPlaceSearchWidgetState createState() =>
+ _MapBoxPlaceSearchWidgetState();
+}
+
+class _MapBoxPlaceSearchWidgetState extends State<MapBoxPlaceSearchWidget>
+ with SingleTickerProviderStateMixin {
+ TextEditingController _textEditingController = TextEditingController();
+ late AnimationController _animationController;
+
+
+ late Animation _containerHeight;
+
+
+ late Animation _listOpacity;
+
+ List<MapBoxPlace> _placePredictions = [];
+
+
+
+ late Timer _debounceTimer;
+
+
+
+
+ @override
+ void initState() {
+ _animationController =
+ AnimationController(vsync: this, duration: Duration(milliseconds: 500));
+
+ _containerHeight = Tween<double>(
+ begin: 73,
+ end: widget.height ??
+ MediaQuery.of(widget.context).size.height - 60 ??
+ 300)
+ .animate(
+ CurvedAnimation(
+ curve: Interval(0.0, 0.5, curve: Curves.easeInOut),
+ parent: _animationController,
+ ),
+ );
+ _listOpacity = Tween<double>(
+ begin: 0,
+ end: 1,
+ ).animate(
+ CurvedAnimation(
+ curve: Interval(0.5, 1.0, curve: Curves.easeInOut),
+ parent: _animationController,
+ ),
+ );
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ _debounceTimer.cancel();
+ _animationController?.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) => Container(
+ padding: EdgeInsets.symmetric(horizontal: 5),
+ width: MediaQuery.of(context).size.width,
+ child: _searchContainer(
+ child: _searchInput(context),
+ ),
+ );
+
+ // Widgets
+ Widget _searchContainer({Widget? child}) {
+ return AnimatedBuilder(
+ animation: _animationController,
+ builder: (context, _) {
+ return Container(
+ height: _containerHeight.value,
+ decoration: _containerDecoration(),
+ padding: EdgeInsets.only(left: 0, right: 0, top: 15),
+ alignment: Alignment.center,
+ child: Column(
+ children: <Widget>[
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12.0),
+ child: child,
+ ),
+ SizedBox(height: 10),
+ Expanded(
+ child: Opacity(
+ opacity: _listOpacity.value,
+ child: ListView(
+ // addSemanticIndexes: true,
+ // itemExtent: 10,
+ children: <Widget>[
+ for (var places in _placePredictions)
+ _placeOption(places),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ });
+ }
+
+ Widget _searchInput(BuildContext context) {
+ return Center(
+ child: Row(
+ children: <Widget>[
+ Expanded(
+ child: TextField(
+ decoration: _inputStyle(),
+ controller: _textEditingController,
+ style: TextStyle(
+ fontSize: MediaQuery.of(context).size.width * 0.04,
+ ),
+ onChanged: (value) async {
+ // _debounceTimer?.cancel();
+ _debounceTimer = Timer(
+ Duration(milliseconds: 750),
+ () async {
+ await _autocompletePlace(value);
+ if (mounted) {
+ setState(() {});
+ }
+ },
+ );
+ },
+ ),
+ ),
+ Container(width: 15),
+ GestureDetector(
+ child: Icon(Icons.search, color: Colors.blue),
+ onTap: () {},
+ )
+ ],
+ ),
+ );
+ }
+
+ Widget _placeOption(MapBoxPlace prediction) {
+ String? place = prediction.text;
+ String? fullName = prediction.placeName;
+
+ return MaterialButton(
+ padding: EdgeInsets.symmetric(horizontal: 10, vertical: 3),
+ onPressed: () => _selectPlace(prediction),
+ child: ListTile(
+ title: Text(
+ place?.length != 0 ? place!.length < 45
+ ? "$place"
+ : "${place?.replaceRange(45, place.length, "")} ..." : "",
+ style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.04),
+ maxLines: 1,
+ ),
+ subtitle: Text(
+ fullName!,
+ overflow: TextOverflow.ellipsis,
+ style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.03),
+ maxLines: 1,
+ ),
+ contentPadding: EdgeInsets.symmetric(
+ horizontal: 10,
+ vertical: 0,
+ ),
+ ),
+ );
+ }
+
+ // Styling
+ InputDecoration _inputStyle() {
+ return InputDecoration(
+ hintText: widget.searchHint,
+ border: InputBorder.none,
+ contentPadding: EdgeInsets.symmetric(horizontal: 0.0, vertical: 0.0),
+ );
+ }
+
+ BoxDecoration _containerDecoration() {
+ return BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.all(Radius.circular(6.0)),
+ boxShadow: [
+ BoxShadow(color: Colors.black, blurRadius: 0, spreadRadius: 0)
+ ],
+ );
+ }
+
+ // Methods
+ Future _autocompletePlace(String input) async {
+ /// Will be called when the input changes. Making callbacks to the Places
+ /// Api and giving the user Place options
+ ///
+ if (input.length > 0) {
+ var placesSearch = PlacesSearch(
+ apiKey: widget.apiKey,
+ country: widget.country,
+ );
+
+ final predictions = await placesSearch.getPlaces(
+ input,
+ location: widget.location,
+ );
+
+ await _animationController.animateTo(0.5);
+
+
+
+ setState(() => _placePredictions = predictions!);
+
+ await _animationController.forward();
+ } else {
+
+ await _animationController.animateTo(0.5);
+ setState(() => _placePredictions = []);
+ await _animationController.reverse();
+ }
+ }
+
+ void _selectPlace(MapBoxPlace prediction) async {
+ /// Will be called when a user selects one of the Place options.
+ // Sets TextField value to be the location selected
+ _textEditingController.value = TextEditingValue(
+ text: prediction.placeName.toString(),
+ selection: TextSelection.collapsed(offset: prediction.placeName!.length),
+ );
+
+ // Makes animation
+ await _animationController.animateTo(0.5);
+ setState(() {
+ _placePredictions = [];
+
+ });
+ _animationController.reverse();
+
+ // Calls the `onSelected` callback
+ widget.onSelected(prediction);
+ if (widget.popOnSelect) Navigator.pop(context);
+ }
+} \ No newline at end of file
diff --git a/lib/provider.dart b/lib/provider.dart
new file mode 100644
index 0000000..228672f
--- /dev/null
+++ b/lib/provider.dart
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:latlong2/latlong.dart';
+
+import 'kuksa/class.dart';
+
+
+final currlnglatProvider = StateNotifierProvider<currentLngLat,LatLng>(
+ (ref)=> currentLngLat(),
+);
+
+class currentLngLat extends StateNotifier<LatLng>{
+ currentLngLat() : super(
+ LatLng(31.706964,76.933138),
+ );
+ Future<void> update(value) async{
+
+ state = value;
+ }
+
+}
+
+final destinationlnglatProvider = StateNotifierProvider<distiLngLat,LatLng>(
+ (ref)=> distiLngLat(),
+);
+
+class distiLngLat extends StateNotifier<LatLng>{
+ distiLngLat() : super(
+ LatLng(0,0),
+ );
+ Future<void> update(value) async{
+ state = value;
+ }
+
+}
+
+final CurrentAdressProvider = StateNotifierProvider<currentAdress,String>(
+ (ref)=> currentAdress(),
+);
+
+class currentAdress extends StateNotifier<String>{
+ currentAdress() : super(
+ ''
+ );
+ Future<void> update(value)async{
+ state = value;
+ }
+}
+
+final DestinationAdressProvider = StateNotifierProvider<destiAdress,String>(
+ (ref)=> destiAdress(),
+);
+
+class destiAdress extends StateNotifier<String>{
+ destiAdress() : super(
+ ''
+ );
+ Future<void> update(value)async{
+ state = value;
+ }
+}
+
+final polylineprovider = StateNotifierProvider<PolyLine,List<LatLng>>((ref) => PolyLine());
+
+class PolyLine extends StateNotifier<List<LatLng>> {
+
+ PolyLine() : super([]);
+ void update(List<LatLng> list) {
+ state = list;
+ }
+}
+
+final Infoprovider = StateNotifierProvider<Info,info>((ref) => Info());
+
+class Info extends StateNotifier<info> {
+
+ Info() : super(initial);
+ static final info initial = info(Duration: 0, Distance: 0, instruction: '');
+
+ void update({
+ num? Duration,
+ num? Distance,
+ String? instruction,
+
+ }){
+ state = state.copywith(
+ Duration: Duration,
+ Distance: Distance,
+ instruction: instruction,
+ );
+
+
+ }
+} \ No newline at end of file
diff --git a/lib/search.dart b/lib/search.dart
new file mode 100644
index 0000000..9e02450
--- /dev/null
+++ b/lib/search.dart
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_navigation/config.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import 'package:http/http.dart' as http;
+import 'package:latlong2/latlong.dart';
+import 'package:flutter_navigation/kuksa/class-provider.dart';
+import 'package:flutter_navigation/provider.dart';
+
+import 'mapbox.dart';
+
+class SearchPage extends ConsumerWidget {
+ bool iscurrent;
+
+ SearchPage({Key? key, required this.iscurrent}) : super(key: key);
+ final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
+
+
+ @override
+ Widget build(BuildContext context,ref) {
+ final config = ref.read(ConfigStateprovider);
+
+ return Scaffold(
+ key: _scaffoldKey,
+ floatingActionButton: FloatingActionButton(
+ child: Icon(Icons.done),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ body: SafeArea(
+ bottom: false,
+ child: MapBoxPlaceSearchWidget(
+ height: 600,
+ popOnSelect: false,
+ apiKey: config.mapboxAccessToken,
+ searchHint: 'Search around your place',
+ onSelected: (place) async{
+ var url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/${place.placeName}.json?proximity=ip&types=place%2Cpostcode%2Caddress&access_token=${config.mapboxAccessToken}';
+ http.Response response = await http.get(Uri.parse(url));
+ Map data = json.decode(response.body);
+ double longi = data['features'][0]['center'][0];
+ double lati = data['features'][0]['center'][1];
+ if(iscurrent){
+ LatLng value = LatLng(lati,longi);
+ ref.read(vehicleSignalProvider.notifier).update(currentLatitude: lati,currentLongitude: longi);
+ ref.read(CurrentAdressProvider.notifier).update(place.placeName);
+
+ }
+ else{
+ ref.read(vehicleSignalProvider.notifier).update(destinationLatitude: lati,destinationLongitude: longi);
+
+ ref.read(DestinationAdressProvider.notifier).update(place.placeName);
+
+ }
+
+
+
+ },
+ context: context,
+ ),
+ ),
+ );
+ }
+} \ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..251aad3
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,96 @@
+name: flutter_navigation
+description: A new Flutter project.
+
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+version: 1.0.0+1
+
+environment:
+ sdk: ">=2.17.6 <3.0.0"
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.2
+ http: ^0.13.5
+ flutter_riverpod: ^1.0.4
+ mapbox_search: ^3.0.1+2
+ flutter_map: ^2.2.0
+ latlong2: ^0.8.1
+ dio: ^4.0.6
+ yaml: ^3.1.1
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^2.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ assets:
+ - assets/
+
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/assets-and-images/#resolution-aware
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/assets-and-images/#from-packages
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/custom-fonts/#from-packages