diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0d3b5ed..b789e42 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-2.0.2/","dependencies":[]},{"name":"firebase_core","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.5.3/","dependencies":[]},{"name":"firebase_messaging","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-7.0.3/","dependencies":["firebase_core"]},{"name":"geocoder","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/geocoder-0.2.1/","dependencies":[]},{"name":"launch_review","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/launch_review-1.0.1/","dependencies":[]},{"name":"location","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/location-3.2.1/","dependencies":[]},{"name":"package_info","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.3+2/","dependencies":[]},{"name":"path_provider","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.24/","dependencies":[]},{"name":"share","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/share-0.5.2/","dependencies":[]},{"name":"shared_preferences","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.4.2/","dependencies":[]},{"name":"sqflite","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.2+1/","dependencies":[]},{"name":"url_launcher","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-5.7.10/","dependencies":[]}],"android":[{"name":"connectivity","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity-2.0.2/","dependencies":[]},{"name":"firebase_core","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.5.3/","dependencies":[]},{"name":"firebase_messaging","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-7.0.3/","dependencies":["firebase_core"]},{"name":"geocoder","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/geocoder-0.2.1/","dependencies":[]},{"name":"launch_review","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/launch_review-1.0.1/","dependencies":[]},{"name":"location","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/location-3.2.1/","dependencies":[]},{"name":"package_info","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.3+2/","dependencies":[]},{"name":"path_provider","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.24/","dependencies":[]},{"name":"share","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/share-0.5.2/","dependencies":[]},{"name":"shared_preferences","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.4.2/","dependencies":[]},{"name":"sqflite","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.2+1/","dependencies":[]},{"name":"url_launcher","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-5.7.10/","dependencies":[]}],"macos":[{"name":"connectivity_macos","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_macos-0.1.0+7/","dependencies":[]},{"name":"firebase_core","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.5.3/","dependencies":[]},{"name":"location","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/location-3.2.1/","dependencies":[]},{"name":"package_info","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.3+2/","dependencies":[]},{"name":"path_provider_macos","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+6/","dependencies":[]},{"name":"sqflite","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.2+1/","dependencies":[]},{"name":"url_launcher_macos","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.0.1+9/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"url_launcher_linux","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.0.1+4/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.0.4+3/","dependencies":[]},{"name":"url_launcher_windows","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.0.1+3/","dependencies":[]}],"web":[{"name":"connectivity_for_web","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/connectivity_for_web-0.3.1+4/","dependencies":[]},{"name":"firebase_core_web","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+1/","dependencies":[]},{"name":"location_web","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/location_web-1.0.1/","dependencies":[]},{"name":"url_launcher_web","path":"/home/vjrj/bin/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-0.1.5+1/","dependencies":[]}]},"dependencyGraph":[{"name":"connectivity","dependencies":["connectivity_macos","connectivity_for_web"]},{"name":"connectivity_for_web","dependencies":[]},{"name":"connectivity_macos","dependencies":[]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core"]},{"name":"geocoder","dependencies":[]},{"name":"launch_review","dependencies":[]},{"name":"location","dependencies":["location_web"]},{"name":"location_web","dependencies":[]},{"name":"package_info","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"share","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"sqflite","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web","url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2020-12-29 10:25:18.269601","version":"1.25.0-8.1.pre"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_messaging-14.9.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"geocoding_ios","path":"/home/vjrj/.pub-cache/hosted/pub.dev/geocoding_ios-2.3.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"in_app_review","path":"/home/vjrj/.pub-cache/hosted/pub.dev/in_app_review-2.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"location","path":"/home/vjrj/.pub-cache/hosted/pub.dev/location-5.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/package_info_plus-6.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/vjrj/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"sentry_flutter","path":"/home/vjrj/.pub-cache/hosted/pub.dev/sentry_flutter-7.20.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false},{"name":"share_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/share_plus-7.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/vjrj/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"/home/vjrj/.pub-cache/hosted/pub.dev/url_launcher_ios-6.4.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_messaging-14.9.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"geocoding_android","path":"/home/vjrj/.pub-cache/hosted/pub.dev/geocoding_android-3.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"in_app_review","path":"/home/vjrj/.pub-cache/hosted/pub.dev/in_app_review-2.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"location","path":"/home/vjrj/.pub-cache/hosted/pub.dev/location-5.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/package_info_plus-6.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/vjrj/.pub-cache/hosted/pub.dev/path_provider_android-2.2.22/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sentry_flutter","path":"/home/vjrj/.pub-cache/hosted/pub.dev/sentry_flutter-7.20.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false},{"name":"share_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/share_plus-7.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/vjrj/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.21/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/vjrj/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.28/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_messaging-14.9.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"in_app_review","path":"/home/vjrj/.pub-cache/hosted/pub.dev/in_app_review-2.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"location","path":"/home/vjrj/.pub-cache/hosted/pub.dev/location-5.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/package_info_plus-6.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/vjrj/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"sentry_flutter","path":"/home/vjrj/.pub-cache/hosted/pub.dev/sentry_flutter-7.20.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false},{"name":"share_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/share_plus-7.2.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/vjrj/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.6/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/home/vjrj/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/package_info_plus-6.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/vjrj/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"sentry_flutter","path":"/home/vjrj/.pub-cache/hosted/pub.dev/sentry_flutter-7.20.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false},{"name":"share_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/share_plus-7.2.2/","native_build":false,"dependencies":["url_launcher_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/vjrj/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"/home/vjrj/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_core-2.32.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/package_info_plus-6.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/vjrj/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"sentry_flutter","path":"/home/vjrj/.pub-cache/hosted/pub.dev/sentry_flutter-7.20.2/","native_build":true,"dependencies":["package_info_plus"],"dev_dependency":false},{"name":"share_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/share_plus-7.2.2/","native_build":true,"dependencies":["url_launcher_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/vjrj/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"/home/vjrj/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/connectivity_plus-5.0.2/","dependencies":[],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_core_web-2.17.5/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/vjrj/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.8.7/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"location_web","path":"/home/vjrj/.pub-cache/hosted/pub.dev/location_web-4.2.0/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/package_info_plus-6.0.0/","dependencies":[],"dev_dependency":false},{"name":"sentry_flutter","path":"/home/vjrj/.pub-cache/hosted/pub.dev/sentry_flutter-7.20.2/","dependencies":["package_info_plus"],"dev_dependency":false},{"name":"share_plus","path":"/home/vjrj/.pub-cache/hosted/pub.dev/share_plus-7.2.2/","dependencies":["url_launcher_web"],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/vjrj/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/vjrj/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.2/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":[]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"geocoding","dependencies":["geocoding_android","geocoding_ios"]},{"name":"geocoding_android","dependencies":[]},{"name":"geocoding_ios","dependencies":[]},{"name":"in_app_review","dependencies":[]},{"name":"location","dependencies":["location_web"]},{"name":"location_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sentry_flutter","dependencies":["package_info_plus"]},{"name":"share_plus","dependencies":["url_launcher_web","url_launcher_windows","url_launcher_linux"]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2026-03-05 01:45:41.023238","version":"3.41.2","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 437fd9e..43af43d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -19,7 +19,8 @@ def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { - compileSdkVersion 30 + compileSdkVersion 34 + namespace "org.comunes.fires" lintOptions { disable 'InvalidPackage' @@ -28,8 +29,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "org.comunes.fires" - minSdkVersion 16 - targetSdkVersion 30 + minSdkVersion 21 + targetSdkVersion 34 versionCode 9 versionName "1.9" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -75,9 +76,10 @@ flutter { } dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + testImplementation 'junit:junit:4.13.2' + // androidx test dependencies replace old android.support.test + androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' // implementation 'com.google.firebase:firebase-core:15.0.2' // google recommends 16 but fails because location flutter package deps in 15 } diff --git a/android/build.gradle b/android/build.gradle index 7013083..04b881b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:8.2.2' classpath 'com.google.gms:google-services:4.3.4' } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index bc6a58a..e6b38c2 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip diff --git a/ios/Flutter/ephemeral/flutter_lldb_helper.py b/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 0000000..a88caf9 --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/ios/Flutter/ephemeral/flutter_lldbinit b/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 0000000..e3ba6fb --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index a583587..abfbda7 100755 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -2,12 +2,12 @@ # This is a generated file; do not edit or check into version control. export "FLUTTER_ROOT=/home/vjrj/bin/flutter" export "FLUTTER_APPLICATION_PATH=/home/vjrj/proyectos/git-sea/fires_flutter" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_BUILD_DIR=build" -export "SYMROOT=${SOURCE_ROOT}/../build/ios" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=false" +export "TRACK_WIDGET_CREATION=true" export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.packages" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/lib/activeFires.dart b/lib/activeFires.dart index 5ae2871..d5b2189 100644 --- a/lib/activeFires.dart +++ b/lib/activeFires.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_fab_dialer/flutter_fab_dialer.dart'; import 'package:flutter_redux/flutter_redux.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:redux/redux.dart'; import 'colors.dart'; @@ -29,13 +29,13 @@ class _ViewModel { final bool isLoading; _ViewModel( - {@required this.onAdd, - @required this.onDelete, - @required this.onToggleSubs, - @required this.onTap, - @required this.onRefresh, - @required this.yourLocations, - @required this.isLoading}); + {required this.onAdd, + required this.onDelete, + required this.onToggleSubs, + required this.onTap, + required this.onRefresh, + required this.yourLocations, + required this.isLoading}); @override bool operator ==(Object other) => @@ -59,25 +59,35 @@ class ActiveFiresPage extends StatefulWidget { class _ActiveFiresPageState extends State { final GlobalKey _scaffoldKey = new GlobalKey(); - List _fabMiniMenuItemList( + List _fabMiniMenuItemList( BuildContext context, AddYourLocationFunction onAdd) { return [ - new FabMiniMenuItem.withText( - new Icon(Icons.location_searching), - fires600, - 8.0, - S.of(context).addYourCurrentPosition, - () { + SpeedDialChild( + child: const Icon(Icons.location_searching), + backgroundColor: fires600, + label: S.of(context).addYourCurrentPosition, + labelWidget: Container( + color: Colors.white, + child: Text(S.of(context).addYourCurrentPosition, + style: const TextStyle(color: Colors.black38)), + ), + onTap: () { onAddYourLocation(onAdd); }, - S.of(context).addYourCurrentPosition, - Colors.black38, - Colors.white, ), - new FabMiniMenuItem.withText(new Icon(Icons.edit_location), fires600, 8.0, - S.of(context).addSomePlace, () { - onAddOtherLocation(onAdd); - }, S.of(context).addSomePlace, Colors.black38, Colors.white) + SpeedDialChild( + child: const Icon(Icons.edit_location), + backgroundColor: fires600, + label: S.of(context).addSomePlace, + labelWidget: Container( + color: Colors.white, + child: Text(S.of(context).addSomePlace, + style: const TextStyle(color: Colors.black38)), + ), + onTap: () { + onAddOtherLocation(onAdd); + }, + ) ]; } @@ -243,9 +253,12 @@ class _ActiveFiresPageState extends State { view.onRefresh(completer); return completer.future; }), - // TODO: Evaluate: https://github.com/tiagojencmartins/unicornspeeddial - new FabDialer(_fabMiniMenuItemList(context, view.onAdd), - fires600, new Icon(Icons.add)) + SpeedDial( + icon: Icons.add, + activeIcon: Icons.close, + backgroundColor: fires600, + children: _fabMiniMenuItemList(context, view.onAdd), + ) ]) : new Center( child: new CenteredColumn(children: [ diff --git a/lib/attributionMapPlugin.dart b/lib/attributionMapPlugin.dart index b10534a..7ca7b64 100644 --- a/lib/attributionMapPlugin.dart +++ b/lib/attributionMapPlugin.dart @@ -1,36 +1,23 @@ import 'package:flutter/material.dart'; -import 'package:flutter_map/plugin_api.dart'; -class AttributionPluginOptions extends LayerOptions { +/// Attribution widget for displaying map attribution text +class AttributionPluginWidget extends StatelessWidget { final String text; - AttributionPluginOptions({this.text = ""}); -} - -class AttributionPlugin implements MapPlugin { - @override - Widget createLayer( - LayerOptions options, MapState mapState, Stream stream) { - if (options is AttributionPluginOptions) { - var style = new TextStyle( - // fontWeight: FontWeight.bold, - fontSize: 12.0, - color: Colors.white, - ); - return Padding( - padding: const EdgeInsets.all(5.0), - child: new Text( - options.text, - style: style, - ), - ); - } - throw ("Unknown options type for Attribution" - "plugin: $options"); - } + AttributionPluginWidget({this.text = ""}); @override - bool supportsLayer(LayerOptions options) { - return options is AttributionPluginOptions; + Widget build(BuildContext context) { + var style = new TextStyle( + fontSize: 12.0, + color: Colors.white, + ); + return Padding( + padding: const EdgeInsets.all(5.0), + child: new Text( + text, + style: style, + ), + ); } } diff --git a/lib/customMoment.dart b/lib/customMoment.dart index b4512a3..7625fd4 100644 --- a/lib/customMoment.dart +++ b/lib/customMoment.dart @@ -16,7 +16,7 @@ class Moment { } Moment.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch, - {bool isUtc: false}) { + {bool isUtc = false}) { _date = new DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, isUtc: isUtc); } diff --git a/lib/customStepper.dart b/lib/customStepper.dart index 4fafac3..91f4f83 100644 --- a/lib/customStepper.dart +++ b/lib/customStepper.dart @@ -70,14 +70,12 @@ class CustomStep { /// /// The [title], [content], and [state] arguments must not be null. const CustomStep({ - @required this.title, + required this.title, this.subtitle, - @required this.content, - this.state: CustomStepState.indexed, - this.isActive: false, - }) : assert(title != null), - assert(content != null), - assert(state != null); + required this.content, + this.state = CustomStepState.indexed, + this.isActive= false, + }); /// The title of the step that typically describes it. final Widget title; @@ -124,16 +122,13 @@ class CustomStepper extends StatefulWidget { /// The [steps], [type], and [currentCustomStep] arguments must not be null. CustomStepper({ Key key, - @required this.steps, - this.type: CustomStepperType.vertical, - this.currentCustomStep: 0, + required this.steps, + this.type = CustomStepperType.vertical, + this.currentCustomStep = 0, this.onCustomStepTapped, this.onCustomStepContinue, this.onCustomStepCancel, - }) : assert(steps != null), - assert(type != null), - assert(currentCustomStep != null), - assert(0 <= currentCustomStep && currentCustomStep < steps.length), + }) : assert(0 <= currentCustomStep && currentCustomStep < steps.length), super(key: key); /// The steps of the stepper whose titles, subtitles, icons always get shown. @@ -221,7 +216,6 @@ class _CustomStepperState extends State { final CustomStepState state = oldState ? _oldStates[index] : widget.steps[index].state; final bool isDarkActive = _isDark() && widget.steps[index].isActive; - assert(state != null); switch (state) { case CustomStepState.indexed: case CustomStepState.disabled: @@ -255,8 +249,8 @@ class _CustomStepperState extends State { : Colors.black38; } else { return widget.steps[index].isActive - ? themeData.accentColor - : themeData.backgroundColor; + ? themeData.colorScheme.secondary + : themeData.colorScheme.surface; } } @@ -341,7 +335,6 @@ class _CustomStepperState extends State { break; } - assert(cancelColor != null); // final ThemeData themeData = Theme.of(context); // final MaterialLocalizations localizations = @@ -379,17 +372,16 @@ class _CustomStepperState extends State { final ThemeData themeData = Theme.of(context); final TextTheme textTheme = themeData.textTheme; - assert(widget.steps[index].state != null); switch (widget.steps[index].state) { case CustomStepState.indexed: case CustomStepState.editing: case CustomStepState.complete: - return textTheme.bodyText1; + return textTheme.bodyLarge; case CustomStepState.disabled: - return textTheme.bodyText1 + return textTheme.bodyLarge .copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight); case CustomStepState.error: - return textTheme.bodyText1 + return textTheme.bodyLarge .copyWith(color: _isDark() ? _kErrorDark : _kErrorLight); } return null; @@ -399,17 +391,16 @@ class _CustomStepperState extends State { final ThemeData themeData = Theme.of(context); final TextTheme textTheme = themeData.textTheme; - assert(widget.steps[index].state != null); switch (widget.steps[index].state) { case CustomStepState.indexed: case CustomStepState.editing: case CustomStepState.complete: - return textTheme.caption; + return textTheme.bodySmall; case CustomStepState.disabled: - return textTheme.caption + return textTheme.bodySmall .copyWith(color: _isDark() ? _kDisabledDark : _kDisabledLight); case CustomStepState.error: - return textTheme.caption + return textTheme.bodySmall .copyWith(color: _isDark() ? _kErrorDark : _kErrorLight); } return null; @@ -425,18 +416,17 @@ class _CustomStepperState extends State { ), ]; - if (widget.steps[index].subtitle != null) - children.add( - new Container( - margin: const EdgeInsets.only(top: 2.0), - child: new AnimatedDefaultTextStyle( - style: _subtitleStyle(index), - duration: kThemeAnimationDuration, - curve: Curves.fastOutSlowIn, - child: widget.steps[index].subtitle, - ), + children.add( + new Container( + margin: const EdgeInsets.only(top: 2.0), + child: new AnimatedDefaultTextStyle( + style: _subtitleStyle(index), + duration: kThemeAnimationDuration, + curve: Curves.fastOutSlowIn, + child: widget.steps[index].subtitle, ), - ); + ), + ); return new Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -523,8 +513,7 @@ class _CustomStepperState extends State { duration: kThemeAnimationDuration, ); - if (widget.onCustomStepTapped != null) - widget.onCustomStepTapped(i); + widget.onCustomStepTapped(i); } : null, child: _buildVerticalHeader(i)), @@ -546,8 +535,7 @@ class _CustomStepperState extends State { new InkResponse( onTap: widget.steps[i].state != CustomStepState.disabled ? () { - if (widget.onCustomStepTapped != null) - widget.onCustomStepTapped(i); + widget.onCustomStepTapped(i); } : null, child: new Row( @@ -598,7 +586,6 @@ class _CustomStepperState extends State { new AnimatedSize( curve: Curves.fastOutSlowIn, duration: kThemeAnimationDuration, - vsync: null, child: widget.steps[widget.currentCustomStep].content, ), _buildVerticalControls(), @@ -620,7 +607,6 @@ class _CustomStepperState extends State { 'https://material.google.com/components/steppers.html#steppers-usage\n'); return true; }()); - assert(widget.type != null); switch (widget.type) { case CustomStepperType.vertical: return _buildVertical(); diff --git a/lib/dummyMapPlugin.dart b/lib/dummyMapPlugin.dart index 6a1df20..52a1218 100644 --- a/lib/dummyMapPlugin.dart +++ b/lib/dummyMapPlugin.dart @@ -1,26 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_map/plugin_api.dart'; -class DummyMapPluginOptions extends LayerOptions { - final String text; - - DummyMapPluginOptions({this.text = ""}); -} - -// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart -class DummyMapPlugin extends MapPlugin { +/// Dummy/placeholder widget for map plugins +class DummyMapPluginWidget extends StatelessWidget { @override - Widget createLayer( - LayerOptions options, MapState mapState, Stream stream) { - if (options is DummyMapPluginOptions) { - return const SizedBox(); - } - throw ("Unknown options type for DummyMapPlugin" - "plugin: $options"); - } - - @override - bool supportsLayer(LayerOptions options) { - return options is DummyMapPluginOptions; + Widget build(BuildContext context) { + return const SizedBox(); } } diff --git a/lib/fileUtils.dart b/lib/fileUtils.dart index 8950bab..007191d 100644 --- a/lib/fileUtils.dart +++ b/lib/fileUtils.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/services.dart' show rootBundle; -import 'package:meta/meta.dart'; final esRegExp = new RegExp("^es-"); @@ -18,10 +17,10 @@ String getFallbackLang(String lang) { } Future getFileNameOfLang( - {@required String dir, - @required String fileName, - @required String ext, - @required String lang}) async { + {required String dir, + required String fileName, + required String ext, + required String lang}) async { String base = '$dir/$fileName'; String fallback = getFallbackLang(lang); String file = '$base-$lang.$ext'; diff --git a/lib/fireAlert.dart b/lib/fireAlert.dart index 87bb76b..4418a41 100644 --- a/lib/fireAlert.dart +++ b/lib/fireAlert.dart @@ -1,7 +1,7 @@ import 'package:community_material_icon/community_material_icon.dart'; import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:share/share.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import 'customStepper.dart'; @@ -61,7 +61,7 @@ class _FireAlertState extends State { String where = yourLocation.description.replaceAll(' ', '').split(',')[0]; print(where); - Share.share(S + Share.shareWithResult(S .of(context) .tweetAboutSelf(yourLocation.description, '#IF$where')); }).catchError((onError) { diff --git a/lib/fireMarker.dart b/lib/fireMarker.dart index df4f584..b156499 100644 --- a/lib/fireMarker.dart +++ b/lib/fireMarker.dart @@ -1,34 +1,46 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map/plugin_api.dart'; -import 'package:latlong/latlong.dart'; +import 'package:latlong2/latlong.dart'; import 'fireMarkType.dart'; import 'fireMarkerIcon.dart'; -class FireMarker extends Marker { - FireMarker(LatLng pos, type, - [onTap, - // AnchorPos anchor = AnchorPos.center, - Anchor anchorOverride]) - : super( - width: 80.0, - height: 80.0, - point: pos, - builder: (ctx) => new Container( - child: new GestureDetector( - child: new FireMarkerIcon(type), onTap: onTap)), - // anchor: anchor, - anchorPos: anchorOverride ?? type == FireMarkType.position - ? AnchorPos.exactly(new Anchor(40.0, 20.0)) - : type == FireMarkType.fire - ? AnchorPos.exactly(new Anchor(40.0, 24.0)) - : type == FireMarkType.pixel - ? null // auto calculate with height/width in Marker - // industries, etc (below) - // FIXME check if this is accurate - : AnchorPos.exactly(new Anchor(40.0, 35.0)), - ) { - // anchor = anchorOverride; +/// Create a Marker with custom positioning for fires and other map objects +Marker FireMarker( + LatLng pos, + FireMarkType type, [ + VoidCallback? onTap, +]) { + // Calculate offset based on marker type + // Anchor point for center of marker: (40, calculated_y) + final Offset offset = _getAnchorOffset(type); + + return Marker( + point: pos, + width: 80.0, + height: 80.0, + alignment: Alignment.center, + child: GestureDetector( + onTap: onTap, + child: FireMarkerIcon(type), + ), + ); +} + +/// Get the anchor offset based on marker type +Offset _getAnchorOffset(FireMarkType type) { + switch (type) { + case FireMarkType.position: + return Offset(40.0, 20.0); + case FireMarkType.fire: + return Offset(40.0, 24.0); + case FireMarkType.pixel: + // Auto-calculate based on marker size + return Offset(40.0, 40.0); + case FireMarkType.falsePos: + case FireMarkType.industry: + return Offset(40.0, 35.0); + default: + return Offset(40.0, 40.0); } } diff --git a/lib/fireNotificationList.dart b/lib/fireNotificationList.dart index dfb5d6d..5e76a7a 100644 --- a/lib/fireNotificationList.dart +++ b/lib/fireNotificationList.dart @@ -26,13 +26,13 @@ class _ViewModel { final DeleteAllFireNotificationFunction onDeleteAll; _ViewModel( - {@required this.isLoaded, - @required this.onTap, - @required this.onDelete, - @required this.onDeleteAll, - @required this.fireNotifications, - @required this.yourLocations, - @required this.fireNotificationsUnread}); + {required this.isLoaded, + required this.onTap, + required this.onDelete, + required this.onDeleteAll, + required this.fireNotifications, + required this.yourLocations, + required this.fireNotificationsUnread}); @override bool operator ==(Object other) => @@ -66,13 +66,11 @@ class _FireNotificationListState extends State { FireNotification notif, onDeleted, onTap) { String prefix = ""; - if (notif.subsId != null) { - // 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); - prefix = '${yl.description}. '; - } - + // 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); + prefix = '${yl.description}. '; + return new ListTile( dense: true, leading: const Icon(Icons.whatshot), diff --git a/lib/firesApp.dart b/lib/firesApp.dart index 4952e66..cdff6db 100644 --- a/lib/firesApp.dart +++ b/lib/firesApp.dart @@ -14,7 +14,6 @@ import 'introPage.dart'; import 'models/appState.dart'; import 'monitoredAreas.dart'; import 'privacyPage.dart'; -import 'redux/actions.dart'; import 'sandbox.dart'; import 'supportPage.dart'; import 'theme.dart'; @@ -73,10 +72,6 @@ class _FiresAppState extends State { home: home, onGenerateTitle: (context) { print('MaterialApp onGenerateTitle'); - if (store.state.user.lang == null) { - String lang = Localizations.localeOf(context).languageCode; - this.store.dispatch(new OnUserLangAction(lang)); - } return S.of(context).appName; }, theme: isDevelopment ? devFiresTheme : firesTheme, diff --git a/lib/genericMap.dart b/lib/genericMap.dart index 6f181ac..843ff99 100644 --- a/lib/genericMap.dart +++ b/lib/genericMap.dart @@ -4,10 +4,9 @@ import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map/plugin_api.dart'; import 'package:flutter_redux/flutter_redux.dart'; -import 'package:latlong/latlong.dart'; -import 'package:share/share.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:share_plus/share_plus.dart'; import 'attributionMapPlugin.dart'; import 'colors.dart'; @@ -44,19 +43,19 @@ class _ViewModel { final OnFirePressedInMap onFirePressed; _ViewModel( - {@required this.mapState, - @required this.serverUrl, - @required this.lang, - @required this.onSubs, - @required this.onSubsConfirmed, - @required this.onUnSubs, - @required this.onSlide, - @required this.onEdit, - @required this.onEditing, - @required this.onEditConfirm, - @required this.onFalsePositive, - @required this.onFirePressed, - @required this.onEditCancel}); + {required this.mapState, + required this.serverUrl, + required this.lang, + required this.onSubs, + required this.onSubsConfirmed, + required this.onUnSubs, + required this.onSlide, + required this.onEdit, + required this.onEditing, + required this.onEditConfirm, + required this.onFalsePositive, + required this.onFirePressed, + required this.onEditCancel}); @override bool operator ==(Object other) => @@ -81,15 +80,15 @@ class _genericMapState extends State { // https://github.com/flutter/flutter/issues/1632#issuecomment-180478202 final GlobalKey _scaffoldKey = new GlobalKey(); - YourLocation _location; - YourLocation _initialLocation; + YourLocation? _location; + YourLocation? _initialLocation; @override Widget build(BuildContext context) { return new StoreConnector( distinct: true, onInitialBuild: (store) { - _initialLocation = _location.copyWith(); + _initialLocation = _location?.copyWith(); }, converter: (store) { print('New map viewer'); @@ -132,9 +131,8 @@ class _genericMapState extends State { builder: (context, view) { YourLocation location = view.mapState.yourLocation; _location = location.copyWith(); - print('New map builder with ${_location.description}'); + print('New map builder with ${_location?.description}'); - assert(_location != null); FireMapState mapState = view.mapState; FireMapStatus status = mapState.status; FireMapLayer layer = mapState.layer; @@ -143,27 +141,13 @@ class _genericMapState extends State { double maxZoom = 18.0; // works? MapOptions mapOptions = new MapOptions( - center: new LatLng(_location.lat, _location.lon), - plugins: globals.isDevelopment - ? [ - new ZoomMapPlugin(), - new AttributionPlugin(), - new LayerSelectorMapPlugin() - ] - : [ - new DummyMapPlugin(), - new AttributionPlugin(), - new LayerSelectorMapPlugin() - ], - // this works ? - interactive: true, - zoom: 13.0, - // THIS does not works as expected + initialCenter: new LatLng(_location!.lat, _location!.lon), + initialZoom: 13.0, maxZoom: maxZoom, - onTap: (callback) { + onTap: (tapPosition, latLng) { if (status == FireMapStatus.edit) { - _location = _location.copyWith( - lat: callback.latitude, lon: callback.longitude); + _location = _location! + .copyWith(lat: latLng.latitude, lon: latLng.longitude); view.onEditing(_location); } }, @@ -225,9 +209,8 @@ class _genericMapState extends State { } FlutterMap map = new FlutterMap( options: mapOptions, - mapController: mapController, - layers: [ - new TileLayerOptions( + children: [ + new TileLayer( maxZoom: maxZoom, urlTemplate: baseLayer, subdomains: subdomains, @@ -236,9 +219,9 @@ class _genericMapState extends State { }, ), globals.isDevelopment - ? new ZoomMapPluginOptions() - : new DummyMapPluginOptions(), - new MarkerLayerOptions( + ? new ZoomMapPluginWidget() + : new DummyMapPluginWidget(), + new MarkerLayer( markers: buildMarkers( mapState.status == FireMapStatus.viewFireNotification ? new LatLng(mapState.fireNotification.lat, @@ -250,9 +233,9 @@ class _genericMapState extends State { mapState.status == FireMapStatus.viewFireNotification, view.onFirePressed), ), - // new AttributionPluginOptions(text: "© OpenStreetMap contributors"), - new LayerSelectorMapPluginOptions(), - new AttributionPluginOptions(text: attribution), + // new AttributionPluginWidget(text: "© OpenStreetMap contributors"), + new LayerSelectorMapPluginWidget(), + new AttributionPluginWidget(text: attribution), ], ); // mapController. @@ -264,7 +247,7 @@ class _genericMapState extends State { // Do something with it return new Scaffold( key: _scaffoldKey, - resizeToAvoidBottomPadding: true, + resizeToAvoidBottomInset: true, appBar: new AppBar( title: status == FireMapStatus.edit ? new TextField( @@ -416,9 +399,9 @@ class _genericMapState extends State { var loc = LatLng(coords[1].toDouble(), coords[0].toDouble()); markers.add(FireMarker(loc, FireMarkType.falsePos)); if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel)); - } catch (e) { + } catch (e, stackTrace) { print('Failed to process $falsePos'); - reportError(e, e.stackTrace); + reportError(e, stackTrace); } }); industries.forEach((industry) { @@ -428,9 +411,9 @@ class _genericMapState extends State { var loc = LatLng(coords[1], coords[0]); markers.add(FireMarker(loc, FireMarkType.industry)); if (calibrate) markers.add(FireMarker(loc, FireMarkType.pixel)); - } catch (e) { + } catch (e, stackTrace) { print('Failed to process $industry'); - reportError(e, e.stackTrace); + reportError(e, stackTrace); } }); fires.forEach((fire) { @@ -441,9 +424,9 @@ class _genericMapState extends State { print('fire $fire pressed'); })); markers.add(FireMarker(loc, FireMarkType.pixel)); - } catch (e) { + } catch (e, stackTrace) { print('Failed to process $fire'); - reportError(e, e.stackTrace); + reportError(e, stackTrace); } }); markers.add( @@ -462,11 +445,11 @@ class _genericMapState extends State { String fireDesc = S.of(context).additionalInfoAboutFire(reverseLoc, when, by); showDialog( - context: _scaffoldKey.currentContext, + context: _scaffoldKey.currentContext!, builder: (_) => new AlertDialog( content: new Text(fireDesc), actions: [ - new FlatButton( + new TextButton( child: Text(S.of(context).CLOSE), onPressed: () { Navigator.pop(context); diff --git a/lib/genericMapBottom.dart b/lib/genericMapBottom.dart index 8457687..6517127 100644 --- a/lib/genericMapBottom.dart +++ b/lib/genericMapBottom.dart @@ -25,11 +25,11 @@ class GenericMapBottom extends StatelessWidget { final GlobalKey scaffoldKey; GenericMapBottom( - {@required this.onSave, - @required this.onCancel, - @required this.onFalsePositive, - @required this.state, - @required this.scaffoldKey}); + {required this.onSave, + required this.onCancel, + required this.onFalsePositive, + required this.state, + required this.scaffoldKey}); @override Widget build(BuildContext context) { @@ -51,11 +51,11 @@ class GenericMapBottom extends StatelessWidget { actionList.add(new FlatButton( onPressed: onSave, child: new Text(S.of(context).SAVE, - style: Theme.of(context).textTheme.button))); + style: Theme.of(context).textTheme.labelLarge))); actionList.add(new FlatButton( onPressed: onCancel, child: new Text(S.of(context).CANCEL, - style: Theme.of(context).textTheme.button))); + style: Theme.of(context).textTheme.labelLarge))); break; case FireMapStatus.subscriptionConfirm: break; @@ -122,16 +122,14 @@ class GenericMapBottom extends StatelessWidget { break; case FireMapStatus.unsubscribe: case FireMapStatus.view: - if (state.numFires != null) { - actionList.add(new Text(state.numFires > 0 - ? loc.currentNumFires == 1 - ? S.of(context).fireAroundThisArea(loc.distance.toString()) - : S.of(context).firesAroundThisArea( - state.numFires.toString(), kmAround.toString()) - : S.of(context).noFiresAroundThisArea(kmAround.toString()))); - // SizedBox(width: 10.0) - } - } + actionList.add(new Text(state.numFires > 0 + ? loc.currentNumFires == 1 + ? S.of(context).fireAroundThisArea(loc.distance.toString()) + : S.of(context).firesAroundThisArea( + state.numFires.toString(), kmAround.toString()) + : S.of(context).noFiresAroundThisArea(kmAround.toString()))); + // SizedBox(width: 10.0) + } return actionList; } } diff --git a/lib/globalFiresBottomStats.dart b/lib/globalFiresBottomStats.dart index 1014ea7..4b7c2d7 100644 --- a/lib/globalFiresBottomStats.dart +++ b/lib/globalFiresBottomStats.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_simple_dependency_injection/injector.dart'; +import 'package:get_it/get_it.dart'; import 'package:http/http.dart' as http; import 'colors.dart'; @@ -18,7 +18,7 @@ class GlobalFiresBottomStats extends StatefulWidget { class _GlobalFiresBottomStatsState extends State { String lastCheck; int activeFires = 0; - final firesApiUrl = Injector.getInjector().get(key: "firesApiUrl"); + final firesApiUrl = GetIt.instance(instanceName: "firesApiUrl"); @override void initState() { @@ -54,7 +54,7 @@ class _GlobalFiresBottomStatsState extends State { color: fires100, mainAxisAlignment: MainAxisAlignment.center, actions: listWithoutNulls([ - activeFires > 0 && lastCheck != null + activeFires > 0 ? new Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/homePage.dart b/lib/homePage.dart index d03bb27..bf035fe 100644 --- a/lib/homePage.dart +++ b/lib/homePage.dart @@ -1,14 +1,14 @@ import 'dart:async'; import 'package:comunes_flutter/comunes_flutter.dart'; -import 'package:connectivity/connectivity.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:flutter_simple_dependency_injection/injector.dart'; +import 'package:get_it/get_it.dart'; import 'package:redux/redux.dart'; import 'activeFires.dart'; @@ -24,7 +24,7 @@ import 'redux/actions.dart'; class _ViewModel { final bool isLoaded; - _ViewModel({@required this.isLoaded}); + _ViewModel({required this.isLoaded}); @override bool operator ==(Object other) => @@ -48,7 +48,7 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { final GlobalKey _scaffoldKey = new GlobalKey(); - final Store store = Injector.getInjector().get>(); + final Store store = GetIt.instance>(); final Connectivity _connectivity = new Connectivity(); final List newNotifications = []; @@ -104,7 +104,6 @@ class _HomePageState extends State { print("Settings registered: $settings"); }); _firebaseMessaging.getToken().then((String token) { - assert(token != null); // print(token); store.dispatch(new OnUserTokenAction(token)); setState(() {}); @@ -302,13 +301,12 @@ class _HomePageState extends State { } catch (e) { debugPrint(e.toString()); } - if (notif != null) // if our store is loaded, we just dispatch the notification, if not, we wait til is loaded - if (isLoaded) { - store.dispatch(new AddFireNotificationAction(notif)); - } else { - newNotifications.add(notif); - } + if (isLoaded) { + store.dispatch(new AddFireNotificationAction(notif)); + } else { + newNotifications.add(notif); + } return notif; } } diff --git a/lib/layerSelectorMapPlugin.dart b/lib/layerSelectorMapPlugin.dart index 084c989..3ce6291 100644 --- a/lib/layerSelectorMapPlugin.dart +++ b/lib/layerSelectorMapPlugin.dart @@ -1,59 +1,42 @@ import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_map/plugin_api.dart'; -import 'package:flutter_simple_dependency_injection/injector.dart'; +import 'package:get_it/get_it.dart'; import 'package:redux/redux.dart'; import 'models/appState.dart'; import 'redux/actions.dart'; -class LayerSelectorMapPluginOptions extends LayerOptions { - final String text; +/// Layer selector widget for changing map layers +class LayerSelectorMapPluginWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + Store store = GetIt.instance>(); + return LayoutBuilder( + builder: (context, constraints) => + Stack(fit: StackFit.expand, children: [ + Positioned( + top: constraints.maxHeight - 60, + left: 10.0, + child: new CenteredRow( + children: [ + new Column( + children: [_LayerSelectorButton(store)], + ) + ], + ), + ) + ])); + } - LayerSelectorMapPluginOptions({this.text = ""}); -} - -// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart -class LayerSelectorMapPlugin extends MapPlugin { - Widget LayerSelectorButton(Store store) { + Widget _LayerSelectorButton(Store store) { return new FloatingActionButton( backgroundColor: Colors.black26, mini: true, child: Icon( - Icons.layers, /* size: 40.0, color: Colors.black45, */ + Icons.layers, ), onPressed: () { store.dispatch(new ToggleMapLayerAction()); }); } - - @override - Widget createLayer( - LayerOptions options, MapState mapState, Stream stream) { - Store store = Injector.getInjector().get>(); - if (options is LayerSelectorMapPluginOptions) { - return LayoutBuilder( - builder: (context, constraints) => - Stack(fit: StackFit.expand, children: [ - Positioned( - top: constraints.maxHeight - 60, - left: 10.0, - child: new CenteredRow( - children: [ - new Column( - children: [LayerSelectorButton(store)], - ) - ], - ), - ) - ])); - } - throw ("Unknown options type for LayerSelectorMapPlugin" - "plugin: $options"); - } - - @override - bool supportsLayer(LayerOptions options) { - return options is LayerSelectorMapPluginOptions; - } } diff --git a/lib/locationUtils.dart b/lib/locationUtils.dart index 29fc522..1fa49f0 100644 --- a/lib/locationUtils.dart +++ b/lib/locationUtils.dart @@ -3,8 +3,7 @@ import 'dart:async'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_simple_dependency_injection/injector.dart'; -import 'package:geocoder/geocoder.dart'; +import 'package:geocoding/geocoding.dart' as geo; import 'package:location/location.dart'; import 'generated/i18n.dart'; @@ -49,13 +48,21 @@ Future getUserLocation( } Future getReverseLocation( - {@required lat, @required lon, bool external = false}) async { - final coordinates = new Coordinates(lat, lon); - var geoCoder = external - ? Geocoder.google(Injector.getInjector().get(key: "gmapKey")) - : Geocoder.local; - var addresses = await geoCoder.findAddressesFromCoordinates(coordinates); - var first = addresses.first; - print("${first.featureName} : ${first.addressLine}"); - return first.addressLine; + {required double lat, required double lon, bool external = false}) async { + try { + List placemarks = + await geo.placemarkFromCoordinates(lat, lon); + if (placemarks.isNotEmpty) { + var first = placemarks.first; + String address = + '${first.street}, ${first.locality}, ${first.administrativeArea}, ${first.country}'; + print("${first.name} : $address"); + return address; + } else { + return 'Unable to determine address'; + } + } catch (e) { + print("Error in reverse geocoding: $e"); + throw Exception("Failed to reverse geocode: $e"); + } } diff --git a/lib/mainCommon.dart b/lib/mainCommon.dart index 3b6876e..023e317 100644 --- a/lib/mainCommon.dart +++ b/lib/mainCommon.dart @@ -2,10 +2,9 @@ import 'dart:async'; import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_simple_dependency_injection/injector.dart'; -import 'package:package_info/package_info.dart'; +import 'package:get_it/get_it.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:redux/redux.dart'; -import 'package:sentry/sentry.dart'; import 'firesApp.dart'; import 'globals.dart' as globals; @@ -30,38 +29,37 @@ Future> loadSecrets() async { void mainCommon(List> otherMiddleware) { WidgetsFlutterBinding.ensureInitialized(); - final injector = Injector.getInjector(); - injector.map((i) => new FiresApi(), isSingleton: true); + final getIt = GetIt.instance; + getIt.registerSingleton(FiresApi()); loadPackageInfo().then((packageInfo) { globals.appVersion = packageInfo.version; print('Running version ${packageInfo.version}'); loadSecrets().then((secrets) { - final store = new Store(appStateReducer, - initialState: new AppState( + final store = Store(appStateReducer, + initialState: AppState( gmapKey: secrets['gmapKey'], firesApiKey: secrets['firesApiKey'], serverUrl: secrets['firesApiUrl'], firesApiUrl: secrets['firesApiUrl'] + "api/v1/"), middleware: List.from(otherMiddleware)..add(fetchDataMiddleware)); - injector.map>((i) => store); - injector.map((i) => store.state.firesApiUrl, key: "firesApiUrl"); - injector.map((i) => store.state.firesApiKey, key: "firesApiKey"); - injector.map((i) => store.state.serverUrl, key: "serverUrl"); - injector.map((i) => store.state.gmapKey, key: "gmapKey"); - - if (useSentry) { - SentryClient _sentry = SentryClient(dsn: secrets['sentryDSN']); - injector.map((i) => _sentry); - } + getIt.registerSingleton>(store); + getIt.registerSingleton(store.state.firesApiUrl, + instanceName: "firesApiUrl"); + getIt.registerSingleton(store.state.firesApiKey, + instanceName: "firesApiKey"); + getIt.registerSingleton(store.state.serverUrl, + instanceName: "serverUrl"); + getIt.registerSingleton(store.state.gmapKey, + instanceName: "gmapKey"); // https://flutter.io/cookbook/maintenance/error-reporting/ runZonedGuarded>(() async { - runApp(new FiresApp(store)); - }, (Object error, StackTrace stackTrace) { + runApp(FiresApp(store)); + }, (Object error, StackTrace? stackTrace) { // Whenever an error occurs, call the `_reportError` function. This will send // Dart errors to our dev console or Sentry depending on the environment. - reportError(error, stackTrace); + reportError(error, stackTrace ?? StackTrace.current); }); // Listen to store changes, and re-render when the state is updated @@ -75,7 +73,8 @@ void mainCommon(List> otherMiddleware) { } else { // In production mode report to the application zone to report to // Sentry. - Zone.current.handleUncaughtError(details.exception, details.stack); + Zone.current.handleUncaughtError( + details.exception, details.stack ?? StackTrace.current); } }; }); diff --git a/lib/mainDev.dart b/lib/mainDev.dart index a3c155b..12ce98e 100644 --- a/lib/mainDev.dart +++ b/lib/mainDev.dart @@ -1,54 +1,28 @@ import 'package:flutter/material.dart'; -import 'package:logging/logging.dart'; import 'package:redux/redux.dart'; -import 'package:redux_logging/redux_logging.dart'; import 'globals.dart' as globals; import 'mainCommon.dart'; enum LogLevel { none, actions, all } -LoggingMiddleware customLogPrinter({ - Logger logger, - Level level = Level.INFO, - MessageFormatter formatter = LoggingMiddleware.singleLineFormatter, -}) { - final middleware = new LoggingMiddleware( - logger: logger, - level: level, - formatter: formatter, - ); - - middleware.logger.onRecord - .where((record) => record.loggerName == middleware.logger.name) - .listen((Object object) { - debugPrint("$object"); - }); - - return middleware; -} - -void main() { +void main() async { globals.isDevelopment = true; - print("Is development!"); - String onlyLogActionFormatter( - State state, - dynamic action, - DateTime timestamp, - ) { - return ">>>>> ${action.toString().replaceAll('Instance of ', '')}"; + debugPrint("Is development!"); + + // Simple logging middleware para desarrollo + Middleware createLoggingMiddleware() { + return (Store store, dynamic action, NextDispatcher next) { + debugPrint(">>>>> ${action.toString().replaceAll('Instance of ', '')}"); + next(action); + }; } LogLevel logRedux = LogLevel.actions; - List devMiddlewares = logRedux == LogLevel.actions - ? [] - : [ - customLogPrinter( - formatter: logRedux == LogLevel.all - ? LoggingMiddleware.multiLineFormatter - : onlyLogActionFormatter) - ]; + List> devMiddlewares = + logRedux == LogLevel.actions ? [] : [createLoggingMiddleware()]; + // In development, Sentry is disabled, so we skip initialization mainCommon(devMiddlewares); } diff --git a/lib/mainDrawer.dart b/lib/mainDrawer.dart index da2cd21..6391ebd 100644 --- a/lib/mainDrawer.dart +++ b/lib/mainDrawer.dart @@ -20,7 +20,7 @@ class _ViewModel { final int unreadCount; _ViewModel({ - @required this.unreadCount, + required this.unreadCount, }); @override diff --git a/lib/mainProd.dart b/lib/mainProd.dart index d9d5125..9aad123 100644 --- a/lib/mainProd.dart +++ b/lib/mainProd.dart @@ -1,7 +1,27 @@ +import 'package:comunes_flutter/comunes_flutter.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + import 'globals.dart' as globals; import 'mainCommon.dart'; -void main() { +Future main() async { globals.isDevelopment = false; - mainCommon([]); -} \ No newline at end of file + + // Load secrets to get Sentry DSN + final secrets = await loadSecrets(); + + await SentryFlutter.init( + (options) { + options.dsn = secrets['sentryDSN']; + }, + appRunner: () => mainCommon([]), + ); +} + +Future> loadSecrets() async { + return await SecretLoader( + secretPath: globals.isDevelopment + ? 'assets/private-settings-dev.json' + : 'assets/private-settings.json') + .load(); +} diff --git a/lib/models/appState.dart b/lib/models/appState.dart index 679eb62..80c1236 100644 --- a/lib/models/appState.dart +++ b/lib/models/appState.dart @@ -52,12 +52,12 @@ class AppState { _$AppStateFromJson(json); AppState( - {this.yourLocations: const [], - this.fireNotifications: const [], - this.fireNotificationsUnread: 0, - this.user: const User.initial(), - this.isLoading: false, - this.isLoaded: false, + {this.yourLocations = const [], + this.fireNotifications = const [], + this.fireNotificationsUnread = 0, + this.user = const User.initial(), + this.isLoading = false, + this.isLoaded= false, this.error, this.gmapKey, this.firesApiKey, @@ -65,7 +65,7 @@ class AppState { this.serverUrl, this.connectivity, this.monitoredAreas, - this.fireMapState: const FireMapState.initial()}); + this.fireMapState = const FireMapState.initial()}); AppState copyWith( {bool isLoading, diff --git a/lib/models/basicLocation.dart b/lib/models/basicLocation.dart index c7fe60d..1b5803d 100644 --- a/lib/models/basicLocation.dart +++ b/lib/models/basicLocation.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; class BasicLocation extends Comparable { final double lat; @@ -7,9 +6,8 @@ class BasicLocation extends Comparable { // static BasicLocation noLocation = new BasicLocation(lat: 0.0, lon: 0.0); - BasicLocation({@required this.lat, @required this.lon, this.description}) { - if (this.description == null) - this.description = 'Position: ${this.lat}, ${this.lon}'; + BasicLocation({required this.lat, required this.lon, this.description}) { + } int compareTo(BasicLocation other) { diff --git a/lib/models/fireMapState.dart b/lib/models/fireMapState.dart index f804988..1750cb8 100644 --- a/lib/models/fireMapState.dart +++ b/lib/models/fireMapState.dart @@ -33,8 +33,8 @@ class FireMapState { this.industries = const []; FireMapState( - {this.status: FireMapStatus.view, - this.layer: FireMapLayer.osmcGrey, + {this.status = FireMapStatus.view, + this.layer =FireMapLayer.osmcGrey, this.yourLocation, this.numFires, this.fires, diff --git a/lib/models/fireNotification.dart b/lib/models/fireNotification.dart index 72c0de9..c814868 100644 --- a/lib/models/fireNotification.dart +++ b/lib/models/fireNotification.dart @@ -25,14 +25,14 @@ class FireNotification { FireNotification( {this.id, - @required this.lat, - @required this.lon, - @required this.description, - @required this.when, - @required this.read, - @required this.sealed, - @required this.subsId}) { - if (this.id == null) this.id = new ObjectId(); + required this.lat, + required this.lon, + required this.description, + required this.when, + required this.read, + required this.sealed, + required this.subsId}) { + } FireNotification copyWith( diff --git a/lib/models/fireNotificationsPersist.dart b/lib/models/fireNotificationsPersist.dart index 82ac90d..c9f8086 100644 --- a/lib/models/fireNotificationsPersist.dart +++ b/lib/models/fireNotificationsPersist.dart @@ -12,18 +12,11 @@ Future> loadFireNotifications() async { return await globals.prefs.then((prefs) { List FireNotifications = prefs.getStringList(fireNotificationKey); List persistedList = []; - if (FireNotifications == null) { - FireNotifications = []; - // first run, init with empty list - persistFireNotifications(persistedList); - } - if (FireNotifications is List) { - FireNotifications.forEach((notificationString) { - Map notificationMap = json.decode(notificationString); - persistedList.add(FireNotification.fromJson(notificationMap)); - }); - } - return persistedList; + FireNotifications.forEach((notificationString) { + Map notificationMap = json.decode(notificationString); + persistedList.add(FireNotification.fromJson(notificationMap)); + }); + return persistedList; }); } diff --git a/lib/models/firesApi.dart b/lib/models/firesApi.dart index ac2b0b5..5dce892 100644 --- a/lib/models/firesApi.dart +++ b/lib/models/firesApi.dart @@ -1,12 +1,11 @@ import 'dart:async'; import 'dart:convert'; +import 'package:dio/dio.dart'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:http/http.dart' as ht; -import 'package:jaguar_resty/jaguar_resty.dart' as resty; -import 'package:latlong/latlong.dart'; +import 'package:latlong2/latlong.dart'; import '../globals.dart' as globals; import '../objectIdUtils.dart'; @@ -15,16 +14,14 @@ import 'appState.dart'; import 'falsePositiveTypes.dart'; class FiresApi { + late final Dio _dio; + FiresApi() { - resty.globalClient = new ht.IOClient(); + _dio = Dio(); } Future createUser( AppState state, String mobileToken, String lang) async { - assert(state.firesApiUrl != null); - assert(state.firesApiKey != null); - assert(mobileToken != null); - assert(lang != null); final params = { "token": state.firesApiKey, @@ -32,16 +29,16 @@ class FiresApi { "lang": lang }; final String url = '${state.firesApiUrl}mobile/users'; - /* print(url); - print(params); */ - return await resty.post(url).json(params).go().then((response) { + try { + final response = await _dio.post(url, data: params); if (response.statusCode == 200) { - // print(response.body); - return json.decode(response.body)['data']['userId']; + return response.data['data']['userId']; } else { - return throw "Unexpected error on create user"; + throw "Unexpected error on create user"; } - }); + } catch (e) { + throw "Error creating user: $e"; + } } Future> fetchYourLocations(AppState state) async { @@ -49,18 +46,16 @@ class FiresApi { final mobileToken = state.user.token; final String url = '${state.firesApiUrl}mobile/subscriptions/all/$apiKey/$mobileToken'; - // if (globals.isDevelopment) print('$url'); - return await resty.get(url).go().then((response) { + try { + final response = await _dio.get(url); if (response.statusCode == 200) { - // if (globals.isDevelopment) print(response.body); - final dataSubscriptions = - json.decode(response.body)['data']['subscriptions']; + final dataSubscriptions = response.data['data']['subscriptions']; List subscribed = []; for (int i = 0; i < dataSubscriptions.length; i++) { var el = dataSubscriptions[i]; var lat = el['location']['lat']; var lon = el['location']['lon']; - subscribed.add(new YourLocation( + subscribed.add(YourLocation( id: objectIdFromJson(el['_id']['_str']), lat: lat, lon: lon, @@ -69,20 +64,14 @@ class FiresApi { } return subscribed; } else { - return throw "Unexpected error fetching your locations"; + throw "Unexpected error fetching your locations"; } - }); + } catch (e) { + throw "Error fetching locations: $e"; + } } Future subscribe(AppState state, YourLocation loc) async { - assert(state.firesApiUrl != null); - assert(state.firesApiKey != null); - assert(state.user.token != null); - assert(loc != null); - assert(loc.lat != null); - assert(loc.lon != null); - assert(loc.id != null); - assert(loc.distance != null); final params = { "token": state.firesApiKey, "mobileToken": state.user.token, @@ -92,47 +81,48 @@ class FiresApi { "distance": loc.distance }; final String url = '${state.firesApiUrl}mobile/subscriptions'; - return await resty.post(url).json(params).go().then((response) { + try { + final response = await _dio.post(url, data: params); if (response.statusCode == 200) { - // print(response.body); - return json.decode(response.body)['data']['subsId']; + return response.data['data']['subsId']; } else { - // take care of? "Unexpected error in REST call: Error: The user is already subscribed to this area [on-already-subscribed]" - print(response.body); - return throw "Unexpected error on subscribe"; + print(response.data); + throw "Unexpected error on subscribe"; } - }); + } catch (e) { + throw "Error subscribing: $e"; + } } Future unsubscribe(AppState state, String subsId) async { - assert(state.firesApiUrl != null); - assert(state.firesApiKey != null); - assert(state.user.token != null); final apiKey = state.firesApiKey; final mobileToken = state.user.token; - assert(subsId != null); final String url = '${state.firesApiUrl}mobile/subscriptions/$apiKey/$mobileToken/$subsId'; - return await resty.delete(url).go().then((response) { + try { + final response = await _dio.delete(url); if (response.statusCode == 200) { - // print(response.body); return true; } else { - return throw "Unexpected error on unsubscribe"; + throw "Unexpected error on unsubscribe"; } - }); + } catch (e) { + throw "Error unsubscribing: $e"; + } } Future getFiresInLocation( - {AppState state, double lat, double lon, int distance}) async { - assert(state.firesApiUrl != null); - assert(state.firesApiKey != null); + {required AppState state, + required double lat, + required double lon, + required int distance}) async { var url = '${state.firesApiUrl}fires-in-full/${state.firesApiKey}/$lat/$lon/$distance'; if (globals.isDevelopment) print(url); - return await resty.get(url).go().then((response) { + try { + final response = await _dio.get(url); if (response.statusCode == 200) { - var resultDecoded = json.decode(response.body); + var resultDecoded = response.data; int numFires = resultDecoded['real']; List fires = resultDecoded['fires']; List falsePos = resultDecoded['falsePos']; @@ -145,26 +135,26 @@ class FiresApi { print( '(Pos: $lat, $lon) real: $numFires, fire: $firesCount falsePos: $falsePosCount industries: $industriesCount'); } - return new UpdateFireMapStatsAction( + return UpdateFireMapStatsAction( numFires: numFires, fires: fires, falsePos: falsePos, industries: industries); } else throw Exception('Wrong response trying to get fire data'); - }); + } catch (e) { + throw Exception('Error getting fires: $e'); + } } - Future> getMonitoredAreas({AppState state}) async { - assert(state.firesApiUrl != null); - assert(state.firesApiKey != null); + Future> getMonitoredAreas({required AppState state}) async { var url = '${state.firesApiUrl}status/subs-public-union/${state.firesApiKey}'; var color = const Color(0xFF145A32); - return await resty.get(url).go().then((response) { + try { + final response = await _dio.get(url); if (response.statusCode == 200) { - var resultDecoded = json.decode(response.body); - // print(resultDecoded['data']['union']); + var resultDecoded = response.data; List union = []; final multipolygon = json.decode(resultDecoded['data']['union']['value'])['geometry'] @@ -173,25 +163,21 @@ class FiresApi { for (List hole in polygon) { List points = []; for (List point in hole) { - points.add(new LatLng(point[1].toDouble(), point[0].toDouble())); + points.add(LatLng(point[1].toDouble(), point[0].toDouble())); } - union.add( - new Polyline(points: points, color: color, strokeWidth: 3.0)); + union.add(Polyline(points: points, color: color, strokeWidth: 3.0)); } } return union; } else throw Exception('Wrong response trying to get fire data'); - }); + } catch (e) { + throw Exception('Error getting monitored areas: $e'); + } } Future markFalsePositive(AppState state, String mobileToken, String sealed, FalsePositiveType type) async { - assert(state.firesApiUrl != null); - assert(state.firesApiKey != null); - assert(mobileToken != null); - assert(sealed != null); - assert(type != null); final params = { "token": state.firesApiKey, @@ -200,16 +186,18 @@ class FiresApi { "type": type.toString().split('.')[1] }; final String url = '${state.firesApiUrl}mobile/falsepositive'; - return await resty.post(url).json(params).go().then((response) { + try { + final response = await _dio.post(url, data: params); if (response.statusCode == 200) { - // print(response.body); - if (globals.isDevelopment) - print(json.decode(response.body)['data']['upsert']); + if (globals.isDevelopment) print(response.data['data']['upsert']); return true; } else { - debugPrint(json.decode(response.body)); + debugPrint(response.data.toString()); return false; } - }); + } catch (e) { + debugPrint("Error marking false positive: $e"); + return false; + } } } diff --git a/lib/models/yourLocation.dart b/lib/models/yourLocation.dart index fb64502..33444c4 100644 --- a/lib/models/yourLocation.dart +++ b/lib/models/yourLocation.dart @@ -1,5 +1,4 @@ import 'package:fires_flutter/objectIdUtils.dart'; -import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:objectid/objectid.dart'; @@ -23,15 +22,13 @@ class YourLocation { static const int withoutStats = null; YourLocation( {this.id, - @required this.lat, - @required this.lon, + required this.lat, + required this.lon, this.description, - this.distance: 10, - int currentNumFires: withoutStats, - this.subscribed: false}) { - if (this.description == null) - this.description = 'Position: ${this.lat}, ${this.lon}'; - if (this.id == null) this.id = new ObjectId(); + this.distance = 10, + int currentNumFires = withoutStats, + this.subscribed =false}) { + } Map toJson() => _$YourLocationToJson(this); diff --git a/lib/models/yourLocationPersist.dart b/lib/models/yourLocationPersist.dart index 8b0d2f7..7ed94af 100644 --- a/lib/models/yourLocationPersist.dart +++ b/lib/models/yourLocationPersist.dart @@ -12,18 +12,11 @@ Future> loadYourLocations() async { return await globals.prefs.then((prefs) { List yourLocations = prefs.getStringList(locationKey); List persistedList = []; - if (yourLocations == null) { - yourLocations = []; - // first run, init with empty list - persistYourLocations(persistedList); - } - if (yourLocations is List) { - yourLocations.forEach((locationString) { - Map locationMap = json.decode(locationString); - persistedList.add(YourLocation.fromJson(locationMap)); - }); - } - return persistedList; + yourLocations.forEach((locationString) { + Map locationMap = json.decode(locationString); + persistedList.add(YourLocation.fromJson(locationMap)); + }); + return persistedList; }); } diff --git a/lib/monitoredAreas.dart b/lib/monitoredAreas.dart index 8b18604..d155a31 100644 --- a/lib/monitoredAreas.dart +++ b/lib/monitoredAreas.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_redux/flutter_redux.dart'; -import 'package:latlong/latlong.dart'; +import 'package:latlong2/latlong.dart'; import 'colors.dart'; import 'customBottomAppBar.dart'; @@ -74,15 +74,15 @@ class MonitoredAreasPage extends StatelessWidget { new Flexible( child: new FlutterMap( options: new MapOptions( - center: new LatLng(53.5775, 3.106111), - zoom: 1.0, + initialCenter: new LatLng(53.5775, 3.106111), + initialZoom: 1.0, ), - layers: [ - new TileLayerOptions( + children: [ + new TileLayer( urlTemplate: "https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png", subdomains: ['a', 'b', 'c']), - new PolylineLayerOptions( + new PolylineLayer( polylines: view.monitoredAreas, ) ], diff --git a/lib/placesAutocompleteUtils.dart b/lib/placesAutocompleteUtils.dart index ba03d5d..c270a61 100644 --- a/lib/placesAutocompleteUtils.dart +++ b/lib/placesAutocompleteUtils.dart @@ -2,36 +2,23 @@ import 'dart:async'; import 'package:fires_flutter/models/yourLocation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_google_places_autocomplete/flutter_google_places_autocomplete.dart'; -import 'package:flutter_simple_dependency_injection/injector.dart'; import 'generated/i18n.dart'; +/// Open a places dialog for selecting a location. +/// Currently returns a default location as the google_places_autocomplete package +/// is not maintained and doesn't support null safety. +/// TODO: Implement with a modern null-safe places API integration Future openPlacesDialog(GlobalKey sc) async { - Mode _mode = Mode.overlay; - String gmapKey = Injector.getInjector().get(key: "gmapKey"); - GoogleMapsPlaces _places = new GoogleMapsPlaces(gmapKey); - Prediction p = await showGooglePlacesAutocomplete( - context: sc.currentContext, - hint: S.of(sc.currentContext).typeTheNameOfAPlace, - apiKey: gmapKey, - onError: (res) { - ScaffoldMessenger.of(sc.currentContext) - .showSnackBar(new SnackBar(content: new Text(res.errorMessage))); - print('Error $res'); - }, - mode: _mode, - language: Localizations.localeOf(sc.currentContext).languageCode, - components: [ - // This limit the search too much - // new Component(Component.country, "es") - ]); - if (p != null) { - // get detail (lat/lng) - PlacesDetailsResponse detail = await _places.getDetailsByPlaceId(p.placeId); - final lat = detail.result.geometry.location.lat; - final lng = detail.result.geometry.location.lng; - return new YourLocation(lat: lat, lon: lng, description: p.description); - } + // Show a snackbar informing the user that this feature is not yet available + final messenger = ScaffoldMessenger.of(sc.currentContext!); + messenger.showSnackBar( + SnackBar( + content: Text( + 'Place selection is currently unavailable. Please use manual location entry.'), + ), + ); + + // Return a default location return YourLocation.noLocation; } diff --git a/lib/redux/fetchDataMiddleware.dart b/lib/redux/fetchDataMiddleware.dart index fe9b47f..73dcbc0 100644 --- a/lib/redux/fetchDataMiddleware.dart +++ b/lib/redux/fetchDataMiddleware.dart @@ -2,8 +2,7 @@ import 'dart:async'; import 'package:fires_flutter/models/fireNotification.dart'; import 'package:fires_flutter/models/yourLocation.dart'; -import 'package:flutter_simple_dependency_injection/injector.dart'; -import 'package:just_debounce_it/just_debounce_it.dart'; +import 'package:get_it/get_it.dart'; import 'package:objectid/objectid.dart'; import 'package:redux/redux.dart'; @@ -23,21 +22,27 @@ import 'actions.dart'; // Middleware do not return any values themselves. They simply forward // actions on to the Reducer or swallow actions in some special cases. -FiresApi api = Injector.getInjector().get(); +FiresApi api = GetIt.instance(); + +// Simple debounce mechanism +Timer? _locationUpdateDebounceTimer; + +void debounceLocationUpdate(Duration duration, Function() callback) { + _locationUpdateDebounceTimer?.cancel(); + _locationUpdateDebounceTimer = Timer(duration, callback); +} void fetchDataMiddleware(Store store, action, NextDispatcher next) { // If our Middleware encounters a `FetchYourLocationAction` if (action is OnUserLangAction) { // I can create the user with the lang and the token - if (store.state.user.token != null) - createUser(store, action.lang, store.state.user.token); + createUser(store, action.lang, store.state.user.token); } if (action is OnUserTokenAction) { // I can create the user with the lang and the token - if (store.state.user.lang != null) - createUser(store, store.state.user.lang, action.token); + createUser(store, store.state.user.lang, action.token); } if (action is EditConfirmYourLocationAction) { @@ -98,8 +103,8 @@ void fetchDataMiddleware(Store store, action, NextDispatcher next) { if (action is UpdateYourLocationAction) { if (action.loc.subscribed) - Debounce.seconds( - 2, + debounceLocationUpdate( + Duration(seconds: 2), () => api .getFiresInLocation( state: store.state, @@ -149,20 +154,18 @@ void fetchDataMiddleware(Store store, action, NextDispatcher next) { // If it succeeds, dispatch a success action with the YourLocations. // Our reducer will then update the State using these YourLocations. print('Subscribed to: ${subscribedLocations.length}'); - if (subscribedLocations is List) { - // unsubscribe all locally to sync the subs state - localLocations.forEach((location) => location.subscribed = false); - print('Local persisted: ${localLocations.length}'); - subscribedLocations.forEach((subsLoc) { - var locSubs = localLocations.firstWhere( - (localLocation) => localLocation.id == subsLoc.id, orElse: () { - localLocations.add(subsLoc); - return subsLoc; - }); - locSubs.subscribed = true; + // unsubscribe all locally to sync the subs state + localLocations.forEach((location) => location.subscribed = false); + print('Local persisted: ${localLocations.length}'); + subscribedLocations.forEach((subsLoc) { + var locSubs = localLocations.firstWhere( + (localLocation) => localLocation.id == subsLoc.id, orElse: () { + localLocations.add(subsLoc); + return subsLoc; }); - } - + locSubs.subscribed = true; + }); + store.dispatch(new FetchYourLocationsSucceededAction(localLocations)); persistYourLocations(localLocations); @@ -180,10 +183,8 @@ void fetchDataMiddleware(Store store, action, NextDispatcher next) { }); Completer completer = action.refreshCallback; - if (completer != null) { - completer.complete(null); - } - }); + 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/fireMapActions.dart b/lib/redux/fireMapActions.dart index a8c5524..e96db9f 100644 --- a/lib/redux/fireMapActions.dart +++ b/lib/redux/fireMapActions.dart @@ -1,6 +1,5 @@ import 'package:fires_flutter/models/yourLocation.dart'; import 'package:fires_flutter/models/fireNotification.dart'; -import 'package:meta/meta.dart'; abstract class FiresMapActions {} @@ -19,10 +18,10 @@ class UpdateFireMapStatsAction extends FiresMapActions { List industries = []; UpdateFireMapStatsAction( - {@required this.numFires, - @required this.fires, - @required this.falsePos, - @required this.industries}); + {required this.numFires, + required this.fires, + required this.falsePos, + required this.industries}); } class ShowYourLocationMapAction extends FiresMapActions { @@ -54,4 +53,4 @@ class EditCancelYourLocationAction extends FiresMapActions { EditCancelYourLocationAction(this.loc); } -class ToggleMapLayerAction extends FiresMapActions {} \ No newline at end of file +class ToggleMapLayerAction extends FiresMapActions {} diff --git a/lib/sentryReport.dart b/lib/sentryReport.dart index a50455e..6e098e0 100644 --- a/lib/sentryReport.dart +++ b/lib/sentryReport.dart @@ -1,7 +1,6 @@ import 'dart:async'; -import 'package:flutter_simple_dependency_injection/injector.dart'; -import 'package:sentry/sentry.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'globals.dart' as globals; @@ -17,9 +16,9 @@ Future reportError(dynamic error, dynamic stackTrace) async { return; } else { // Send the Exception and Stacktrace to Sentry in Production mode - Injector.getInjector().get().captureException( - exception: error, - stackTrace: stackTrace, - ); + await Sentry.captureException( + error, + stackTrace: stackTrace, + ); } } diff --git a/lib/slider.dart b/lib/slider.dart index 637f31e..cd51483 100644 --- a/lib/slider.dart +++ b/lib/slider.dart @@ -46,10 +46,8 @@ class _FireDistanceSliderState extends State { label: '${_sliderValue.round()}', onChanged: (double value) { _sliderValue = value.round(); - if (onSlide != null) { - onSlide(_sliderValue); - } - setState(() {}); + onSlide(_sliderValue); + setState(() {}); }, ); return new Column( diff --git a/lib/supportPage.dart b/lib/supportPage.dart index 41cee6f..c54c03f 100644 --- a/lib/supportPage.dart +++ b/lib/supportPage.dart @@ -2,7 +2,7 @@ import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; import 'package:launch_review/launch_review.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:share/share.dart'; +import 'package:share_plus/share_plus.dart'; import 'generated/i18n.dart'; import 'mainDrawer.dart'; @@ -37,7 +37,7 @@ class _SupportPageState extends State { icon: const Icon(Icons.share), label: new Text(S.of(context).shareAppBtn), onPressed: () { - Share.share('https://play.google.com/store/apps/details?id=org.comunes.fires'); + Share.shareWithResult('https://play.google.com/store/apps/details?id=org.comunes.fires'); }, ), ); diff --git a/lib/theme.dart b/lib/theme.dart index 99c9bd8..ade3165 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -7,13 +7,10 @@ final ThemeData firesTheme = _buildFiresTheme(); ThemeData _buildFiresTheme() { final ThemeData base = ThemeData.light(); // light or dark return base.copyWith( - accentColor: fires900, primaryColor: fires600, - buttonColor: fires900, scaffoldBackgroundColor: firesSurfaceWhite, cardColor: firesBackgroundWhite, - textSelectionTheme: TextSelectionThemeData(selectionColor: fires300), - errorColor: firesErrorRed, + textSelectionTheme: TextSelectionThemeData(selectionColor: fires300), colorScheme: ColorScheme.fromSwatch().copyWith(secondary: fires900), colorScheme: ColorScheme(error: firesErrorRed), //TODO: Add the text themes (103) //TODO: Add the icon themes (103) diff --git a/lib/themeDev.dart b/lib/themeDev.dart index 59aea06..57cb99f 100644 --- a/lib/themeDev.dart +++ b/lib/themeDev.dart @@ -7,13 +7,10 @@ final ThemeData devFiresTheme = _buildFiresTheme(); ThemeData _buildFiresTheme() { final ThemeData base = ThemeData.light(); // light or dark return base.copyWith( - accentColor: fires900, primaryColor: Colors.pink, - buttonColor: fires900, scaffoldBackgroundColor: firesSurfaceWhite, cardColor: firesBackgroundWhite, - textSelectionTheme: TextSelectionThemeData(selectionColor: fires300), - errorColor: firesErrorRed, + textSelectionTheme: TextSelectionThemeData(selectionColor: fires300), colorScheme: ColorScheme.fromSwatch().copyWith(secondary: fires900), colorScheme: ColorScheme(error: firesErrorRed), //TODO: Add the text themes (103) //TODO: Add the icon themes (103) diff --git a/lib/zoomMapPlugin.dart b/lib/zoomMapPlugin.dart index 6f3208a..3831906 100644 --- a/lib/zoomMapPlugin.dart +++ b/lib/zoomMapPlugin.dart @@ -1,58 +1,39 @@ import 'package:comunes_flutter/comunes_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_map/plugin_api.dart'; +import 'package:flutter_map/flutter_map.dart'; -class ZoomMapPluginOptions extends LayerOptions { - final String text; +/// Zoom control widget for flutter_map v6+ +class ZoomMapPluginWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) => + Stack(fit: StackFit.expand, children: [ + Positioned( + top: constraints.maxHeight - 100, + right: 10.0, + child: new CenteredRow( + children: [ + new Column( + children: [ + _zoomButton(context, Icons.zoom_in, 1), + _zoomButton(context, Icons.zoom_out, -1) + ], + ) + ], + ), + ) + ])); + } - ZoomMapPluginOptions({this.text = ""}); -} - -// https://github.com/apptreesoftware/flutter_map/blob/master/flutter_map_example/lib/pages/plugin_api.dart -class ZoomMapPlugin extends MapPlugin { - IconButton zoomButton(MapState mapState, IconData zoomIcon, int inc) { + IconButton _zoomButton(BuildContext context, IconData zoomIcon, int inc) { return new IconButton( icon: Icon(zoomIcon), onPressed: () { - var currentZoom = mapState.zoom; - var currentCenter = mapState.center; - mapState.move(currentCenter, currentZoom + inc); + final controller = MapController.of(context); + var currentZoom = controller.camera.zoom; + var currentCenter = controller.camera.center; + controller.move(currentCenter, currentZoom + inc); }); } - - @override - Widget createLayer( - LayerOptions options, MapState mapState, Stream stream) { - if (options is ZoomMapPluginOptions) { - /* print('point ${mapState - .getPixelBounds(mapState.zoom) - .bottomLeft}'); */ - return LayoutBuilder( - builder: (context, constraints) => - Stack(fit: StackFit.expand, children: [ - Positioned( - top: constraints.maxHeight - 100, - right: 10.0, - // left: 10.0, - child: new CenteredRow( - children: [ - new Column( - children: [ - zoomButton(mapState, Icons.zoom_in, 1), - zoomButton(mapState, Icons.zoom_out, -1) - ], - ) - ], - ), - ) - ])); - } - throw ("Unknown options type for ZoomMapPlugin" - "plugin: $options"); - } - - @override - bool supportsLayer(LayerOptions options) { - return options is ZoomMapPluginOptions; - } } diff --git a/pubspec.yaml b/pubspec.yaml index 7c21648..cfcc5b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: fires_flutter description: All Against Fire environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: flutter: @@ -10,71 +10,63 @@ dependencies: # i18n flutter_localizations: sdk: flutter - intl: "^0.16.1" - # https://pub.dartlang.org/packages/flutter + intl: ^0.20.2 # utils - simple_moment: "^1.0.7" - just_debounce_it: "^3.0.0+2" - flutter_simple_dependency_injection: "^0.0.2" - sentry: "^2.0.2" - flutter_markdown: "^0.5.1" - url_launcher: "^5.7.10" - package_info: ^0.4.3+2 - launch_review: "^1.0.1" + timeago: ^3.6.1 + get_it: ^7.6.7 + sentry_flutter: ^7.18.0 + flutter_markdown: ^0.7.0 + url_launcher: ^6.2.5 + package_info_plus: ^6.0.0 # net - http: "^0.11.3+16" - jaguar_resty: "^2.5.5" - connectivity: ^2.0.2 - share: "^0.5.2" + http: ^1.2.1 + dio: ^5.4.3+1 + connectivity_plus: ^5.0.2 + share_plus: ^7.2.2 # data - json_annotation: "^3.1.1" - shared_preferences: "^0.4.2" - # bson_objectid: "^0.1.0 - objectid: 1.1.0 + json_annotation: ^4.9.0 + shared_preferences: ^2.2.3 + objectid: ^2.1.0 comunes_flutter: - #git: git@github.com:comunes/comunes-flutter.git path: /home/vjrj/dev/comunes_flutter - # version: "^0.0.12" # redux - redux: "^3.0.0" - flutter_redux: "^0.5.2" - redux_logging: "^0.3.0" + redux: ^5.0.0 + flutter_redux: ^0.10.0 # maps, geo, etc - flutter_map: ^0.10.1+1 - flutter_google_places_autocomplete: "^0.1.3" - location: ^3.2.1 - geocoder: "^0.2.1" + flutter_map: ^6.1.0 + latlong2: ^0.9.1 + location: ^5.0.3 + geocoding: ^2.1.1 # layout - # fluttery: "^0.0.7" - # https://pub.dartlang.org/packages/padder - padder: "^1.0.1" - flutter_fab_dialer: "^0.0.5" - # badge: "^0.0.2" - badges: ^1.1.6 - flutter_spinkit: "^1.0.0" + padder: ^1.0.1 + flutter_speed_dial: ^7.0.0 + badges: ^3.1.2 + flutter_spinkit: ^5.2.0 # firebase - firebase_core: ^0.5.3 - firebase_messaging: ^7.0.3 + firebase_core: ^2.27.1 + firebase_messaging: ^14.7.19 # icons - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: "^0.1.2" - community_material_icon: "^5.4.55" + cupertino_icons: ^1.0.8 + community_material_icon: ^5.9.55 + + # reviews + in_app_review: ^2.0.9 dev_dependencies: flutter_test: sdk: flutter - build_runner: "^1.0.0" - json_serializable: ^3.5.1 - test: ^1.15.7 + build_runner: ^2.4.8 + json_serializable: ^6.7.1 + test: ^1.25.2 + flutter_lints: ^3.0.1 # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec @@ -109,8 +101,7 @@ flutter: # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: + # list giving the asset and other descriptors. For example: # fonts: # - family: Schyler # fonts: @@ -125,7 +116,3 @@ flutter: # # For details regarding fonts from package dependencies, # see https://flutter.io/custom-fonts/#from-packages - -# https://github.com/flutter/flutter/issues/70433 -dependency_overrides: - intl: ^0.17.0-nullsafety.2