Complete v2.0 ultra-lightweight rebuild with premium color themes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mikkeli Matlock
2025-08-24 22:35:20 +09:00
parent 23b232f8f0
commit bab90a9830
37 changed files with 550 additions and 315 deletions
+1 -1
View File
@@ -17,5 +17,5 @@
],
"defaultMode": "acceptEdits"
},
"outputStyle": "Explanatory"
"outputStyle": "koivisto"
}
+11
View File
@@ -43,3 +43,14 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
# User notes - contains oversights and current matters
# DO NOT REMOVE FROM GITIGNORE
NOTES.txt
# Local TODO for next Claude Code sessions
# DO NOT REMOVE FROM GITIGNORE
TODO.md
# Development tools - generic utilities, not project-specific
.tools/
+4 -22
View File
@@ -1,46 +1,28 @@
# GPS Speedometer
A customizable Flutter speedometer app using GPS location services to display real-time speed.
A GPS Speedometer aimed at Android on Motorcycle / Bicycle applications.
**Created with the help of Claude Code**
## Features
### Core Functionality
- Real-time speed display using GPS
- High-precision location tracking
- Works offline (no internet connection required)
- Automatic portrait/landscape orientation support
- Maybe also direction display using GPS
- Good floating window / split screen support(hopefully)
### Customizable Settings
- **Speed Units**: mph, km/h, knots (with convenient unit selector buttons)
- **Display Style**: Digital speedometer, analog gauge (tap gauge to switch)
- **Theme**: Light/Dark mode (expandable for custom themes)
- **Metrics Display**: Toggle additional metrics on/off
- Current location coordinates
- Distance traveled
- Trip duration
- Current speed accuracy
### Technical Specifications
- Target Platform: Android (primary)
- Screen Orientation: Auto-rotate (portrait/landscape)
- Target Device: Mobile phones and tablets
- GPS Requirements: Location permissions required
- Offline Capability: Full functionality without internet
### New Features in v1.1
- **Auto-rotate Support**: App now supports both portrait and landscape orientations
- **Interactive Gauge**: Tap the speedometer to switch between digital and analog modes
- **Extended Units**: Added knots as a speed unit option
- **Unit Selector**: Quick access unit selection buttons next to the speedometer
## Architecture Design
The app is designed with customization and extensibility in mind:
- Settings system supports multiple options per category
- Modular design allows easy addition of new speedometer styles
- Theme system supports unlimited themes
- Metrics system allows toggle individual data points
*To be updated*
## Permissions Required
- `ACCESS_FINE_LOCATION` - For high-precision GPS tracking
+3 -26
View File
@@ -1,28 +1,5 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
analyzer:
exclude:
- backup_v1.1/**
+3
View File
@@ -5,6 +5,9 @@
<!-- Optional: for background location access -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- TODO: Enable for display-over-apps functionality -->
<!-- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> -->
<application
android:label="gps_speedo"
android:name="${applicationName}"
@@ -650,7 +650,7 @@ code + .copy-button {
<script type="text/javascript">
function configurationCacheProblems() { return (
// begin-report-data
{"diagnostics":[{"problem":[{"text":"Executing Gradle on JVM versions 16 and lower has been deprecated."}],"severity":"WARNING","problemDetails":[{"text":"This will fail with an error in Gradle 9.0."}],"contextualLabel":"Executing Gradle on JVM versions 16 and lower has been deprecated.","documentationLink":"https://docs.gradle.org/8.12/userguide/upgrading_version_8.html#minimum_daemon_jvm_version","problemId":[{"name":"deprecation","displayName":"Deprecation"},{"name":"executing-gradle-on-jvm-versions-and-lower","displayName":"Executing Gradle on JVM versions 16 and lower has been deprecated."}],"solutions":[[{"text":"Use JVM 17 or greater to execute Gradle. Projects can continue to use older JVM versions via toolchains."}]]}],"problemsReport":{"totalProblemCount":1,"requestedTasks":"","documentationLink":"https://docs.gradle.org/8.12/userguide/problems-report.html","documentationLinkCaption":"Problem report","summaries":[]}}
{"diagnostics":[{"problem":[{"text":"Executing Gradle on JVM versions 16 and lower has been deprecated."}],"severity":"WARNING","problemDetails":[{"text":"This will fail with an error in Gradle 9.0."}],"contextualLabel":"Executing Gradle on JVM versions 16 and lower has been deprecated.","documentationLink":"https://docs.gradle.org/8.12/userguide/upgrading_version_8.html#minimum_daemon_jvm_version","problemId":[{"name":"deprecation","displayName":"Deprecation"},{"name":"executing-gradle-on-jvm-versions-and-lower","displayName":"Executing Gradle on JVM versions 16 and lower has been deprecated."}],"solutions":[[{"text":"Use JVM 17 or greater to execute Gradle. Projects can continue to use older JVM versions via toolchains."}]]},{"problem":[{"text":"No variants exist that would match the request"}],"severity":"ERROR","contextualLabel":"Dependency requires at least JVM runtime version 11. This build uses a Java 8 JVM.","documentationLink":"https://docs.gradle.org/8.12/userguide/variant_model.html#sec:variant-select-errors","problemId":[{"name":"dependency-variant-resolution","displayName":"Variant resolution"},{"name":"no-compatible-variants","displayName":"No variants exist that would match the request"}]}],"problemsReport":{"totalProblemCount":2,"requestedTasks":"","documentationLink":"https://docs.gradle.org/8.12/userguide/problems-report.html","documentationLinkCaption":"Problem report","summaries":[]}}
// end-report-data
);}
</script>
+52
View File
@@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'providers/location_provider.dart';
import 'providers/settings_provider.dart';
import 'screens/speedometer_screen.dart';
void main() {
runApp(const SpeedometerApp());
}
class SpeedometerApp extends StatelessWidget {
const SpeedometerApp({super.key});
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SettingsProvider()),
ChangeNotifierProvider(create: (_) => LocationProvider()),
],
child: Consumer<SettingsProvider>(
builder: (context, settings, child) {
return MaterialApp(
title: 'GPS Speedometer',
debugShowCheckedModeBanner: false,
theme: _buildTheme(settings.isDarkMode),
home: const SpeedometerScreen(),
);
},
),
);
}
ThemeData _buildTheme(bool isDarkMode) {
return ThemeData(
useMaterial3: true,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
),
);
}
}
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+51
View File
@@ -0,0 +1,51 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Location permissions for GPS speedometer -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Optional: for background location access -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<application
android:label="gps_speedo"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
@@ -0,0 +1,34 @@
package io.flutter.plugins;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
/**
* Generated file. Do not edit.
* This file is generated by the Flutter tool based on the
* plugins that support the Android platform.
*/
@Keep
public final class GeneratedPluginRegistrant {
private static final String TAG = "GeneratedPluginRegistrant";
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
try {
flutterEngine.getPlugins().add(new com.baseflow.geolocator.GeolocatorPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin geolocator_android, com.baseflow.geolocator.GeolocatorPlugin", e);
}
try {
flutterEngine.getPlugins().add(new com.baseflow.permissionhandler.PermissionHandlerPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin permission_handler_android, com.baseflow.permissionhandler.PermissionHandlerPlugin", e);
}
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin shared_preferences_android, io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin", e);
}
}
}
@@ -0,0 +1,5 @@
package com.example.gps_speedo
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+51
View File
@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
class ColorTheme {
final Color background;
final Color speedText;
final Color headingText;
final Color unitText;
final String name;
const ColorTheme({
required this.background,
required this.speedText,
required this.headingText,
required this.unitText,
required this.name,
});
}
class ColorThemes {
static const List<ColorTheme> themes = [
ColorTheme(
name: 'Classic Dark',
background: Color(0xFF121212),
speedText: Color(0xFF4CAF50),
headingText: Color(0xFFFF9800),
unitText: Color(0xFF9E9E9E),
),
ColorTheme(
name: 'Electric Blue',
background: Color(0xFF0D1421),
speedText: Color(0xFF00E5FF),
headingText: Color(0xFFFFEB3B),
unitText: Color(0xFF78909C),
),
ColorTheme(
name: 'Racing Red',
background: Color(0xFF1A0A0A),
speedText: Color(0xFFFF1744),
headingText: Color(0xFFFFFFFF),
unitText: Color(0xFFB0BEC5),
),
];
static ColorTheme getTheme(int index) {
return themes[index % themes.length];
}
static int getNextThemeIndex(int currentIndex) {
return (currentIndex + 1) % themes.length;
}
}
+36
View File
@@ -0,0 +1,36 @@
import 'dart:async';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
class GpsService {
static Stream<Position> get positionStream {
return Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.bestForNavigation,
distanceFilter: 1,
),
);
}
static Future<bool> requestPermissions() async {
final permission = await Permission.locationWhenInUse.request();
return permission.isGranted;
}
static Future<bool> isLocationServiceEnabled() async {
return await Geolocator.isLocationServiceEnabled();
}
static String getCompassDirection(double heading) {
if (heading < 0) return 'N/A';
const directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
final index = ((heading + 22.5) / 45).floor() % 8;
return directions[index];
}
static String formatHeading(double heading) {
if (heading < 0) return 'N/A';
return '${getCompassDirection(heading)} ${heading.round()}°';
}
}
+184 -34
View File
@@ -1,51 +1,201 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'providers/location_provider.dart';
import 'providers/settings_provider.dart';
import 'screens/speedometer_screen.dart';
import 'dart:async';
import 'package:geolocator/geolocator.dart';
import 'speed_units.dart';
import 'gps_service.dart';
import 'color_themes.dart';
void main() {
runApp(const SpeedometerApp());
runApp(const GpsSpeedoApp());
}
class SpeedometerApp extends StatelessWidget {
const SpeedometerApp({super.key});
// Entry point for future overlay mode
void mainOverlay() {
// TODO: Initialize overlay-specific setup
runApp(const GpsSpeedoApp(isOverlayMode: true));
}
class GpsSpeedoApp extends StatelessWidget {
final bool isOverlayMode;
const GpsSpeedoApp({super.key, this.isOverlayMode = false});
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SettingsProvider()),
ChangeNotifierProvider(create: (_) => LocationProvider()),
],
child: Consumer<SettingsProvider>(
builder: (context, settings, child) {
return MaterialApp(
title: 'GPS Speedometer',
title: 'GPS Speedo',
debugShowCheckedModeBanner: false,
theme: _buildTheme(settings.isDarkMode),
home: const SpeedometerScreen(),
);
},
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorSchemeSeed: Colors.green,
),
home: SpeedometerScreen(isOverlayMode: isOverlayMode),
);
}
}
ThemeData _buildTheme(bool isDarkMode) {
return ThemeData(
useMaterial3: true,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
class SpeedometerScreen extends StatefulWidget {
final bool isOverlayMode;
const SpeedometerScreen({super.key, this.isOverlayMode = false});
@override
State<SpeedometerScreen> createState() => _SpeedometerScreenState();
}
class _SpeedometerScreenState extends State<SpeedometerScreen> {
double _speed = 0.0;
double _heading = -1.0;
SpeedUnit _currentUnit = SpeedUnit.kmh;
int _currentThemeIndex = 0;
StreamSubscription<Position>? _positionSubscription;
String _errorMessage = '';
@override
void initState() {
super.initState();
_initializeGps();
}
@override
void dispose() {
_positionSubscription?.cancel();
super.dispose();
}
Future<void> _initializeGps() async {
try {
final serviceEnabled = await GpsService.isLocationServiceEnabled();
if (!serviceEnabled) {
setState(() => _errorMessage = 'Location services disabled');
return;
}
final permissionGranted = await GpsService.requestPermissions();
if (!permissionGranted) {
setState(() => _errorMessage = 'Location permission denied');
return;
}
_positionSubscription = GpsService.positionStream.listen(
_onPositionUpdate,
onError: (error) => setState(() => _errorMessage = 'GPS error: $error'),
);
} catch (e) {
setState(() => _errorMessage = 'Failed to initialize GPS');
}
}
void _onPositionUpdate(Position position) {
setState(() {
_speed = position.speed;
_heading = position.heading;
_errorMessage = '';
});
}
void _cycleUnit() {
setState(() {
_currentUnit = _currentUnit.next;
});
}
void _cycleTheme() {
setState(() {
_currentThemeIndex = ColorThemes.getNextThemeIndex(_currentThemeIndex);
});
}
@override
Widget build(BuildContext context) {
final displaySpeed = _currentUnit.convert(_speed);
final speedText = displaySpeed.toStringAsFixed(0);
final currentTheme = ColorThemes.getTheme(_currentThemeIndex);
return Scaffold(
backgroundColor: currentTheme.background,
body: SafeArea(
child: GestureDetector(
onTap: _cycleTheme,
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.transparent,
child: Column(
children: [
// Speed display - takes most space, tappable
Expanded(
flex: 3,
child: GestureDetector(
onTap: _cycleUnit,
child: Container(
width: double.infinity,
color: Colors.transparent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (_errorMessage.isNotEmpty)
Text(
_errorMessage,
style: TextStyle(
color: currentTheme.speedText,
fontSize: 16,
),
textAlign: TextAlign.center,
)
else ...[
Text(
speedText,
style: TextStyle(
fontSize: 120,
fontWeight: FontWeight.w300,
color: currentTheme.speedText,
),
),
Text(
_currentUnit.label,
style: TextStyle(
fontSize: 24,
color: currentTheme.unitText,
),
),
],
],
),
),
),
),
// Compass display - compact
Expanded(
flex: 1,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.navigation,
size: 32,
color: currentTheme.headingText,
),
const SizedBox(height: 8),
Text(
GpsService.formatHeading(_heading),
style: TextStyle(
fontSize: 18,
color: currentTheme.headingText,
),
),
],
),
),
),
],
),
),
),
),
);
}
+20
View File
@@ -0,0 +1,20 @@
enum SpeedUnit {
kmh('km/h', 1.0),
mph('mph', 0.621371),
knots('kts', 0.539957);
const SpeedUnit(this.label, this.multiplier);
final String label;
final double multiplier;
double convert(double speedMps) {
return speedMps * 3.6 * multiplier;
}
SpeedUnit get next {
final values = SpeedUnit.values;
final currentIndex = values.indexOf(this);
return values[(currentIndex + 1) % values.length];
}
}
@@ -6,9 +6,7 @@ import FlutterMacOS
import Foundation
import geolocator_apple
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}
+5 -141
View File
@@ -65,22 +65,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.3"
ffi:
dependency: transitive
description:
name: ffi
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
fixnum:
dependency: transitive
description:
@@ -98,18 +82,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_material_color_picker:
dependency: "direct main"
description:
name: flutter_material_color_picker
sha256: ca1e7749d228c9155ea24bce98e647cdbffa350e6f334f6c001f841cd3d9c987
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "6.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -196,10 +172,10 @@ packages:
dependency: transitive
description:
name: lints
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
url: "https://pub.dev"
source: hosted
version: "5.1.1"
version: "6.0.0"
matcher:
dependency: transitive
description:
@@ -224,14 +200,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.16.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path:
dependency: transitive
description:
@@ -240,30 +208,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.3.0"
permission_handler:
dependency: "direct main"
description:
@@ -312,14 +256,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
@@ -328,70 +264,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
provider:
dependency: "direct main"
description:
name: provider
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
url: "https://pub.dev"
source: hosted
version: "6.1.5+1"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
url: "https://pub.dev"
source: hosted
version: "2.4.11"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sky_engine:
dependency: transitive
description: flutter
@@ -493,14 +365,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
sdks:
dart: ">=3.9.0 <4.0.0"
flutter: ">=3.27.0"
flutter: ">=3.24.0"
+5 -78
View File
@@ -1,99 +1,26 @@
name: gps_speedo
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
description: "Ultra-lightweight GPS speedometer for Android split-screen usage."
publish_to: 'none'
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
version: 2.0.0+1
environment:
sdk: ^3.9.0
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# UI Icons
cupertino_icons: ^1.0.8
# GPS and Location Services
# GPS and Location Services - Essential only
geolocator: ^13.0.2
permission_handler: ^11.3.1
# State Management and Settings
provider: ^6.1.2
shared_preferences: ^2.3.3
# UI and Theming
flutter_material_color_picker: ^1.2.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^5.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
+2 -2
View File
@@ -13,9 +13,9 @@ import 'package:gps_speedo/main.dart';
void main() {
testWidgets('GPS Speedometer app loads', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const SpeedometerApp());
await tester.pumpWidget(const GpsSpeedoApp());
// Verify that the app loads with the title
expect(find.text('GPS Speedometer'), findsOneWidget);
expect(find.text('0'), findsOneWidget);
});
}