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, }; get acronym => switch (this) { SpeedUnit.kilometersPerHour => 'kmph', SpeedUnit.milesPerHour => 'mph', }; } 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( title: 'Speedometer', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.red), ), darkTheme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: Colors.red, brightness: Brightness.dark, ), ), home: const MyHomePage(title: 'Speedometer'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and // used by the build method of the State. Fields in a Widget subclass are // always marked "final". final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { StreamSubscription? _positionStream; double _speed = 0.0; double _speedAccuracy = 0.0; SpeedUnit _speedUnit = SpeedUnit.milesPerHour; LocationSettings _locationSettings = LocationSettings(); @override void initState() { super.initState(); _positionStream = Geolocator.getPositionStream( locationSettings: _locationSettings, ).listen((Position? position) { if (position != null) { _speed = position.speed; _speedAccuracy = position.speedAccuracy; } }); } @override void dispose() { super.dispose(); _positionStream?.cancel(); } @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done // by the _incrementCounter method above. // // The Flutter framework has been optimized to make rerunning build methods // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. return Scaffold( appBar: AppBar( // TRY THIS: Try changing the color here to a specific color (to // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar // change color while the other colors stay the same. backgroundColor: Theme.of(context).colorScheme.inversePrimary, // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center( // Center is a layout widget. It takes a single child and positions it // in the middle of the parent. child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Flex(direction: Axis.horizontal), Text( '${_speedUnit.fromMetersPerSecond(_speed)} ${_speedUnit.acronym}', style: Theme.of(context).textTheme.displayLarge, ), Text( '± ${_speedUnit.fromMetersPerSecond(_speedAccuracy)} ${_speedUnit.acronym}', style: Theme.of(context).textTheme.displaySmall, ), ], ), ), ); } }