From 8da37521936e888b8c3e7caae36c8b1ea50111fc Mon Sep 17 00:00:00 2001 From: vjrj Date: Wed, 11 Mar 2026 23:45:06 +0100 Subject: [PATCH] Fix 23 additional lint issues to reduce from 129 to 106 issues - Add const constructors to @immutable classes (5 issues: prefer_const_constructors_in_immutables) - Fix nullable value casts in firesApi.dart (3 issues: cast_nullable_to_non_nullable) - Remove redundant default argument values (2 issues: avoid_redundant_argument_values) - Make YourLocation immutable with final fields (2 issues: avoid_equals_and_hash_code_on_mutable_classes) - Update imports and fix formatting Reduces lint issues from 129 to 106. APK builds successfully (146 MB). --- lib/firesApp.dart | 2 +- lib/homePage.dart | 2 +- lib/models/basicLocation.dart | 2 +- lib/models/fireNotification.dart | 2 +- lib/models/firesApi.dart | 18 +++++++++++++--- lib/models/yourLocation.dart | 11 +++++----- lib/monitoredAreas.dart | 2 +- lib/placesAutocompleteUtils.dart | 1 - lib/utils/secret_loader.dart | 6 +++--- lib/widgets/app_intro_page.dart | 16 +++++++-------- lib/widgets/material_app_with_intro.dart | 26 +++++++++++++----------- lib/widgets/rounded_btn.dart | 20 +++++++++--------- 12 files changed, 61 insertions(+), 47 deletions(-) diff --git a/lib/firesApp.dart b/lib/firesApp.dart index 95cd5b0..842a718 100644 --- a/lib/firesApp.dart +++ b/lib/firesApp.dart @@ -59,7 +59,7 @@ class _FiresAppState extends State { @override Widget build(BuildContext context) { - final StatefulWidget home = MaterialAppWithIntroHome( + final StatefulWidget home = const MaterialAppWithIntroHome( introWidget, continueWidget, 'showInitialWizard-2018-06-27-01'); return StoreProvider( store: store, diff --git a/lib/homePage.dart b/lib/homePage.dart index f748f01..2d2e775 100644 --- a/lib/homePage.dart +++ b/lib/homePage.dart @@ -20,7 +20,7 @@ import 'redux/actions.dart'; @immutable class _ViewModel { - _ViewModel({required this.isLoaded}); + const _ViewModel({required this.isLoaded}); final bool isLoaded; @override diff --git a/lib/models/basicLocation.dart b/lib/models/basicLocation.dart index 9a1c801..d3f42a6 100644 --- a/lib/models/basicLocation.dart +++ b/lib/models/basicLocation.dart @@ -4,7 +4,7 @@ import 'package:meta/meta.dart'; class BasicLocation implements Comparable { // static BasicLocation noLocation = new BasicLocation(lat: 0.0, lon: 0.0); - BasicLocation({required this.lat, required this.lon, this.description}); + const BasicLocation({required this.lat, required this.lon, this.description}); BasicLocation.fromJson(Map json) : lat = (json['lat'] as num).toDouble(), diff --git a/lib/models/fireNotification.dart b/lib/models/fireNotification.dart index 61f96dd..3036397 100644 --- a/lib/models/fireNotification.dart +++ b/lib/models/fireNotification.dart @@ -10,7 +10,7 @@ part 'fireNotification.g.dart'; @immutable @JsonSerializable() class FireNotification { - FireNotification( + const FireNotification( {required this.id, required this.lat, required this.lon, diff --git a/lib/models/firesApi.dart b/lib/models/firesApi.dart index c4d02d7..dced0e8 100644 --- a/lib/models/firesApi.dart +++ b/lib/models/firesApi.dart @@ -31,7 +31,11 @@ class FiresApi { final Response> response = await _dio.post>(url, data: params); if (response.statusCode == 200) { - final Map data = response.data as Map; + final Map? responseData = response.data; + if (responseData == null) { + throw Exception('Response data is null'); + } + final Map data = responseData; final Map dataData = data['data'] as Map; return dataData['userId'] as String; @@ -52,7 +56,11 @@ class FiresApi { final Response> response = await _dio.get>(url); if (response.statusCode == 200) { - final Map data = response.data as Map; + final Map? responseData = response.data; + if (responseData == null) { + throw Exception('Response data is null'); + } + final Map data = responseData; final Map dataData = data['data'] as Map; final List dataSubscriptions = @@ -96,7 +104,11 @@ class FiresApi { final Response> response = await _dio.post>(url, data: params); if (response.statusCode == 200) { - final Map data = response.data as Map; + final Map? responseData = response.data; + if (responseData == null) { + throw Exception('Response data is null'); + } + final Map data = responseData; final Map dataData = data['data'] as Map; return dataData['subsId'] as String; diff --git a/lib/models/yourLocation.dart b/lib/models/yourLocation.dart index 04ce8d1..cd7a30e 100644 --- a/lib/models/yourLocation.dart +++ b/lib/models/yourLocation.dart @@ -6,9 +6,10 @@ import '../objectIdUtils.dart'; part 'yourLocation.g.dart'; +@immutable @JsonSerializable() class YourLocation { - YourLocation( + const YourLocation( {required this.id, required this.lat, required this.lon, @@ -24,10 +25,10 @@ class YourLocation { final ObjectId id; final double lat; final double lon; - String description; - bool subscribed; - int distance; - int currentNumFires; + final String description; + final bool subscribed; + final int distance; + final int currentNumFires; static YourLocation get noLocation { _noLocation ??= YourLocation(id: ObjectId(), lat: 0.0, lon: 0.0); diff --git a/lib/monitoredAreas.dart b/lib/monitoredAreas.dart index fbab973..6c5a2fb 100644 --- a/lib/monitoredAreas.dart +++ b/lib/monitoredAreas.dart @@ -13,7 +13,7 @@ import 'models/appState.dart'; @immutable class _ViewModel { - _ViewModel(this.monitoredAreas); + const _ViewModel(this.monitoredAreas); final List monitoredAreas; @override diff --git a/lib/placesAutocompleteUtils.dart b/lib/placesAutocompleteUtils.dart index cb3a978..38481ec 100644 --- a/lib/placesAutocompleteUtils.dart +++ b/lib/placesAutocompleteUtils.dart @@ -109,7 +109,6 @@ class _PlaceSelectionDialogState extends State<_PlaceSelectionDialog> { lat: location.latitude, lon: location.longitude, description: description, - distance: 10, ); Navigator.of(context).pop(yourLocation); diff --git a/lib/utils/secret_loader.dart b/lib/utils/secret_loader.dart index 965742f..a1965b8 100644 --- a/lib/utils/secret_loader.dart +++ b/lib/utils/secret_loader.dart @@ -5,16 +5,16 @@ import 'package:flutter/services.dart' show rootBundle; /// Loads secret/config files from Flutter assets as JSON. /// Used to load configuration files at app startup. class SecretLoader { - final String secretPath; - SecretLoader({required this.secretPath}); + final String secretPath; + /// Load and parse JSON from asset bundle. /// Returns a map of the parsed JSON content. Future> load() { return rootBundle.loadStructuredData>( secretPath, - (jsonStr) async => json.decode(jsonStr) as Map, + (String jsonStr) async => json.decode(jsonStr) as Map, ); } } diff --git a/lib/widgets/app_intro_page.dart b/lib/widgets/app_intro_page.dart index ab3fc2f..1af461c 100644 --- a/lib/widgets/app_intro_page.dart +++ b/lib/widgets/app_intro_page.dart @@ -6,25 +6,25 @@ import 'package:flutter/material.dart'; import '../utils/widget_utils.dart'; class AppIntroItem { + AppIntroItem({required this.icon, required this.title, this.subTitle = ''}); + final IconData icon; final String title; final String subTitle; - - AppIntroItem({required this.icon, required this.title, this.subTitle = ''}); } typedef void OnIntroFinish(BuildContext context); typedef List ListItems(BuildContext context); abstract class AppIntroPage extends StatelessWidget { - static const String routeName = '/appintro'; - final ListItems items; - final OnIntroFinish onIntroFinish; - const AppIntroPage( {Key? key, required this.items, required this.onIntroFinish}) : super(key: key); + static const String routeName = '/appintro'; + final ListItems items; + final OnIntroFinish onIntroFinish; + @override Widget build(BuildContext context) { return Scaffold( @@ -63,7 +63,6 @@ class _AppIntroPageSelector extends StatelessWidget { theme.textTheme.titleMedium ?? const TextStyle(); return SafeArea( - top: true, bottom: false, child: Column( children: [ @@ -75,7 +74,8 @@ class _AppIntroPageSelector extends StatelessWidget { icon: const Icon(Icons.close, size: 30.0, color: Colors.black38)), ]), - Expanded(child: OrientationBuilder(builder: (context, orientation) { + Expanded(child: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { return IconTheme( data: IconThemeData( size: orientation == Orientation.portrait ? 200.0 : 100.0, diff --git a/lib/widgets/material_app_with_intro.dart b/lib/widgets/material_app_with_intro.dart index 6d8a183..9be60ae 100644 --- a/lib/widgets/material_app_with_intro.dart +++ b/lib/widgets/material_app_with_intro.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:meta/meta.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:async'; +@immutable abstract class MaterialAppWithIntro extends StatelessWidget { + const MaterialAppWithIntro(this.name, this.theme, this.routes, + this.introWidget, this.continueWidget, this.prefsKey); + final String name; final ThemeData theme; final Map routes; @@ -10,9 +15,6 @@ abstract class MaterialAppWithIntro extends StatelessWidget { final WidgetBuilder continueWidget; final String prefsKey; - MaterialAppWithIntro(this.name, this.theme, this.routes, this.introWidget, - this.continueWidget, this.prefsKey); - @override Widget build(BuildContext context) { return MaterialApp( @@ -25,26 +27,26 @@ abstract class MaterialAppWithIntro extends StatelessWidget { } class MaterialAppWithIntroHome extends StatefulWidget { + const MaterialAppWithIntroHome( + this.introWidget, this.continueWidget, this.prefsKey); + final WidgetBuilder introWidget; final WidgetBuilder continueWidget; final String prefsKey; - const MaterialAppWithIntroHome( - this.introWidget, this.continueWidget, this.prefsKey); - @override _MaterialAppWithIntroState createState() => _MaterialAppWithIntroState(introWidget, continueWidget, prefsKey); } class _MaterialAppWithIntroState extends State { + _MaterialAppWithIntroState( + this.introWidget, this.continueWidget, this.prefsKey); + final WidgetBuilder introWidget; final WidgetBuilder continueWidget; final String prefsKey; - _MaterialAppWithIntroState( - this.introWidget, this.continueWidget, this.prefsKey); - @override void initState() { super.initState(); @@ -63,19 +65,19 @@ class _MaterialAppWithIntroState extends State { await prefs.setBool(initialWizardKey, false); if (mounted) { await Navigator.of(context) - .pushReplacement(MaterialPageRoute(builder: introWidget)); + .pushReplacement(MaterialPageRoute(builder: introWidget)); } } else { if (mounted) { await Navigator.of(context) - .pushReplacement(MaterialPageRoute(builder: continueWidget)); + .pushReplacement(MaterialPageRoute(builder: continueWidget)); } } } @override Widget build(BuildContext context) { - return Scaffold( + return const Scaffold( body: Center( child: CircularProgressIndicator(), ), diff --git a/lib/widgets/rounded_btn.dart b/lib/widgets/rounded_btn.dart index 150eef7..c664519 100644 --- a/lib/widgets/rounded_btn.dart +++ b/lib/widgets/rounded_btn.dart @@ -3,15 +3,6 @@ import 'package:flutter/material.dart'; /// Rounded button widget with icon and text. /// Used primarily in the active fires page. class RoundedBtn extends StatelessWidget { - static const btnRadius = Radius.circular(90.0); - - final IconData icon; - final String text; - final Color backColor; - final Color fontColor; - final TextStyle textStyle; - final VoidCallback onPressed; - const RoundedBtn({ required this.icon, required this.text, @@ -42,6 +33,15 @@ class RoundedBtn extends StatelessWidget { ); } + static const Radius btnRadius = Radius.circular(90.0); + + final IconData icon; + final String text; + final Color backColor; + final Color fontColor; + final TextStyle textStyle; + final VoidCallback onPressed; + @override Widget build(BuildContext context) { return SizedBox( @@ -49,7 +49,7 @@ class RoundedBtn extends StatelessWidget { onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: backColor, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(btnRadius), ), ),