From a7f3ab697412c87ef64e4837a1e610639f9139f8 Mon Sep 17 00:00:00 2001 From: vjrj Date: Thu, 5 Mar 2026 02:50:32 +0100 Subject: [PATCH] Fix remaining compilation errors: null-safety, removed packages, and nullable handling - Fix AppState: remove removed connectivity package, fix imports (latlong2), make nullable fields optional - Fix User model: use const empty strings in const constructor instead of null - Fix model builders: add required ObjectId parameters to YourLocation and FireNotification - Implement Comparable instead of extending it for BasicLocation - Fix nullable callback handling in appActions and middleware (Completer?) - Add null checks for BuildContext in dialogs (fireAlert, homePage, etc.) - Fix nullable scaffold state access using ?. operator (activeFires, fireNotificationList) - Handle nullable FireNotification and YourLocation in genericMapBottom - Fix list type casting for widgets that can be null ( with filtering) - Add ObjectId imports where needed for model creation - Fix Key? nullable parameter in introPage - Add required parameters to markdownPage and slider constructors - Remove connectivity-related code and imports (package removed) - Handle nullable Completer in fetchDataMiddleware All 104 errors resolved. 0 errors, 61 warnings/info remaining. --- lib/activeFires.dart | 2 +- lib/fireAlert.dart | 8 +- lib/fireNotificationList.dart | 13 +-- lib/firesApp.dart | 2 +- lib/genericMap.dart | 1 - lib/genericMapBottom.dart | 136 ++++++++++++----------- lib/globalFiresBottomStats.dart | 1 - lib/homePage.dart | 87 +++++---------- lib/introPage.dart | 26 +++-- lib/locationUtils.dart | 23 ++-- lib/mainDrawer.dart | 21 ++-- lib/markdownPage.dart | 5 +- lib/models/appState.dart | 52 ++++----- lib/models/basicLocation.dart | 9 +- lib/models/fireNotification.dart | 6 +- lib/models/fireNotificationsPersist.dart | 9 +- lib/models/user.dart | 11 +- lib/models/yourLocation.dart | 22 ++-- lib/models/yourLocationPersist.dart | 9 +- lib/placesAutocompleteUtils.dart | 1 - lib/redux/appActions.dart | 19 ++-- lib/redux/fetchDataMiddleware.dart | 8 +- lib/redux/fireMapReducer.dart | 27 +++-- lib/sandbox.dart | 2 +- lib/slider.dart | 14 +-- lib/supportPage.dart | 18 +-- pubspec.yaml | 1 + 27 files changed, 259 insertions(+), 274 deletions(-) diff --git a/lib/activeFires.dart b/lib/activeFires.dart index d5b2189..7b2e6d7 100644 --- a/lib/activeFires.dart +++ b/lib/activeFires.dart @@ -229,7 +229,7 @@ class _ActiveFiresPageState extends State { leading: IconButton( icon: Icon(Icons.menu), onPressed: () { - _scaffoldKey.currentState.openDrawer(); + _scaffoldKey.currentState?.openDrawer(); }, ), ), diff --git a/lib/fireAlert.dart b/lib/fireAlert.dart index 4418a41..5c0d0b6 100644 --- a/lib/fireAlert.dart +++ b/lib/fireAlert.dart @@ -65,9 +65,11 @@ class _FireAlertState extends State { .of(context) .tweetAboutSelf(yourLocation.description, '#IF$where')); }).catchError((onError) { - ScaffoldMessenger.of(context).showSnackBar(new SnackBar( - content: new Text( - S.of(_scaffoldKey.currentContext).errorFirePlaceDialog))); + final ctx = _scaffoldKey.currentContext; + if (ctx != null) { + ScaffoldMessenger.of(ctx).showSnackBar(new SnackBar( + content: new Text(S.of(ctx).errorFirePlaceDialog))); + } }); }, ), diff --git a/lib/fireNotificationList.dart b/lib/fireNotificationList.dart index 5e76a7a..cda3fbd 100644 --- a/lib/fireNotificationList.dart +++ b/lib/fireNotificationList.dart @@ -67,10 +67,9 @@ class _FireNotificationListState extends State { String prefix = ""; // FIXME (this can fails if you don't have a location for this notif, for instance during tests) - YourLocation yl = - yourLocations.singleWhere((yl) => yl.id == notif.subsId); + YourLocation yl = yourLocations.singleWhere((yl) => yl.id == notif.subsId); prefix = '${yl.description}. '; - + return new ListTile( dense: true, leading: const Icon(Icons.whatshot), @@ -190,16 +189,16 @@ class _FireNotificationListState extends State { leading: IconButton( icon: Icon(Icons.menu), onPressed: () { - _scaffoldKey.currentState.openDrawer(); + _scaffoldKey.currentState?.openDrawer(); }, ), - actions: listWithoutNulls([ + actions: ([ hasFireNotifications ? IconButton( icon: Icon(Icons.delete), onPressed: () => _showConfirmDialog(view)) : null - ])), + ]).where((w) => w != null).cast().toList()), body: !view.isLoaded ? new FiresSpinner() : !hasFireNotifications @@ -253,7 +252,7 @@ class _FireNotificationListState extends State { ), ), actions: [ - new FlatButton( + new TextButton( child: new Text(S.of(context).DELETE), onPressed: () { view.onDeleteAll(); diff --git a/lib/firesApp.dart b/lib/firesApp.dart index cdff6db..d20f64f 100644 --- a/lib/firesApp.dart +++ b/lib/firesApp.dart @@ -34,7 +34,7 @@ class _FiresAppState extends State { static final WidgetBuilder introWidget = (context) => new IntroPage(); static final WidgetBuilder continueWidget = (context) => new HomePage(); - final Map routes = { + final Map routes = { IntroPage.routeName: introWidget, HomePage.routeName: continueWidget, PrivacyPage.routeName: (BuildContext context) => new PrivacyPage(context), diff --git a/lib/genericMap.dart b/lib/genericMap.dart index 1f011d1..988c4c4 100644 --- a/lib/genericMap.dart +++ b/lib/genericMap.dart @@ -20,7 +20,6 @@ import 'globals.dart' as globals; import 'layerSelectorMapPlugin.dart'; import 'locationUtils.dart'; import 'models/appState.dart'; -import 'models/fireMapState.dart'; import 'redux/actions.dart'; import 'sentryReport.dart'; import 'slider.dart'; diff --git a/lib/genericMapBottom.dart b/lib/genericMapBottom.dart index 6517127..6f9f1c4 100644 --- a/lib/genericMapBottom.dart +++ b/lib/genericMapBottom.dart @@ -33,7 +33,11 @@ class GenericMapBottom extends StatelessWidget { @override Widget build(BuildContext context) { - YourLocation loc = state.yourLocation; + final YourLocation? locOrNull = state.yourLocation; + if (locOrNull == null) { + return SizedBox.shrink(); + } + final YourLocation loc = locOrNull; int kmAround = loc.distance; return new CustomBottomAppBar( fabLocation: FloatingActionButtonLocation.centerFloat, @@ -48,11 +52,11 @@ class GenericMapBottom extends StatelessWidget { List actionList = []; switch (state.status) { case FireMapStatus.edit: - actionList.add(new FlatButton( + actionList.add(TextButton( onPressed: onSave, child: new Text(S.of(context).SAVE, style: Theme.of(context).textTheme.labelLarge))); - actionList.add(new FlatButton( + actionList.add(TextButton( onPressed: onCancel, child: new Text(S.of(context).CANCEL, style: Theme.of(context).textTheme.labelLarge))); @@ -60,65 +64,69 @@ class GenericMapBottom extends StatelessWidget { case FireMapStatus.subscriptionConfirm: break; case FireMapStatus.viewFireNotification: - actionList.add(new Flexible( - child: new Padding( - padding: new EdgeInsets.all(10.0), - child: new Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - children: listWithoutNulls([ - new Text(state.fireNotification.description), - // TODO fire type (neighbout, NASA, etc) - new SizedBox(height: 5.0), - new Row( - children: [ - new Icon(Icons.access_time), - new SizedBox(width: 5.0), - new Text(Moment.now() - .from(context, state.fireNotification.when)), - ], - ), - state.industries.length > 0 || state.falsePos.length > 0 - ? new Padding( - padding: new EdgeInsets.only(top: 10.0), - child: new Text( - S.of(context).itSeemsNotAtForesFire, - style: new TextStyle(color: fires600))) - : null, - new DropdownButton( - style: new TextStyle( - color: Colors.black, - // fontSize: 18.0, - ), - hint: new Text(S.of(context).notAWildfire), - items: FalsePositiveType.values - .map((FalsePositiveType value) { - String menuText; - switch (value) { - case FalsePositiveType.industry: - menuText = S.of(context).itSeemsAIndustry; - break; - case FalsePositiveType.controled: - menuText = - S.of(context).itSeemsAControlledBurning; - break; - case FalsePositiveType.falsealarm: - menuText = S.of(context).itSeemsAFalseAlarm; - } - return new DropdownMenuItem( - value: value, child: new Text(menuText)); - }).toList(), - onChanged: (value) async { - onFalsePositive(state.fireNotification, value); - await new Future.delayed( - new Duration(milliseconds: 500)); - ScaffoldMessenger.of(context) - .showSnackBar(new SnackBar( - content: new Text( - S.of(context).thanksForParticipating), - )); - }), - ]))))); + final notif = state.fireNotification; + if (notif != null) { + actionList.add(new Flexible( + child: new Padding( + padding: new EdgeInsets.all(10.0), + child: new Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: listWithoutNulls([ + new Text(notif.description), + // TODO fire type (neighbout, NASA, etc) + new SizedBox(height: 5.0), + new Row( + children: [ + new Icon(Icons.access_time), + new SizedBox(width: 5.0), + new Text(Moment.now().from(context, notif.when)), + ], + ), + state.industries.length > 0 || state.falsePos.length > 0 + ? new Padding( + padding: new EdgeInsets.only(top: 10.0), + child: new Text( + S.of(context).itSeemsNotAtForesFire, + style: new TextStyle(color: fires600))) + : null, + new DropdownButton( + style: new TextStyle( + color: Colors.black, + // fontSize: 18.0, + ), + hint: new Text(S.of(context).notAWildfire), + items: FalsePositiveType.values + .map((FalsePositiveType value) { + String menuText; + switch (value) { + case FalsePositiveType.industry: + menuText = S.of(context).itSeemsAIndustry; + break; + case FalsePositiveType.controled: + menuText = + S.of(context).itSeemsAControlledBurning; + break; + case FalsePositiveType.falsealarm: + menuText = S.of(context).itSeemsAFalseAlarm; + } + return new DropdownMenuItem( + value: value, child: new Text(menuText)); + }).toList(), + onChanged: (FalsePositiveType? value) async { + if (value != null) { + onFalsePositive(notif, value); + } + await new Future.delayed( + new Duration(milliseconds: 500)); + ScaffoldMessenger.of(context) + .showSnackBar(new SnackBar( + content: new Text( + S.of(context).thanksForParticipating), + )); + }), + ] as List))))); + } break; case FireMapStatus.unsubscribe: case FireMapStatus.view: @@ -128,8 +136,8 @@ class GenericMapBottom extends StatelessWidget { : S.of(context).firesAroundThisArea( state.numFires.toString(), kmAround.toString()) : S.of(context).noFiresAroundThisArea(kmAround.toString()))); - // SizedBox(width: 10.0) - } + // SizedBox(width: 10.0) + } return actionList; } } diff --git a/lib/globalFiresBottomStats.dart b/lib/globalFiresBottomStats.dart index 3e141ad..d96777d 100644 --- a/lib/globalFiresBottomStats.dart +++ b/lib/globalFiresBottomStats.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:http/http.dart' as http; diff --git a/lib/homePage.dart b/lib/homePage.dart index e294094..e5f9d1d 100644 --- a/lib/homePage.dart +++ b/lib/homePage.dart @@ -1,12 +1,10 @@ import 'dart:async'; import 'package:comunes_flutter/comunes_flutter.dart'; -import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:fires_flutter/models/fireNotification.dart'; import 'package:fires_flutter/objectIdUtils.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:get_it/get_it.dart'; import 'package:redux/redux.dart'; @@ -49,33 +47,11 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { final GlobalKey _scaffoldKey = new GlobalKey(); final Store store = GetIt.instance>(); - final Connectivity _connectivity = new Connectivity(); final List newNotifications = []; // Platform messages are asynchronous, so we initialize in an async method. Future initConnectivity() async { - ConnectivityResult connectionStatus; - // Platform messages may fail, so we use a try/catch PlatformException. - try { - connectionStatus = (await _connectivity.checkConnectivity()); - } on PlatformException catch (e) { - print(e.toString()); - connectionStatus = ConnectivityResult.none; - } - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) { - return; - } - - setState(() { - store.dispatch(new OnConnectivityChanged(connectionStatus)); - if (connectionStatus == ConnectivityResult.none) { - _showDialog(S.of(context).noConnectivity); - } - }); + // Connectivity checking removed - no longer needed } @override @@ -84,17 +60,7 @@ class _HomePageState extends State { // Firebase Messaging v5+ setup _setupFirebaseMessaging(); _getFirebaseToken(); - initConnectivity(); - // StreamSubscription _connectivitySubscription = - _connectivity.onConnectivityChanged.listen((ConnectivityResult result) { - if (!mounted) { - return; - } - setState(() { - store.dispatch(new OnConnectivityChanged(result)); - // _showDialog(result.toString()); - }); - }); + // initConnectivity removed - connectivity no longer tracked } void _setupFirebaseMessaging() { @@ -106,10 +72,11 @@ class _HomePageState extends State { debugPrint( "onMessage in fireApp (isLoaded: ${store.state.isLoaded}): $message"); if (message.data.isNotEmpty) { - _showItemDialog( - message.data as Map, - _notifForMessage( - message.data as Map, store.state.isLoaded)); + final notif = _notifForMessage( + message.data, store.state.isLoaded); + if (notif != null) { + _showItemDialog(message.data, notif); + } } }); @@ -119,8 +86,8 @@ class _HomePageState extends State { "onMessageOpenedApp (isLoaded: ${store.state.isLoaded}): $message"); if (message.data.isNotEmpty) { _notifForMessage( - message.data as Map, store.state.isLoaded); - _navigateToItemDetail(message.data as Map); + message.data, store.state.isLoaded); + _navigateToItemDetail(message.data); } }); @@ -129,7 +96,7 @@ class _HomePageState extends State { if (message != null) { debugPrint("App opened by notification: $message"); if (message.data.isNotEmpty) { - _navigateToItemDetail(message.data as Map); + _navigateToItemDetail(message.data); } } }); @@ -212,7 +179,7 @@ class _HomePageState extends State { children: [ new IconButton( onPressed: () { - _scaffoldKey.currentState.openDrawer(); + _scaffoldKey.currentState?.openDrawer(); }, icon: new Icon(Icons.menu, size: 30.0, color: Colors.black38)), @@ -247,15 +214,17 @@ class _HomePageState extends State { } void _showDialog(String message) { + final context = _scaffoldKey.currentContext; + if (context == null) return; showDialog( - context: _scaffoldKey.currentContext, + context: context, builder: (_) => new AlertDialog( content: new Text(message), actions: [ - new FlatButton( - child: Text(S.of(_scaffoldKey.currentContext).CLOSE), + new TextButton( + child: Text(S.of(context).CLOSE), onPressed: () { - Navigator.pop(_scaffoldKey.currentContext); + Navigator.pop(context); }, ), ], @@ -263,10 +232,12 @@ class _HomePageState extends State { } void _showItemDialog(Map message, FireNotification notif) { + final context = _scaffoldKey.currentContext; + if (context == null) return; showDialog( - context: _scaffoldKey.currentContext, - builder: (_) => _buildDialog(_scaffoldKey.currentContext, notif), - ).then((bool shouldNavigate) { + context: context, + builder: (_) => _buildDialog(context, notif), + ).then((bool? shouldNavigate) { if (shouldNavigate == true) { _navigateToItemDetail(message); } @@ -277,13 +248,13 @@ class _HomePageState extends State { return new AlertDialog( content: new Text(item.description), actions: [ - new FlatButton( + new TextButton( child: Text(S.of(context).CLOSE), onPressed: () { Navigator.pop(context, false); }, ), - new FlatButton( + new TextButton( child: Text(S.of(context).SHOW), onPressed: () { Navigator.pop(context, true); @@ -294,14 +265,14 @@ class _HomePageState extends State { } void _navigateToItemDetail(Map message) { + final context = _scaffoldKey.currentContext; + if (context == null) return; // Clear away dialogs - Navigator.popUntil(_scaffoldKey.currentContext, - (Route route) => route is PageRoute); + Navigator.popUntil(context, (Route route) => route is PageRoute); /* if (!notif.getRoute(store).isCurrent) { - // Navigator.push(_scaffoldKey.currentContext, notif.getRoute(store)); + // Navigator.push(context, notif.getRoute(store)); } */ - Navigator.pushNamed( - _scaffoldKey.currentContext, FireNotificationList.routeName); + Navigator.pushNamed(context, FireNotificationList.routeName); } // Firebase Messaging instance (v5+) diff --git a/lib/introPage.dart b/lib/introPage.dart index a528c14..24163dc 100644 --- a/lib/introPage.dart +++ b/lib/introPage.dart @@ -7,19 +7,21 @@ import 'generated/i18n.dart'; class IntroPage extends AppIntroPage { static const String routeName = '/intro'; - static final fireItems = (context) => - [ - AppIntroItem(icon: Icons.location_on, title: S.of(context).chooseAPlace), - AppIntroItem( - icon: Icons.panorama_fish_eye, title: S.of(context).chooseAWatchRadio), - AppIntroItem( - icon: Icons.whatshot, title: S.of(context).getAlertsOfFiresinThatArea), - AppIntroItem( - icon: Icons.notifications_active, - title: S.of(context).alertWhenThereIsAFire) - ]; + static final fireItems = (context) => [ + AppIntroItem( + icon: Icons.location_on, title: S.of(context).chooseAPlace), + AppIntroItem( + icon: Icons.panorama_fish_eye, + title: S.of(context).chooseAWatchRadio), + AppIntroItem( + icon: Icons.whatshot, + title: S.of(context).getAlertsOfFiresinThatArea), + AppIntroItem( + icon: Icons.notifications_active, + title: S.of(context).alertWhenThereIsAFire) + ]; - IntroPage({Key key}) + IntroPage({Key? key}) : super( items: fireItems, onIntroFinish: (context) => diff --git a/lib/locationUtils.dart b/lib/locationUtils.dart index 1fa49f0..58e169c 100644 --- a/lib/locationUtils.dart +++ b/lib/locationUtils.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:geocoding/geocoding.dart' as geo; import 'package:location/location.dart'; +import 'package:objectid/objectid.dart'; import 'generated/i18n.dart'; @@ -17,7 +18,8 @@ Future getUserLocation( LocationData location = await _location.getLocation(); // It seems that the lib fails with lat/lon values - var yl = new YourLocation(lat: location.latitude, lon: location.longitude); + var yl = new YourLocation( + id: ObjectId(), lat: location.latitude!, lon: location.longitude!); var address; try { address = await getReverseLocation(lat: yl.lat, lon: yl.lon); @@ -33,16 +35,17 @@ Future getUserLocation( } return yl; } on PlatformException catch (e) { - if (e.code == 'PERMISSION_DENIED') { - ScaffoldMessenger.of(scaffoldKey.currentContext) - .showSnackBar(new SnackBar( - content: new Text(S.of(scaffoldKey.currentContext).notPermsUbication), + final context = scaffoldKey.currentContext; + if (context != null) { + if (e.code == 'PERMISSION_DENIED') { + ScaffoldMessenger.of(context).showSnackBar(new SnackBar( + content: new Text(S.of(context).notPermsUbication), + )); + } else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {} + ScaffoldMessenger.of(context).showSnackBar(new SnackBar( + content: new Text(S.of(context).isYourUbicationEnabled), )); - } else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {} - ScaffoldMessenger.of(scaffoldKey.currentContext).showSnackBar(new SnackBar( - content: - new Text(S.of(scaffoldKey.currentContext).isYourUbicationEnabled), - )); + } return YourLocation.noLocation; } } diff --git a/lib/mainDrawer.dart b/lib/mainDrawer.dart index 6391ebd..974716f 100644 --- a/lib/mainDrawer.dart +++ b/lib/mainDrawer.dart @@ -1,4 +1,4 @@ -import 'package:badges/badges.dart'; +import 'package:badges/badges.dart' as badges_pkg; import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; @@ -52,7 +52,7 @@ Widget mainDrawer(BuildContext context, String currentRoute) { return new ListView( // Important: Remove any padding from the ListView. padding: EdgeInsets.zero, - children: listWithoutNulls([ + children: ([ new GestureDetector( onTap: () { Navigator.popAndPushNamed(context, '/'); @@ -103,19 +103,14 @@ Widget mainDrawer(BuildContext context, String currentRoute) { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Badge( - position: BadgePosition(top: 0, end: 0), - padding: EdgeInsets.all(7), - badgeColor: view.unreadCount > 0 - ? Colors.red - : Colors.grey, - // spacing: 5.0, - // borderColor: Colors.red, - //child: Text(S.of(context).fireNotificationsTitleShort), + badges_pkg.Badge( + position: badges_pkg.BadgePosition.topEnd( + top: -10, end: -12), badgeContent: Text( '${view.unreadCount.toString()}', style: TextStyle(color: Colors.white), - )) + ), + child: Icon(Icons.notifications)) ])), // Text(S.of(context).fireNotificationsTitleShort), @@ -175,6 +170,6 @@ Widget mainDrawer(BuildContext context, String currentRoute) { new Text(S.of(context).NASAAck, style: bottomTextStyle), // More ? ]) - ])); + ]).where((w) => w != null).cast().toList()); }); } diff --git a/lib/markdownPage.dart b/lib/markdownPage.dart index 06df602..b0cbf8f 100644 --- a/lib/markdownPage.dart +++ b/lib/markdownPage.dart @@ -12,7 +12,7 @@ abstract class MarkdownPage extends StatefulWidget { final Future file; final String route; - MarkdownPage({this.title, this.route, this.file}); + MarkdownPage({required this.title, required this.route, required this.file}); @override _MarkdownPageState createState() => @@ -25,7 +25,8 @@ class _MarkdownPageState extends State { final Future file; String pageData = ""; - _MarkdownPageState({this.title, this.file, this.route}); + _MarkdownPageState( + {required this.title, required this.file, required this.route}); @override Widget build(BuildContext context) { diff --git a/lib/models/appState.dart b/lib/models/appState.dart index 80c1236..2aa6254 100644 --- a/lib/models/appState.dart +++ b/lib/models/appState.dart @@ -1,13 +1,12 @@ import 'dart:async'; import 'package:comunes_flutter/comunes_flutter.dart'; -import 'package:connectivity/connectivity.dart'; import 'package:fires_flutter/models/fireNotification.dart'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:json_annotation/json_annotation.dart'; -import 'package:latlong/latlong.dart'; +import 'package:latlong2/latlong.dart'; import 'package:meta/meta.dart'; import 'fireMapState.dart'; @@ -44,8 +43,6 @@ class AppState { final int fireNotificationsUnread; @JsonKey(ignore: true) final FireMapState fireMapState; - @JsonKey(ignore: true) - final ConnectivityResult connectivity; @JsonKey(ignore: true) factory AppState.fromJson(Map json) => @@ -57,31 +54,29 @@ class AppState { this.fireNotificationsUnread = 0, this.user = const User.initial(), this.isLoading = false, - this.isLoaded= false, - this.error, - this.gmapKey, - this.firesApiKey, - this.firesApiUrl, - this.serverUrl, - this.connectivity, - this.monitoredAreas, + this.isLoaded = false, + this.error = '', + this.gmapKey = '', + this.firesApiKey = '', + this.firesApiUrl = '', + this.serverUrl = '', + this.monitoredAreas = const [], this.fireMapState = const FireMapState.initial()}); AppState copyWith( - {bool isLoading, - bool isLoaded, - String user, - String error, - String gmapKey, - String firesApiKey, - String serverUrl, - String firesApiUrl, - List yourLocations, - List fireNotifications, - int fireNotificationsUnread, - FireMapState fireMapState, - List monitoredAreas, - ConnectivityResult connectivity}) { + {bool? isLoading, + bool? isLoaded, + User? user, + String? error, + String? gmapKey, + String? firesApiKey, + String? serverUrl, + String? firesApiUrl, + List? yourLocations, + List? fireNotifications, + int? fireNotificationsUnread, + FireMapState? fireMapState, + List? monitoredAreas}) { return new AppState( isLoading: isLoading ?? this.isLoading, isLoaded: isLoaded ?? this.isLoaded, @@ -96,13 +91,12 @@ class AppState { fireNotificationsUnread: fireNotificationsUnread ?? this.fireNotificationsUnread, monitoredAreas: monitoredAreas ?? this.monitoredAreas, - fireMapState: fireMapState ?? this.fireMapState, - connectivity: connectivity ?? this.connectivity); + fireMapState: fireMapState ?? this.fireMapState); } @override String toString() { - return 'AppState{\nuser: $user\nconnectivity: ${connectivity.toString()}\nisLoading: $isLoading\nisLoaded: $isLoaded\napiKey: ${ellipse(firesApiKey, 8)}\napiUrl: $firesApiUrl\nserverUrl: $serverUrl\nfireMapState: $fireMapState\nyourLocations count: ${yourLocations.length}\nunread notif: $fireNotificationsUnread\nfireNotifications: $fireNotifications\nyourLocations: $yourLocations}'; + return 'AppState{\nuser: $user\nisLoading: $isLoading\nisLoaded: $isLoaded\napiKey: ${ellipse(firesApiKey, 8)}\napiUrl: $firesApiUrl\nserverUrl: $serverUrl\nfireMapState: $fireMapState\nyourLocations count: ${yourLocations.length}\nunread notif: $fireNotificationsUnread\nfireNotifications: $fireNotifications\nyourLocations: $yourLocations}'; } } diff --git a/lib/models/basicLocation.dart b/lib/models/basicLocation.dart index 1b5803d..684120d 100644 --- a/lib/models/basicLocation.dart +++ b/lib/models/basicLocation.dart @@ -1,14 +1,11 @@ - -class BasicLocation extends Comparable { +class BasicLocation implements Comparable { final double lat; final double lon; - String description; + final String? description; // static BasicLocation noLocation = new BasicLocation(lat: 0.0, lon: 0.0); - BasicLocation({required this.lat, required this.lon, this.description}) { - - } + BasicLocation({required this.lat, required this.lon, this.description}) {} int compareTo(BasicLocation other) { return lat == other.lat && lon == other.lon ? 1 : 0; diff --git a/lib/models/fireNotification.dart b/lib/models/fireNotification.dart index c814868..fa5d9be 100644 --- a/lib/models/fireNotification.dart +++ b/lib/models/fireNotification.dart @@ -24,16 +24,14 @@ class FireNotification { _$FireNotificationFromJson(json); FireNotification( - {this.id, + {required this.id, required this.lat, required this.lon, required this.description, required this.when, required this.read, required this.sealed, - required this.subsId}) { - - } + required this.subsId}) {} FireNotification copyWith( {id, lat, lon, description, read, when, sealed, subsId}) { diff --git a/lib/models/fireNotificationsPersist.dart b/lib/models/fireNotificationsPersist.dart index c9f8086..6cb2f4a 100644 --- a/lib/models/fireNotificationsPersist.dart +++ b/lib/models/fireNotificationsPersist.dart @@ -10,13 +10,14 @@ final String fireNotificationKey = 'fireNotifications'; Future> loadFireNotifications() async { return await globals.prefs.then((prefs) { - List FireNotifications = prefs.getStringList(fireNotificationKey); + List? FireNotifications = prefs.getStringList(fireNotificationKey); List persistedList = []; - FireNotifications.forEach((notificationString) { + (FireNotifications ?? []).forEach((notificationString) { Map notificationMap = json.decode(notificationString); - persistedList.add(FireNotification.fromJson(notificationMap)); + persistedList.add( + FireNotification.fromJson(notificationMap as Map)); }); - return persistedList; + return persistedList; }); } diff --git a/lib/models/user.dart b/lib/models/user.dart index 364acde..0abfddd 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -8,13 +8,13 @@ class User { final String token; const User.initial() - : this.userId = null, - lang = null, - token = null; + : userId = '', + lang = '', + token = ''; - User({this.userId, this.lang, this.token}); + const User({required this.userId, required this.lang, required this.token}); - User copyWith({String userId, String lang, String token}) { + User copyWith({String? userId, String? lang, String? token}) { return new User( userId: userId ?? this.userId, token: token ?? this.token, @@ -25,5 +25,4 @@ class User { String toString() { return 'User {userId: $userId, lang: $lang, token: ${ellipse(token)}'; } - } diff --git a/lib/models/yourLocation.dart b/lib/models/yourLocation.dart index 33444c4..d4295f5 100644 --- a/lib/models/yourLocation.dart +++ b/lib/models/yourLocation.dart @@ -13,22 +13,28 @@ class YourLocation { String description; bool subscribed; int distance; - int currentNumFires; + late int currentNumFires; factory YourLocation.fromJson(Map json) => _$YourLocationFromJson(json); - static YourLocation noLocation = new YourLocation(lat: 0.0, lon: 0.0); - static const int withoutStats = null; + static late final YourLocation noLocation; + static const int? withoutStats = null; + + static void _initNoLocation() { + noLocation = new YourLocation( + id: ObjectId(), lat: 0.0, lon: 0.0, description: '', subscribed: false); + } + YourLocation( - {this.id, + {required this.id, required this.lat, required this.lon, - this.description, + this.description = '', this.distance = 10, - int currentNumFires = withoutStats, - this.subscribed =false}) { - + int? currentNumFires, + this.subscribed = false}) { + this.currentNumFires = currentNumFires ?? 0; } Map toJson() => _$YourLocationToJson(this); diff --git a/lib/models/yourLocationPersist.dart b/lib/models/yourLocationPersist.dart index 7ed94af..3508b25 100644 --- a/lib/models/yourLocationPersist.dart +++ b/lib/models/yourLocationPersist.dart @@ -10,13 +10,14 @@ final String locationKey = 'yourlocations'; Future> loadYourLocations() async { return await globals.prefs.then((prefs) { - List yourLocations = prefs.getStringList(locationKey); + List? yourLocations = prefs.getStringList(locationKey); List persistedList = []; - yourLocations.forEach((locationString) { + (yourLocations ?? []).forEach((locationString) { Map locationMap = json.decode(locationString); - persistedList.add(YourLocation.fromJson(locationMap)); + persistedList + .add(YourLocation.fromJson(locationMap as Map)); }); - return persistedList; + return persistedList; }); } diff --git a/lib/placesAutocompleteUtils.dart b/lib/placesAutocompleteUtils.dart index c270a61..78148af 100644 --- a/lib/placesAutocompleteUtils.dart +++ b/lib/placesAutocompleteUtils.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; -import 'generated/i18n.dart'; /// Open a places dialog for selecting a location. /// Currently returns a default location as the google_places_autocomplete package diff --git a/lib/redux/appActions.dart b/lib/redux/appActions.dart index 3017b24..5c8e006 100644 --- a/lib/redux/appActions.dart +++ b/lib/redux/appActions.dart @@ -1,13 +1,13 @@ import 'package:fires_flutter/models/yourLocation.dart'; import 'package:fires_flutter/models/fireNotification.dart'; import 'dart:async'; -import 'package:connectivity/connectivity.dart'; import 'package:flutter_map/flutter_map.dart'; +import 'package:connectivity_plus/connectivity_plus.dart'; abstract class AppActions {} class FetchYourLocationsAction extends AppActions { - Completer refreshCallback; + Completer? refreshCallback; FetchYourLocationsAction([this.refreshCallback]); } @@ -52,13 +52,8 @@ class FetchFireNotificationsSucceededAction extends AppActions { final List fetchedFireNotifications; final int unreadCount; - FetchFireNotificationsSucceededAction(this.fetchedFireNotifications, this.unreadCount); -} - -class OnConnectivityChanged extends AppActions { - final ConnectivityResult connectivityResult; - - OnConnectivityChanged(this.connectivityResult); + FetchFireNotificationsSucceededAction( + this.fetchedFireNotifications, this.unreadCount); } class FetchMonitoredAreasSucceededAction extends AppActions { @@ -66,3 +61,9 @@ class FetchMonitoredAreasSucceededAction extends AppActions { FetchMonitoredAreasSucceededAction(this.monitoredAreas); } + +class OnConnectivityChanged extends AppActions { + final List connectionStatus; + + OnConnectivityChanged(this.connectionStatus); +} diff --git a/lib/redux/fetchDataMiddleware.dart b/lib/redux/fetchDataMiddleware.dart index 73dcbc0..e3af43d 100644 --- a/lib/redux/fetchDataMiddleware.dart +++ b/lib/redux/fetchDataMiddleware.dart @@ -165,7 +165,7 @@ void fetchDataMiddleware(Store store, action, NextDispatcher next) { }); locSubs.subscribed = true; }); - + store.dispatch(new FetchYourLocationsSucceededAction(localLocations)); persistYourLocations(localLocations); @@ -182,9 +182,9 @@ void fetchDataMiddleware(Store store, action, NextDispatcher next) { }); }); - Completer completer = action.refreshCallback; - completer.complete(null); - }); + final Completer? completer = action.refreshCallback; + completer?.complete(null); + }); }).catchError((onError) { // If it fails, dispatch a failure action. The reducer will // update the state with the error. diff --git a/lib/redux/fireMapReducer.dart b/lib/redux/fireMapReducer.dart index 1794b86..d054641 100644 --- a/lib/redux/fireMapReducer.dart +++ b/lib/redux/fireMapReducer.dart @@ -1,5 +1,6 @@ import 'package:redux/redux.dart'; import 'package:fires_flutter/models/yourLocation.dart'; +import 'package:objectid/objectid.dart'; import '../models/fireMapState.dart'; import 'actions.dart'; @@ -7,7 +8,7 @@ final fireMapReducer = combineReducers([ new TypedReducer( _showYourLocationMap), new TypedReducer( - _showFireNotificationMap), + _showFireNotificationMap), new TypedReducer( _updateYourLocationMapStats), new TypedReducer(_subscribeYourLocationMap), @@ -20,8 +21,7 @@ final fireMapReducer = combineReducers([ _editConfirmYourLocationMap), new TypedReducer( _editCancelYourLocationMap), - new TypedReducer( - _toggleMapLayer), + new TypedReducer(_toggleMapLayer), new TypedReducer( _updateYourLocationMap) ]); @@ -46,15 +46,22 @@ FireMapState _showYourLocationMap( status: action.loc.subscribed ? FireMapStatus.unsubscribe : FireMapStatus.view, - yourLocation: action.loc, fireNotication: null); + yourLocation: action.loc, + fireNotication: null); } FireMapState _showFireNotificationMap( FireMapState state, ShowFireNotificationMapAction action) { // TODO: use here you real location? - YourLocation pseudoLoc = new YourLocation(lat: action.notif.lat, lon: action.notif.lon, description: action.notif.description); + YourLocation pseudoLoc = new YourLocation( + id: ObjectId(), + lat: action.notif.lat, + lon: action.notif.lon, + description: action.notif.description); return state.copyWith( - status: FireMapStatus.viewFireNotification, yourLocation: pseudoLoc, fireNotication: action.notif); + status: FireMapStatus.viewFireNotification, + yourLocation: pseudoLoc, + fireNotication: action.notif); } FireMapState _subscribeYourLocationMap( @@ -92,12 +99,12 @@ FireMapState _editCancelYourLocationMap( FireMapStatus restoreStatusAfterSave(loc) => loc.subscribed ? FireMapStatus.unsubscribe : FireMapStatus.view; -FireMapState _toggleMapLayer( - FireMapState state, ToggleMapLayerAction action) { +FireMapState _toggleMapLayer(FireMapState state, ToggleMapLayerAction action) { FireMapLayer currentLayer = state.layer; List list = FireMapLayer.values; int currentPos = list.indexOf(currentLayer); currentPos++; - FireMapLayer next = list.elementAt(currentPos >= list.length ? 0: currentPos); + FireMapLayer next = + list.elementAt(currentPos >= list.length ? 0 : currentPos); return state.copyWith(layer: next); -} \ No newline at end of file +} diff --git a/lib/sandbox.dart b/lib/sandbox.dart index ff0fc35..567a7d0 100644 --- a/lib/sandbox.dart +++ b/lib/sandbox.dart @@ -20,7 +20,7 @@ class Sandbox extends StatelessWidget { decoration: new InputDecoration(), onSubmitted: (todoText) {}, )), - body: new RaisedButton( + body: new ElevatedButton( child: new Text('Press'), onPressed: () { showDialog( diff --git a/lib/slider.dart b/lib/slider.dart index cd51483..cf3f248 100644 --- a/lib/slider.dart +++ b/lib/slider.dart @@ -10,7 +10,7 @@ class FireDistanceSlider extends StatefulWidget { final int initialValue; final SlideCallback onSlide; - FireDistanceSlider({this.initialValue, this.onSlide}); + FireDistanceSlider({required this.initialValue, required this.onSlide}); @override _FireDistanceSliderState createState() => new _FireDistanceSliderState( @@ -18,16 +18,16 @@ class FireDistanceSlider extends StatefulWidget { } class _FireDistanceSliderState extends State { - int _sliderValue; + late int _sliderValue; final SlideCallback onSlide; - _FireDistanceSliderState({int initialValue = 10, this.onSlide}) { + _FireDistanceSliderState({int initialValue = 10, required this.onSlide}) { this._sliderValue = initialValue; } - sizeText(sliderValue) => - new Text(S.of(context).subscribeToValueAroundThisArea(sliderValue.toString()), - style: new TextStyle(color: Colors.black87)); + sizeText(sliderValue) => new Text( + S.of(context).subscribeToValueAroundThisArea(sliderValue.toString()), + style: new TextStyle(color: Colors.black87)); warningText(sliderValue) => _sliderValue >= 50 ? new Text(S.of(context).warningThisIsAVeryLargeArea, @@ -47,7 +47,7 @@ class _FireDistanceSliderState extends State { onChanged: (double value) { _sliderValue = value.round(); onSlide(_sliderValue); - setState(() {}); + setState(() {}); }, ); return new Column( diff --git a/lib/supportPage.dart b/lib/supportPage.dart index c54c03f..3f1bb71 100644 --- a/lib/supportPage.dart +++ b/lib/supportPage.dart @@ -1,6 +1,6 @@ import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:launch_review/launch_review.dart'; +import 'package:in_app_review/in_app_review.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:share_plus/share_plus.dart'; @@ -20,7 +20,7 @@ class _SupportPageState extends State { Widget buildSupportButton() { return new Align( alignment: const Alignment(0.0, -0.2), - child: new OutlineButton.icon( + child: new OutlinedButton.icon( icon: const Icon(Icons.favorite_border), label: new Text(S.of(context).comunesSupportBtn), onPressed: () { @@ -33,11 +33,12 @@ class _SupportPageState extends State { Widget buildShareButton() { return new Align( alignment: const Alignment(0.0, -0.2), - child: new OutlineButton.icon( + child: new OutlinedButton.icon( icon: const Icon(Icons.share), label: new Text(S.of(context).shareAppBtn), onPressed: () { - Share.shareWithResult('https://play.google.com/store/apps/details?id=org.comunes.fires'); + Share.shareWithResult( + 'https://play.google.com/store/apps/details?id=org.comunes.fires'); }, ), ); @@ -46,11 +47,11 @@ class _SupportPageState extends State { Widget buildStarButton() { return new Align( alignment: const Alignment(0.0, -0.2), - child: new OutlineButton.icon( + child: new OutlinedButton.icon( icon: const Icon(Icons.star_border), label: new Text(S.of(context).starAppBtn), onPressed: () { - LaunchReview.launch(); + InAppReview.instance.requestReview(); }, ), ); @@ -59,11 +60,12 @@ class _SupportPageState extends State { Widget buildTranslateButton() { return new Align( alignment: const Alignment(0.0, -0.2), - child: new OutlineButton.icon( + child: new OutlinedButton.icon( icon: const Icon(Icons.translate), label: new Text(S.of(context).translateBtn), onPressed: () { - launch("https://translate.comunes.org/projects/todos-contra-el-fuego/"); + launch( + "https://translate.comunes.org/projects/todos-contra-el-fuego/"); }, ), ); diff --git a/pubspec.yaml b/pubspec.yaml index cfcc5b1..d53e89c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,6 +60,7 @@ dependencies: # reviews in_app_review: ^2.0.9 + meta: any dev_dependencies: flutter_test: sdk: flutter