summaryrefslogtreecommitdiff
path: root/lib/main.dart
blob: 273f93fb3b07252165be7007cacc97e193c4870c (plain)
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

enum SpeedUnit { milesPerHour, kilometersPerHour }

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',
  };
}

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Speedometer',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.red),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.red,
          brightness: Brightness.dark,
        ),
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  StreamSubscription<Position>? _positionStream;
  double _speed = 0.0;
  double _speedAccuracy = 0.0;
  SpeedUnit _speedUnit = SpeedUnit.milesPerHour;
  LocationSettings _locationSettings = LocationSettings();

  _initPositionStream() {
    _positionStream =
        Geolocator.getPositionStream(
          locationSettings: _locationSettings,
        ).listen((Position? position) {
          if (position != null) {
            setState(() {
              _speed = position.speed;
              _speedAccuracy = position.speedAccuracy;
            });
          }
        });
  }

  @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();
          }
        });
  }

  @override
  void dispose() {
    super.dispose();
    _positionStream?.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text("Speedometer"),
        actions: [
          MenuAnchor(
            builder: (context, controller, _child) => IconButton(
              icon: Icon(Icons.more_vert),
              onPressed: () =>
                  controller.isOpen ? controller.close() : controller.open(),
              tooltip: "Navigation menu",
            ),
            menuChildren: [
              MenuItemButton(child: Text('Settings')),
              MenuItemButton(child: Text('About')),
            ],
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Flex(direction: Axis.horizontal),
            Text(
              '${_speedUnit.fromMetersPerSecond(_speed).round()} ${_speedUnit.acronym}',
              style: Theme.of(context).textTheme.displayLarge,
            ),
            Text(
              '± ${_speedUnit.fromMetersPerSecond(_speedAccuracy).round()} ${_speedUnit.acronym}',
              style: Theme.of(context).textTheme.displaySmall,
            ),
          ],
        ),
      ),
    );
  }
}