Building a Flutter App to Track and Calculate Total Distance in Real-Time Using Latitude,Longtitude

Introduction

         In this Flutter application, we aim to create a user-friendly tool that allows users to track their movements and calculate the distance covered using latitude and longitude coordinates. The app employs the geolocator package for location services and includes features such as continuous location tracking, real-time distance updates, and the ability to export location data to an Excel file.

Getting Started

Let's start by setting up a basic Flutter project. Ensure you have Flutter and Dart installed on your machine. Create a new Flutter project using the following command:

flutter create distance_tracker

Navigate to the project directory:

cd distance_tracker

Now, replace the contents of the lib/main.dart file with the provided code. This code sets up the basic structure of a Flutter app and includes the necessary dependencies for geolocation.

Dependencies

Our app relies on the geolocator package to access the device's location services. To include this package, open your pubspec.yaml file and add the following dependency:

dependencies: 
    flutter: 
        sdk: 
    flutter geolocator: ^7.9.1

Don't forget to run:

flutter pub get

App Structure

Main App Widget

The MyApp widget is the main entry point of our application. It sets up the theme and defines the home screen as an instance of the Home widget.

void main() {
runApp(const MyApp());
}

Home Widget

The Home widget is a stateful widget representing the main screen of our app. It includes a Google Map controller, markers for the map, and polylines to visualize the traveled path.

class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Home(),
);
}
}

Location Tracking

The determinePosition method checks and requests location permissions. It subscribes to the device's location stream and continuously updates the user's location. The locationCheck method calculates the distance traveled using the Haversine formula.

int distanse2 = 0;

Future<void> determinePosition() async {
bool serviceEnabled;
LocationPermission permission;

serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// log("Location permission true"+permission.toString());
Geolocator.openLocationSettings();
} else {
permission = await Geolocator.checkPermission();

if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {}
}

if (permission == LocationPermission.deniedForever) {
// Geolocator.openAppSettings();
} else {
await locationCheck();
}
if (permission == LocationPermission.always ||
permission == LocationPermission.whileInUse) {
await locationCheck();
}
}
}

List<latlongdetails> data = [];
double totalDistance = 0;

Future<void> locationCheck() async {
StreamSubscription<Position> positionStream =
                Geolocator.getPositionStream(
locationSettings: LocationSettings(
distanceFilter: distanse2,
accuracy: LocationAccuracy.best,
)).listen((Position? position) async {
setState(() {
double oldlat = 0.00;
double oldlong = 0.00;
latnew = position!.latitude;
longnew = position.longitude;
print('lat::' + latnew.toString());
print('long::' + longnew.toString());

if (startLatitude != 0.00 && startLongtitue != 0.00) {
data.add(latlongdetails(
lat: latnew, long: longnew, totaldistance: totalDistance));

if (data.length == 1) {
oldlat = latnew;
oldlong = longnew;
// if (data[data.length].lat != oldlat &&
// data[data.length].long != oldlong) {
// totalDistance += calculateDistance(oldlat, oldlong,
// data[data.length].lat, data[data.length].long);
// }
} else {
oldlat = data[data.length - 2].lat;
oldlong = data[data.length - 2].long;
totalDistance +=
calculateDistance(oldlat, oldlong, latnew, longnew);
}

print('distance:::' + totalDistance.toString());
}

setState(() {
distance = totalDistance;
});
});
});
}


Full Source Code :

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';


void main() {
  runApp(const MyApp());
}


class MyApp extends StatelessWidget {
  const MyApp({super.key});
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: Home(),
    );
  }
}



class Home extends StatefulWidget {
  Home({Key? key}) : super(key: key);
  @override
  _HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {


  double distance = 0.0;
  double latnew = 0.0;
  double longnew = 0.0;
  @override
  void initState() {
    setState(() {
      determinePosition();
    });
    super.initState();
  }
  int distanse2 = 0;
  


  Future<void> determinePosition() async {
    bool serviceEnabled;
    LocationPermission permission;
    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      // log("Location permission true"+permission.toString());
      Geolocator.openLocationSettings();
    } else {
      permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {}
      }
      if (permission == LocationPermission.deniedForever) {
        // Geolocator.openAppSettings();
      } else {
        await locationCheck();
      }
      if (permission == LocationPermission.always ||
          permission == LocationPermission.whileInUse) {
        await locationCheck();
      }
    }
  }


  List<latlongdetails> data = [];
  double totalDistance = 0;
  Future<void> locationCheck() async {
    StreamSubscription<Position> positionStream = Geolocator.getPositionStream(
        locationSettings: LocationSettings(
      distanceFilter: distanse2,
      accuracy: LocationAccuracy.best,
    )).listen((Position? position) async {
      setState(() {
        double oldlat = 0.00;
        double oldlong = 0.00;
        latnew = position!.latitude;
        longnew = position.longitude;
        print('lat::' + latnew.toString());
        print('long::' + longnew.toString());
        if (startLatitude != 0.00 && startLongtitue != 0.00) {
          data.add(latlongdetails(
              lat: latnew, long: longnew, totaldistance: totalDistance));
          if (data.length == 1) {
            oldlat = latnew;
            oldlong = longnew;
            // if (data[data.length].lat != oldlat &&
            //     data[data.length].long != oldlong) {
            //   totalDistance += calculateDistance(oldlat, oldlong,
            //       data[data.length].lat, data[data.length].long);
            // }
          } else {
            oldlat = data[data.length - 2].lat;
            oldlong = data[data.length - 2].long;
            totalDistance +=
                calculateDistance(oldlat, oldlong, latnew, longnew);
          }
          // for (var i = 0; i < data.length - 1; i++) {
          //   totalDistance += calculateDistance(
          //       data[i].lat, data[i].long, data[i + 1].lat, data[i + 1].long);
          // }
          print('distance:::' + totalDistance.toString());
        }
        setState(() {
          distance = totalDistance;
        });
      });
    });
  }


  double? startLatitude = 0.00;
  double? startLongtitue = 0.00;
  getLocation() async {
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.best);
    setState(() {
      startLatitude = position.latitude;
      startLongtitue = position.longitude;
    });
  }


  double calculateDistance(lat1, lon1, lat2, lon2) {
    print('process lat' + lat1.toString());
    print('process long' + lon1.toString());
    var p = 0.017453292519943295;
    var a = 0.5 -
        cos((lat2 - lat1) * p) / 2 +
        cos(lat1 * p) * cos(lat2 * p) * (1 - cos((lon2 - lon1) * p)) / 2;
    return 12742 * asin(sqrt(a));
  }


  clearall() {
    setState(() {
      data.clear();
      latnew = 0.00;
      longnew = 0.00;
      distance = 0.0;
      startLatitude = 0.00;
      startLongtitue = 0.00;
      totalDistance = 0;
    });
  }


  setstring2(String temp) {
    setState(() {
      if (temp.isNotEmpty) {
        distanse2 = int.parse(temp.toString());
      }
    });
  }
 


  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Calculate Distance"),
          backgroundColor: Colors.deepPurpleAccent,
        ),
        body: Container(
          width: double.infinity,
          height: double.infinity,
          child: SingleChildScrollView(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Container(
                    alignment: Alignment.center,
                    color: Colors.grey[200],
                    width: 400,
                    height: 50,
                    child: Text(
                        'Start Point:${startLatitude} , ${startLongtitue}'),
                  ),
                  Container(
                    alignment: Alignment.center,
                    color: Colors.grey[200],
                    width: 400,
                    height: 50,
                    child: Text('Live:${latnew} , ${longnew}'),
                  ),
                  Container(
                      child: Card(
                    child: Container(
                        padding: EdgeInsets.all(20),
                        child: Text(
                            "Total Distance: " +
                                distance.toString() +
                                " KM \n Dis.Met:${distanse2}",
                            style: TextStyle(
                                fontSize: 20, fontWeight: FontWeight.bold))),
                  )),
                  SizedBox(
                    height: 100,
                  ),
                  Container(
                    width: 300,
                    child: TextFormField(
                      decoration: InputDecoration(
                        contentPadding: EdgeInsets.symmetric(
                            vertical: 10.0, horizontal: 10.0),
                        fillColor: Colors.grey[200],
                        filled: true,
                        labelText: "Distant Value",
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(10.0),
                          borderSide: const BorderSide(
                            color: Colors.lightBlueAccent,
                          ),
                        ),
                      ),
                      onChanged: (value) {
                        setState(() {
                          setstring2(value);
                        });
                      },
                    ),
                  ),
                  ElevatedButton(
                      onPressed: () {
                        setState(() {
                          clearall();
                          getLocation();
                        });
                      },
                      child: Text('Start Track')),
                  ElevatedButton(
                      onPressed: () {
                        setState(() {
                          clearall();
                          determinePosition();
                        });
                      },
                      child: Text('Clear All')),
                  //exportexcel()
                  
                  
                ]),
          ),
        ));
  }
}
class latlongdetails {
  dynamic lat;
  dynamic long;
  double totaldistance;
  latlongdetails(
      {required this.lat, required this.long, required this.totaldistance});
}




App:

















User Interface

The UI includes components to display the starting point, live location, and total distance covered. Users can input a distance filter, start tracking their movement, and export tracked data to an Excel file.

Running the App

Before running the app, ensure your device's location services are enabled. Run the app using

flutter run

Conclusion

In this tutorial, we've built a Flutter app that calculates and tracks the distance based on real-time location updates. This app can serve as a foundation for more advanced features, such as map integration, data visualization, and offline mode.

Feel free to enhance the app further, add new features, and adapt it to your specific use case. Happy coding!



Thank You

Previous Post Next Post