Merge branch 'beta'

This commit is contained in:
Juan Gilsanz Polo 2024-09-11 19:17:02 +02:00
commit 6e0f437c6b
107 changed files with 1108 additions and 771 deletions

View file

@ -42,6 +42,15 @@ This is an unofficial application. The AdGuard Home team and the development of
## Recommended configuration and lists ## Recommended configuration and lists
On [this repository](https://github.com/juanico10/Pihole_list) you can find a recommended configuration for AdGuard Home and some lists. Thanks to [juanico10](https://github.com/juanico10). On [this repository](https://github.com/juanico10/Pihole_list) you can find a recommended configuration for AdGuard Home and some lists. Thanks to [juanico10](https://github.com/juanico10).
## Donations
If you like the project and you want to contribute with the development, you can [become a sponsor on GitHub](https://github.com/sponsors/JGeek00), or you can donate using PayPal.
<div align="center">
<a href="https://www.paypal.com/donate/?hosted_button_id=T63UK6AVL3MG8">
<img src="https://raw.githubusercontent.com/stefan-niedermann/paypal-donate-button/master/paypal-donate-button.png" alt="Donate with PayPal" height="100" />
</a>
</div>
## Generate production build ## Generate production build
<ul> <ul>
<li> <li>
@ -114,7 +123,6 @@ On [this repository](https://github.com/juanico10/Pihole_list) you can find a re
- [fl chart](https://pub.dev/packages/fl_chart) - [fl chart](https://pub.dev/packages/fl_chart)
- [flutter svg](https://pub.dev/packages/flutter_svg) - [flutter svg](https://pub.dev/packages/flutter_svg)
- [percent indicator](https://pub.dev/packages/percent_indicator) - [percent indicator](https://pub.dev/packages/percent_indicator)
- [store checker](https://pub.dev/packages/store_checker)
- [flutter markdown](https://pub.dev/packages/flutter_markdown) - [flutter markdown](https://pub.dev/packages/flutter_markdown)
- [markdown](https://pub.dev/packages/markdown) - [markdown](https://pub.dev/packages/markdown)
- [html](https://pub.dev/packages/html) - [html](https://pub.dev/packages/html)
@ -132,6 +140,9 @@ On [this repository](https://github.com/juanico10/Pihole_list) you can find a re
- [timezone](https://pub.dev/packages/timezone) - [timezone](https://pub.dev/packages/timezone)
- [url launcher](https://pub.dev/packages/url_launcher) - [url launcher](https://pub.dev/packages/url_launcher)
- [flutter custom tabs](https://pub.dev/packages/flutter_custom_tabs) - [flutter custom tabs](https://pub.dev/packages/flutter_custom_tabs)
- [shared preferences](https://pub.dev/packages/shared_preferences)
- [window manager](https://pub.dev/packages/window_manager)
- [install referrer](https://pub.dev/packages/install_referrer)
<br> <br>

View file

@ -24,6 +24,9 @@ ThemeData lightTheme(ColorScheme? dynamicColorScheme) => ThemeData(
navigationBarTheme: NavigationBarThemeData( navigationBarTheme: NavigationBarThemeData(
surfaceTintColor: dynamicColorScheme?.surfaceTint surfaceTintColor: dynamicColorScheme?.surfaceTint
), ),
dialogTheme: DialogTheme(
surfaceTintColor: dynamicColorScheme?.surfaceTint
),
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
builders: { builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder() TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
@ -56,6 +59,9 @@ ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
navigationBarTheme: NavigationBarThemeData( navigationBarTheme: NavigationBarThemeData(
surfaceTintColor: dynamicColorScheme?.surfaceTint surfaceTintColor: dynamicColorScheme?.surfaceTint
), ),
dialogTheme: DialogTheme(
surfaceTintColor: dynamicColorScheme?.surfaceTint
),
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
builders: { builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder() TargetPlatform.android: PredictiveBackPageTransitionsBuilder()

View file

@ -1,6 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:store_checker/store_checker.dart'; import 'package:install_referrer/install_referrer.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/services/external_requests.dart'; import 'package:adguard_home_manager/services/external_requests.dart';
@ -9,7 +9,7 @@ import 'package:adguard_home_manager/models/github_release.dart';
Future<GitHubRelease?> checkAppUpdates({ Future<GitHubRelease?> checkAppUpdates({
required String currentBuildNumber, required String currentBuildNumber,
required void Function(GitHubRelease?) setUpdateAvailable, required void Function(GitHubRelease?) setUpdateAvailable,
required Source installationSource, required InstallationAppReferrer? installationSource,
required bool isBeta required bool isBeta
}) async { }) async {
var result = isBeta var result = isBeta
@ -35,11 +35,7 @@ Future<GitHubRelease?> checkAppUpdates({
setUpdateAvailable(gitHubRelease); setUpdateAvailable(gitHubRelease);
if (Platform.isAndroid) { if (Platform.isAndroid) {
if ( if (installationSource == InstallationAppReferrer.androidManually) {
installationSource == Source.IS_INSTALLED_FROM_LOCAL_SOURCE ||
installationSource == Source.IS_INSTALLED_FROM_PLAY_PACKAGE_INSTALLER ||
installationSource == Source.UNKNOWN
) {
return gitHubRelease; return gitHubRelease;
} }
else { else {

View file

@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/config/globals.dart'; import 'package:adguard_home_manager/config/globals.dart';
void showSnacbkar({ void showSnackbar({
required AppConfigProvider appConfigProvider, required AppConfigProvider appConfigProvider,
required String label, required String label,
required Color color, required Color color,

View file

@ -795,5 +795,7 @@
"clientIpCopied": "Client IP copied to the clipboard", "clientIpCopied": "Client IP copied to the clipboard",
"clientNameCopied": "Client name copied to the clipboard", "clientNameCopied": "Client name copied to the clipboard",
"dnsServerAddressCopied": "DNS server address copied to the clipboard", "dnsServerAddressCopied": "DNS server address copied to the clipboard",
"select": "Select" "select": "Select",
"liveLogs": "Live logs",
"hereWillAppearRealtimeLogs": "Here there will appear the logs on realtime."
} }

View file

@ -795,5 +795,7 @@
"clientIpCopied": "Dirección IP del cliente copiada al portapapeles", "clientIpCopied": "Dirección IP del cliente copiada al portapapeles",
"clientNameCopied": "Nombre del cliente copiado al portapapeles", "clientNameCopied": "Nombre del cliente copiado al portapapeles",
"dnsServerAddressCopied": "Dirección del servidor DNS copiada al portapapeles", "dnsServerAddressCopied": "Dirección del servidor DNS copiada al portapapeles",
"select": "Seleccionar" "select": "Seleccionar",
"liveLogs": "Registros en directo",
"hereWillAppearRealtimeLogs": "Aquí aparecerán los registros en tiempo real."
} }

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:install_referrer/install_referrer.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
@ -12,7 +13,6 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:store_checker/store_checker.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -80,7 +80,7 @@ void main() async {
} }
if (Platform.isAndroid || Platform.isIOS) { if (Platform.isAndroid || Platform.isIOS) {
Source installationSource = await StoreChecker.getSource; InstallationAppReferrer installationSource = await InstallReferrer.referrer;
appConfigProvider.setInstallationSource(installationSource); appConfigProvider.setInstallationSource(installationSource);
} }

View file

@ -63,7 +63,7 @@ class Filter {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"url": url, "url": url,
"name": name, "name": name,
"last_updated": lastUpdated != null ? lastUpdated!.toIso8601String() : null, "last_updated": lastUpdated?.toIso8601String(),
"id": id, "id": id,
"rules_count": rulesCount, "rules_count": rulesCount,
"enabled": enabled, "enabled": enabled,

View file

@ -65,7 +65,7 @@ class Filter {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"url": url, "url": url,
"name": name, "name": name,
"last_updated": lastUpdated != null ? lastUpdated!.toIso8601String() : null, "last_updated": lastUpdated?.toIso8601String(),
"id": id, "id": id,
"rules_count": rulesCount, "rules_count": rulesCount,
"enabled": enabled, "enabled": enabled,

View file

@ -30,7 +30,7 @@ class LogsData {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data.map((x) => x.toJson())), "data": List<dynamic>.from(data.map((x) => x.toJson())),
"oldest": oldest != null ? oldest!.toIso8601String() : null, "oldest": oldest?.toIso8601String(),
}; };
} }

View file

@ -2,9 +2,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:install_referrer/install_referrer.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:store_checker/store_checker.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
@ -33,7 +33,7 @@ class AppConfigProvider with ChangeNotifier {
int _selectedTheme = 0; int _selectedTheme = 0;
bool _useDynamicColor = true; bool _useDynamicColor = true;
int _staticColor = 0; int _staticColor = 0;
bool _useThemeColorForStatus = false; final bool _useThemeColorForStatus = false;
int _selectedClientsTab = 0; int _selectedClientsTab = 0;
int _selectedFiltersTab = 0; int _selectedFiltersTab = 0;
@ -58,7 +58,7 @@ class AppConfigProvider with ChangeNotifier {
GitHubRelease? _appUpdatesAvailable; GitHubRelease? _appUpdatesAvailable;
Source _installationSource = Source.UNKNOWN; InstallationAppReferrer? _installationSource;
PackageInfo? get getAppInfo { PackageInfo? get getAppInfo {
return _appInfo; return _appInfo;
@ -162,7 +162,7 @@ class AppConfigProvider with ChangeNotifier {
return _appUpdatesAvailable; return _appUpdatesAvailable;
} }
Source get installationSource { InstallationAppReferrer? get installationSource {
return _installationSource; return _installationSource;
} }
@ -227,7 +227,7 @@ class AppConfigProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void setInstallationSource(Source value) { void setInstallationSource(InstallationAppReferrer value) {
_installationSource = value; _installationSource = value;
notifyListeners(); notifyListeners();
} }

View file

@ -0,0 +1,51 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class LiveLogsProvider with ChangeNotifier {
ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
bool _isDisposed = false;
@override
void dispose() {
_isDisposed = true;
super.dispose();
}
List<Log> _logs = [];
List<Log> get logs {
return _logs;
}
DateTime? _lastTime;
void startFetchLogs() {
_lastTime = DateTime.now();
_fetchLogs();
}
void _fetchLogs() async {
if (_lastTime == null) return;
final result = await _serversProvider!.apiClient2!.getLogs(
count: 100
);
if (result.successful == false || result.content == null) return;
final valid = (result.content as LogsData).data.where((e) => e.time.isAfter(_lastTime!));
_logs = [...valid, ..._logs];
_lastTime = DateTime.now();
notifyListeners();
await Future.delayed(const Duration(seconds: 2));
if (_isDisposed == true) return;
_fetchLogs();
}
}

View file

@ -82,14 +82,14 @@ class _AddedListState extends State<AddedList> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully, label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotUpdated, label: AppLocalizations.of(context)!.clientNotUpdated,
color: Colors.red color: Colors.red
@ -109,14 +109,14 @@ class _AddedListState extends State<AddedList> {
if (widget.splitView == true) { if (widget.splitView == true) {
Navigator.of(clientsNavigatorKey.currentContext!).popUntil((route) => false); Navigator.of(clientsNavigatorKey.currentContext!).popUntil((route) => false);
} }
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientDeletedSuccessfully, label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotDeleted, label: AppLocalizations.of(context)!.clientNotDeleted,
color: Colors.red color: Colors.red

View file

@ -1,11 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ClientPlaceholder extends StatelessWidget { class ClientPlaceholder extends StatelessWidget {
const ClientPlaceholder({Key? key}) : super(key: key); const ClientPlaceholder({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return const Center(
child: Text("Select a client"), child: Text("Select a client"),
); );
} }

View file

@ -237,7 +237,8 @@ class _LogsListClientState extends State<LogsListClient> {
context: context, context: context,
builder: (context) => LogDetailsScreen( builder: (context) => LogDetailsScreen(
log: log, log: log,
dialog: true dialog: true,
twoColumns: widget.splitView,
) )
) )
} }
@ -246,7 +247,8 @@ class _LogsListClientState extends State<LogsListClient> {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => LogDetailsScreen( builder: (context) => LogDetailsScreen(
log: log, log: log,
dialog: false dialog: false,
twoColumns: widget.splitView,
) )
) )
) )

View file

@ -5,9 +5,9 @@ class RemoveClientModal extends StatelessWidget {
final void Function() onConfirm; final void Function() onConfirm;
const RemoveClientModal({ const RemoveClientModal({
Key? key, super.key,
required this.onConfirm required this.onConfirm
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -11,11 +11,11 @@ class SafeSearchModal extends StatefulWidget {
final void Function(SafeSearch) onConfirm; final void Function(SafeSearch) onConfirm;
const SafeSearchModal({ const SafeSearchModal({
Key? key, super.key,
required this.safeSearch, required this.safeSearch,
required this.disabled, required this.disabled,
required this.onConfirm required this.onConfirm
}) : super(key: key); });
@override @override
State<SafeSearchModal> createState() => _SafeSearchModalState(); State<SafeSearchModal> createState() => _SafeSearchModalState();

View file

@ -10,10 +10,10 @@ class ServicesModal extends StatefulWidget {
final void Function(List<String>) onConfirm; final void Function(List<String>) onConfirm;
const ServicesModal({ const ServicesModal({
Key? key, super.key,
required this.blockedServices, required this.blockedServices,
required this.onConfirm, required this.onConfirm,
}) : super(key: key); });
@override @override
State<ServicesModal> createState() => _ServicesModalStateWidget(); State<ServicesModal> createState() => _ServicesModalStateWidget();

View file

@ -33,14 +33,14 @@ class ClientsFab extends StatelessWidget {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully, label: AppLocalizations.of(context)!.clientAddedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotAdded, label: AppLocalizations.of(context)!.clientNotAdded,
color: Colors.red color: Colors.red

View file

@ -95,14 +95,14 @@ class _SearchClientsState extends State<SearchClients> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientDeletedSuccessfully, label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotDeleted, label: AppLocalizations.of(context)!.clientNotDeleted,
color: Colors.red color: Colors.red
@ -119,14 +119,14 @@ class _SearchClientsState extends State<SearchClients> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully, label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotUpdated, label: AppLocalizations.of(context)!.clientNotUpdated,
color: Colors.red color: Colors.red
@ -205,7 +205,7 @@ class _SearchClientsState extends State<SearchClients> {
height: 1, height: 1,
decoration: BoxDecoration( decoration: BoxDecoration(
color: showDivider == true color: showDivider == true
? Theme.of(context).colorScheme.surfaceVariant ? Theme.of(context).colorScheme.surfaceContainerHighest
: Colors.transparent : Colors.transparent
), ),
), ),

View file

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart'; import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
class FabConnect extends StatelessWidget { class FabConnect extends StatelessWidget {
const FabConnect({Key? key}) : super(key: key); const FabConnect({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -42,14 +42,14 @@ class AddFiltersButton extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleAddedSuccessfully, label: AppLocalizations.of(context)!.ruleAddedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotAdded, label: AppLocalizations.of(context)!.ruleNotAdded,
color: Colors.red color: Colors.red
@ -67,14 +67,14 @@ class AddFiltersButton extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.customRulesUpdatedSuccessfully, label: AppLocalizations.of(context)!.customRulesUpdatedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.customRulesNotUpdated, label: AppLocalizations.of(context)!.customRulesNotUpdated,
color: Colors.red color: Colors.red
@ -146,28 +146,28 @@ class AddFiltersButton extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result['success'] == true) { if (result['success'] == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: "${AppLocalizations.of(context)!.listAdded} ${result['data']}.", label: "${AppLocalizations.of(context)!.listAdded} ${result['data']}.",
color: Colors.green color: Colors.green
); );
} }
else if (result['success'] == false && result['error'] == 'invalid_url') { else if (result['success'] == false && result['error'] == 'invalid_url') {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listUrlInvalid, label: AppLocalizations.of(context)!.listUrlInvalid,
color: Colors.red color: Colors.red
); );
} }
else if (result['success'] == false && result['error'] == 'url_exists') { else if (result['success'] == false && result['error'] == 'url_exists') {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listAlreadyAdded, label: AppLocalizations.of(context)!.listAlreadyAdded,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listNotAdded, label: AppLocalizations.of(context)!.listNotAdded,
color: Colors.red color: Colors.red

View file

@ -163,7 +163,7 @@ class _CustomRulesListState extends State<CustomRulesList> {
onPressed: () async { onPressed: () async {
final result = await filteringProvider.fetchFilters(); final result = await filteringProvider.fetchFilters();
if (result == false) { if (result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters, label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red color: Colors.red
@ -203,7 +203,7 @@ class _CustomRulesListState extends State<CustomRulesList> {
onRefresh: () async { onRefresh: () async {
final result = await filteringProvider.fetchFilters(); final result = await filteringProvider.fetchFilters();
if (result == false) { if (result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters, label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red color: Colors.red

View file

@ -94,14 +94,14 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
); );
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated, label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated, label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red color: Colors.red
@ -175,6 +175,7 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
_Content( _Content(
isDialog: widget.dialog, isDialog: widget.dialog,
list: list, list: list,
type: widget.type,
) )
], ],
), ),
@ -216,6 +217,7 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
_Content( _Content(
isDialog: widget.dialog, isDialog: widget.dialog,
list: list, list: list,
type: widget.type,
) )
], ],
), ),
@ -261,10 +263,12 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
class _Content extends StatelessWidget { class _Content extends StatelessWidget {
final Filter list; final Filter list;
final bool isDialog; final bool isDialog;
final String type;
const _Content({ const _Content({
required this.list, required this.list,
required this.isDialog required this.isDialog,
required this.type,
}); });
@override @override
@ -339,7 +343,7 @@ class _Content extends StatelessWidget {
CustomListTile( CustomListTile(
icon: Icons.shield_rounded, icon: Icons.shield_rounded,
title: AppLocalizations.of(context)!.listType, title: AppLocalizations.of(context)!.listType,
subtitle: isDialog == 'whitelist' subtitle: type == 'whitelist'
? AppLocalizations.of(context)!.whitelist ? AppLocalizations.of(context)!.whitelist
: AppLocalizations.of(context)!.blacklist, : AppLocalizations.of(context)!.blacklist,
padding: isDialog == true padding: isDialog == true
@ -431,7 +435,7 @@ class _Actions extends StatelessWidget {
); );
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDeleted, label: AppLocalizations.of(context)!.listDeleted,
color: Colors.green color: Colors.green
@ -439,7 +443,7 @@ class _Actions extends StatelessWidget {
Navigator.pop(context); Navigator.pop(context);
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listNotDeleted, label: AppLocalizations.of(context)!.listNotDeleted,
color: Colors.red color: Colors.red

View file

@ -24,7 +24,7 @@ import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
class Filters extends StatefulWidget { class Filters extends StatefulWidget {
const Filters({Key? key}) : super(key: key); const Filters({super.key});
@override @override
State<Filters> createState() => _FiltersState(); State<Filters> createState() => _FiltersState();
@ -57,14 +57,14 @@ class _FiltersState extends State<Filters> {
if (!mounted) return; if (!mounted) return;
processModal.close(); processModal.close();
if (result['success'] == true) { if (result['success'] == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: "${result['data']['updated']} ${AppLocalizations.of(context)!.listsUpdated}", label: "${result['data']['updated']} ${AppLocalizations.of(context)!.listsUpdated}",
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listsNotUpdated, label: AppLocalizations.of(context)!.listsNotUpdated,
color: Colors.red color: Colors.red
@ -109,14 +109,14 @@ class _FiltersState extends State<Filters> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.filteringStatusUpdated, label: AppLocalizations.of(context)!.filteringStatusUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.filteringStatusNotUpdated, label: AppLocalizations.of(context)!.filteringStatusNotUpdated,
color: Colors.red color: Colors.red
@ -133,14 +133,14 @@ class _FiltersState extends State<Filters> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.updateFrequencyChanged, label: AppLocalizations.of(context)!.updateFrequencyChanged,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.updateFrequencyNotChanged, label: AppLocalizations.of(context)!.updateFrequencyNotChanged,
color: Colors.red color: Colors.red
@ -163,14 +163,14 @@ class _FiltersState extends State<Filters> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleRemovedSuccessfully, label: AppLocalizations.of(context)!.ruleRemovedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotRemoved, label: AppLocalizations.of(context)!.ruleNotRemoved,
color: Colors.red color: Colors.red

View file

@ -27,13 +27,13 @@ class FiltersList extends StatefulWidget {
final void Function(Filter, String) onOpenDetailsScreen; final void Function(Filter, String) onOpenDetailsScreen;
const FiltersList({ const FiltersList({
Key? key, super.key,
required this.loadStatus, required this.loadStatus,
required this.scrollController, required this.scrollController,
required this.data, required this.data,
required this.type, required this.type,
required this.onOpenDetailsScreen required this.onOpenDetailsScreen
}) : super(key: key); });
@override @override
State<FiltersList> createState() => _FiltersListState(); State<FiltersList> createState() => _FiltersListState();
@ -133,7 +133,7 @@ class _FiltersListState extends State<FiltersList> {
onPressed: () async { onPressed: () async {
final result = await filteringProvider.fetchFilters(); final result = await filteringProvider.fetchFilters();
if (result == false && mounted) { if (result == false && mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters, label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red color: Colors.red
@ -173,7 +173,7 @@ class _FiltersListState extends State<FiltersList> {
onRefresh: () async { onRefresh: () async {
final result = await filteringProvider.fetchFilters(); final result = await filteringProvider.fetchFilters();
if (result == false && mounted) { if (result == false && mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters, label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red color: Colors.red

View file

@ -84,7 +84,7 @@ class FiltersTripleColumn extends StatelessWidget {
onPressed: () async { onPressed: () async {
final result = await filteringProvider.fetchFilters(); final result = await filteringProvider.fetchFilters();
if (result == false && context.mounted) { if (result == false && context.mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters, label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red color: Colors.red

View file

@ -59,14 +59,14 @@ class ListOptionsMenu extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated, label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated, label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red color: Colors.red

View file

@ -68,14 +68,14 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.blockedServicesUpdated, label: AppLocalizations.of(context)!.blockedServicesUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.blockedServicesNotUpdated, label: AppLocalizations.of(context)!.blockedServicesNotUpdated,
color: Colors.red color: Colors.red
@ -119,24 +119,26 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
SliverOverlapInjector( SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
), ),
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loading) Container( if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loading) SliverFillRemaining(
padding: const EdgeInsets.symmetric(horizontal: 16), child: Container(
width: double.maxFinite, padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column( width: double.maxFinite,
mainAxisAlignment: MainAxisAlignment.center, child: Column(
crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ crossAxisAlignment: CrossAxisAlignment.center,
const CircularProgressIndicator(), children: [
const SizedBox(height: 30), const CircularProgressIndicator(),
Text( const SizedBox(height: 30),
AppLocalizations.of(context)!.loadingBlockedServicesList, Text(
textAlign: TextAlign.center, AppLocalizations.of(context)!.loadingBlockedServicesList,
style: TextStyle( textAlign: TextAlign.center,
fontSize: 22, style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 22,
), color: Theme.of(context).colorScheme.onSurfaceVariant,
) ),
], )
],
),
), ),
), ),
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loaded) SliverList.builder( if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loaded) SliverList.builder(
@ -181,28 +183,30 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
), ),
) )
), ),
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.error) Container( if (filteringProvider.blockedServicesLoadStatus == LoadStatus.error) SliverFillRemaining(
padding: const EdgeInsets.symmetric(horizontal: 16), child: Container(
width: double.maxFinite, padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column( width: double.maxFinite,
mainAxisAlignment: MainAxisAlignment.center, child: Column(
crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ crossAxisAlignment: CrossAxisAlignment.center,
const Icon( children: [
Icons.error, const Icon(
color: Colors.red, Icons.error,
size: 50, color: Colors.red,
), size: 50,
const SizedBox(height: 30),
Text(
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
) const SizedBox(height: 30),
], Text(
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
)
],
),
), ),
) )
], ],

View file

@ -276,16 +276,22 @@ class _CustomRuleEditor extends StatelessWidget {
colors: SegmentedButtonSlideColors( colors: SegmentedButtonSlideColors(
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2), barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
backgroundSelectedColor: Theme.of(context).colorScheme.primary, backgroundSelectedColor: Theme.of(context).colorScheme.primary,
foregroundSelectedColor: Theme.of(context).colorScheme.onPrimary,
foregroundUnselectedColor: Theme.of(context).colorScheme.onSurface,
hoverColor: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
textOverflow: TextOverflow.ellipsis, textOverflow: TextOverflow.ellipsis,
fontSize: 14,
height: 40, height: 40,
margin: const EdgeInsets.symmetric( margin: const EdgeInsets.symmetric(
horizontal: 24, horizontal: 24,
), ),
selectedTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: FontWeight.w700
),
unselectedTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
hoverTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
), ),
Container(height: 20), Container(height: 20),
Material( Material(

View file

@ -5,9 +5,9 @@ class RemoveCustomRule extends StatelessWidget {
final void Function() onConfirm; final void Function() onConfirm;
const RemoveCustomRule({ const RemoveCustomRule({
Key? key, super.key,
required this.onConfirm required this.onConfirm
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -235,10 +235,10 @@ class _Content extends StatelessWidget {
} }
: null, : null,
style: ButtonStyle( style: ButtonStyle(
overlayColor: MaterialStateProperty.all( overlayColor: WidgetStateProperty.all(
Theme.of(context).colorScheme.primary.withOpacity(0.1) Theme.of(context).colorScheme.primary.withOpacity(0.1)
), ),
foregroundColor: MaterialStateProperty.all( foregroundColor: WidgetStateProperty.all(
selectedOption != null selectedOption != null
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Colors.grey, : Colors.grey,

View file

@ -9,11 +9,11 @@ class DeleteSelectionModal extends StatefulWidget {
final void Function() onDelete; final void Function() onDelete;
const DeleteSelectionModal({ const DeleteSelectionModal({
Key? key, super.key,
required this.selectedBlacklists, required this.selectedBlacklists,
required this.selectedWhitelists, required this.selectedWhitelists,
required this.onDelete, required this.onDelete,
}) : super(key: key); });
@override @override
State<DeleteSelectionModal> createState() => _DeleteSelectionModalState(); State<DeleteSelectionModal> createState() => _DeleteSelectionModalState();

View file

@ -9,11 +9,11 @@ class EnableDisableSelectionModal extends StatefulWidget {
final void Function() onDelete; final void Function() onDelete;
const EnableDisableSelectionModal({ const EnableDisableSelectionModal({
Key? key, super.key,
required this.selectedBlacklists, required this.selectedBlacklists,
required this.selectedWhitelists, required this.selectedWhitelists,
required this.onDelete, required this.onDelete,
}) : super(key: key); });
@override @override
State<EnableDisableSelectionModal> createState() => _EnableDisableSelectionModalState(); State<EnableDisableSelectionModal> createState() => _EnableDisableSelectionModalState();

View file

@ -13,13 +13,13 @@ class SelectionList extends StatelessWidget {
final void Function() unselectAll; final void Function() unselectAll;
const SelectionList({ const SelectionList({
Key? key, super.key,
required this.lists, required this.lists,
required this.selectedLists, required this.selectedLists,
required this.onSelect, required this.onSelect,
required this.selectAll, required this.selectAll,
required this.unselectAll, required this.unselectAll,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -231,11 +231,10 @@ class _CheckboxTile extends StatelessWidget {
final bool isSelected; final bool isSelected;
const _CheckboxTile({ const _CheckboxTile({
Key? key,
required this.list, required this.list,
required this.onSelect, required this.onSelect,
required this.isSelected, required this.isSelected,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -82,8 +82,8 @@ class _SelectionScreenState extends State<SelectionScreen> with TickerProviderSt
blacklists: _selectedBlacklists, blacklists: _selectedBlacklists,
whitelists: _selectedWhitelists whitelists: _selectedWhitelists
); );
if (!mounted) return;
processModal.close(); processModal.close();
if (!context.mounted) return;
showDialog( showDialog(
context: context, context: context,
builder: (ctx) => SelectionResultModal( builder: (ctx) => SelectionResultModal(
@ -113,8 +113,8 @@ class _SelectionScreenState extends State<SelectionScreen> with TickerProviderSt
blacklists: _selectedBlacklists, blacklists: _selectedBlacklists,
whitelists: _selectedWhitelists whitelists: _selectedWhitelists
); );
if (!mounted) return;
processModal.close(); processModal.close();
if (!context.mounted) return;
showDialog( showDialog(
context: context, context: context,
builder: (ctx) => SelectionResultModal( builder: (ctx) => SelectionResultModal(

View file

@ -37,7 +37,7 @@ class CombinedChartItem {
} }
class CombinedHomeChart extends StatelessWidget { class CombinedHomeChart extends StatelessWidget {
const CombinedHomeChart({Key? key}) : super(key: key); const CombinedHomeChart({super.key});
List<int>? removeZero(List<int> list) { List<int>? removeZero(List<int> list) {
final removed = list.where((i) => i > 0); final removed = list.where((i) => i > 0);
@ -266,12 +266,11 @@ class _Legend extends StatelessWidget {
final String? secondaryValue; final String? secondaryValue;
const _Legend({ const _Legend({
Key? key,
required this.label, required this.label,
required this.color, required this.color,
required this.primaryValue, required this.primaryValue,
this.secondaryValue this.secondaryValue
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -7,7 +7,7 @@ import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
class HomeFab extends StatelessWidget { class HomeFab extends StatelessWidget {
const HomeFab({Key? key}) : super(key: key); const HomeFab({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -93,7 +93,7 @@ class _HomeState extends State<Home> {
onRefresh: () async { onRefresh: () async {
final result = await statusProvider.getServerStatus(); final result = await statusProvider.getServerStatus();
if (mounted && result == false) { if (mounted && result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverStatusNotRefreshed, label: AppLocalizations.of(context)!.serverStatusNotRefreshed,
color: Colors.red color: Colors.red

View file

@ -82,7 +82,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
time: time time: time
); );
if (mounted && result == false) { if (mounted && result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.invalidUsernamePassword, label: AppLocalizations.of(context)!.invalidUsernamePassword,
color: Colors.red color: Colors.red

View file

@ -8,13 +8,13 @@ class SmallSwitch extends StatelessWidget {
final bool disabled; final bool disabled;
const SmallSwitch({ const SmallSwitch({
Key? key, super.key,
required this.label, required this.label,
required this.icon, required this.icon,
required this.value, required this.value,
required this.onChange, required this.onChange,
required this.disabled, required this.disabled,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -83,14 +83,14 @@ class TopItemsLists extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (rules == true) { if (rules == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated, label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated, label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: Colors.red color: Colors.red
@ -121,21 +121,21 @@ class TopItemsLists extends StatelessWidget {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully, label: AppLocalizations.of(context)!.clientAddedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.content == 'client_another_list') { else if (result.successful == false && result.content == 'client_another_list') {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAnotherList, label: AppLocalizations.of(context)!.clientAnotherList,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: newList == AccessSettingsList.allowed || newList == AccessSettingsList.disallowed label: newList == AccessSettingsList.allowed || newList == AccessSettingsList.disallowed
? AppLocalizations.of(context)!.clientNotRemoved ? AppLocalizations.of(context)!.clientNotRemoved

View file

@ -9,6 +9,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/options_menu.dart'; import 'package:adguard_home_manager/widgets/options_menu.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/widgets/floating_search_bar.dart';
import 'package:adguard_home_manager/models/menu_option.dart'; import 'package:adguard_home_manager/models/menu_option.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
@ -16,6 +17,7 @@ import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/providers/status_provider.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
enum _SortingOptions { highestToLowest, lowestToHighest } enum _SortingOptions { highestToLowest, lowestToHighest }
final GlobalKey _searchButtonKey = GlobalKey();
class TopItemsScreen extends StatefulWidget { class TopItemsScreen extends StatefulWidget {
final HomeTopItems type; final HomeTopItems type;
@ -47,15 +49,18 @@ class TopItemsScreen extends StatefulWidget {
class _TopItemsScreenState extends State<TopItemsScreen> { class _TopItemsScreenState extends State<TopItemsScreen> {
_SortingOptions _sortingOptions = _SortingOptions.highestToLowest; _SortingOptions _sortingOptions = _SortingOptions.highestToLowest;
bool searchActive = false;
final TextEditingController searchController = TextEditingController(); final TextEditingController searchController = TextEditingController();
String? _currentSearchValue = "";
List<Map<String, dynamic>> data = []; List<Map<String, dynamic>> data = [];
List<Map<String, dynamic>> screenData = []; List<Map<String, dynamic>> screenData = [];
void search(String value) { void search(String value) {
List<Map<String, dynamic>> newValues = widget.data.where((item) => item.keys.toList()[0].contains(value)).toList(); List<Map<String, dynamic>> newValues = widget.data.where((item) => item.keys.toList()[0].contains(value)).toList();
setState(() => screenData = newValues); setState(() {
screenData = newValues;
_currentSearchValue = searchController.text;
});
} }
@override @override
@ -75,118 +80,132 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
final sortedValues = _sortingOptions == _SortingOptions.lowestToHighest final sortedValues = _sortingOptions == _SortingOptions.lowestToHighest
? screenData.reversed.toList() ? screenData.reversed.toList()
: screenData.toList(); : screenData.toList();
void showSearchDialog() {
showDialog(
context: context,
builder: (context) => FloatingSearchBar(
existingSearchValue: _currentSearchValue,
searchButtonRenderBox: _searchButtonKey.currentContext?.findRenderObject() as RenderBox?,
onSearchCompleted: (v) {
List<Map<String, dynamic>> newValues = widget.data.where((item) => item.keys.toList()[0].contains(v)).toList();
setState(() {
screenData = newValues;
_currentSearchValue = v;
});
},
),
);
}
if (widget.isFullscreen == true) { if (widget.isFullscreen == true) {
return Dialog.fullscreen( return Scaffold(
child: Scaffold( body: NestedScrollView(
appBar: AppBar( headerSliverBuilder: (context, innerBoxIsScrolled) => [
title: searchActive == true SliverOverlapAbsorber(
? Padding( handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
padding: const EdgeInsets.only(bottom: 3), sliver: SliverAppBar.large(
child: TextFormField( title: Text(widget.title),
controller: searchController, actions: [
onChanged: search, IconButton(
decoration: InputDecoration( key: _searchButtonKey,
hintText: AppLocalizations.of(context)!.search, onPressed: showSearchDialog,
hintStyle: const TextStyle( icon: const Icon(Icons.search_rounded),
fontWeight: FontWeight.normal, tooltip: AppLocalizations.of(context)!.search,
fontSize: 18 ),
PopupMenuButton(
icon: const Icon(Icons.sort_rounded),
itemBuilder: (context) => [
PopupMenuItem(
onTap: () => setState(() => _sortingOptions = _SortingOptions.highestToLowest),
child: Row(
children: [
const Icon(Icons.arrow_downward_rounded),
const SizedBox(width: 8),
Expanded(
child: Text(AppLocalizations.of(context)!.fromHighestToLowest)
),
const SizedBox(width: 16),
Icon(
_sortingOptions == _SortingOptions.highestToLowest
? Icons.radio_button_checked_rounded
: Icons.radio_button_unchecked_rounded,
color: _sortingOptions == _SortingOptions.highestToLowest
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurfaceVariant,
)
],
)
), ),
border: InputBorder.none, PopupMenuItem(
), onTap: () => setState(() => _sortingOptions = _SortingOptions.lowestToHighest),
style: const TextStyle( child: Row(
fontWeight: FontWeight.normal, children: [
fontSize: 18 const Icon(Icons.arrow_upward_rounded),
), const SizedBox(width: 8),
autofocus: true, Expanded(
), child: Text(AppLocalizations.of(context)!.fromLowestToHighest)
) ),
: Text(widget.title), const SizedBox(width: 16),
leading: searchActive == true ? Icon(
IconButton( _sortingOptions == _SortingOptions.lowestToHighest
onPressed: () => setState(() { ? Icons.radio_button_checked_rounded
searchActive = false; : Icons.radio_button_unchecked_rounded,
searchController.text = ''; color: _sortingOptions == _SortingOptions.lowestToHighest
screenData = data; ? Theme.of(context).colorScheme.primary
}), : Theme.of(context).colorScheme.onSurfaceVariant,
icon: const Icon(Icons.arrow_back), )
tooltip: AppLocalizations.of(context)!.exitSearch, ],
) : null,
actions: [
if (searchActive == false) IconButton(
onPressed: () => setState(() => searchActive = true),
icon: const Icon(Icons.search),
tooltip: AppLocalizations.of(context)!.search,
),
if (searchActive == true) IconButton(
onPressed: () => setState(() {
searchController.text = '';
screenData = data;
}),
icon: const Icon(Icons.clear_rounded),
tooltip: AppLocalizations.of(context)!.clearSearch,
),
PopupMenuButton(
icon: const Icon(Icons.sort_rounded),
itemBuilder: (context) => [
PopupMenuItem(
onTap: () => setState(() => _sortingOptions = _SortingOptions.highestToLowest),
child: Row(
children: [
const Icon(Icons.arrow_downward_rounded),
const SizedBox(width: 8),
Expanded(
child: Text(AppLocalizations.of(context)!.fromHighestToLowest)
),
const SizedBox(width: 16),
Icon(
_sortingOptions == _SortingOptions.highestToLowest
? Icons.radio_button_checked_rounded
: Icons.radio_button_unchecked_rounded,
color: _sortingOptions == _SortingOptions.highestToLowest
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurfaceVariant,
) )
], ),
) ],
), ),
PopupMenuItem( const SizedBox(width: 8)
onTap: () => setState(() => _sortingOptions = _SortingOptions.lowestToHighest), ],
child: Row( )
children: [ )
const Icon(Icons.arrow_upward_rounded), ],
const SizedBox(width: 8), body: SafeArea(
Expanded( top: false,
child: Text(AppLocalizations.of(context)!.fromLowestToHighest) bottom: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
if (sortedValues.isEmpty) Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
AppLocalizations.of(context)!.noItemsSearch,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
const SizedBox(width: 16), ),
Icon( ),
_sortingOptions == _SortingOptions.lowestToHighest ),
? Icons.radio_button_checked_rounded if (sortedValues.isNotEmpty) SliverPadding(
: Icons.radio_button_unchecked_rounded, padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewPadding.bottom),
color: _sortingOptions == _SortingOptions.lowestToHighest sliver: SliverList.builder(
? Theme.of(context).colorScheme.primary itemCount: sortedValues.length,
: Theme.of(context).colorScheme.onSurfaceVariant, itemBuilder: (context, index) => _Item(
) data: sortedValues[index],
], isClient: widget.isClient,
) options: widget.options,
total: total,
withProgressBar: widget.withProgressBar,
onTapEntry: widget.onTapEntry,
buildValue: widget.buildValue,
),
),
), ),
], ],
), ),
const SizedBox(width: 8) )
], )
),
body: SafeArea(
child: _Content(
buildValue: widget.buildValue,
isClient: widget.isClient,
onTapEntry: widget.onTapEntry,
options: widget.options,
screenData: sortedValues,
total: total,
withProgressBar: widget.withProgressBar,
),
),
), ),
); );
} }
@ -242,14 +261,29 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
), ),
), ),
Expanded( Expanded(
child: _Content( child: sortedValues.isNotEmpty ? ListView.builder(
buildValue: widget.buildValue, itemCount: sortedValues.length,
isClient: widget.isClient, itemBuilder: (context, index) => _Item(
onTapEntry: widget.onTapEntry, data: sortedValues[index],
options: widget.options, isClient: widget.isClient,
screenData: sortedValues, options: widget.options,
total: total, withProgressBar: widget.withProgressBar,
withProgressBar: widget.withProgressBar, onTapEntry: widget.onTapEntry,
buildValue: widget.buildValue,
total: total,
),
) : Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
AppLocalizations.of(context)!.noItemsSearch,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
), ),
), ),
], ],
@ -260,8 +294,8 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
} }
} }
class _Content extends StatelessWidget { class _Item extends StatelessWidget {
final List<Map<String, dynamic>> screenData; final dynamic data;
final bool? isClient; final bool? isClient;
final List<MenuOption> Function(dynamic) options; final List<MenuOption> Function(dynamic) options;
final bool withProgressBar; final bool withProgressBar;
@ -269,8 +303,8 @@ class _Content extends StatelessWidget {
final String Function(dynamic) buildValue; final String Function(dynamic) buildValue;
final double total; final double total;
const _Content({ const _Item({
required this.screenData, required this.data,
required this.isClient, required this.isClient,
required this.options, required this.options,
required this.withProgressBar, required this.withProgressBar,
@ -283,98 +317,75 @@ class _Content extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final statusProvider = Provider.of<StatusProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
if (screenData.isNotEmpty) { String? name;
return ListView.builder( if (isClient != null && isClient == true) {
padding: const EdgeInsets.only(top: 0), try {
itemCount: screenData.length, name = statusProvider.serverStatus!.clients.firstWhere((c) => c.ids.contains(data.keys.toList()[0])).name;
itemBuilder: (context, index) { } catch (e) {
String? name; // ---- //
if (isClient != null && isClient == true) { }
try {
name = statusProvider.serverStatus!.clients.firstWhere((c) => c.ids.contains(screenData[index].keys.toList()[0])).name;
} catch (e) {
// ---- //
}
}
return OptionsMenu(
options: options,
value: screenData[index].keys.toList()[0],
onTap: onTapEntry != null
? (v) {
onTapEntry!(v);
Navigator.pop(context);
}
: null,
child: CustomListTile(
title: screenData[index].keys.toList()[0],
trailing: Text(
buildValue(screenData[index].values.toList()[0]),
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant
),
),
subtitleWidget: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (name != null) ...[
Text(
name,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 5),
],
if (withProgressBar == true) Row(
children: [
SizedBox(
width: 50,
child: Text(
"${doubleFormat((screenData[index].values.toList()[0]/total*100), Platform.localeName)}%",
style: TextStyle(
color: Theme.of(context).listTileTheme.textColor
),
),
),
const SizedBox(width: 10),
Flexible(
child: LinearPercentIndicator(
animation: true,
lineHeight: 4,
animationDuration: 500,
curve: Curves.easeOut,
percent: screenData[index].values.toList()[0]/total,
barRadius: const Radius.circular(5),
progressColor: Theme.of(context).colorScheme.primary,
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
),
),
const SizedBox(width: 10),
],
),
],
)
),
);
}
);
} }
else {
return Center( return OptionsMenu(
child: Padding( options: options,
padding: const EdgeInsets.symmetric(horizontal: 20), value: data.keys.toList()[0],
child: Text( onTap: onTapEntry != null
AppLocalizations.of(context)!.noItemsSearch, ? (v) {
textAlign: TextAlign.center, onTapEntry!(v);
style: TextStyle( Navigator.pop(context);
fontSize: 22, }
color: Theme.of(context).colorScheme.onSurfaceVariant, : null,
), child: CustomListTile(
title: data.keys.toList()[0],
trailing: Text(
buildValue(data.values.toList()[0]),
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant
), ),
), ),
); subtitleWidget: Column(
} crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (name != null) ...[
Text(
name,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 5),
],
if (withProgressBar == true) Row(
children: [
SizedBox(
width: 50,
child: Text(
"${doubleFormat((data.values.toList()[0]/total*100), Platform.localeName)}%",
style: TextStyle(
color: Theme.of(context).listTileTheme.textColor
),
),
),
const SizedBox(width: 10),
Flexible(
child: LinearPercentIndicator(
animation: true,
lineHeight: 4,
animationDuration: 500,
curve: Curves.easeOut,
percent: data.values.toList()[0]/total,
barRadius: const Radius.circular(5),
progressColor: Theme.of(context).colorScheme.primary,
backgroundColor: Theme.of(context).colorScheme.surfaceTint.withOpacity(0.2),
),
),
const SizedBox(width: 10),
],
),
],
)
),
);
} }
} }

View file

@ -1,6 +1,5 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@ -11,6 +10,7 @@ import 'package:adguard_home_manager/screens/logs/details/log_list_tile.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart'; import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
import 'package:adguard_home_manager/constants/urls.dart'; import 'package:adguard_home_manager/constants/urls.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/get_filtered_status.dart'; import 'package:adguard_home_manager/functions/get_filtered_status.dart';
@ -24,11 +24,13 @@ import 'package:adguard_home_manager/providers/app_config_provider.dart';
class LogDetailsScreen extends StatelessWidget { class LogDetailsScreen extends StatelessWidget {
final Log log; final Log log;
final bool dialog; final bool dialog;
final bool twoColumns;
const LogDetailsScreen({ const LogDetailsScreen({
super.key, super.key,
required this.log, required this.log,
required this.dialog required this.dialog,
required this.twoColumns,
}); });
@override @override
@ -50,14 +52,14 @@ class LogDetailsScreen extends StatelessWidget {
processModal.close(); processModal.close();
if (rules == true) { if (rules == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated, label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated, label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: Colors.red color: Colors.red
@ -148,6 +150,7 @@ class LogDetailsScreen extends StatelessWidget {
centerTitle: false, centerTitle: false,
forceElevated: innerBoxIsScrolled, forceElevated: innerBoxIsScrolled,
surfaceTintColor: isDesktop(width) ? Colors.transparent : null, surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
automaticallyImplyLeading: twoColumns != true,
title: Text(AppLocalizations.of(context)!.logDetails), title: Text(AppLocalizations.of(context)!.logDetails),
actions: [ actions: [
IconButton( IconButton(

View file

@ -187,9 +187,15 @@ class _ClientsModalState extends State<ClientsModal> {
colors: SegmentedButtonSlideColors( colors: SegmentedButtonSlideColors(
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2), barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
backgroundSelectedColor: Theme.of(context).colorScheme.primary, backgroundSelectedColor: Theme.of(context).colorScheme.primary,
foregroundSelectedColor: Theme.of(context).colorScheme.onPrimary, ),
foregroundUnselectedColor: Theme.of(context).colorScheme.onSurface, selectedTextStyle: TextStyle(
hoverColor: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onPrimary,
),
unselectedTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
hoverTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
), ),
@ -274,9 +280,16 @@ class _ClientsModalState extends State<ClientsModal> {
colors: SegmentedButtonSlideColors( colors: SegmentedButtonSlideColors(
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2), barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
backgroundSelectedColor: Theme.of(context).colorScheme.primary, backgroundSelectedColor: Theme.of(context).colorScheme.primary,
foregroundSelectedColor: Theme.of(context).colorScheme.onPrimary, ),
foregroundUnselectedColor: Theme.of(context).colorScheme.onSurface, selectedTextStyle: TextStyle(
hoverColor: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onPrimary,
fontWeight: FontWeight.w700
),
unselectedTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
hoverTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
), ),

View file

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/logs/log_tile.dart';
import 'package:adguard_home_manager/screens/logs/details/log_details_screen.dart';
import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/providers/live_logs_provider.dart';
class LiveLogsList extends StatelessWidget {
final Log? selectedLog;
final void Function(Log) onLogSelected;
final bool twoColumns;
const LiveLogsList({
super.key,
required this.selectedLog,
required this.onLogSelected,
required this.twoColumns,
});
@override
Widget build(BuildContext context) {
final liveLogsProvider = Provider.of<LiveLogsProvider>(context);
return NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar.large(
title: Text(AppLocalizations.of(context)!.liveLogs),
)
)
],
body: SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
if (liveLogsProvider.logs.isEmpty) SliverFillRemaining(
child: Center(
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(
AppLocalizations.of(context)!.hereWillAppearRealtimeLogs,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 22
),
),
),
),
),
if (liveLogsProvider.logs.isNotEmpty) SliverPadding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewPadding.bottom),
sliver: SliverList.builder(
itemCount: liveLogsProvider.logs.length,
itemBuilder: (context, index) => LogTile(
log: liveLogsProvider.logs[index],
length: liveLogsProvider.logs.length,
index: index,
onLogTap: (log) {
if (!twoColumns) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => LogDetailsScreen(
log: log,
dialog: false,
twoColumns: twoColumns,
)
)
);
}
onLogSelected(log);
},
isLogSelected: selectedLog == liveLogsProvider.logs[index],
twoColumns: twoColumns
),
),
)
],
),
)
)
);
}
}

View file

@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:adguard_home_manager/screens/logs/details/log_details_screen.dart';
import 'package:adguard_home_manager/screens/logs/live/live_logs_list.dart';
import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/providers/live_logs_provider.dart';
class LiveLogsScreen extends StatefulWidget {
const LiveLogsScreen({super.key});
@override
State<LiveLogsScreen> createState() => _LiveLogsScreenState();
}
class _LiveLogsScreenState extends State<LiveLogsScreen> {
Log? _selectedLog;
@override
void initState() {
Provider.of<LiveLogsProvider>(context, listen: false).startFetchLogs();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 800) {
return Material(
color: Colors.transparent,
child: Row(
children: [
Expanded(
flex: 2,
child: LiveLogsList(
twoColumns: true,
selectedLog: _selectedLog,
onLogSelected: (log) => setState(() => _selectedLog = log),
)
),
Expanded(
flex: 3,
child: _selectedLog != null
? LogDetailsScreen(
log: _selectedLog!,
dialog: false,
twoColumns: true,
)
: const SizedBox()
)
],
),
);
}
else {
return LiveLogsList(
twoColumns: false,
selectedLog: _selectedLog,
onLogSelected: (log) => setState(() => _selectedLog = log),
);
}
},
),
);
}
}

View file

@ -108,14 +108,14 @@ class LogTile extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (rules == true) { if (rules == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated, label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated, label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: Colors.red color: Colors.red
@ -134,14 +134,14 @@ class LogTile extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully, label: AppLocalizations.of(context)!.clientAddedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotAdded, label: AppLocalizations.of(context)!.clientNotAdded,
color: Colors.red color: Colors.red
@ -163,7 +163,7 @@ class LogTile extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: isDomainBlocked(log.reason) == true label: isDomainBlocked(log.reason) == true
? AppLocalizations.of(context)!.domainUnblockedThisClient(log.question.name!) ? AppLocalizations.of(context)!.domainUnblockedThisClient(log.question.name!)
@ -172,7 +172,7 @@ class LogTile extends StatelessWidget {
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotAdded, label: AppLocalizations.of(context)!.ruleNotAdded,
color: Colors.red color: Colors.red
@ -199,21 +199,21 @@ class LogTile extends StatelessWidget {
if (!context.mounted) return; if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully, label: AppLocalizations.of(context)!.clientAddedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.content == 'client_another_list') { else if (result.successful == false && result.content == 'client_another_list') {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAnotherList, label: AppLocalizations.of(context)!.clientAnotherList,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.changesNotSaved, label: AppLocalizations.of(context)!.changesNotSaved,
color: Colors.red color: Colors.red

View file

@ -48,6 +48,7 @@ class _LogsState extends State<Logs> {
? LogDetailsScreen( ? LogDetailsScreen(
log: _selectedLog!, log: _selectedLog!,
dialog: false, dialog: false,
twoColumns: true,
) )
: const SizedBox() : const SizedBox()
) )

View file

@ -42,7 +42,7 @@ class _LogsListWidgetState extends State<LogsListWidget> {
final result = await statusProvider.getFilteringRules(); final result = await statusProvider.getFilteringRules();
if (mounted && result == false) { if (mounted && result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.couldntGetFilteringStatus, label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
color: Colors.red color: Colors.red
@ -56,7 +56,7 @@ class _LogsListWidgetState extends State<LogsListWidget> {
final result = await clientsProvider.fetchClients(); final result = await clientsProvider.fetchClients();
if (mounted && result == false) { if (mounted && result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.couldntGetFilteringStatus, label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
color: Colors.red color: Colors.red
@ -188,6 +188,7 @@ class _LogsListWidgetState extends State<LogsListWidget> {
builder: (context) => LogDetailsScreen( builder: (context) => LogDetailsScreen(
log: log, log: log,
dialog: false, dialog: false,
twoColumns: widget.twoColumns,
) )
) )
); );

View file

@ -6,11 +6,14 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/logs/live/live_logs_screen.dart';
import 'package:adguard_home_manager/screens/logs/filters/logs_filters_modal.dart'; import 'package:adguard_home_manager/screens/logs/filters/logs_filters_modal.dart';
import 'package:adguard_home_manager/widgets/floating_search_bar.dart';
import 'package:adguard_home_manager/config/globals.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart'; import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/providers/live_logs_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/applied_filters.dart'; import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
@ -58,9 +61,10 @@ class LogsListAppBar extends StatelessWidget {
void showSearchDialog() { void showSearchDialog() {
showDialog( showDialog(
context: context, context: context,
builder: (context) => _Search( builder: (context) => FloatingSearchBar(
existingSearchValue: logsProvider.appliedFilters.searchText ?? "",
searchButtonRenderBox: _searchButtonKey.currentContext?.findRenderObject() as RenderBox?, searchButtonRenderBox: _searchButtonKey.currentContext?.findRenderObject() as RenderBox?,
onSearch: (v) { onSearchCompleted: (v) {
logsProvider.setAppliedFilters( logsProvider.setAppliedFilters(
AppliedFiters( AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus, selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
@ -70,10 +74,36 @@ class LogsListAppBar extends StatelessWidget {
); );
logsProvider.filterLogs(); logsProvider.filterLogs();
}, },
onSearchFieldUpdated: (v) {
if (v == "") {
logsProvider.setSearchText(null);
return;
}
logsProvider.setSearchText(v);
},
onSearchFieldCleared: () {
logsProvider.setSearchText(null);
},
), ),
); );
} }
void openLiveLogsScreen() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MultiProvider(
providers: [
ChangeNotifierProxyProvider<ServersProvider, LiveLogsProvider>(
create: (context) => LiveLogsProvider(),
update: (context, servers, logs) => logs!..update(servers),
),
],
child: const LiveLogsScreen()
)
)
);
}
final Map<String, String> translatedString = { final Map<String, String> translatedString = {
"all": AppLocalizations.of(context)!.all, "all": AppLocalizations.of(context)!.all,
"filtered": AppLocalizations.of(context)!.filtered, "filtered": AppLocalizations.of(context)!.filtered,
@ -104,10 +134,29 @@ class LogsListAppBar extends StatelessWidget {
icon: const Icon(Icons.search_rounded), icon: const Icon(Icons.search_rounded),
tooltip: AppLocalizations.of(context)!.search, tooltip: AppLocalizations.of(context)!.search,
), ),
if (logsProvider.loadStatus == LoadStatus.loaded) IconButton( if (logsProvider.loadStatus == LoadStatus.loaded) PopupMenuButton(
onPressed: openFilersModal, itemBuilder: (context) => [
icon: const Icon(Icons.filter_list_rounded), PopupMenuItem(
tooltip: AppLocalizations.of(context)!.filters, onTap: openFilersModal,
child: Row(
children: [
const Icon(Icons.filter_list_rounded),
const SizedBox(width: 10),
Text(AppLocalizations.of(context)!.filters)
],
)
),
PopupMenuItem(
onTap: openLiveLogsScreen,
child: Row(
children: [
const Icon(Icons.stream_rounded),
const SizedBox(width: 10),
Text(AppLocalizations.of(context)!.liveLogs)
],
)
),
],
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
], ],
@ -241,105 +290,3 @@ class LogsListAppBar extends StatelessWidget {
} }
} }
class _Search extends StatefulWidget {
final void Function(String) onSearch;
final RenderBox? searchButtonRenderBox;
const _Search({
required this.onSearch,
required this.searchButtonRenderBox,
});
@override
State<_Search> createState() => _SearchState();
}
class _SearchState extends State<_Search> {
final _searchController = TextEditingController();
@override
void initState() {
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
_searchController.text = logsProvider.appliedFilters.searchText ?? "";
super.initState();
}
@override
Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
final position = widget.searchButtonRenderBox?.localToGlobal(Offset.zero);
final topPadding = MediaQuery.of(globalNavigatorKey.currentContext!).viewPadding.top;
return GestureDetector(
onTap: () => Navigator.pop(context),
child: Material(
color: Colors.transparent,
child: LayoutBuilder(
builder: (context, constraints) {
final double width = constraints.maxWidth - 32 > 500 ? 500 : constraints.maxWidth - 32;
return Stack(
alignment: Alignment.topCenter,
children: [
Positioned(
top: position != null ? position.dy - topPadding : topPadding,
child: SizedBox(
width: width,
child: GestureDetector(
onTap: () => {},
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16)
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: TextFormField(
controller: _searchController,
onChanged: (v) {
if (v == "") {
logsProvider.setSearchText(null);
return;
}
logsProvider.setSearchText(v);
},
onFieldSubmitted: (v) {
widget.onSearch(v);
Navigator.pop(context);
},
autofocus: true,
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.search,
prefixIcon: const Icon(Icons.search_rounded),
border: InputBorder.none,
filled: true,
fillColor: Colors.grey.withOpacity(0.2),
suffixIcon: _searchController.text != ""
? IconButton(
onPressed: () {
_searchController.text = "";
logsProvider.setSearchText(null);
},
icon: const Icon(
Icons.close_rounded,
size: 20,
),
tooltip: AppLocalizations.of(context)!.clearSearch,
)
: null
),
),
),
),
),
),
)
],
);
}
),
),
);
}
}

View file

@ -71,7 +71,7 @@ class _ClientsListState extends State<ClientsList> {
Future refetchClients() async { Future refetchClients() async {
final result = await clientsProvider.fetchClients(); final result = await clientsProvider.fetchClients();
if (result == false && mounted) { if (result == false && mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientsNotLoaded, label: AppLocalizations.of(context)!.clientsNotLoaded,
color: Colors.red color: Colors.red
@ -104,21 +104,21 @@ class _ClientsListState extends State<ClientsList> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientRemovedSuccessfully, label: AppLocalizations.of(context)!.clientRemovedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.content == 'client_another_list') { else if (result.successful == false && result.content == 'client_another_list') {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAnotherList, label: AppLocalizations.of(context)!.clientAnotherList,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: type == AccessSettingsList.allowed || type == AccessSettingsList.disallowed label: type == AccessSettingsList.allowed || type == AccessSettingsList.disallowed
? AppLocalizations.of(context)!.clientNotRemoved ? AppLocalizations.of(context)!.clientNotRemoved
@ -137,21 +137,21 @@ class _ClientsListState extends State<ClientsList> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully, label: AppLocalizations.of(context)!.clientAddedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.content == 'client_another_list') { else if (result.successful == false && result.content == 'client_another_list') {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAnotherList, label: AppLocalizations.of(context)!.clientAnotherList,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: type == AccessSettingsList.allowed || type == AccessSettingsList.disallowed label: type == AccessSettingsList.allowed || type == AccessSettingsList.disallowed
? AppLocalizations.of(context)!.clientNotRemoved ? AppLocalizations.of(context)!.clientNotRemoved

View file

@ -26,14 +26,14 @@ class AdvancedSettings extends StatelessWidget {
final result = await function(newStatus); final result = await function(newStatus);
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully, label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.cannotUpdateSettings, label: AppLocalizations.of(context)!.cannotUpdateSettings,
color: Colors.red color: Colors.red

View file

@ -31,7 +31,7 @@ class ColorItem extends StatelessWidget {
child: InkWell( child: InkWell(
onTap: () => onChanged(numericValue), onTap: () => onChanged(numericValue),
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
overlayColor: const MaterialStatePropertyAll(Colors.grey), overlayColor: const WidgetStatePropertyAll(Colors.grey),
child: Container( child: Container(
width: 50, width: 50,
height: 50, height: 50,

View file

@ -9,14 +9,14 @@ class ThemeModeButton extends StatelessWidget {
final bool? disabled; final bool? disabled;
const ThemeModeButton({ const ThemeModeButton({
Key? key, super.key,
required this.icon, required this.icon,
required this.value, required this.value,
required this.selected, required this.selected,
required this.label, required this.label,
required this.onChanged, required this.onChanged,
this.disabled this.disabled
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -32,19 +32,19 @@ class ThemeModeButton extends StatelessWidget {
? () => onChanged(value) ? () => onChanged(value)
: null, : null,
style: ButtonStyle( style: ButtonStyle(
elevation: MaterialStateProperty.all(0), elevation: WidgetStateProperty.all(0),
shape: MaterialStateProperty.all( shape: WidgetStateProperty.all(
RoundedRectangleBorder( RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
) )
), ),
backgroundColor: MaterialStateProperty.all( backgroundColor: WidgetStateProperty.all(
value == selected value == selected
? disabled == null || disabled == false ? disabled == null || disabled == false
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: greyBackgroundColor : greyBackgroundColor
: disabled == null || disabled == false : disabled == null || disabled == false
? Theme.of(context).colorScheme.surfaceVariant ? Theme.of(context).colorScheme.surfaceTint.withOpacity(0.1)
: greyBackgroundColor, : greyBackgroundColor,
) )
), ),

View file

@ -5,9 +5,9 @@ class DeleteStaticLeaseModal extends StatelessWidget {
final void Function() onConfirm; final void Function() onConfirm;
const DeleteStaticLeaseModal({ const DeleteStaticLeaseModal({
Key? key, super.key,
required this.onConfirm required this.onConfirm
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -221,14 +221,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
if (!mounted) return; if (!mounted) return;
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsSaved, label: AppLocalizations.of(context)!.settingsSaved,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved, label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red color: Colors.red
@ -245,14 +245,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
clearAll(); clearAll();
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.configRestored, label: AppLocalizations.of(context)!.configRestored,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.configNotRestored, label: AppLocalizations.of(context)!.configNotRestored,
color: Colors.red color: Colors.red
@ -276,14 +276,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
data.dhcpStatus!.leases = []; data.dhcpStatus!.leases = [];
dhcpProvider.setDhcpData(data); dhcpProvider.setDhcpData(data);
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.leasesRestored, label: AppLocalizations.of(context)!.leasesRestored,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.leasesNotRestored, label: AppLocalizations.of(context)!.leasesNotRestored,
color: Colors.red color: Colors.red

View file

@ -43,14 +43,14 @@ class DhcpLeases extends StatelessWidget {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseDeleted, label: AppLocalizations.of(context)!.staticLeaseDeleted,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseNotDeleted, label: AppLocalizations.of(context)!.staticLeaseNotDeleted,
color: Colors.red color: Colors.red
@ -67,28 +67,28 @@ class DhcpLeases extends StatelessWidget {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseCreated, label: AppLocalizations.of(context)!.staticLeaseCreated,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.content == "already_exists") { else if (result.successful == false && result.content == "already_exists") {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseExists, label: AppLocalizations.of(context)!.staticLeaseExists,
color: Colors.red color: Colors.red
); );
} }
else if (result.successful == false && result.content == "server_not_configured") { else if (result.successful == false && result.content == "server_not_configured") {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverNotConfigured, label: AppLocalizations.of(context)!.serverNotConfigured,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseNotCreated, label: AppLocalizations.of(context)!.staticLeaseNotCreated,
color: Colors.red color: Colors.red

View file

@ -80,21 +80,21 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.statusCode == 400) { else if (result.successful == false && result.statusCode == 400) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,
color: Colors.red color: Colors.red
@ -197,7 +197,7 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
) )
], ],
), ),
)).toList(), )),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View file

@ -86,21 +86,21 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful== false && result.statusCode == 400) { else if (result.successful== false && result.statusCode == 400) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,
color: Colors.red color: Colors.red
@ -139,14 +139,14 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
void clearCache() async { void clearCache() async {
final result = await clearDnsCache(context, serversProvider.selectedServer!); final result = await clearDnsCache(context, serversProvider.selectedServer!);
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsCacheCleared, label: AppLocalizations.of(context)!.dnsCacheCleared,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsCacheNotCleared, label: AppLocalizations.of(context)!.dnsCacheNotCleared,
color: Colors.red color: Colors.red

View file

@ -66,14 +66,14 @@ class _DnsSettingsState extends State<DnsSettings> {
void clearCache() async { void clearCache() async {
final result = await clearDnsCache(context, serversProvider.selectedServer!); final result = await clearDnsCache(context, serversProvider.selectedServer!);
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsCacheCleared, label: AppLocalizations.of(context)!.dnsCacheCleared,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsCacheNotCleared, label: AppLocalizations.of(context)!.dnsCacheNotCleared,
color: Colors.red color: Colors.red

View file

@ -183,21 +183,21 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.statusCode == 400) { else if (result.successful == false && result.statusCode == 400) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,
color: Colors.red color: Colors.red

View file

@ -91,21 +91,21 @@ class _FallbackDnsScreenState extends State<FallbackDnsScreen> {
if (!context.mounted) return; if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.statusCode == 400) { else if (result.successful == false && result.statusCode == 400) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,
color: Colors.red color: Colors.red

View file

@ -112,21 +112,21 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.statusCode == 400) { else if (result.successful == false && result.statusCode == 400) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,
color: Colors.red color: Colors.red

View file

@ -152,21 +152,21 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result.successful == false && result.statusCode == 400) { else if (result.successful == false && result.statusCode == 400) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
color: Colors.red color: Colors.red
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,
color: Colors.red color: Colors.red

View file

@ -5,9 +5,9 @@ class DeleteDnsRewrite extends StatelessWidget {
final void Function() onConfirm; final void Function() onConfirm;
const DeleteDnsRewrite({ const DeleteDnsRewrite({
Key? key, super.key,
required this.onConfirm required this.onConfirm
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -67,14 +67,14 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleDeleted, label: AppLocalizations.of(context)!.dnsRewriteRuleDeleted,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleNotDeleted, label: AppLocalizations.of(context)!.dnsRewriteRuleNotDeleted,
color: Colors.red color: Colors.red
@ -91,14 +91,14 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleAdded, label: AppLocalizations.of(context)!.dnsRewriteRuleAdded,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleNotAdded, label: AppLocalizations.of(context)!.dnsRewriteRuleNotAdded,
color: Colors.red color: Colors.red
@ -115,14 +115,14 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleUpdated, label: AppLocalizations.of(context)!.dnsRewriteRuleUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleNotUpdated, label: AppLocalizations.of(context)!.dnsRewriteRuleNotUpdated,
color: Colors.red color: Colors.red
@ -169,7 +169,7 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
onRefresh: () async { onRefresh: () async {
final result = await rewriteRulesProvider.fetchRules(); final result = await rewriteRulesProvider.fetchRules();
if (result == false) { if (result == false) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.rewriteRulesNotLoaded, label: AppLocalizations.of(context)!.rewriteRulesNotLoaded,
color: Colors.red color: Colors.red

View file

@ -5,9 +5,9 @@ class EncryptionErrorModal extends StatelessWidget {
final String error; final String error;
const EncryptionErrorModal({ const EncryptionErrorModal({
Key? key, super.key,
required this.error, required this.error,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -12,7 +12,7 @@ class EncryptionTextField extends StatelessWidget {
final String? helperText; final String? helperText;
const EncryptionTextField({ const EncryptionTextField({
Key? key, super.key,
required this.enabled, required this.enabled,
required this.controller, required this.controller,
required this.icon, required this.icon,
@ -22,7 +22,7 @@ class EncryptionTextField extends StatelessWidget {
this.keyboardType, this.keyboardType,
this.multiline, this.multiline,
this.helperText, this.helperText,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -233,14 +233,14 @@ class _EncryptionSettingsState extends State<EncryptionSettings> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.encryptionConfigSaved, label: AppLocalizations.of(context)!.encryptionConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.encryptionConfigNotSaved, label: AppLocalizations.of(context)!.encryptionConfigNotSaved,
color: Colors.red color: Colors.red
@ -282,14 +282,14 @@ class _EncryptionSettingsState extends State<EncryptionSettings> {
processModal.close(); processModal.close();
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.configurationResetSuccessfully, label: AppLocalizations.of(context)!.configurationResetSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.configurationResetError, label: AppLocalizations.of(context)!.configurationResetError,
color: Colors.red color: Colors.red

View file

@ -5,9 +5,9 @@ class ErrorMessageEncryption extends StatelessWidget {
final String errorMessage; final String errorMessage;
const ErrorMessageEncryption({ const ErrorMessageEncryption({
Key? key, super.key,
required this.errorMessage, required this.errorMessage,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -6,10 +6,10 @@ class EncryptionMasterSwitch extends StatelessWidget {
final void Function(bool) onChange; final void Function(bool) onChange;
const EncryptionMasterSwitch({ const EncryptionMasterSwitch({
Key? key, super.key,
required this.value, required this.value,
required this.onChange required this.onChange
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -8,10 +8,10 @@ class Status extends StatelessWidget {
final String label; final String label;
const Status({ const Status({
Key? key, super.key,
required this.valid, required this.valid,
required this.label required this.label
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -3,8 +3,8 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:install_referrer/install_referrer.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:store_checker/store_checker.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/settings.dart'; import 'package:adguard_home_manager/screens/settings/settings.dart';
@ -49,14 +49,14 @@ class _GeneralSettingsState extends State<GeneralSettings> {
}) async { }) async {
final result = await function(newStatus); final result = await function(newStatus);
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully, label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.cannotUpdateSettings, label: AppLocalizations.of(context)!.cannotUpdateSettings,
color: Colors.red color: Colors.red
@ -253,14 +253,7 @@ class _GeneralSettingsState extends State<GeneralSettings> {
right: 10 right: 10
) )
), ),
if ( if (!(Platform.isAndroid || Platform.isIOS) || (Platform.isAndroid && (appConfigProvider.installationSource == InstallationAppReferrer.androidManually ))) ...[
!(Platform.isAndroid || Platform.isIOS) ||
(Platform.isAndroid && (
appConfigProvider.installationSource == Source.IS_INSTALLED_FROM_LOCAL_SOURCE ||
appConfigProvider.installationSource == Source.IS_INSTALLED_FROM_PLAY_PACKAGE_INSTALLER ||
appConfigProvider.installationSource == Source.UNKNOWN
))
) ...[
SectionLabel(label: AppLocalizations.of(context)!.application), SectionLabel(label: AppLocalizations.of(context)!.application),
CustomListTile( CustomListTile(
icon: Icons.system_update_rounded, icon: Icons.system_update_rounded,

View file

@ -43,14 +43,14 @@ class _TopItemsListSettingsState extends State<TopItemsListSettings> with Ticker
final result = await appConfigProvider.setHomeTopItemsOrder(persistHomeTopItemsList); final result = await appConfigProvider.setHomeTopItemsOrder(persistHomeTopItemsList);
if (!context.mounted) return; if (!context.mounted) return;
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsSaved, label: AppLocalizations.of(context)!.settingsSaved,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved, label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red color: Colors.red

View file

@ -102,17 +102,17 @@ class _LogsSettingsState extends State<LogsSettings> {
processModal.close(); processModal.close();
if (!mounted) return; if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsCleared, label: AppLocalizations.of(context)!.logsCleared,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsNotCleared, label: AppLocalizations.of(context)!.logsNotCleared,
color: Colors.red color: Colors.red
@ -135,17 +135,17 @@ class _LogsSettingsState extends State<LogsSettings> {
processModal.close(); processModal.close();
if (!mounted) return; if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsConfigUpdated, label: AppLocalizations.of(context)!.logsConfigUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsConfigNotUpdated, label: AppLocalizations.of(context)!.logsConfigNotUpdated,
color: Colors.red color: Colors.red

View file

@ -90,7 +90,7 @@ class _SafeSearchSettingsScreenState extends State<SafeSearchSettingsScreen> {
processModal.close(); processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully, label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
color: Colors.green, color: Colors.green,
@ -98,7 +98,7 @@ class _SafeSearchSettingsScreenState extends State<SafeSearchSettingsScreen> {
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved, label: AppLocalizations.of(context)!.settingsNotSaved,
color: Colors.red, color: Colors.red,

View file

@ -148,14 +148,14 @@ class _StatisticsSettingsState extends State<StatisticsSettings> {
if (!context.mounted) return; if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.statisticsConfigUpdated, label: AppLocalizations.of(context)!.statisticsConfigUpdated,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.statisticsConfigNotUpdated, label: AppLocalizations.of(context)!.statisticsConfigNotUpdated,
color: Colors.red color: Colors.red

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class AutoUpdateUnavailableModal extends StatelessWidget { class AutoUpdateUnavailableModal extends StatelessWidget {
const AutoUpdateUnavailableModal({Key? key}) : super(key: key); const AutoUpdateUnavailableModal({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -41,7 +41,7 @@ class UpdateScreen extends StatelessWidget {
if (result.successful == true) { if (result.successful == true) {
serversProvider.recheckPeriodServerUpdated(); serversProvider.recheckPeriodServerUpdated();
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.requestStartUpdateSuccessful, label: AppLocalizations.of(context)!.requestStartUpdateSuccessful,
color: Colors.green, color: Colors.green,
@ -49,7 +49,7 @@ class UpdateScreen extends StatelessWidget {
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.requestStartUpdateFailed, label: AppLocalizations.of(context)!.requestStartUpdateFailed,
color: Colors.red, color: Colors.red,
@ -203,7 +203,7 @@ class UpdateScreen extends StatelessWidget {
body: Column( body: Column(
children: [ children: [
Container( Container(
color: Theme.of(context).colorScheme.surfaceVariant, color: Theme.of(context).colorScheme.surfaceContainerHighest,
child: SafeArea( child: SafeArea(
child: headerPortrait() child: headerPortrait()
) )

View file

@ -88,7 +88,7 @@ class _UpdateScreenState extends State<UpdateScreen> {
if (!context.mounted) return; if (!context.mounted) return;
if (result.successful == true) { if (result.successful == true) {
serversProvider.recheckPeriodServerUpdated(); serversProvider.recheckPeriodServerUpdated();
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.requestStartUpdateSuccessful, label: AppLocalizations.of(context)!.requestStartUpdateSuccessful,
color: Colors.green, color: Colors.green,
@ -96,7 +96,7 @@ class _UpdateScreenState extends State<UpdateScreen> {
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.requestStartUpdateFailed, label: AppLocalizations.of(context)!.requestStartUpdateFailed,
color: Colors.red, color: Colors.red,
@ -220,7 +220,7 @@ class _Header extends SliverPersistentHeaderDelegate {
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) => Container( builder: (context, constraints) => Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceVariant, color: Theme.of(context).colorScheme.surfaceContainerHighest,
), ),
child: Align( child: Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,

View file

@ -206,14 +206,14 @@ class ApiClientV2 {
} }
Future<ApiResponse> getLogs({ Future<ApiResponse> getLogs({
required int count, int? count,
int? offset, int? offset,
DateTime? olderThan, DateTime? olderThan,
String? responseStatus, String? responseStatus,
String? search String? search
}) async { }) async {
final result = await HttpRequestClient.get( final result = await HttpRequestClient.get(
urlPath: '/querylog?limit=$count${offset != null ? '&offset=$offset' : ''}${olderThan != null ? '&older_than=${olderThan.toIso8601String()}' : ''}${responseStatus != null ? '&response_status=$responseStatus' : ''}${search != null ? '&search=$search' : ''}', urlPath: '/querylog?${count != null ? 'limit=$count' : ''}${offset != null ? '&offset=$offset' : ''}${olderThan != null ? '&older_than=${olderThan.toIso8601String()}' : ''}${responseStatus != null ? '&response_status=$responseStatus' : ''}${search != null ? '&search=$search' : ''}',
server: server server: server
); );
if (result.successful == true) { if (result.successful == true) {

View file

@ -157,7 +157,7 @@ class _AddServerModalState extends State<AddServerModal> {
if (result != AuthStatus.success) { if (result != AuthStatus.success) {
cancelConnecting(); cancelConnecting();
if (mounted) { if (mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: getErrorMessage(result), label: getErrorMessage(result),
color: Colors.red color: Colors.red
@ -206,7 +206,7 @@ class _AddServerModalState extends State<AddServerModal> {
if (serverCreated != null) { if (serverCreated != null) {
if (mounted) setState(() => isConnecting = false); if (mounted) setState(() => isConnecting = false);
if (mounted) { if (mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionNotCreated, label: AppLocalizations.of(context)!.connectionNotCreated,
color: Colors.red color: Colors.red
@ -256,7 +256,7 @@ class _AddServerModalState extends State<AddServerModal> {
if (result != AuthStatus.success) { if (result != AuthStatus.success) {
cancelConnecting(); cancelConnecting();
if (mounted) { if (mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: getErrorMessage(result), label: getErrorMessage(result),
color: Colors.red color: Colors.red
@ -306,7 +306,7 @@ class _AddServerModalState extends State<AddServerModal> {
) )
); );
if (mounted) { if (mounted) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionNotCreated, label: AppLocalizations.of(context)!.connectionNotCreated,
color: Colors.red color: Colors.red
@ -419,16 +419,22 @@ class _AddServerModalState extends State<AddServerModal> {
colors: SegmentedButtonSlideColors( colors: SegmentedButtonSlideColors(
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2), barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
backgroundSelectedColor: Theme.of(context).colorScheme.primary, backgroundSelectedColor: Theme.of(context).colorScheme.primary,
foregroundSelectedColor: Theme.of(context).colorScheme.onPrimary,
foregroundUnselectedColor: Theme.of(context).colorScheme.onSurface,
hoverColor: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
textOverflow: TextOverflow.ellipsis, textOverflow: TextOverflow.ellipsis,
fontSize: 14,
height: 40, height: 40,
margin: const EdgeInsets.symmetric( margin: const EdgeInsets.symmetric(
horizontal: 24, horizontal: 24,
), ),
selectedTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: FontWeight.w700
),
unselectedTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
hoverTextStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
), ),
Card( Card(
margin: const EdgeInsets.only( margin: const EdgeInsets.only(

View file

@ -13,7 +13,7 @@ class FormTextField extends StatelessWidget {
final bool isConnecting; final bool isConnecting;
const FormTextField({ const FormTextField({
Key? key, super.key,
required this.label, required this.label,
required this.controller, required this.controller,
this.error, this.error,
@ -24,7 +24,7 @@ class FormTextField extends StatelessWidget {
this.hintText, this.hintText,
this.helperText, this.helperText,
required this.isConnecting required this.isConnecting
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -15,12 +15,12 @@ class CustomCombinedLineChart extends StatelessWidget {
final bool daysInterval; final bool daysInterval;
const CustomCombinedLineChart({ const CustomCombinedLineChart({
Key? key, super.key,
required this.inputData, required this.inputData,
required this.context, required this.context,
required this.dates, required this.dates,
required this.daysInterval required this.daysInterval
}) : super(key: key); });
LineChartData mainData(Map<String, dynamic> data, ThemeMode selectedTheme) { LineChartData mainData(Map<String, dynamic> data, ThemeMode selectedTheme) {
String chartDate(DateTime date) { String chartDate(DateTime date) {
@ -55,11 +55,11 @@ class CustomCombinedLineChart extends StatelessWidget {
} }
return LineChartData( return LineChartData(
gridData: FlGridData( gridData: const FlGridData(
show: false, show: false,
drawVerticalLine: false, drawVerticalLine: false,
), ),
titlesData: FlTitlesData( titlesData: const FlTitlesData(
show: false, show: false,
), ),
borderData: FlBorderData( borderData: FlBorderData(
@ -73,7 +73,7 @@ class CustomCombinedLineChart extends StatelessWidget {
barWidth: 2, barWidth: 2,
isStrokeCapRound: true, isStrokeCapRound: true,
preventCurveOverShooting: true, preventCurveOverShooting: true,
dotData: FlDotData( dotData: const FlDotData(
show: false, show: false,
), ),
belowBarData: BarAreaData( belowBarData: BarAreaData(

View file

@ -8,12 +8,12 @@ class ConfirmActionModal extends StatelessWidget {
final void Function() onConfirm; final void Function() onConfirm;
const ConfirmActionModal({ const ConfirmActionModal({
Key? key, super.key,
required this.icon, required this.icon,
required this.title, required this.title,
required this.message, required this.message,
required this.onConfirm required this.onConfirm
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -9,14 +9,14 @@ class CustomCheckboxListTile extends StatelessWidget {
final EdgeInsets? padding; final EdgeInsets? padding;
const CustomCheckboxListTile({ const CustomCheckboxListTile({
Key? key, super.key,
required this.value, required this.value,
required this.onChanged, required this.onChanged,
required this.title, required this.title,
this.disabled, this.disabled,
this.subtitle, this.subtitle,
this.padding this.padding
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -14,7 +14,7 @@ class CustomListTile extends StatelessWidget {
final Color? color; final Color? color;
const CustomListTile({ const CustomListTile({
Key? key, super.key,
required this.title, required this.title,
this.subtitle, this.subtitle,
this.subtitleWidget, this.subtitleWidget,
@ -26,7 +26,7 @@ class CustomListTile extends StatelessWidget {
this.disabled, this.disabled,
this.onHover, this.onHover,
this.color, this.color,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -7,12 +7,12 @@ class CustomRadio extends StatelessWidget {
final Color backgroundColor; final Color backgroundColor;
const CustomRadio({ const CustomRadio({
Key? key, super.key,
required this.value, required this.value,
required this.groupValue, required this.groupValue,
this.onChange, this.onChange,
required this.backgroundColor, required this.backgroundColor,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -11,14 +11,14 @@ class CustomRadioListTile extends StatelessWidget {
final void Function(String) onChanged; final void Function(String) onChanged;
const CustomRadioListTile({ const CustomRadioListTile({
Key? key, super.key,
required this.groupValue, required this.groupValue,
required this.value, required this.value,
required this.radioBackgroundColor, required this.radioBackgroundColor,
required this.title, required this.title,
this.subtitle, this.subtitle,
required this.onChanged, required this.onChanged,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -7,12 +7,12 @@ class CustomRadioToggle extends StatelessWidget {
final void Function(String) onTap; final void Function(String) onTap;
const CustomRadioToggle({ const CustomRadioToggle({
Key? key, super.key,
required this.groupSelected, required this.groupSelected,
required this.value, required this.value,
required this.label, required this.label,
required this.onTap, required this.onTap,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -0,0 +1,110 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/config/globals.dart';
class FloatingSearchBar extends StatefulWidget {
final void Function(String) onSearchCompleted;
final RenderBox? searchButtonRenderBox;
final String? existingSearchValue;
final void Function(String)? onSearchFieldUpdated;
final void Function()? onSearchFieldCleared;
const FloatingSearchBar({
super.key,
required this.onSearchCompleted,
required this.searchButtonRenderBox,
this.existingSearchValue,
this.onSearchFieldUpdated,
this.onSearchFieldCleared,
});
@override
State<FloatingSearchBar> createState() => _SearchState();
}
class _SearchState extends State<FloatingSearchBar> {
final _searchController = TextEditingController();
@override
void initState() {
if (widget.existingSearchValue != null) {
_searchController.text = widget.existingSearchValue!;
}
super.initState();
}
@override
Widget build(BuildContext context) {
final position = widget.searchButtonRenderBox?.localToGlobal(Offset.zero);
final topPadding = MediaQuery.of(globalNavigatorKey.currentContext!).viewPadding.top;
return GestureDetector(
onTap: () => Navigator.pop(context),
child: Material(
color: Colors.transparent,
child: LayoutBuilder(
builder: (context, constraints) {
final double width = constraints.maxWidth - 32 > 500 ? 500 : constraints.maxWidth - 32;
return Stack(
alignment: Alignment.topCenter,
children: [
Positioned(
top: position != null ? position.dy - topPadding : topPadding,
child: SizedBox(
width: width,
child: GestureDetector(
onTap: () => {},
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16)
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: TextFormField(
controller: _searchController,
onChanged: widget.onSearchFieldUpdated,
onFieldSubmitted: (v) {
widget.onSearchCompleted(v);
Navigator.pop(context);
},
autofocus: true,
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.search,
prefixIcon: const Icon(Icons.search_rounded),
border: InputBorder.none,
filled: true,
fillColor: Colors.grey.withOpacity(0.2),
suffixIcon: _searchController.text != ""
? IconButton(
onPressed: () {
setState(() => _searchController.text = "");
if (widget.onSearchFieldCleared != null) {
widget.onSearchFieldCleared!();
}
},
icon: const Icon(
Icons.close_rounded,
size: 20,
),
tooltip: AppLocalizations.of(context)!.clearSearch,
)
: null,
contentPadding: const EdgeInsets.symmetric(vertical: 12),
),
),
),
),
),
),
)
],
);
}
),
),
);
}
}

View file

@ -13,13 +13,13 @@ class CustomLineChart extends StatelessWidget {
final BuildContext context; final BuildContext context;
const CustomLineChart({ const CustomLineChart({
Key? key, super.key,
required this.data, required this.data,
required this.color, required this.color,
required this.dates, required this.dates,
required this.daysInterval, required this.daysInterval,
required this.context required this.context
}) : super(key: key); });
String chartDate(DateTime date) { String chartDate(DateTime date) {
String twoDigits(int number) => number.toString().padLeft(2, '0'); String twoDigits(int number) => number.toString().padLeft(2, '0');
@ -55,11 +55,11 @@ class CustomLineChart extends StatelessWidget {
LineChartData mainData(Map<String, dynamic> data, ThemeMode selectedTheme) { LineChartData mainData(Map<String, dynamic> data, ThemeMode selectedTheme) {
return LineChartData( return LineChartData(
gridData: FlGridData( gridData: const FlGridData(
show: false, show: false,
drawVerticalLine: false, drawVerticalLine: false,
), ),
titlesData: FlTitlesData( titlesData: const FlTitlesData(
show: false, show: false,
), ),
borderData: FlBorderData( borderData: FlBorderData(
@ -73,7 +73,7 @@ class CustomLineChart extends StatelessWidget {
barWidth: 2, barWidth: 2,
isStrokeCapRound: true, isStrokeCapRound: true,
preventCurveOverShooting: true, preventCurveOverShooting: true,
dotData: FlDotData( dotData: const FlDotData(
show: false, show: false,
), ),
belowBarData: BarAreaData( belowBarData: BarAreaData(

View file

@ -11,9 +11,9 @@ class CustomMenuBar extends StatelessWidget {
final Widget child; final Widget child;
const CustomMenuBar({ const CustomMenuBar({
Key? key, super.key,
required this.child required this.child
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -7,12 +7,12 @@ class OptionBox extends StatelessWidget {
final String label; final String label;
const OptionBox({ const OptionBox({
Key? key, super.key,
required this.optionsValue, required this.optionsValue,
required this.itemValue, required this.itemValue,
required this.onTap, required this.onTap,
required this.label, required this.label,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -4,9 +4,9 @@ class ProcessDialog extends StatelessWidget {
final String message; final String message;
const ProcessDialog({ const ProcessDialog({
Key? key, super.key,
required this.message, required this.message,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -5,10 +5,10 @@ class SectionLabel extends StatelessWidget {
final EdgeInsets? padding; final EdgeInsets? padding;
const SectionLabel({ const SectionLabel({
Key? key, super.key,
required this.label, required this.label,
this.padding this.padding
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -13,9 +13,9 @@ class DeleteModal extends StatelessWidget {
final Server serverToDelete; final Server serverToDelete;
const DeleteModal({ const DeleteModal({
Key? key, super.key,
required this.serverToDelete, required this.serverToDelete,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -34,14 +34,14 @@ class DeleteModal extends StatelessWidget {
appConfigProvider.setSelectedScreen(0); appConfigProvider.setSelectedScreen(0);
} }
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionRemoved, label: AppLocalizations.of(context)!.connectionRemoved,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionCannotBeRemoved, label: AppLocalizations.of(context)!.connectionCannotBeRemoved,
color: Colors.red color: Colors.red

View file

@ -50,14 +50,15 @@ void showDeleteModal({
required BuildContext context, required BuildContext context,
required Server server required Server server
}) async { }) async {
await Future.delayed(const Duration(seconds: 0), () => { await Future.delayed(const Duration(seconds: 0), () {
if (!context.mounted) return;
showDialog( showDialog(
context: context, context: context,
builder: (context) => DeleteModal( builder: (context) => DeleteModal(
serverToDelete: server, serverToDelete: server,
), ),
barrierDismissible: false barrierDismissible: false
) );
}); });
} }
@ -133,7 +134,7 @@ void connectToServer({
process.close(); process.close();
if (!context.mounted) return; if (!context.mounted) return;
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false); final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.cannotConnect, label: AppLocalizations.of(context)!.cannotConnect,
color: Colors.red color: Colors.red
@ -150,14 +151,14 @@ void setDefaultServer({
if (!context.mounted) return; if (!context.mounted) return;
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false); final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
if (result == null) { if (result == null) {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionDefaultSuccessfully, label: AppLocalizations.of(context)!.connectionDefaultSuccessfully,
color: Colors.green color: Colors.green
); );
} }
else { else {
showSnacbkar( showSnackbar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.connectionDefaultFailed, label: AppLocalizations.of(context)!.connectionDefaultFailed,
color: Colors.red color: Colors.red

View file

@ -16,13 +16,13 @@ class ServersList extends StatelessWidget {
final double breakingWidth; final double breakingWidth;
const ServersList({ const ServersList({
Key? key, super.key,
required this.context, required this.context,
required this.controllers, required this.controllers,
required this.onChange, required this.onChange,
required this.scrollController, required this.scrollController,
required this.breakingWidth required this.breakingWidth
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

Some files were not shown because too many files have changed in this diff Show more