diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..791c93f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "editor.formatOnSave": false, + "editor.formatOnPaste": false, + "editor.formatOnType": false, + "editor.defaultFormatter": "Dart-Code.flutter", + "dart.lineLength": 120, + "[dart]": { + "editor.rulers": [ + 120 + ], + "editor.defaultFormatter": "Dart-Code.dart-code", + "editor.formatOnSave": false, + "editor.formatOnPaste": false, + "editor.formatOnType": false + } +} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 8ab520c..29785d0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -29,7 +29,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 33 + compileSdkVersion 34 ndkVersion flutter.ndkVersion compileOptions { @@ -51,7 +51,7 @@ android { // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. minSdkVersion 26 - targetSdkVersion 33 + targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 439dac5..89d1fb5 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -754,6 +754,8 @@ "statisticsSettingsDescription": "Configure data collection for statistics", "loadingStatisticsSettings": "Loading statistics settings...", "statisticsSettingsLoadError": "An error occured when loading statistics settings.", + "statisticsConfigUpdated": "Statistics settings updated successfully", + "statisticsConfigNotUpdated": "Statistics settings couldn't be updated", "customTimeInHours": "Custom time (in hours)", "invalidTime": "Invalid time", "removeDomain": "Remove domain", @@ -776,5 +778,6 @@ "enablePlainDns": "Enable plain DNS", "enablePlainDnsDescription": "Plain DNS is enabled by default. You can disable it to force all devices to use encrypted DNS. To do this, you must enable at least one encrypted DNS protocol.", "date": "Date", - "loadingChangelog": "Loading changelog..." + "loadingChangelog": "Loading changelog...", + "invalidIpOrUrl": "Invalid IP address or URL" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 79aaa7d..32fb2c6 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -754,6 +754,8 @@ "statisticsSettingsDescription": "Configura la recolección de datos para estadísticas", "loadingStatisticsSettings": "Cargando ajustes de estadísticas...", "statisticsSettingsLoadError": "Ocurrió un error al cargar los ajustes de estadísticas.", + "statisticsConfigNotUpdated": "La configuración de estadísticas no pudo ser actualizada.", + "statisticsConfigUpdated": "Configuración de estadísticas actualizada correctamente.", "customTimeInHours": "Tiempo personalizado (en horas)", "invalidTime": "Tiempo no válido", "removeDomain": "Eliminar dominio", @@ -776,5 +778,6 @@ "enablePlainDns": "Activar DNS simple (sin cifrado)", "enablePlainDnsDescription": "El DNS simple (sin cifrado) está activado de forma predeterminada. Puedes desactivarlo para obligar a todos los dispositivos a utilizar DNS cifrado. Para ello, debes habilitar al menos un protocolo DNS cifrado.", "date": "Fecha", - "loadingChangelog": "Cargando registro de cambios..." + "loadingChangelog": "Cargando registro de cambios...", + "invalidIpOrUrl": "Dirección IP o URL no válida" } \ No newline at end of file diff --git a/lib/screens/home/chart.dart b/lib/screens/home/chart.dart index 0093ae8..ac1fce5 100644 --- a/lib/screens/home/chart.dart +++ b/lib/screens/home/chart.dart @@ -43,7 +43,7 @@ class _HomeChartState extends State { if (!(appConfigProvider.hideZeroValues == true && isEmpty == true)) { List dateTimes = []; - DateTime currentDate = DateTime.now().subtract(Duration(hours: widget.hoursInterval*widget.data.length+1)); + DateTime currentDate = DateTime.now().subtract(Duration(hours: widget.hoursInterval*widget.data.length)); for (var i = 0; i < widget.data.length; i++) { currentDate = currentDate.add(Duration(hours: widget.hoursInterval)); dateTimes.add(currentDate); diff --git a/lib/screens/logs/logs_list.dart b/lib/screens/logs/logs_list.dart index ced94ca..6036f77 100644 --- a/lib/screens/logs/logs_list.dart +++ b/lib/screens/logs/logs_list.dart @@ -33,6 +33,7 @@ class LogsListWidget extends StatefulWidget { } class _LogsListWidgetState extends State { + final _scaffoldMessengerKey = GlobalKey(); bool showDivider = true; void fetchFilteringRules() async { @@ -93,194 +94,197 @@ class _LogsListWidgetState extends State { Widget build(BuildContext context) { final logsProvider = Provider.of(context); - return Scaffold( - body: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - sliver: LogsListAppBar( - innerBoxIsScrolled: innerBoxIsScrolled, - showDivider: showDivider, + return ScaffoldMessenger( + key: widget.twoColumns ? _scaffoldMessengerKey : null, + child: Scaffold( + body: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverOverlapAbsorber( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + sliver: LogsListAppBar( + innerBoxIsScrolled: innerBoxIsScrolled, + showDivider: showDivider, + ) ) - ) - ], - body: Builder( - builder: (context) { - switch (logsProvider.loadStatus) { - case LoadStatus.loading: - return SafeArea( - top: false, - bottom: false, - child: Builder( - builder: (context) => CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - ), - SliverFillRemaining( - child: SizedBox( - width: double.maxFinite, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - const SizedBox(height: 30), - Text( - AppLocalizations.of(context)!.loadingLogs, - style: TextStyle( - fontSize: 22, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ) - ], - ), + ], + body: Builder( + builder: (context) { + switch (logsProvider.loadStatus) { + case LoadStatus.loading: + return SafeArea( + top: false, + bottom: false, + child: Builder( + builder: (context) => CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + SliverFillRemaining( + child: SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 30), + Text( + AppLocalizations.of(context)!.loadingLogs, + style: TextStyle( + fontSize: 22, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ) + ], + ), + ) ) - ) - ], - ), - ) - ); - - case LoadStatus.loaded: - return SafeArea( - top: false, - bottom: false, - child: Builder( - builder: (context) => RefreshIndicator( - onRefresh: () async { - await logsProvider.fetchLogs(inOffset: 0); - }, - displacement: 95, - child: NotificationListener( - onNotification: scrollListener, - child: CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - ), - if (logsProvider.logsData!.data.isNotEmpty) SliverList.builder( - itemCount: logsProvider.isLoadingMore - ? logsProvider.logsData!.data.length + 1 - : logsProvider.logsData!.data.length, - itemBuilder: (context, index) { - if (logsProvider.isLoadingMore == true && index == logsProvider.logsData!.data.length) { - return const Padding( - padding: EdgeInsets.symmetric(vertical: 20), - child: Center( - child: CircularProgressIndicator(), - ), - ); - } - else if (logsProvider.logsData!.data[index].question.name != null) { - return LogTile( - log: logsProvider.logsData!.data[index], - index: index, - length: logsProvider.logsData!.data.length, - isLogSelected: widget.selectedLog != null && widget.selectedLog == logsProvider.logsData!.data[index], - onLogTap: (log) { - if (!widget.twoColumns) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => LogDetailsScreen( - log: log, - dialog: false, + ], + ), + ) + ); + + case LoadStatus.loaded: + return SafeArea( + top: false, + bottom: false, + child: Builder( + builder: (context) => RefreshIndicator( + onRefresh: () async { + await logsProvider.fetchLogs(inOffset: 0); + }, + displacement: 95, + child: NotificationListener( + onNotification: scrollListener, + child: CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + if (logsProvider.logsData!.data.isNotEmpty) SliverList.builder( + itemCount: logsProvider.isLoadingMore + ? logsProvider.logsData!.data.length + 1 + : logsProvider.logsData!.data.length, + itemBuilder: (context, index) { + if (logsProvider.isLoadingMore == true && index == logsProvider.logsData!.data.length) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: Center( + child: CircularProgressIndicator(), + ), + ); + } + else if (logsProvider.logsData!.data[index].question.name != null) { + return LogTile( + log: logsProvider.logsData!.data[index], + index: index, + length: logsProvider.logsData!.data.length, + isLogSelected: widget.selectedLog != null && widget.selectedLog == logsProvider.logsData!.data[index], + onLogTap: (log) { + if (!widget.twoColumns) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LogDetailsScreen( + log: log, + dialog: false, + ) ) - ) - ); - } - widget.onLogSelected(log); - }, - twoColumns: widget.twoColumns, - ); + ); + } + widget.onLogSelected(log); + }, + twoColumns: widget.twoColumns, + ); + } + else { + return null; + } } - else { - return null; - } - } - ), - if (logsProvider.logsData!.data.isEmpty) SliverFillRemaining( - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.of(context)!.noLogsDisplay, - style: TextStyle( - fontSize: 24, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - if (logsProvider.logsOlderThan != null) Padding( - padding: const EdgeInsets.only( - top: 30, - left: 20, - right: 20 - ), - child: Text( - AppLocalizations.of(context)!.noLogsThatOld, - textAlign: TextAlign.center, + ), + if (logsProvider.logsData!.data.isEmpty) SliverFillRemaining( + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + AppLocalizations.of(context)!.noLogsDisplay, style: TextStyle( - fontSize: 16, + fontSize: 24, color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), - ), - ] + if (logsProvider.logsOlderThan != null) Padding( + padding: const EdgeInsets.only( + top: 30, + left: 20, + right: 20 + ), + child: Text( + AppLocalizations.of(context)!.noLogsThatOld, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + ] + ), ), - ), - ) - ], + ) + ], + ), ), ), - ), - ) - ); - - case LoadStatus.error: - return SafeArea( - top: false, - bottom: false, - child: Builder( - builder: (context) => CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - ), - SliverFillRemaining( - child: SizedBox( - width: double.maxFinite, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Icon( - Icons.error, - color: Colors.red, - size: 50, - ), - const SizedBox(height: 30), - Text( - AppLocalizations.of(context)!.logsNotLoaded, - style: TextStyle( - fontSize: 22, - color: Theme.of(context).colorScheme.onSurfaceVariant, + ) + ); + + case LoadStatus.error: + return SafeArea( + top: false, + bottom: false, + child: Builder( + builder: (context) => CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + SliverFillRemaining( + child: SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Icon( + Icons.error, + color: Colors.red, + size: 50, ), - ) - ], - ), + const SizedBox(height: 30), + Text( + AppLocalizations.of(context)!.logsNotLoaded, + style: TextStyle( + fontSize: 22, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ) + ], + ), + ) ) - ) - ], - ), - ) - ); - - default: - return const SizedBox(); - } - }, - ) + ], + ), + ) + ); + + default: + return const SizedBox(); + } + }, + ) + ), ), ); } diff --git a/lib/screens/settings/dns/fallback_dns.dart b/lib/screens/settings/dns/fallback_dns.dart index dcae0a2..849eb4d 100644 --- a/lib/screens/settings/dns/fallback_dns.dart +++ b/lib/screens/settings/dns/fallback_dns.dart @@ -1,5 +1,6 @@ -// ignore_for_file: use_build_context_synchronously +import 'dart:io'; +import 'package:adguard_home_manager/screens/settings/dns/comment_modal.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -24,11 +25,12 @@ class _FallbackDnsScreenState extends State { void validateIp(Map field, String value) { RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)'); - if (ipAddress.hasMatch(value) == true) { + RegExp url = RegExp(r'(https?|tls):\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)'); + if (ipAddress.hasMatch(value) == true || url.hasMatch(value) == true) { setState(() => field['error'] = null); } else { - setState(() => field['error'] = AppLocalizations.of(context)!.invalidIp); + setState(() => field['error'] = AppLocalizations.of(context)!.invalidIpOrUrl); } checkValidValues(); } @@ -47,12 +49,20 @@ class _FallbackDnsScreenState extends State { final dnsProvider = Provider.of(context, listen: false); for (var item in dnsProvider.dnsInfo!.fallbackDns!) { - final controller = TextEditingController(); - controller.text = item; - fallbackControllers.add({ - 'controller': controller, - 'error': null - }); + if (item.contains("#")) { + fallbackControllers.add({ + 'comment': item + }); + } + else { + final controller = TextEditingController(); + controller.text = item; + fallbackControllers.add({ + 'controller': controller, + 'error': null, + 'isComment': item.contains("#") + }); + } } validValues = true; super.initState(); @@ -70,11 +80,16 @@ class _FallbackDnsScreenState extends State { processModal.open(AppLocalizations.of(context)!.savingConfig); final result = await dnsProvider.saveFallbackDnsConfig({ - "fallback_dns": fallbackControllers.map((e) => e['controller'].text).toList(), + "fallback_dns": fallbackControllers.map( + (e) => e['controller'] != null + ? e['controller'].text + : e['comment'] + ).toList(), }); processModal.close(); + if (!context.mounted) return; if (result.successful == true) { showSnacbkar( appConfigProvider: appConfigProvider, @@ -98,6 +113,75 @@ class _FallbackDnsScreenState extends State { } } + void openAddCommentModal() { + if (width > 900 || !(Platform.isAndroid || Platform.isIOS)) { + showDialog( + context: context, + builder: (context) => CommentModal( + onConfirm: (value) { + setState(() { + fallbackControllers.add({ + 'comment': value + }); + }); + }, + dialog: true, + ), + ); + } + else { + showModalBottomSheet( + context: context, + useRootNavigator: true, + builder: (context) => CommentModal( + onConfirm: (value) { + setState(() { + fallbackControllers.add({ + 'comment': value + }); + }); + }, + dialog: false, + ), + backgroundColor: Colors.transparent, + isScrollControlled: true, + isDismissible: true + ); + } + } + + + void openEditCommentModal(Map item, int position) { + if (width > 900 || !(Platform.isAndroid || Platform.isIOS)) { + showDialog( + context: context, + builder: (context) => CommentModal( + comment: item['comment'], + onConfirm: (value) { + setState(() => fallbackControllers[position] = { 'comment': value }); + }, + dialog: true, + ), + ); + } + else { + showModalBottomSheet( + context: context, + useRootNavigator: true, + builder: (context) => CommentModal( + comment: item['comment'], + onConfirm: (value) { + setState(() => fallbackControllers[position] = { 'comment': value }); + }, + dialog: false, + ), + backgroundColor: Colors.transparent, + isScrollControlled: true, + isDismissible: true + ); + } + } + return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.fallbackDnsServers), @@ -167,37 +251,68 @@ class _FallbackDnsScreenState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( + if (c['controller'] != null) Expanded( child: TextFormField( controller: c['controller'], onChanged: (value) => validateIp(c, value), decoration: InputDecoration( - prefixIcon: const Icon(Icons.dns_rounded), + prefixIcon: Icon( + c['isComment'] == true + ? Icons.comment_rounded + : Icons.dns_rounded + ), border: const OutlineInputBorder( borderRadius: BorderRadius.all( Radius.circular(10) ) ), errorText: c['error'], - labelText: AppLocalizations.of(context)!.dnsServer, + labelText: c['isComment'] == true + ? AppLocalizations.of(context)!.comment + : AppLocalizations.of(context)!.dnsServer, ) ), ), const SizedBox(width: 8), + if (c['comment'] != null) Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + c['comment'], + style: TextStyle( + fontSize: 16, + color: Theme.of(context).listTileTheme.iconColor + ), + ), + IconButton( + onPressed: () => openEditCommentModal(c, fallbackControllers.indexOf(c)), + icon: const Icon(Icons.edit), + tooltip: AppLocalizations.of(context)!.edit, + ) + ], + ), + ), IconButton( onPressed: () { setState(() => fallbackControllers = fallbackControllers.where((con) => con != c).toList()); checkValidValues(); }, - icon: const Icon(Icons.remove_circle_outline) + icon: const Icon(Icons.remove_circle_outline), + tooltip: AppLocalizations.of(context)!.remove, ) ], ), )), Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisSize: MainAxisSize.min, children: [ + ElevatedButton.icon( + onPressed: openAddCommentModal, + icon: const Icon(Icons.add), + label: Text(AppLocalizations.of(context)!.comment) + ), ElevatedButton.icon( onPressed: () { setState(() => fallbackControllers.add({ @@ -207,7 +322,7 @@ class _FallbackDnsScreenState extends State { checkValidValues(); }, icon: const Icon(Icons.add), - label: Text(AppLocalizations.of(context)!.addItem) + label: Text(AppLocalizations.of(context)!.address) ), ], ), diff --git a/lib/screens/settings/dns/upstream_dns.dart b/lib/screens/settings/dns/upstream_dns.dart index e540053..c99c9bc 100644 --- a/lib/screens/settings/dns/upstream_dns.dart +++ b/lib/screens/settings/dns/upstream_dns.dart @@ -47,7 +47,7 @@ class _UpstreamDnsScreenState extends State { final dnsProvider = Provider.of(context, listen: false); for (var item in dnsProvider.dnsInfo!.upstreamDns) { - if (item == '#') { + if (item.contains("#")) { dnsServers.add({ 'comment': item }); @@ -263,7 +263,7 @@ class _UpstreamDnsScreenState extends State { const SizedBox(width: 4), ], ), - )).toList(), + )), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, diff --git a/lib/screens/settings/settings.dart b/lib/screens/settings/settings.dart index 718593e..bce5e11 100644 --- a/lib/screens/settings/settings.dart +++ b/lib/screens/settings/settings.dart @@ -83,7 +83,7 @@ class _SettingsWidget extends StatefulWidget { } class _SettingsWidgetState extends State<_SettingsWidget> { - final scaffoldMessengerKey = GlobalKey(); + final _scaffoldMessengerKey = GlobalKey(); @override void initState() { @@ -104,7 +104,7 @@ class _SettingsWidgetState extends State<_SettingsWidget> { } return ScaffoldMessenger( - key: widget.twoColumns ? scaffoldMessengerKey : null, + key: widget.twoColumns ? _scaffoldMessengerKey : null, child: Scaffold( body: NestedScrollView( headerSliverBuilder: (context, innerBoxIsScrolled) => [ diff --git a/lib/screens/settings/statistics_settings/statistics_settings.dart b/lib/screens/settings/statistics_settings/statistics_settings.dart index f514e78..27e4570 100644 --- a/lib/screens/settings/statistics_settings/statistics_settings.dart +++ b/lib/screens/settings/statistics_settings/statistics_settings.dart @@ -145,19 +145,19 @@ class _StatisticsSettingsState extends State { processModal.close(); - if (!mounted) return; + if (!context.mounted) return; if (result.successful == true) { showSnacbkar( appConfigProvider: appConfigProvider, - label: AppLocalizations.of(context)!.logsConfigUpdated, + label: AppLocalizations.of(context)!.statisticsConfigUpdated, color: Colors.green ); } else { showSnacbkar( appConfigProvider: appConfigProvider, - label: AppLocalizations.of(context)!.logsConfigNotUpdated, + label: AppLocalizations.of(context)!.statisticsConfigNotUpdated, color: Colors.red ); } @@ -209,7 +209,7 @@ class _StatisticsSettingsState extends State { if (value != null && value != "custom") { _customTimeError = null; _customTimeController.text = ""; - }; + } _retentionTime = value; }), decoration: InputDecoration( diff --git a/pubspec.lock b/pubspec.lock index c1c90ca..38751b2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: "direct main" description: name: fl_chart - sha256: b5e2b0f13d93f8c532b5a2786bfb44580de1f50b927bf95813fa1af617e9caf8 + sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d" url: "https://pub.dev" source: hosted - version: "0.66.1" + version: "0.66.2" flutter: dependency: "direct main" description: flutter @@ -311,10 +311,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "30088ce826b5b9cfbf9e8bece34c716c8a59fa54461dcae1e4ac01a94639e762" + sha256: a64c5323ac83ed2b7940d2b6288d160aa1753ff271ba9d9b2a86770414aa3eab url: "https://pub.dev" source: hosted - version: "0.6.18+3" + version: "0.6.20+1" flutter_native_splash: dependency: "direct dev" description: @@ -344,10 +344,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter @@ -386,10 +386,10 @@ packages: dependency: transitive description: name: image - sha256: "49a0d4b0c12402853d3f227fe7c315601b238d126aa4caa5dbb2dcf99421aa4a" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.6" + version: "4.1.7" intl: dependency: "direct main" description: @@ -414,6 +414,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.8.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -442,26 +466,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" nested: dependency: transitive description: @@ -490,10 +514,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -578,10 +602,10 @@ packages: dependency: "direct main" description: name: provider - sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" segmented_button_slide: dependency: "direct main" description: @@ -594,18 +618,18 @@ packages: dependency: transitive description: name: sentry - sha256: a7946f4a90b0feb47214981d881b98149e05f6c576da9f2a2f33945bf561de25 + sha256: d2ee9c850d876d285f22e2e662f400ec2438df9939fe4acd5d780df9841794ce url: "https://pub.dev" source: hosted - version: "7.16.0" + version: "7.16.1" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "6db7fa1b076faf2f5dd77d8cc9ef206171f32a290cc638842d78e5d62b441a27" + sha256: "5b428c189c825f16fb14e9166529043f06b965d5b59bfc3a1415e39c082398c0" url: "https://pub.dev" source: hosted - version: "7.16.0" + version: "7.16.1" shared_preferences: dependency: "direct main" description: @@ -711,10 +735,10 @@ packages: dependency: transitive description: name: sqlite3 - sha256: c4a4c5a4b2a32e2d0f6837b33d7c91a67903891a5b7dbe706cf4b1f6b0c798c5 + sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" sqlite3_flutter_libs: dependency: "direct main" description: @@ -807,26 +831,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.2.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" + sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.2.5" url_launcher_linux: dependency: transitive description: @@ -847,10 +871,10 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" url_launcher_web: dependency: transitive description: @@ -879,26 +903,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "4ac59808bbfca6da38c99f415ff2d3a5d7ca0a6b4809c71d9cf30fba5daf9752" + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.1.11+1" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: f3247e7ab0ec77dc759263e68394990edc608fb2b480b80db8aa86ed09279e33 + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.1.11+1" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "18489bdd8850de3dd7ca8a34e0c446f719ec63e2bab2e7a8cc66a9028dd76c5a" + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.1.11+1" vector_math: dependency: transitive description: @@ -907,14 +931,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.4.2" win32: dependency: transitive description: @@ -965,5 +997,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3ef7c66..70e1dff 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 2.16.3+133 +version: 2.16.4+134 environment: sdk: '>=2.18.1 <3.0.0'