summaryrefslogtreecommitdiff
path: root/lib/home.dart
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-09-28 19:23:35 -0400
committerMica White <botahamec@outlook.com>2026-09-28 19:23:35 -0400
commit1c8fee757e6125ff510f07106fb6304e89b2fad5 (patch)
tree7b1d4b885ded011de77fc77389d86de0ffaf7a05 /lib/home.dart
Condense all commits into one commit
At some point, I think I committed the Flutter binary. It's too deep to fix it now. At this point, I think my only solution is to delete my .git directory and re-initialize it.
Diffstat (limited to 'lib/home.dart')
-rw-r--r--lib/home.dart158
1 files changed, 158 insertions, 0 deletions
diff --git a/lib/home.dart b/lib/home.dart
new file mode 100644
index 0000000..dc80128
--- /dev/null
+++ b/lib/home.dart
@@ -0,0 +1,158 @@
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:geolocator/geolocator.dart';
+import 'package:region_settings/region_settings.dart';
+import 'package:speedometer/jotai.dart';
+
+import 'main.dart';
+import 'settings.dart';
+
+extension on SpeedUnit {
+ double fromMetersPerSecond(double metersPerSecond) => switch (this) {
+ SpeedUnit.kilometersPerHour => metersPerSecond * 3.6,
+ SpeedUnit.milesPerHour => metersPerSecond * 2.236936,
+ };
+
+ String get acronym => switch (this) {
+ SpeedUnit.kilometersPerHour => 'kmph',
+ SpeedUnit.milesPerHour => 'mph',
+ };
+}
+
+class HomePage extends StatefulWidget {
+ const HomePage({super.key});
+
+ @override
+ State<HomePage> createState() => _HomePageState();
+}
+
+class _HomePageState extends State<HomePage> {
+ StreamSubscription<Position>? _positionStream;
+
+ // I was not able to get StreamBuilder or FutureBuilder to work correctly,
+ // so these are stored manually.
+ bool _usesMetric = true;
+ double _speed = 0.0;
+ double _speedAccuracy = 0.0;
+
+ void _initPositionStream(LocationAccuracy locationAccuracy) {
+ setState(
+ () => _positionStream =
+ Geolocator.getPositionStream(
+ locationSettings: AndroidSettings(
+ accuracy: locationAccuracy,
+ forceLocationManager: true,
+ ),
+ ).listen((Position? position) {
+ if (position != null) {
+ setState(() {
+ _speed = position.speed;
+ _speedAccuracy = position.speedAccuracy;
+ });
+ } else {
+ log("Position was null");
+ }
+ }),
+ );
+ _positionStream?.onError((error, stack) {
+ _positionStream?.cancel();
+ logObservable.value = logObservable.value..add('$error\n$stack');
+ Timer(Duration(seconds: 1), () => _initPositionStream(locationAccuracy));
+ });
+ }
+
+ @override
+ void initState() {
+ super.initState();
+
+ Geolocator.checkPermission()
+ .then(
+ (permission) => permission == LocationPermission.denied
+ ? Geolocator.requestPermission()
+ : permission,
+ )
+ .then((permission) {
+ if (![
+ LocationPermission.deniedForever,
+ LocationPermission.denied,
+ ].contains(permission)) {
+ _initPositionStream(locationAccuracyObservable.value);
+ } else {
+ log("Location permission was denied");
+ }
+ })
+ .catchError((error, stack) {
+ log("$error\n$stack");
+ });
+
+ locationAccuracyObservable.subscribe((locationAccuracy) {
+ _positionStream?.cancel();
+ _initPositionStream(locationAccuracy);
+ });
+
+ // It takes time to load this data in, but I've only noticed it in debug mode
+ RegionSettings.getUsesMetricSystem().then(
+ (usesMetricSystem) => setState(() => _usesMetric = usesMetricSystem),
+ );
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ _positionStream?.cancel();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ actions: [
+ // This button is big enough and descriptive enough to be easily
+ // discoverable, but small enough to not get in the way.
+ TextButton.icon(
+ icon: Icon(Icons.settings),
+ label: Text('Settings'),
+ onPressed: () => Navigator.of(
+ context,
+ ).push(MaterialPageRoute(builder: (context) => SettingsPage())),
+ ),
+ ],
+ ),
+ body: Center(
+ child: ObserverBuilder(
+ observable: speedUnitsObservable,
+ builder: (context, speedUnitsSetting, _) {
+ final speedUnits =
+ speedUnitsSetting ??
+ (_usesMetric
+ ? SpeedUnit.kilometersPerHour
+ : SpeedUnit.milesPerHour);
+
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Flex(direction: Axis.horizontal),
+ Text(
+ '${speedUnits.fromMetersPerSecond(_speed).round()} ${speedUnits.acronym}',
+ style: Theme.of(context).textTheme.displayLarge,
+ ),
+ ObserverBuilder(
+ observable: showMarginOfErrorObservable,
+ builder: (context, showMarginOfError, _) =>
+ showMarginOfError == true
+ ? Text(
+ '± ${speedUnits.fromMetersPerSecond(_speedAccuracy).round()} ${speedUnits.acronym}',
+ style: Theme.of(context).textTheme.displaySmall,
+ )
+ : SizedBox(),
+ ),
+ ],
+ );
+ },
+ ),
+ ),
+ );
+ }
+}