From de2ed3cdc1a47c783c0afb378c058c16c6ed8ac8 Mon Sep 17 00:00:00 2001 From: Mica White Date: Sun, 28 Dec 2025 18:50:31 -0500 Subject: Remove title from home page --- lib/about.dart | 74 +++++++++++++++++++++++++++++++++++ lib/home.dart | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 lib/about.dart create mode 100644 lib/home.dart (limited to 'lib') diff --git a/lib/about.dart b/lib/about.dart new file mode 100644 index 0000000..6e829dc --- /dev/null +++ b/lib/about.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +class AboutPage extends StatefulWidget { + const AboutPage({super.key}); + + @override + State createState() => _AboutPageState(); +} + +class _AboutPageState extends State { + Future<(PackageInfo, String)>? _loadedData; + + @override + void initState() { + super.initState(); + _loadedData = Future(() async { + var packageInfo = await PackageInfo.fromPlatform(); + var license = await rootBundle.loadString('LICENSE'); + return (packageInfo, license); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('About')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.speed, + size: Theme.of(context).textTheme.displayLarge?.fontSize ?? 72, + ), + Text( + 'Simple Speedometer', + style: Theme.of(context).textTheme.titleLarge, + ), + Text('© 2025 Mica White'), + Text(''), + TextButton.icon( + icon: Icon(Icons.code), + label: Text('View source code'), + onPressed: () => + launchUrlString("https://www.botahamec.dev/cgit/speedometer"), + ), + FutureBuilder( + future: _loadedData, + builder: (context, snapshot) => TextButton.icon( + icon: Icon(Icons.copyright), + label: Text('View licenses'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LicensePage( + applicationIcon: Icon(Icons.speed), + applicationName: snapshot.data?.$1.appName, + applicationVersion: snapshot.data?.$1.version, + applicationLegalese: snapshot.data?.$2, + ), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/home.dart b/lib/home.dart new file mode 100644 index 0000000..0235016 --- /dev/null +++ b/lib/home.dart @@ -0,0 +1,119 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; + +import 'main.dart'; +import 'about.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 createState() => _HomePageState(); +} + +class _HomePageState extends State { + StreamSubscription? _positionStream; + double _speed = 0.0; + double _speedAccuracy = 0.0; + SpeedUnit _speedUnit = SpeedUnit.milesPerHour; + LocationSettings _locationSettings = LocationSettings(); + + void _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( + 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'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (context) => AboutPage()), + ), + ), + ], + ), + ], + ), + 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, + ), + ], + ), + ), + ); + } +} -- cgit v1.2.3