From bab90a9830b834b5202207498f5a910889db97c4 Mon Sep 17 00:00:00 2001 From: Mikkeli Matlock Date: Sun, 24 Aug 2025 22:35:20 +0900 Subject: [PATCH] Complete v2.0 ultra-lightweight rebuild with premium color themes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .claude/settings.local.json | 2 +- .gitignore | 11 + README.md | 26 +- analysis_options.yaml | 29 +-- android/app/src/main/AndroidManifest.xml | 3 + .../reports/problems/problems-report.html | 2 +- backup_v1.1/lib/main.dart | 52 ++++ .../lib}/providers/location_provider.dart | 0 .../lib}/providers/settings_provider.dart | 0 .../lib}/screens/settings_screen.dart | 0 .../lib}/screens/speedometer_screen.dart | 0 .../lib}/widgets/analog_speedometer.dart | 0 .../lib}/widgets/digital_speedometer.dart | 0 .../lib}/widgets/info_panel.dart | 0 .../lib}/widgets/speed_unit_selector.dart | 0 backup_v1.1/src/debug/AndroidManifest.xml | 7 + backup_v1.1/src/main/AndroidManifest.xml | 51 ++++ .../plugins/GeneratedPluginRegistrant.java | 34 +++ .../com/example/gps_speedo/MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../src/main/res/values-night/styles.xml | 18 ++ backup_v1.1/src/main/res/values/styles.xml | 18 ++ backup_v1.1/src/profile/AndroidManifest.xml | 7 + lib/color_themes.dart | 51 ++++ lib/gps_service.dart | 36 +++ lib/main.dart | 230 +++++++++++++++--- lib/speed_units.dart | 20 ++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 - pubspec.lock | 146 +---------- pubspec.yaml | 87 +------ test/widget_test.dart | 4 +- 37 files changed, 550 insertions(+), 315 deletions(-) create mode 100644 backup_v1.1/lib/main.dart rename {lib => backup_v1.1/lib}/providers/location_provider.dart (100%) rename {lib => backup_v1.1/lib}/providers/settings_provider.dart (100%) rename {lib => backup_v1.1/lib}/screens/settings_screen.dart (100%) rename {lib => backup_v1.1/lib}/screens/speedometer_screen.dart (100%) rename {lib => backup_v1.1/lib}/widgets/analog_speedometer.dart (100%) rename {lib => backup_v1.1/lib}/widgets/digital_speedometer.dart (100%) rename {lib => backup_v1.1/lib}/widgets/info_panel.dart (100%) rename {lib => backup_v1.1/lib}/widgets/speed_unit_selector.dart (100%) create mode 100644 backup_v1.1/src/debug/AndroidManifest.xml create mode 100644 backup_v1.1/src/main/AndroidManifest.xml create mode 100644 backup_v1.1/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java create mode 100644 backup_v1.1/src/main/kotlin/com/example/gps_speedo/MainActivity.kt create mode 100644 backup_v1.1/src/main/res/drawable-v21/launch_background.xml create mode 100644 backup_v1.1/src/main/res/drawable/launch_background.xml create mode 100644 backup_v1.1/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 backup_v1.1/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 backup_v1.1/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 backup_v1.1/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 backup_v1.1/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 backup_v1.1/src/main/res/values-night/styles.xml create mode 100644 backup_v1.1/src/main/res/values/styles.xml create mode 100644 backup_v1.1/src/profile/AndroidManifest.xml create mode 100644 lib/color_themes.dart create mode 100644 lib/gps_service.dart create mode 100644 lib/speed_units.dart diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9085051..8966d00 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -17,5 +17,5 @@ ], "defaultMode": "acceptEdits" }, - "outputStyle": "Explanatory" + "outputStyle": "koivisto" } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3820a95..5680cd6 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ \ No newline at end of file diff --git a/README.md b/README.md index bc44a16..65dddaf 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/analysis_options.yaml b/analysis_options.yaml index 0d29021..2d1006a 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -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/** \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3643690..2a51eea 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,6 +5,9 @@ + + + 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 );} diff --git a/backup_v1.1/lib/main.dart b/backup_v1.1/lib/main.dart new file mode 100644 index 0000000..a7aa7d1 --- /dev/null +++ b/backup_v1.1/lib/main.dart @@ -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( + 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, + ), + ); + } +} diff --git a/lib/providers/location_provider.dart b/backup_v1.1/lib/providers/location_provider.dart similarity index 100% rename from lib/providers/location_provider.dart rename to backup_v1.1/lib/providers/location_provider.dart diff --git a/lib/providers/settings_provider.dart b/backup_v1.1/lib/providers/settings_provider.dart similarity index 100% rename from lib/providers/settings_provider.dart rename to backup_v1.1/lib/providers/settings_provider.dart diff --git a/lib/screens/settings_screen.dart b/backup_v1.1/lib/screens/settings_screen.dart similarity index 100% rename from lib/screens/settings_screen.dart rename to backup_v1.1/lib/screens/settings_screen.dart diff --git a/lib/screens/speedometer_screen.dart b/backup_v1.1/lib/screens/speedometer_screen.dart similarity index 100% rename from lib/screens/speedometer_screen.dart rename to backup_v1.1/lib/screens/speedometer_screen.dart diff --git a/lib/widgets/analog_speedometer.dart b/backup_v1.1/lib/widgets/analog_speedometer.dart similarity index 100% rename from lib/widgets/analog_speedometer.dart rename to backup_v1.1/lib/widgets/analog_speedometer.dart diff --git a/lib/widgets/digital_speedometer.dart b/backup_v1.1/lib/widgets/digital_speedometer.dart similarity index 100% rename from lib/widgets/digital_speedometer.dart rename to backup_v1.1/lib/widgets/digital_speedometer.dart diff --git a/lib/widgets/info_panel.dart b/backup_v1.1/lib/widgets/info_panel.dart similarity index 100% rename from lib/widgets/info_panel.dart rename to backup_v1.1/lib/widgets/info_panel.dart diff --git a/lib/widgets/speed_unit_selector.dart b/backup_v1.1/lib/widgets/speed_unit_selector.dart similarity index 100% rename from lib/widgets/speed_unit_selector.dart rename to backup_v1.1/lib/widgets/speed_unit_selector.dart diff --git a/backup_v1.1/src/debug/AndroidManifest.xml b/backup_v1.1/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/backup_v1.1/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/backup_v1.1/src/main/AndroidManifest.xml b/backup_v1.1/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3643690 --- /dev/null +++ b/backup_v1.1/src/main/AndroidManifest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backup_v1.1/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/backup_v1.1/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 0000000..6ca0ba5 --- /dev/null +++ b/backup_v1.1/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -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); + } + } +} diff --git a/backup_v1.1/src/main/kotlin/com/example/gps_speedo/MainActivity.kt b/backup_v1.1/src/main/kotlin/com/example/gps_speedo/MainActivity.kt new file mode 100644 index 0000000..d5079cc --- /dev/null +++ b/backup_v1.1/src/main/kotlin/com/example/gps_speedo/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.gps_speedo + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/backup_v1.1/src/main/res/drawable-v21/launch_background.xml b/backup_v1.1/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/backup_v1.1/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/backup_v1.1/src/main/res/drawable/launch_background.xml b/backup_v1.1/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/backup_v1.1/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/backup_v1.1/src/main/res/mipmap-hdpi/ic_launcher.png b/backup_v1.1/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/backup_v1.1/src/main/res/mipmap-mdpi/ic_launcher.png b/backup_v1.1/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/backup_v1.1/src/main/res/mipmap-xxhdpi/ic_launcher.png b/backup_v1.1/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/backup_v1.1/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/backup_v1.1/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/backup_v1.1/src/main/res/values-night/styles.xml b/backup_v1.1/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/backup_v1.1/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/backup_v1.1/src/main/res/values/styles.xml b/backup_v1.1/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/backup_v1.1/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/backup_v1.1/src/profile/AndroidManifest.xml b/backup_v1.1/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/backup_v1.1/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/lib/color_themes.dart b/lib/color_themes.dart new file mode 100644 index 0000000..acbb24d --- /dev/null +++ b/lib/color_themes.dart @@ -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 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; + } +} \ No newline at end of file diff --git a/lib/gps_service.dart b/lib/gps_service.dart new file mode 100644 index 0000000..fa133e2 --- /dev/null +++ b/lib/gps_service.dart @@ -0,0 +1,36 @@ +import 'dart:async'; +import 'package:geolocator/geolocator.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class GpsService { + static Stream get positionStream { + return Geolocator.getPositionStream( + locationSettings: const LocationSettings( + accuracy: LocationAccuracy.bestForNavigation, + distanceFilter: 1, + ), + ); + } + + static Future requestPermissions() async { + final permission = await Permission.locationWhenInUse.request(); + return permission.isGranted; + } + + static Future 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()}°'; + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index a7aa7d1..146fb08 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,52 +1,202 @@ 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( - 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, + return MaterialApp( + title: 'GPS Speedo', + debugShowCheckedModeBanner: false, + theme: ThemeData( + useMaterial3: true, + brightness: Brightness.dark, + colorSchemeSeed: Colors.green, ), + home: SpeedometerScreen(isOverlayMode: isOverlayMode), ); } } + +class SpeedometerScreen extends StatefulWidget { + final bool isOverlayMode; + + const SpeedometerScreen({super.key, this.isOverlayMode = false}); + + @override + State createState() => _SpeedometerScreenState(); +} + +class _SpeedometerScreenState extends State { + double _speed = 0.0; + double _heading = -1.0; + SpeedUnit _currentUnit = SpeedUnit.kmh; + int _currentThemeIndex = 0; + StreamSubscription? _positionSubscription; + String _errorMessage = ''; + + @override + void initState() { + super.initState(); + _initializeGps(); + } + + @override + void dispose() { + _positionSubscription?.cancel(); + super.dispose(); + } + + Future _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, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/speed_units.dart b/lib/speed_units.dart new file mode 100644 index 0000000..914b731 --- /dev/null +++ b/lib/speed_units.dart @@ -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]; + } +} \ No newline at end of file diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index de906b1..977f380 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -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")) } diff --git a/pubspec.lock b/pubspec.lock index 9de250e..b191756 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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" diff --git a/pubspec.yaml b/pubspec.yaml index 6f7c509..068f5e4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 + uses-material-design: true \ No newline at end of file diff --git a/test/widget_test.dart b/test/widget_test.dart index 61d81ea..834d5db 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -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); }); }