Forked from christocracy/flutter_background_geolocation_helloworld.dart
Last active
February 2, 2024 05:52
-
-
Save sisyfus/86a2817bc0d7c7f06e7cb866596c79d8 to your computer and use it in GitHub Desktop.
Flutter Background Geolocation hello_world.dart https://shop.transistorsoft.com/blogs/news
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Forked from https://gist.github.com/christocracy/a0464846de8a9c27c7e9de5616082878 | |
* Modified to use the geolocation package as a Riverpod provider | |
* flutter_background_geolocation Hello World | |
* https://github.com/transistorsoft/flutter_background_geolocation | |
*/ | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' | |
as bg; | |
import 'package:flutter_riverpod/flutter_riverpod.dart'; | |
// For pretty-printing location JSON. Not a requirement of flutter_background_geolocation | |
// | |
import 'dart:convert'; | |
JsonEncoder encoder = const JsonEncoder.withIndent(" "); | |
// | |
void main() => runApp(const ProviderScope(child: MyApp())); | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'BackgroundGeolocation Demo', | |
theme: ThemeData( | |
primarySwatch: Colors.amber, | |
), | |
home: const MyHomePage(title: 'BackgroundGeolocation Demo'), | |
); | |
} | |
} | |
class MyHomePage extends ConsumerWidget { | |
const MyHomePage({super.key, required this.title}); | |
final String title; | |
@override | |
Widget build(BuildContext context, WidgetRef ref) { | |
final locationData = ref.watch(bgLocationNotifierProvider); | |
final bg.Location? bgLocation = locationData.bgLocation; | |
final bg.ProviderChangeEvent? bgProviderChangeEvent = | |
locationData.bgProviderChangeEvent; | |
String mainContent = ''; | |
String odometerKM = ''; | |
if (bgLocation != null) { | |
mainContent = encoder.convert(bgLocation.toMap()); | |
odometerKM = (bgLocation.odometer / 1000.0).toStringAsFixed(1); | |
} | |
if (bgProviderChangeEvent != null) { | |
mainContent = encoder.convert(bgProviderChangeEvent.toMap()); | |
} | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Background Geolocation'), | |
actions: <Widget>[ | |
Switch( | |
value: locationData.enabled, | |
onChanged: (bool enabled) { | |
ref | |
.read(bgLocationNotifierProvider.notifier) | |
.onClickEnable(enabled); | |
}), | |
], | |
), | |
body: SingleChildScrollView( | |
child: Text(mainContent), | |
), | |
bottomNavigationBar: BottomAppBar( | |
child: Container( | |
padding: const EdgeInsets.only(left: 5.0, right: 5.0), | |
child: Row( | |
mainAxisSize: MainAxisSize.max, | |
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
children: <Widget>[ | |
IconButton( | |
icon: const Icon(Icons.gps_fixed), | |
onPressed: () { | |
ref | |
.read(bgLocationNotifierProvider.notifier) | |
.onClickGetCurrentPosition(); | |
}, | |
), | |
Text('${locationData.motionActivity} · $odometerKM km'), | |
MaterialButton( | |
minWidth: 50.0, | |
color: (locationData.isMoving) ? Colors.red : Colors.green, | |
onPressed: () => ref | |
.read(bgLocationNotifierProvider.notifier) | |
.onClickChangePace(), | |
child: Icon( | |
(locationData.isMoving) ? Icons.pause : Icons.play_arrow, | |
color: Colors.white), | |
), | |
], | |
), | |
)), | |
); | |
} | |
} | |
class LocationData { | |
LocationData({ | |
this.bgLocation, | |
this.bgProviderChangeEvent, | |
required this.isMoving, | |
required this.enabled, | |
required this.motionActivity, | |
}); | |
final bg.Location? bgLocation; | |
final bg.ProviderChangeEvent? bgProviderChangeEvent; | |
final bool isMoving; | |
final bool enabled; | |
final String motionActivity; | |
LocationData copyWith({ | |
bg.Location? bgLocation, | |
bg.ProviderChangeEvent? bgProviderChangeEvent, | |
bool? isMoving, | |
bool? enabled, | |
String? motionActivity, | |
}) { | |
return LocationData( | |
bgLocation: bgLocation ?? this.bgLocation, | |
bgProviderChangeEvent: | |
bgProviderChangeEvent ?? this.bgProviderChangeEvent, | |
isMoving: isMoving ?? this.isMoving, | |
enabled: enabled ?? this.enabled, | |
motionActivity: motionActivity ?? this.motionActivity, | |
); | |
} | |
} | |
class BGLocationNotifier extends Notifier<LocationData> { | |
@override | |
build() { | |
_initializeBGGeolocation(); | |
return LocationData( | |
bgLocation: null, | |
isMoving: false, | |
enabled: false, | |
motionActivity: 'UNKNOWN', | |
); | |
} | |
void _initializeBGGeolocation() async { | |
final bg.State bgState = await bg.BackgroundGeolocation.ready( | |
bg.Config( | |
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH, | |
distanceFilter: 10.0, | |
persistMode: bg.Config.PERSIST_MODE_NONE, //non default | |
stopOnTerminate: true, //non default | |
startOnBoot: false, //non default | |
logLevel: bg.Config.LOG_LEVEL_VERBOSE, | |
reset: true), | |
); | |
state = state.copyWith( | |
isMoving: bgState.isMoving!, | |
enabled: bgState.enabled, | |
); | |
bg.BackgroundGeolocation.onLocation(_onLocation); | |
bg.BackgroundGeolocation.onProviderChange(_onProviderChange); | |
bg.BackgroundGeolocation.onMotionChange(_onMotionChange); | |
bg.BackgroundGeolocation.onActivityChange(_onActivityChange); | |
} | |
void _onLocation(bg.Location location) { | |
print('[location] - $location'); | |
state = state.copyWith( | |
bgLocation: location, | |
bgProviderChangeEvent: null, | |
); | |
} | |
void _onMotionChange(bg.Location location) { | |
print('[motionchange] - $location'); | |
} | |
void _onActivityChange(bg.ActivityChangeEvent event) { | |
print('[activitychange] - $event'); | |
state = state.copyWith( | |
motionActivity: event.activity, | |
); | |
} | |
void _onProviderChange(bg.ProviderChangeEvent event) { | |
print('$event'); | |
state = state.copyWith( | |
bgLocation: null, | |
bgProviderChangeEvent: event, | |
); | |
} | |
void _onConnectivityChange(bg.ConnectivityChangeEvent event) { | |
print('$event'); | |
} | |
void onClickEnable(bool enabled) async { | |
if (enabled) { | |
final bgState = await bg.BackgroundGeolocation.start(); | |
print('[start] success $bgState'); | |
state = state.copyWith( | |
enabled: bgState.enabled, | |
isMoving: bgState.isMoving, | |
); | |
} else { | |
final bgState = await bg.BackgroundGeolocation.stop(); | |
print('[stop] success: $bgState'); | |
// Reset odometer. | |
bg.BackgroundGeolocation.setOdometer(0.0); | |
state = state.copyWith( | |
enabled: bgState.enabled, | |
isMoving: bgState.isMoving, | |
); | |
} | |
} | |
void onClickChangePace() async { | |
state = state.copyWith(isMoving: !state.isMoving); | |
print("[onClickChangePace] -> ${state.isMoving}"); | |
try { | |
final isMoving = | |
await bg.BackgroundGeolocation.changePace(state.isMoving); | |
print('[changePace] success $isMoving'); | |
} on Exception catch (e) { | |
print('[changePace] ERROR: $e'); | |
} | |
} | |
void onClickGetCurrentPosition() async { | |
try { | |
final location = await bg.BackgroundGeolocation.getCurrentPosition( | |
persist: false, // <-- do not persist this location | |
desiredAccuracy: 0, // <-- desire best possible accuracy | |
timeout: 30000, // <-- wait 30s before giving up. | |
samples: 3 // <-- sample 3 location before selecting best. | |
); | |
print('[getCurrentPosition] - $location'); | |
} on Exception catch (e) { | |
print('[getCurrentPosition] ERROR: $e'); | |
} | |
} | |
} | |
final bgLocationNotifierProvider = | |
NotifierProvider<BGLocationNotifier, LocationData>(BGLocationNotifier.new); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment