refactor: remove comunes-flutter dependency and inline components
Remove the external comunes-flutter library dependency and replace all its components with local implementations: - Utility functions: Created lib/utils/widget_utils.dart with compactWidgets() and ellipse() functions, replacing the comunes-flutter helpers with modern Dart null-safety patterns (whereType instead of where(notNull)) - Secret loader: Inlined as lib/utils/secret_loader.dart for loading JSON config - Layout widgets: Replaced CenteredRow/CenteredColumn with standard Row/Column with MainAxisAlignment.center - Intro screens: Copied AppIntroPage and MaterialAppWithIntro locally in lib/widgets/ with cleaned-up deprecated code patterns - Button widget: Created lib/widgets/rounded_btn.dart for the RoundedBtn used in activeFires.dart Changes span 20 files: - 5 new utility/widget files created - Updated imports in 15 files - Removed path dependency from pubspec.yaml - All functionality preserved, build verified with flutter pub get Impact: - Removes external dependency, simplifying project structure - Modern Dart patterns (proper null-safety) - Better code clarity with explicit widget properties - Easier onboarding (no 'what is comunes-flutter?' questions)
This commit is contained in:
parent
46305ee587
commit
2bf42ce262
31 changed files with 484 additions and 124 deletions
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||||
|
|
@ -17,6 +16,7 @@ import 'models/appState.dart';
|
||||||
import 'models/yourLocation.dart';
|
import 'models/yourLocation.dart';
|
||||||
import 'placesAutocompleteUtils.dart';
|
import 'placesAutocompleteUtils.dart';
|
||||||
import 'redux/actions.dart';
|
import 'redux/actions.dart';
|
||||||
|
import 'widgets/rounded_btn.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class _ViewModel {
|
class _ViewModel {
|
||||||
|
|
@ -264,19 +264,21 @@ class _ActiveFiresPageState extends State<ActiveFiresPage> {
|
||||||
return completer.future;
|
return completer.future;
|
||||||
})
|
})
|
||||||
: Center(
|
: Center(
|
||||||
child: CenteredColumn(children: <Widget>[
|
child: Column(
|
||||||
RoundedBtn(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
icon: Icons.location_searching,
|
children: <Widget>[
|
||||||
text: S.of(context).addYourCurrentPosition,
|
RoundedBtn(
|
||||||
onPressed: () => onAddYourLocation(view.onAdd),
|
icon: Icons.location_searching,
|
||||||
backColor: fires600),
|
text: S.of(context).addYourCurrentPosition,
|
||||||
const SizedBox(height: 26.0),
|
onPressed: () => onAddYourLocation(view.onAdd),
|
||||||
RoundedBtn(
|
backColor: fires600),
|
||||||
icon: Icons.edit_location,
|
const SizedBox(height: 26.0),
|
||||||
text: S.of(context).addSomePlace,
|
RoundedBtn(
|
||||||
onPressed: () => onAddOtherLocation(view.onAdd),
|
icon: Icons.edit_location,
|
||||||
backColor: fires600),
|
text: S.of(context).addSomePlace,
|
||||||
])),
|
onPressed: () => onAddOtherLocation(view.onAdd),
|
||||||
|
backColor: fires600),
|
||||||
|
])),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
|
||||||
|
|
@ -78,7 +77,8 @@ class _CompassMapPluginWidgetState extends State<CompassMapPluginWidget> {
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 10.0,
|
top: 10.0,
|
||||||
right: 10.0,
|
right: 10.0,
|
||||||
child: CenteredRow(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Column(
|
Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:community_material_icon/community_material_icon.dart';
|
import 'package:community_material_icon/community_material_icon.dart';
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
@ -79,7 +78,7 @@ class _FireAlertState extends State<FireAlert> {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CustomStep> listWithoutNulls(List<CustomStep> children) =>
|
List<CustomStep> listWithoutNulls(List<CustomStep> children) =>
|
||||||
children.where(notNull).toList();
|
children.whereType<CustomStep>().toList();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
@ -209,20 +208,24 @@ class _FireNotificationListState extends State<FireNotificationList> {
|
||||||
child: Card(
|
child: Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
child: CenteredColumn(children: <Widget>[
|
child: Column(
|
||||||
const Icon(Icons.notifications_none,
|
mainAxisAlignment:
|
||||||
size: 150.0, color: Colors.black26),
|
MainAxisAlignment.center,
|
||||||
const SizedBox(height: 20.0),
|
children: <Widget>[
|
||||||
Text(
|
const Icon(Icons.notifications_none,
|
||||||
S
|
size: 150.0, color: Colors.black26),
|
||||||
.of(context)
|
const SizedBox(height: 20.0),
|
||||||
.fireNotificationsDescription,
|
Text(
|
||||||
textAlign: TextAlign.center,
|
S
|
||||||
textScaler:
|
.of(context)
|
||||||
const TextScaler.linear(1.1),
|
.fireNotificationsDescription,
|
||||||
style: const TextStyle(
|
textAlign: TextAlign.center,
|
||||||
height: 1.3, color: Colors.black45))
|
textScaler:
|
||||||
]))))
|
const TextScaler.linear(1.1),
|
||||||
|
style: const TextStyle(
|
||||||
|
height: 1.3,
|
||||||
|
color: Colors.black45))
|
||||||
|
]))))
|
||||||
: _buildSavedFireNotifications(
|
: _buildSavedFireNotifications(
|
||||||
context,
|
context,
|
||||||
view.yourLocations,
|
view.yourLocations,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
|
@ -18,6 +17,7 @@ import 'sandbox.dart';
|
||||||
import 'supportPage.dart';
|
import 'supportPage.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
import 'themeDev.dart';
|
import 'themeDev.dart';
|
||||||
|
import 'widgets/material_app_with_intro.dart';
|
||||||
|
|
||||||
class FiresApp extends StatefulWidget {
|
class FiresApp extends StatefulWidget {
|
||||||
const FiresApp(this.store, {super.key});
|
const FiresApp(this.store, {super.key});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
|
@ -334,7 +333,8 @@ class GenericMapState extends State<GenericMap> {
|
||||||
top: constraints.maxHeight - 200,
|
top: constraints.maxHeight - 200,
|
||||||
right: 10.0,
|
right: 10.0,
|
||||||
left: 10.0,
|
left: 10.0,
|
||||||
child: CenteredRow(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
// Fit sample:
|
// Fit sample:
|
||||||
// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/map_controller.dart
|
// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/map_controller.dart
|
||||||
children: status ==
|
children: status ==
|
||||||
|
|
@ -401,8 +401,11 @@ class GenericMapState extends State<GenericMap> {
|
||||||
// const calibrate = false; // useful when we change the fire icons size
|
// const calibrate = false; // useful when we change the fire icons size
|
||||||
for (final dynamic falsePos in falsePosList) {
|
for (final dynamic falsePos in falsePosList) {
|
||||||
try {
|
try {
|
||||||
final List<dynamic> coords =
|
final Map<String, dynamic> falsePosMap =
|
||||||
falsePos['geo']['coordinates'] as List<dynamic>;
|
falsePos as Map<String, dynamic>;
|
||||||
|
final Map<String, dynamic> geo =
|
||||||
|
falsePosMap['geo'] as Map<String, dynamic>;
|
||||||
|
final List<dynamic> coords = geo['coordinates'] as List<dynamic>;
|
||||||
// print('false pos: ${coords}');
|
// print('false pos: ${coords}');
|
||||||
final LatLng loc = LatLng(
|
final LatLng loc = LatLng(
|
||||||
(coords[1] as num).toDouble(), (coords[0] as num).toDouble());
|
(coords[1] as num).toDouble(), (coords[0] as num).toDouble());
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
|
|
@ -12,6 +11,7 @@ import 'models/falsePositiveTypes.dart';
|
||||||
import 'models/fireMapState.dart';
|
import 'models/fireMapState.dart';
|
||||||
import 'models/fireNotification.dart';
|
import 'models/fireNotification.dart';
|
||||||
import 'models/yourLocation.dart';
|
import 'models/yourLocation.dart';
|
||||||
|
import 'utils/widget_utils.dart';
|
||||||
|
|
||||||
typedef OnSave = void Function();
|
typedef OnSave = void Function();
|
||||||
typedef OnCancel = void Function();
|
typedef OnCancel = void Function();
|
||||||
|
|
@ -70,7 +70,7 @@ class GenericMapBottom extends StatelessWidget {
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: listWithoutNulls(<Widget?>[
|
children: compactWidgets(<Widget?>[
|
||||||
Text(notif.description),
|
Text(notif.description),
|
||||||
// TODOfire type (neighbout, NASA, etc)
|
// TODOfire type (neighbout, NASA, etc)
|
||||||
const SizedBox(height: 5.0),
|
const SizedBox(height: 5.0),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
|
@ -170,40 +169,43 @@ class _HomePageState extends State<HomePage> {
|
||||||
? const FiresSpinner()
|
? const FiresSpinner()
|
||||||
: SafeArea(
|
: SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: CenteredColumn(children: <Widget>[
|
child: Column(
|
||||||
Row(children: <Widget>[
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
IconButton(
|
children: <Widget>[
|
||||||
onPressed: () {
|
Row(children: <Widget>[
|
||||||
_scaffoldKey.currentState?.openDrawer();
|
IconButton(
|
||||||
},
|
onPressed: () {
|
||||||
icon: const Icon(Icons.menu,
|
_scaffoldKey.currentState?.openDrawer();
|
||||||
size: 30.0, color: Colors.black38)),
|
},
|
||||||
]),
|
icon: const Icon(Icons.menu,
|
||||||
Expanded(
|
size: 30.0, color: Colors.black38)),
|
||||||
child: FractionallySizedBox(
|
]),
|
||||||
alignment: FractionalOffset.center,
|
Expanded(
|
||||||
heightFactor: 0.7,
|
child: FractionallySizedBox(
|
||||||
child: Image.asset('images/logo-200.png',
|
alignment: FractionalOffset.center,
|
||||||
fit: BoxFit.fitHeight))),
|
heightFactor: 0.7,
|
||||||
Expanded(
|
child: Image.asset('images/logo-200.png',
|
||||||
child: FractionallySizedBox(
|
fit: BoxFit.fitHeight))),
|
||||||
alignment: FractionalOffset.topCenter,
|
Expanded(
|
||||||
heightFactor: 1.0,
|
child: FractionallySizedBox(
|
||||||
child: Column(
|
alignment: FractionalOffset.topCenter,
|
||||||
children: <Widget>[
|
heightFactor: 1.0,
|
||||||
Padding(
|
child: Column(
|
||||||
padding: const EdgeInsets.symmetric(
|
children: <Widget>[
|
||||||
vertical: 10.0, horizontal: 20.0),
|
Padding(
|
||||||
child: FittedBox(
|
padding: const EdgeInsets.symmetric(
|
||||||
fit: BoxFit.scaleDown,
|
vertical: 10.0,
|
||||||
child: Text(S.of(context).appName,
|
horizontal: 20.0),
|
||||||
maxLines: 2,
|
child: FittedBox(
|
||||||
textAlign: TextAlign.center,
|
fit: BoxFit.scaleDown,
|
||||||
style: _homeFont),
|
child: Text(S.of(context).appName,
|
||||||
)),
|
maxLines: 2,
|
||||||
],
|
textAlign: TextAlign.center,
|
||||||
)))
|
style: _homeFont),
|
||||||
])),
|
)),
|
||||||
|
],
|
||||||
|
)))
|
||||||
|
])),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'generated/i18n.dart';
|
import 'generated/i18n.dart';
|
||||||
import 'homePage.dart';
|
import 'homePage.dart';
|
||||||
|
import 'widgets/app_intro_page.dart';
|
||||||
|
|
||||||
class IntroPage extends AppIntroPage {
|
class IntroPage extends AppIntroPage {
|
||||||
IntroPage({super.key})
|
IntroPage({super.key})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
@ -19,7 +18,8 @@ class LayerSelectorMapPluginWidget extends StatelessWidget {
|
||||||
Positioned(
|
Positioned(
|
||||||
top: constraints.maxHeight - 60,
|
top: constraints.maxHeight - 60,
|
||||||
left: 10.0,
|
left: 10.0,
|
||||||
child: CenteredRow(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Column(
|
Column(
|
||||||
children: <Widget>[_LayerSelectorButton(store)],
|
children: <Widget>[_LayerSelectorButton(store)],
|
||||||
|
|
@ -31,7 +31,8 @@ class LayerSelectorMapPluginWidget extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _LayerSelectorButton(Store<AppState> store) {
|
Widget _LayerSelectorButton(Store<AppState> store) {
|
||||||
final GlobalKey<PopupMenuButtonState<FireMapLayer>> key = GlobalKey<PopupMenuButtonState<FireMapLayer>>();
|
final GlobalKey<PopupMenuButtonState<FireMapLayer>> key =
|
||||||
|
GlobalKey<PopupMenuButtonState<FireMapLayer>>();
|
||||||
|
|
||||||
return PopupMenuButton<FireMapLayer>(
|
return PopupMenuButton<FireMapLayer>(
|
||||||
key: key,
|
key: key,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get_it/get_it.dart';
|
import 'package:get_it/get_it.dart';
|
||||||
|
|
@ -14,6 +13,7 @@ import 'models/firesApi.dart';
|
||||||
import 'redux/fetchDataMiddleware.dart';
|
import 'redux/fetchDataMiddleware.dart';
|
||||||
import 'redux/reducers.dart';
|
import 'redux/reducers.dart';
|
||||||
import 'sentryReport.dart';
|
import 'sentryReport.dart';
|
||||||
|
import 'utils/secret_loader.dart';
|
||||||
|
|
||||||
Future<PackageInfo> loadPackageInfo() async {
|
Future<PackageInfo> loadPackageInfo() async {
|
||||||
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:redux/src/store.dart';
|
import 'package:redux/src/store.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
|
||||||
import 'globals.dart' as globals;
|
import 'globals.dart' as globals;
|
||||||
import 'mainCommon.dart';
|
import 'mainCommon.dart';
|
||||||
import 'models/appState.dart';
|
import 'models/appState.dart';
|
||||||
|
import 'utils/secret_loader.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
globals.isDevelopment = false;
|
globals.isDevelopment = false;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
import '../utils/widget_utils.dart';
|
||||||
import 'fireMapState.dart';
|
import 'fireMapState.dart';
|
||||||
import 'fireNotification.dart';
|
import 'fireNotification.dart';
|
||||||
import 'user.dart';
|
import 'user.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
// ignore_for_file: type=lint
|
|
||||||
|
|
||||||
part of 'appState.dart';
|
part of 'appState.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:objectid/objectid.dart';
|
import 'package:objectid/objectid.dart';
|
||||||
|
|
||||||
import '../objectIdUtils.dart';
|
import '../objectIdUtils.dart';
|
||||||
|
import '../utils/widget_utils.dart';
|
||||||
|
|
||||||
part 'fireNotification.g.dart';
|
part 'fireNotification.g.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
// ignore_for_file: type=lint
|
|
||||||
|
|
||||||
part of 'fireNotification.dart';
|
part of 'fireNotification.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:shared_preferences/src/shared_preferences_legacy.dart';
|
import 'package:shared_preferences/src/shared_preferences_legacy.dart';
|
||||||
|
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
|
@ -11,7 +10,8 @@ const String fireNotificationKey = 'fireNotifications';
|
||||||
|
|
||||||
Future<List<FireNotification>> loadFireNotifications() async {
|
Future<List<FireNotification>> loadFireNotifications() async {
|
||||||
return globals.prefs.then((SharedPreferences prefs) {
|
return globals.prefs.then((SharedPreferences prefs) {
|
||||||
final List<String>? FireNotifications = prefs.getStringList(fireNotificationKey);
|
final List<String>? FireNotifications =
|
||||||
|
prefs.getStringList(fireNotificationKey);
|
||||||
final List<FireNotification> persistedList = <FireNotification>[];
|
final List<FireNotification> persistedList = <FireNotification>[];
|
||||||
for (final String notificationString in (FireNotifications ?? <String>[])) {
|
for (final String notificationString in (FireNotifications ?? <String>[])) {
|
||||||
final Map<String, dynamic> notificationMap =
|
final Map<String, dynamic> notificationMap =
|
||||||
|
|
@ -26,7 +26,9 @@ void persistFireNotifications(List<FireNotification> notif) {
|
||||||
// print('Persisting $notif');
|
// print('Persisting $notif');
|
||||||
globals.prefs.then((SharedPreferences prefs) {
|
globals.prefs.then((SharedPreferences prefs) {
|
||||||
final List<String> notifAsString = <String>[];
|
final List<String> notifAsString = <String>[];
|
||||||
notif.where(notNull).toList().forEach((FireNotification notification) {
|
notif
|
||||||
|
.whereType<FireNotification>()
|
||||||
|
.forEach((FireNotification notification) {
|
||||||
notifAsString.add(json.encode(notification.toJson()));
|
notifAsString.add(json.encode(notification.toJson()));
|
||||||
});
|
});
|
||||||
prefs.setStringList(fireNotificationKey, notifAsString);
|
prefs.setStringList(fireNotificationKey, notifAsString);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,9 @@ class FiresApi {
|
||||||
await _dio.post<Map<String, dynamic>>(url, data: params);
|
await _dio.post<Map<String, dynamic>>(url, data: params);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
|
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
|
||||||
return data['data']['userId'] as String;
|
final Map<String, dynamic> dataData =
|
||||||
|
data['data'] as Map<String, dynamic>;
|
||||||
|
return dataData['userId'] as String;
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Unexpected error on create user');
|
throw Exception('Unexpected error on create user');
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +97,9 @@ class FiresApi {
|
||||||
await _dio.post<Map<String, dynamic>>(url, data: params);
|
await _dio.post<Map<String, dynamic>>(url, data: params);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
|
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
|
||||||
return data['data']['subsId'] as String;
|
final Map<String, dynamic> dataData =
|
||||||
|
data['data'] as Map<String, dynamic>;
|
||||||
|
return dataData['subsId'] as String;
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Unexpected error on subscribe');
|
throw Exception('Unexpected error on subscribe');
|
||||||
}
|
}
|
||||||
|
|
@ -168,10 +172,14 @@ class FiresApi {
|
||||||
final Map<String, dynamic> resultDecoded =
|
final Map<String, dynamic> resultDecoded =
|
||||||
response.data as Map<String, dynamic>;
|
response.data as Map<String, dynamic>;
|
||||||
final List<Polyline> union = <Polyline>[];
|
final List<Polyline> union = <Polyline>[];
|
||||||
|
final Map<String, dynamic> dataData =
|
||||||
|
resultDecoded['data'] as Map<String, dynamic>;
|
||||||
|
final Map<String, dynamic> unionData =
|
||||||
|
dataData['union'] as Map<String, dynamic>;
|
||||||
|
final String unionValue = unionData['value'] as String;
|
||||||
final List<dynamic> multipolygon =
|
final List<dynamic> multipolygon =
|
||||||
(json.decode(resultDecoded['data']['union']['value'] as String)
|
(json.decode(unionValue) as Map<String, dynamic>)['geometry']
|
||||||
as Map<String, dynamic>)['geometry']['coordinates']
|
['coordinates'] as List<dynamic>;
|
||||||
as List<dynamic>;
|
|
||||||
for (final dynamic polygonDynamic in multipolygon) {
|
for (final dynamic polygonDynamic in multipolygon) {
|
||||||
final List<dynamic> polygon = polygonDynamic as List<dynamic>;
|
final List<dynamic> polygon = polygonDynamic as List<dynamic>;
|
||||||
for (final dynamic holeDynamic in polygon) {
|
for (final dynamic holeDynamic in polygon) {
|
||||||
|
|
@ -206,7 +214,11 @@ class FiresApi {
|
||||||
final Response<dynamic> response = await _dio.post(url, data: params);
|
final Response<dynamic> response = await _dio.post(url, data: params);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
if (globals.isDevelopment) {
|
if (globals.isDevelopment) {
|
||||||
print(response.data['data']['upsert']);
|
final Map<String, dynamic> data =
|
||||||
|
response.data as Map<String, dynamic>;
|
||||||
|
final Map<String, dynamic> dataData =
|
||||||
|
data['data'] as Map<String, dynamic>;
|
||||||
|
print(dataData['upsert']);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
import '../utils/widget_utils.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class User {
|
class User {
|
||||||
|
|
||||||
const User({required this.userId, required this.lang, required this.token});
|
const User({required this.userId, required this.lang, required this.token});
|
||||||
|
|
||||||
const User.initial()
|
const User.initial()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
// ignore_for_file: type=lint
|
|
||||||
|
|
||||||
part of 'yourLocation.dart';
|
part of 'yourLocation.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:shared_preferences/src/shared_preferences_legacy.dart';
|
import 'package:shared_preferences/src/shared_preferences_legacy.dart';
|
||||||
|
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
|
|
@ -26,7 +25,7 @@ void persistYourLocations(List<YourLocation> yl) {
|
||||||
// debugPrint('Persisting $yl');
|
// debugPrint('Persisting $yl');
|
||||||
globals.prefs.then((SharedPreferences prefs) {
|
globals.prefs.then((SharedPreferences prefs) {
|
||||||
final List<String> ylAsString = <String>[];
|
final List<String> ylAsString = <String>[];
|
||||||
yl.where(notNull).toList().forEach((YourLocation location) {
|
yl.whereType<YourLocation>().forEach((YourLocation location) {
|
||||||
ylAsString.add(json.encode(location.toJson()));
|
ylAsString.add(json.encode(location.toJson()));
|
||||||
});
|
});
|
||||||
prefs.setStringList(locationKey, ylAsString);
|
prefs.setStringList(locationKey, ylAsString);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'generated/i18n.dart';
|
import 'generated/i18n.dart';
|
||||||
|
import 'utils/widget_utils.dart';
|
||||||
|
|
||||||
typedef SlideCallback = void Function(int distance);
|
typedef SlideCallback = void Function(int distance);
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ class _FireDistanceSliderState extends State<FireDistanceSlider> {
|
||||||
);
|
);
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: listWithoutNulls(<Widget>[
|
children: compactWidgets(<Widget?>[
|
||||||
const SizedBox(height: 50.0),
|
const SizedBox(height: 50.0),
|
||||||
Row(children: <Widget>[slider]),
|
Row(children: <Widget>[slider]),
|
||||||
// new SizedBox(height: 5.0),
|
// new SizedBox(height: 5.0),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:in_app_review/in_app_review.dart';
|
import 'package:in_app_review/in_app_review.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
|
|
@ -79,6 +78,7 @@ class _SupportPageState extends State<SupportPage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
@ -87,23 +87,29 @@ class _SupportPageState extends State<SupportPage> {
|
||||||
drawer: MainDrawer(context, SupportPage.routeName),
|
drawer: MainDrawer(context, SupportPage.routeName),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: CenteredColumn(children: <Widget>[
|
child: Column(
|
||||||
Flexible(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
child: CenteredColumn(children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Flexible(
|
||||||
S.of(context).supportPageDescription,
|
child: Column(
|
||||||
textAlign: TextAlign.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
),
|
children: <Widget>[
|
||||||
const SizedBox(height: 20.0),
|
Text(
|
||||||
buildSupportButton(),
|
S.of(context).supportPageDescription,
|
||||||
const SizedBox(height: 20.0),
|
textAlign: TextAlign.center,
|
||||||
buildTranslateButton(),
|
),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
buildStarButton(),
|
buildSupportButton(),
|
||||||
const SizedBox(height: 20.0),
|
const SizedBox(height: 20.0),
|
||||||
buildShareButton()
|
buildTranslateButton(),
|
||||||
]))
|
const SizedBox(height: 20.0),
|
||||||
]),
|
buildStarButton(),
|
||||||
|
const SizedBox(height: 20.0),
|
||||||
|
buildShareButton()
|
||||||
|
],
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
lib/utils/secret_loader.dart
Normal file
20
lib/utils/secret_loader.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'dart:async' show Future;
|
||||||
|
import 'dart:convert' show json;
|
||||||
|
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});
|
||||||
|
|
||||||
|
/// Load and parse JSON from asset bundle.
|
||||||
|
/// Returns a map of the parsed JSON content.
|
||||||
|
Future<Map<String, dynamic>> load() {
|
||||||
|
return rootBundle.loadStructuredData<Map<String, dynamic>>(
|
||||||
|
secretPath,
|
||||||
|
(jsonStr) async => json.decode(jsonStr) as Map<String, dynamic>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
lib/utils/widget_utils.dart
Normal file
13
lib/utils/widget_utils.dart
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Modern null-safe widget list compaction.
|
||||||
|
/// Filters out null values from a list of nullable widgets.
|
||||||
|
/// Example: compactWidgets([widget1, null, widget2]) → [widget1, widget2]
|
||||||
|
List<Widget> compactWidgets(List<Widget?> children) =>
|
||||||
|
children.whereType<Widget>().toList();
|
||||||
|
|
||||||
|
/// String truncation for debug output and logging.
|
||||||
|
/// Truncates a string to [end] characters and appends '...'
|
||||||
|
/// Example: ellipse('abcdefgh', 4) → 'abcd...'
|
||||||
|
String ellipse(String s, [int end = 4]) =>
|
||||||
|
s.length > end ? '${s.substring(0, end)}...' : s;
|
||||||
149
lib/widgets/app_intro_page.dart
Normal file
149
lib/widgets/app_intro_page.dart
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../utils/widget_utils.dart';
|
||||||
|
|
||||||
|
class AppIntroItem {
|
||||||
|
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<AppIntroItem> 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);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: DefaultTabController(
|
||||||
|
length: items(context).length,
|
||||||
|
child: _AppIntroPageSelector(items: items, onFinish: onIntroFinish),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppIntroPageSelector extends StatelessWidget {
|
||||||
|
const _AppIntroPageSelector({required this.items, required this.onFinish});
|
||||||
|
|
||||||
|
final ListItems items;
|
||||||
|
final OnIntroFinish onFinish;
|
||||||
|
|
||||||
|
void _handleArrowButtonPress(BuildContext context, int delta) {
|
||||||
|
final TabController controller = DefaultTabController.of(context)!;
|
||||||
|
if (!controller.indexIsChanging)
|
||||||
|
controller.animateTo(
|
||||||
|
(controller.index + delta).clamp(0, items(context).length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final TabController controller = DefaultTabController.of(context)!;
|
||||||
|
final ThemeData theme = Theme.of(context);
|
||||||
|
final Color color = theme.colorScheme.secondary;
|
||||||
|
final TextStyle titleStyle =
|
||||||
|
(theme.textTheme.headlineSmall ?? const TextStyle())
|
||||||
|
.copyWith(color: color);
|
||||||
|
final TextStyle subTitleStyle =
|
||||||
|
theme.textTheme.titleMedium ?? const TextStyle();
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
top: true,
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Row(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
onFinish(context);
|
||||||
|
},
|
||||||
|
icon:
|
||||||
|
const Icon(Icons.close, size: 30.0, color: Colors.black38)),
|
||||||
|
]),
|
||||||
|
Expanded(child: OrientationBuilder(builder: (context, orientation) {
|
||||||
|
return IconTheme(
|
||||||
|
data: IconThemeData(
|
||||||
|
size: orientation == Orientation.portrait ? 200.0 : 100.0,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
child: TabBarView(
|
||||||
|
children: items(context).map((AppIntroItem item) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
item.icon,
|
||||||
|
semanticLabel: item.title,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(left: 16.0, right: 16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
item.title,
|
||||||
|
style: titleStyle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20.0),
|
||||||
|
Text(
|
||||||
|
item.subTitle,
|
||||||
|
style: subTitleStyle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList()),
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 16.0),
|
||||||
|
child: Row(
|
||||||
|
children: compactWidgets(<Widget?>[
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.chevron_left),
|
||||||
|
color: color,
|
||||||
|
onPressed: () {
|
||||||
|
_handleArrowButtonPress(context, -1);
|
||||||
|
},
|
||||||
|
tooltip: 'Page back'),
|
||||||
|
TabPageSelector(controller: controller),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.chevron_right),
|
||||||
|
color: color,
|
||||||
|
onPressed: () {
|
||||||
|
_handleArrowButtonPress(context, 1);
|
||||||
|
if (!controller.indexIsChanging &&
|
||||||
|
controller.index == items(context).length - 1) {
|
||||||
|
onFinish(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: 'Page forward'),
|
||||||
|
]),
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
84
lib/widgets/material_app_with_intro.dart
Normal file
84
lib/widgets/material_app_with_intro.dart
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
abstract class MaterialAppWithIntro extends StatelessWidget {
|
||||||
|
final String name;
|
||||||
|
final ThemeData theme;
|
||||||
|
final Map<String, WidgetBuilder> routes;
|
||||||
|
final WidgetBuilder introWidget;
|
||||||
|
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(
|
||||||
|
home: MaterialAppWithIntroHome(introWidget, continueWidget, prefsKey),
|
||||||
|
title: name,
|
||||||
|
theme: theme,
|
||||||
|
routes: routes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MaterialAppWithIntroHome extends StatefulWidget {
|
||||||
|
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<MaterialAppWithIntroHome> {
|
||||||
|
final WidgetBuilder introWidget;
|
||||||
|
final WidgetBuilder continueWidget;
|
||||||
|
final String prefsKey;
|
||||||
|
|
||||||
|
_MaterialAppWithIntroState(
|
||||||
|
this.introWidget, this.continueWidget, this.prefsKey);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Timer(const Duration(milliseconds: 1000), () {
|
||||||
|
checkFirstStart();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/50654195/flutter-one-time-intro-screen
|
||||||
|
Future<void> checkFirstStart() async {
|
||||||
|
final String initialWizardKey = prefsKey;
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
final bool showInitialWizard = (prefs.getBool(initialWizardKey) ?? true);
|
||||||
|
|
||||||
|
if (showInitialWizard) {
|
||||||
|
await prefs.setBool(initialWizardKey, false);
|
||||||
|
if (mounted) {
|
||||||
|
await Navigator.of(context)
|
||||||
|
.pushReplacement(MaterialPageRoute(builder: introWidget));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mounted) {
|
||||||
|
await Navigator.of(context)
|
||||||
|
.pushReplacement(MaterialPageRoute(builder: continueWidget));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
70
lib/widgets/rounded_btn.dart
Normal file
70
lib/widgets/rounded_btn.dart
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
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,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.backColor,
|
||||||
|
this.textStyle = const TextStyle(fontSize: 20.0, color: Colors.white),
|
||||||
|
this.fontColor = Colors.white,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RoundedBtn.nav({
|
||||||
|
required IconData icon,
|
||||||
|
required String text,
|
||||||
|
required BuildContext context,
|
||||||
|
required String route,
|
||||||
|
required Color backColor,
|
||||||
|
TextStyle textStyle = const TextStyle(fontSize: 20.0, color: Colors.white),
|
||||||
|
Color fontColor = Colors.white,
|
||||||
|
}) {
|
||||||
|
return RoundedBtn(
|
||||||
|
icon: icon,
|
||||||
|
text: text,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, route);
|
||||||
|
},
|
||||||
|
backColor: backColor,
|
||||||
|
textStyle: textStyle,
|
||||||
|
fontColor: fontColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: onPressed,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: backColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(btnRadius),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(icon, size: 32.0, color: fontColor),
|
||||||
|
const SizedBox(width: 10.0),
|
||||||
|
Text(text, style: textStyle),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:comunes_flutter/comunes_flutter.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
@ -15,7 +14,8 @@ class ZoomMapPluginWidget extends StatelessWidget {
|
||||||
Positioned(
|
Positioned(
|
||||||
top: constraints.maxHeight - 100,
|
top: constraints.maxHeight - 100,
|
||||||
right: 10.0,
|
right: 10.0,
|
||||||
child: CenteredRow(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Column(
|
Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@ dependencies:
|
||||||
json_annotation: ^4.9.0
|
json_annotation: ^4.9.0
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
objectid: ^2.1.0
|
objectid: ^2.1.0
|
||||||
comunes_flutter:
|
|
||||||
path: /home/vjrj/dev/comunes_flutter
|
|
||||||
|
|
||||||
# redux
|
# redux
|
||||||
redux: ^5.0.0
|
redux: ^5.0.0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue