mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-06-28 11:59:52 +00:00
Merge branch 'beta'
This commit is contained in:
commit
6e0f437c6b
107 changed files with 1108 additions and 771 deletions
13
README.md
13
README.md
|
@ -42,6 +42,15 @@ This is an unofficial application. The AdGuard Home team and the development of
|
|||
## 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).
|
||||
|
||||
## 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
|
||||
<ul>
|
||||
<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)
|
||||
- [flutter svg](https://pub.dev/packages/flutter_svg)
|
||||
- [percent indicator](https://pub.dev/packages/percent_indicator)
|
||||
- [store checker](https://pub.dev/packages/store_checker)
|
||||
- [flutter markdown](https://pub.dev/packages/flutter_markdown)
|
||||
- [markdown](https://pub.dev/packages/markdown)
|
||||
- [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)
|
||||
- [url launcher](https://pub.dev/packages/url_launcher)
|
||||
- [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>
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ ThemeData lightTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
|||
navigationBarTheme: NavigationBarThemeData(
|
||||
surfaceTintColor: dynamicColorScheme?.surfaceTint
|
||||
),
|
||||
dialogTheme: DialogTheme(
|
||||
surfaceTintColor: dynamicColorScheme?.surfaceTint
|
||||
),
|
||||
pageTransitionsTheme: const PageTransitionsTheme(
|
||||
builders: {
|
||||
TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
|
||||
|
@ -56,6 +59,9 @@ ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
|||
navigationBarTheme: NavigationBarThemeData(
|
||||
surfaceTintColor: dynamicColorScheme?.surfaceTint
|
||||
),
|
||||
dialogTheme: DialogTheme(
|
||||
surfaceTintColor: dynamicColorScheme?.surfaceTint
|
||||
),
|
||||
pageTransitionsTheme: const PageTransitionsTheme(
|
||||
builders: {
|
||||
TargetPlatform.android: PredictiveBackPageTransitionsBuilder()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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/services/external_requests.dart';
|
||||
|
@ -9,7 +9,7 @@ import 'package:adguard_home_manager/models/github_release.dart';
|
|||
Future<GitHubRelease?> checkAppUpdates({
|
||||
required String currentBuildNumber,
|
||||
required void Function(GitHubRelease?) setUpdateAvailable,
|
||||
required Source installationSource,
|
||||
required InstallationAppReferrer? installationSource,
|
||||
required bool isBeta
|
||||
}) async {
|
||||
var result = isBeta
|
||||
|
@ -35,11 +35,7 @@ Future<GitHubRelease?> checkAppUpdates({
|
|||
setUpdateAvailable(gitHubRelease);
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
if (
|
||||
installationSource == Source.IS_INSTALLED_FROM_LOCAL_SOURCE ||
|
||||
installationSource == Source.IS_INSTALLED_FROM_PLAY_PACKAGE_INSTALLER ||
|
||||
installationSource == Source.UNKNOWN
|
||||
) {
|
||||
if (installationSource == InstallationAppReferrer.androidManually) {
|
||||
return gitHubRelease;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/config/globals.dart';
|
||||
|
||||
void showSnacbkar({
|
||||
void showSnackbar({
|
||||
required AppConfigProvider appConfigProvider,
|
||||
required String label,
|
||||
required Color color,
|
||||
|
|
|
@ -795,5 +795,7 @@
|
|||
"clientIpCopied": "Client IP copied to the clipboard",
|
||||
"clientNameCopied": "Client name 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."
|
||||
}
|
|
@ -795,5 +795,7 @@
|
|||
"clientIpCopied": "Dirección IP del cliente copiada al portapapeles",
|
||||
"clientNameCopied": "Nombre del cliente copiado 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."
|
||||
}
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:install_referrer/install_referrer.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_displaymode/flutter_displaymode.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:shared_preferences/shared_preferences.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:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
@ -80,7 +80,7 @@ void main() async {
|
|||
}
|
||||
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
Source installationSource = await StoreChecker.getSource;
|
||||
InstallationAppReferrer installationSource = await InstallReferrer.referrer;
|
||||
appConfigProvider.setInstallationSource(installationSource);
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class Filter {
|
|||
Map<String, dynamic> toJson() => {
|
||||
"url": url,
|
||||
"name": name,
|
||||
"last_updated": lastUpdated != null ? lastUpdated!.toIso8601String() : null,
|
||||
"last_updated": lastUpdated?.toIso8601String(),
|
||||
"id": id,
|
||||
"rules_count": rulesCount,
|
||||
"enabled": enabled,
|
||||
|
|
|
@ -65,7 +65,7 @@ class Filter {
|
|||
Map<String, dynamic> toJson() => {
|
||||
"url": url,
|
||||
"name": name,
|
||||
"last_updated": lastUpdated != null ? lastUpdated!.toIso8601String() : null,
|
||||
"last_updated": lastUpdated?.toIso8601String(),
|
||||
"id": id,
|
||||
"rules_count": rulesCount,
|
||||
"enabled": enabled,
|
||||
|
|
|
@ -30,7 +30,7 @@ class LogsData {
|
|||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"data": List<dynamic>.from(data.map((x) => x.toJson())),
|
||||
"oldest": oldest != null ? oldest!.toIso8601String() : null,
|
||||
"oldest": oldest?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:install_referrer/install_referrer.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.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:adguard_home_manager/constants/enums.dart';
|
||||
|
@ -33,7 +33,7 @@ class AppConfigProvider with ChangeNotifier {
|
|||
int _selectedTheme = 0;
|
||||
bool _useDynamicColor = true;
|
||||
int _staticColor = 0;
|
||||
bool _useThemeColorForStatus = false;
|
||||
final bool _useThemeColorForStatus = false;
|
||||
|
||||
int _selectedClientsTab = 0;
|
||||
int _selectedFiltersTab = 0;
|
||||
|
@ -58,7 +58,7 @@ class AppConfigProvider with ChangeNotifier {
|
|||
|
||||
GitHubRelease? _appUpdatesAvailable;
|
||||
|
||||
Source _installationSource = Source.UNKNOWN;
|
||||
InstallationAppReferrer? _installationSource;
|
||||
|
||||
PackageInfo? get getAppInfo {
|
||||
return _appInfo;
|
||||
|
@ -162,7 +162,7 @@ class AppConfigProvider with ChangeNotifier {
|
|||
return _appUpdatesAvailable;
|
||||
}
|
||||
|
||||
Source get installationSource {
|
||||
InstallationAppReferrer? get installationSource {
|
||||
return _installationSource;
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ class AppConfigProvider with ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
void setInstallationSource(Source value) {
|
||||
void setInstallationSource(InstallationAppReferrer value) {
|
||||
_installationSource = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
51
lib/providers/live_logs_provider.dart
Normal file
51
lib/providers/live_logs_provider.dart
Normal 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();
|
||||
}
|
||||
}
|
|
@ -82,14 +82,14 @@ class _AddedListState extends State<AddedList> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -109,14 +109,14 @@ class _AddedListState extends State<AddedList> {
|
|||
if (widget.splitView == true) {
|
||||
Navigator.of(clientsNavigatorKey.currentContext!).popUntil((route) => false);
|
||||
}
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientNotDeleted,
|
||||
color: Colors.red
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ClientPlaceholder extends StatelessWidget {
|
||||
const ClientPlaceholder({Key? key}) : super(key: key);
|
||||
const ClientPlaceholder({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
return const Center(
|
||||
child: Text("Select a client"),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -237,7 +237,8 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
context: context,
|
||||
builder: (context) => LogDetailsScreen(
|
||||
log: log,
|
||||
dialog: true
|
||||
dialog: true,
|
||||
twoColumns: widget.splitView,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -246,7 +247,8 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
MaterialPageRoute(
|
||||
builder: (context) => LogDetailsScreen(
|
||||
log: log,
|
||||
dialog: false
|
||||
dialog: false,
|
||||
twoColumns: widget.splitView,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -5,9 +5,9 @@ class RemoveClientModal extends StatelessWidget {
|
|||
final void Function() onConfirm;
|
||||
|
||||
const RemoveClientModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.onConfirm
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -11,11 +11,11 @@ class SafeSearchModal extends StatefulWidget {
|
|||
final void Function(SafeSearch) onConfirm;
|
||||
|
||||
const SafeSearchModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.safeSearch,
|
||||
required this.disabled,
|
||||
required this.onConfirm
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<SafeSearchModal> createState() => _SafeSearchModalState();
|
||||
|
|
|
@ -10,10 +10,10 @@ class ServicesModal extends StatefulWidget {
|
|||
final void Function(List<String>) onConfirm;
|
||||
|
||||
const ServicesModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.blockedServices,
|
||||
required this.onConfirm,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<ServicesModal> createState() => _ServicesModalStateWidget();
|
||||
|
|
|
@ -33,14 +33,14 @@ class ClientsFab extends StatelessWidget {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientNotAdded,
|
||||
color: Colors.red
|
||||
|
|
|
@ -95,14 +95,14 @@ class _SearchClientsState extends State<SearchClients> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientNotDeleted,
|
||||
color: Colors.red
|
||||
|
@ -119,14 +119,14 @@ class _SearchClientsState extends State<SearchClients> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -205,7 +205,7 @@ class _SearchClientsState extends State<SearchClients> {
|
|||
height: 1,
|
||||
decoration: BoxDecoration(
|
||||
color: showDivider == true
|
||||
? Theme.of(context).colorScheme.surfaceVariant
|
||||
? Theme.of(context).colorScheme.surfaceContainerHighest
|
||||
: Colors.transparent
|
||||
),
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
|
||||
|
||||
class FabConnect extends StatelessWidget {
|
||||
const FabConnect({Key? key}) : super(key: key);
|
||||
const FabConnect({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -42,14 +42,14 @@ class AddFiltersButton extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.ruleAddedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.ruleNotAdded,
|
||||
color: Colors.red
|
||||
|
@ -67,14 +67,14 @@ class AddFiltersButton extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.customRulesUpdatedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.customRulesNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -146,28 +146,28 @@ class AddFiltersButton extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result['success'] == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: "${AppLocalizations.of(context)!.listAdded} ${result['data']}.",
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result['success'] == false && result['error'] == 'invalid_url') {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listUrlInvalid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['success'] == false && result['error'] == 'url_exists') {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listAlreadyAdded,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listNotAdded,
|
||||
color: Colors.red
|
||||
|
|
|
@ -163,7 +163,7 @@ class _CustomRulesListState extends State<CustomRulesList> {
|
|||
onPressed: () async {
|
||||
final result = await filteringProvider.fetchFilters();
|
||||
if (result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.errorLoadFilters,
|
||||
color: Colors.red
|
||||
|
@ -203,7 +203,7 @@ class _CustomRulesListState extends State<CustomRulesList> {
|
|||
onRefresh: () async {
|
||||
final result = await filteringProvider.fetchFilters();
|
||||
if (result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.errorLoadFilters,
|
||||
color: Colors.red
|
||||
|
|
|
@ -94,14 +94,14 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
);
|
||||
processModal.close();
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listDataUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listDataNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -175,6 +175,7 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
_Content(
|
||||
isDialog: widget.dialog,
|
||||
list: list,
|
||||
type: widget.type,
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -216,6 +217,7 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
_Content(
|
||||
isDialog: widget.dialog,
|
||||
list: list,
|
||||
type: widget.type,
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -261,10 +263,12 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
|||
class _Content extends StatelessWidget {
|
||||
final Filter list;
|
||||
final bool isDialog;
|
||||
final String type;
|
||||
|
||||
const _Content({
|
||||
required this.list,
|
||||
required this.isDialog
|
||||
required this.isDialog,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -339,7 +343,7 @@ class _Content extends StatelessWidget {
|
|||
CustomListTile(
|
||||
icon: Icons.shield_rounded,
|
||||
title: AppLocalizations.of(context)!.listType,
|
||||
subtitle: isDialog == 'whitelist'
|
||||
subtitle: type == 'whitelist'
|
||||
? AppLocalizations.of(context)!.whitelist
|
||||
: AppLocalizations.of(context)!.blacklist,
|
||||
padding: isDialog == true
|
||||
|
@ -431,7 +435,7 @@ class _Actions extends StatelessWidget {
|
|||
);
|
||||
processModal.close();
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listDeleted,
|
||||
color: Colors.green
|
||||
|
@ -439,7 +443,7 @@ class _Actions extends StatelessWidget {
|
|||
Navigator.pop(context);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listNotDeleted,
|
||||
color: Colors.red
|
||||
|
|
|
@ -24,7 +24,7 @@ import 'package:adguard_home_manager/constants/enums.dart';
|
|||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
|
||||
class Filters extends StatefulWidget {
|
||||
const Filters({Key? key}) : super(key: key);
|
||||
const Filters({super.key});
|
||||
|
||||
@override
|
||||
State<Filters> createState() => _FiltersState();
|
||||
|
@ -57,14 +57,14 @@ class _FiltersState extends State<Filters> {
|
|||
if (!mounted) return;
|
||||
processModal.close();
|
||||
if (result['success'] == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: "${result['data']['updated']} ${AppLocalizations.of(context)!.listsUpdated}",
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listsNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -109,14 +109,14 @@ class _FiltersState extends State<Filters> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.filteringStatusUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.filteringStatusNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -133,14 +133,14 @@ class _FiltersState extends State<Filters> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.updateFrequencyChanged,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.updateFrequencyNotChanged,
|
||||
color: Colors.red
|
||||
|
@ -163,14 +163,14 @@ class _FiltersState extends State<Filters> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.ruleRemovedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.ruleNotRemoved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -27,13 +27,13 @@ class FiltersList extends StatefulWidget {
|
|||
final void Function(Filter, String) onOpenDetailsScreen;
|
||||
|
||||
const FiltersList({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.loadStatus,
|
||||
required this.scrollController,
|
||||
required this.data,
|
||||
required this.type,
|
||||
required this.onOpenDetailsScreen
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<FiltersList> createState() => _FiltersListState();
|
||||
|
@ -133,7 +133,7 @@ class _FiltersListState extends State<FiltersList> {
|
|||
onPressed: () async {
|
||||
final result = await filteringProvider.fetchFilters();
|
||||
if (result == false && mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.errorLoadFilters,
|
||||
color: Colors.red
|
||||
|
@ -173,7 +173,7 @@ class _FiltersListState extends State<FiltersList> {
|
|||
onRefresh: () async {
|
||||
final result = await filteringProvider.fetchFilters();
|
||||
if (result == false && mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.errorLoadFilters,
|
||||
color: Colors.red
|
||||
|
|
|
@ -84,7 +84,7 @@ class FiltersTripleColumn extends StatelessWidget {
|
|||
onPressed: () async {
|
||||
final result = await filteringProvider.fetchFilters();
|
||||
if (result == false && context.mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.errorLoadFilters,
|
||||
color: Colors.red
|
||||
|
|
|
@ -59,14 +59,14 @@ class ListOptionsMenu extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listDataUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.listDataNotUpdated,
|
||||
color: Colors.red
|
||||
|
|
|
@ -68,14 +68,14 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.blockedServicesUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.blockedServicesNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -119,24 +119,26 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
|
|||
SliverOverlapInjector(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
),
|
||||
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loading) Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.loadingBlockedServicesList,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loading) SliverFillRemaining(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.loadingBlockedServicesList,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.loaded) SliverList.builder(
|
||||
|
@ -181,28 +183,30 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
|
|||
),
|
||||
)
|
||||
),
|
||||
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.error) Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
if (filteringProvider.blockedServicesLoadStatus == LoadStatus.error) SliverFillRemaining(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
)
|
||||
],
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.blockedServicesListNotLoaded,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
|
|
@ -276,16 +276,22 @@ class _CustomRuleEditor extends StatelessWidget {
|
|||
colors: SegmentedButtonSlideColors(
|
||||
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
|
||||
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,
|
||||
fontSize: 14,
|
||||
height: 40,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
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),
|
||||
Material(
|
||||
|
|
|
@ -5,9 +5,9 @@ class RemoveCustomRule extends StatelessWidget {
|
|||
final void Function() onConfirm;
|
||||
|
||||
const RemoveCustomRule({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.onConfirm
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -235,10 +235,10 @@ class _Content extends StatelessWidget {
|
|||
}
|
||||
: null,
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateProperty.all(
|
||||
overlayColor: WidgetStateProperty.all(
|
||||
Theme.of(context).colorScheme.primary.withOpacity(0.1)
|
||||
),
|
||||
foregroundColor: MaterialStateProperty.all(
|
||||
foregroundColor: WidgetStateProperty.all(
|
||||
selectedOption != null
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.grey,
|
||||
|
|
|
@ -9,11 +9,11 @@ class DeleteSelectionModal extends StatefulWidget {
|
|||
final void Function() onDelete;
|
||||
|
||||
const DeleteSelectionModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.selectedBlacklists,
|
||||
required this.selectedWhitelists,
|
||||
required this.onDelete,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<DeleteSelectionModal> createState() => _DeleteSelectionModalState();
|
||||
|
|
|
@ -9,11 +9,11 @@ class EnableDisableSelectionModal extends StatefulWidget {
|
|||
final void Function() onDelete;
|
||||
|
||||
const EnableDisableSelectionModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.selectedBlacklists,
|
||||
required this.selectedWhitelists,
|
||||
required this.onDelete,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<EnableDisableSelectionModal> createState() => _EnableDisableSelectionModalState();
|
||||
|
|
|
@ -13,13 +13,13 @@ class SelectionList extends StatelessWidget {
|
|||
final void Function() unselectAll;
|
||||
|
||||
const SelectionList({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.lists,
|
||||
required this.selectedLists,
|
||||
required this.onSelect,
|
||||
required this.selectAll,
|
||||
required this.unselectAll,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -231,11 +231,10 @@ class _CheckboxTile extends StatelessWidget {
|
|||
final bool isSelected;
|
||||
|
||||
const _CheckboxTile({
|
||||
Key? key,
|
||||
required this.list,
|
||||
required this.onSelect,
|
||||
required this.isSelected,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -82,8 +82,8 @@ class _SelectionScreenState extends State<SelectionScreen> with TickerProviderSt
|
|||
blacklists: _selectedBlacklists,
|
||||
whitelists: _selectedWhitelists
|
||||
);
|
||||
if (!mounted) return;
|
||||
processModal.close();
|
||||
if (!context.mounted) return;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => SelectionResultModal(
|
||||
|
@ -113,8 +113,8 @@ class _SelectionScreenState extends State<SelectionScreen> with TickerProviderSt
|
|||
blacklists: _selectedBlacklists,
|
||||
whitelists: _selectedWhitelists
|
||||
);
|
||||
if (!mounted) return;
|
||||
processModal.close();
|
||||
if (!context.mounted) return;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => SelectionResultModal(
|
||||
|
|
|
@ -37,7 +37,7 @@ class CombinedChartItem {
|
|||
}
|
||||
|
||||
class CombinedHomeChart extends StatelessWidget {
|
||||
const CombinedHomeChart({Key? key}) : super(key: key);
|
||||
const CombinedHomeChart({super.key});
|
||||
|
||||
List<int>? removeZero(List<int> list) {
|
||||
final removed = list.where((i) => i > 0);
|
||||
|
@ -266,12 +266,11 @@ class _Legend extends StatelessWidget {
|
|||
final String? secondaryValue;
|
||||
|
||||
const _Legend({
|
||||
Key? key,
|
||||
required this.label,
|
||||
required this.color,
|
||||
required this.primaryValue,
|
||||
this.secondaryValue
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:adguard_home_manager/providers/status_provider.dart';
|
|||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
|
||||
class HomeFab extends StatelessWidget {
|
||||
const HomeFab({Key? key}) : super(key: key);
|
||||
const HomeFab({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -93,7 +93,7 @@ class _HomeState extends State<Home> {
|
|||
onRefresh: () async {
|
||||
final result = await statusProvider.getServerStatus();
|
||||
if (mounted && result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.serverStatusNotRefreshed,
|
||||
color: Colors.red
|
||||
|
|
|
@ -82,7 +82,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
|
|||
time: time
|
||||
);
|
||||
if (mounted && result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.invalidUsernamePassword,
|
||||
color: Colors.red
|
||||
|
|
|
@ -8,13 +8,13 @@ class SmallSwitch extends StatelessWidget {
|
|||
final bool disabled;
|
||||
|
||||
const SmallSwitch({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
required this.value,
|
||||
required this.onChange,
|
||||
required this.disabled,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -83,14 +83,14 @@ class TopItemsLists extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (rules == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -121,21 +121,21 @@ class TopItemsLists extends StatelessWidget {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.content == 'client_another_list') {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAnotherList,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: newList == AccessSettingsList.allowed || newList == AccessSettingsList.disallowed
|
||||
? AppLocalizations.of(context)!.clientNotRemoved
|
||||
|
|
|
@ -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/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/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';
|
||||
|
||||
enum _SortingOptions { highestToLowest, lowestToHighest }
|
||||
final GlobalKey _searchButtonKey = GlobalKey();
|
||||
|
||||
class TopItemsScreen extends StatefulWidget {
|
||||
final HomeTopItems type;
|
||||
|
@ -47,15 +49,18 @@ class TopItemsScreen extends StatefulWidget {
|
|||
|
||||
class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||
_SortingOptions _sortingOptions = _SortingOptions.highestToLowest;
|
||||
bool searchActive = false;
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
String? _currentSearchValue = "";
|
||||
|
||||
List<Map<String, dynamic>> data = [];
|
||||
List<Map<String, dynamic>> screenData = [];
|
||||
|
||||
void search(String value) {
|
||||
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
|
||||
|
@ -75,118 +80,132 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
|||
final sortedValues = _sortingOptions == _SortingOptions.lowestToHighest
|
||||
? screenData.reversed.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) {
|
||||
return Dialog.fullscreen(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: searchActive == true
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(bottom: 3),
|
||||
child: TextFormField(
|
||||
controller: searchController,
|
||||
onChanged: search,
|
||||
decoration: InputDecoration(
|
||||
hintText: AppLocalizations.of(context)!.search,
|
||||
hintStyle: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
return Scaffold(
|
||||
body: NestedScrollView(
|
||||
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar.large(
|
||||
title: Text(widget.title),
|
||||
actions: [
|
||||
IconButton(
|
||||
key: _searchButtonKey,
|
||||
onPressed: showSearchDialog,
|
||||
icon: const Icon(Icons.search_rounded),
|
||||
tooltip: AppLocalizations.of(context)!.search,
|
||||
),
|
||||
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,
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
autofocus: true,
|
||||
),
|
||||
)
|
||||
: Text(widget.title),
|
||||
leading: searchActive == true ?
|
||||
IconButton(
|
||||
onPressed: () => setState(() {
|
||||
searchActive = false;
|
||||
searchController.text = '';
|
||||
screenData = data;
|
||||
}),
|
||||
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(
|
||||
onTap: () => setState(() => _sortingOptions = _SortingOptions.lowestToHighest),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.arrow_upward_rounded),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(AppLocalizations.of(context)!.fromLowestToHighest)
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Icon(
|
||||
_sortingOptions == _SortingOptions.lowestToHighest
|
||||
? Icons.radio_button_checked_rounded
|
||||
: Icons.radio_button_unchecked_rounded,
|
||||
color: _sortingOptions == _SortingOptions.lowestToHighest
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () => setState(() => _sortingOptions = _SortingOptions.lowestToHighest),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.arrow_upward_rounded),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(AppLocalizations.of(context)!.fromLowestToHighest)
|
||||
const SizedBox(width: 8)
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
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
|
||||
: Icons.radio_button_unchecked_rounded,
|
||||
color: _sortingOptions == _SortingOptions.lowestToHighest
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
if (sortedValues.isNotEmpty) SliverPadding(
|
||||
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewPadding.bottom),
|
||||
sliver: SliverList.builder(
|
||||
itemCount: sortedValues.length,
|
||||
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(
|
||||
child: _Content(
|
||||
buildValue: widget.buildValue,
|
||||
isClient: widget.isClient,
|
||||
onTapEntry: widget.onTapEntry,
|
||||
options: widget.options,
|
||||
screenData: sortedValues,
|
||||
total: total,
|
||||
withProgressBar: widget.withProgressBar,
|
||||
child: sortedValues.isNotEmpty ? ListView.builder(
|
||||
itemCount: sortedValues.length,
|
||||
itemBuilder: (context, index) => _Item(
|
||||
data: sortedValues[index],
|
||||
isClient: widget.isClient,
|
||||
options: widget.options,
|
||||
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 {
|
||||
final List<Map<String, dynamic>> screenData;
|
||||
class _Item extends StatelessWidget {
|
||||
final dynamic data;
|
||||
final bool? isClient;
|
||||
final List<MenuOption> Function(dynamic) options;
|
||||
final bool withProgressBar;
|
||||
|
@ -269,8 +303,8 @@ class _Content extends StatelessWidget {
|
|||
final String Function(dynamic) buildValue;
|
||||
final double total;
|
||||
|
||||
const _Content({
|
||||
required this.screenData,
|
||||
const _Item({
|
||||
required this.data,
|
||||
required this.isClient,
|
||||
required this.options,
|
||||
required this.withProgressBar,
|
||||
|
@ -283,98 +317,75 @@ class _Content extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final statusProvider = Provider.of<StatusProvider>(context);
|
||||
|
||||
if (screenData.isNotEmpty) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
itemCount: screenData.length,
|
||||
itemBuilder: (context, index) {
|
||||
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),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
String? name;
|
||||
if (isClient != null && isClient == true) {
|
||||
try {
|
||||
name = statusProvider.serverStatus!.clients.firstWhere((c) => c.ids.contains(data.keys.toList()[0])).name;
|
||||
} catch (e) {
|
||||
// ---- //
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 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,
|
||||
),
|
||||
|
||||
return OptionsMenu(
|
||||
options: options,
|
||||
value: data.keys.toList()[0],
|
||||
onTap: onTapEntry != null
|
||||
? (v) {
|
||||
onTapEntry!(v);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
: 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),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.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/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/classes/process_modal.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 {
|
||||
final Log log;
|
||||
final bool dialog;
|
||||
final bool twoColumns;
|
||||
|
||||
const LogDetailsScreen({
|
||||
super.key,
|
||||
required this.log,
|
||||
required this.dialog
|
||||
required this.dialog,
|
||||
required this.twoColumns,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -50,14 +52,14 @@ class LogDetailsScreen extends StatelessWidget {
|
|||
processModal.close();
|
||||
|
||||
if (rules == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -148,6 +150,7 @@ class LogDetailsScreen extends StatelessWidget {
|
|||
centerTitle: false,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
|
||||
automaticallyImplyLeading: twoColumns != true,
|
||||
title: Text(AppLocalizations.of(context)!.logDetails),
|
||||
actions: [
|
||||
IconButton(
|
||||
|
|
|
@ -187,9 +187,15 @@ class _ClientsModalState extends State<ClientsModal> {
|
|||
colors: SegmentedButtonSlideColors(
|
||||
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
|
||||
backgroundSelectedColor: Theme.of(context).colorScheme.primary,
|
||||
foregroundSelectedColor: Theme.of(context).colorScheme.onPrimary,
|
||||
foregroundUnselectedColor: Theme.of(context).colorScheme.onSurface,
|
||||
hoverColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
selectedTextStyle: TextStyle(
|
||||
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(
|
||||
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
|
||||
backgroundSelectedColor: Theme.of(context).colorScheme.primary,
|
||||
foregroundSelectedColor: Theme.of(context).colorScheme.onPrimary,
|
||||
foregroundUnselectedColor: Theme.of(context).colorScheme.onSurface,
|
||||
hoverColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
93
lib/screens/logs/live/live_logs_list.dart
Normal file
93
lib/screens/logs/live/live_logs_list.dart
Normal 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
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
70
lib/screens/logs/live/live_logs_screen.dart
Normal file
70
lib/screens/logs/live/live_logs_screen.dart
Normal 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),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -108,14 +108,14 @@ class LogTile extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (rules == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -134,14 +134,14 @@ class LogTile extends StatelessWidget {
|
|||
if (!context.mounted) return;
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientNotAdded,
|
||||
color: Colors.red
|
||||
|
@ -163,7 +163,7 @@ class LogTile extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: isDomainBlocked(log.reason) == true
|
||||
? AppLocalizations.of(context)!.domainUnblockedThisClient(log.question.name!)
|
||||
|
@ -172,7 +172,7 @@ class LogTile extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.ruleNotAdded,
|
||||
color: Colors.red
|
||||
|
@ -199,21 +199,21 @@ class LogTile extends StatelessWidget {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.content == 'client_another_list') {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAnotherList,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.changesNotSaved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -48,6 +48,7 @@ class _LogsState extends State<Logs> {
|
|||
? LogDetailsScreen(
|
||||
log: _selectedLog!,
|
||||
dialog: false,
|
||||
twoColumns: true,
|
||||
)
|
||||
: const SizedBox()
|
||||
)
|
||||
|
|
|
@ -42,7 +42,7 @@ class _LogsListWidgetState extends State<LogsListWidget> {
|
|||
|
||||
final result = await statusProvider.getFilteringRules();
|
||||
if (mounted && result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
|
||||
color: Colors.red
|
||||
|
@ -56,7 +56,7 @@ class _LogsListWidgetState extends State<LogsListWidget> {
|
|||
|
||||
final result = await clientsProvider.fetchClients();
|
||||
if (mounted && result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
|
||||
color: Colors.red
|
||||
|
@ -188,6 +188,7 @@ class _LogsListWidgetState extends State<LogsListWidget> {
|
|||
builder: (context) => LogDetailsScreen(
|
||||
log: log,
|
||||
dialog: false,
|
||||
twoColumns: widget.twoColumns,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -6,11 +6,14 @@ 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/live/live_logs_screen.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/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/providers/logs_provider.dart';
|
||||
|
||||
|
@ -58,9 +61,10 @@ class LogsListAppBar extends StatelessWidget {
|
|||
void showSearchDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => _Search(
|
||||
builder: (context) => FloatingSearchBar(
|
||||
existingSearchValue: logsProvider.appliedFilters.searchText ?? "",
|
||||
searchButtonRenderBox: _searchButtonKey.currentContext?.findRenderObject() as RenderBox?,
|
||||
onSearch: (v) {
|
||||
onSearchCompleted: (v) {
|
||||
logsProvider.setAppliedFilters(
|
||||
AppliedFiters(
|
||||
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
|
||||
|
@ -70,10 +74,36 @@ class LogsListAppBar extends StatelessWidget {
|
|||
);
|
||||
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 = {
|
||||
"all": AppLocalizations.of(context)!.all,
|
||||
"filtered": AppLocalizations.of(context)!.filtered,
|
||||
|
@ -104,10 +134,29 @@ class LogsListAppBar extends StatelessWidget {
|
|||
icon: const Icon(Icons.search_rounded),
|
||||
tooltip: AppLocalizations.of(context)!.search,
|
||||
),
|
||||
if (logsProvider.loadStatus == LoadStatus.loaded) IconButton(
|
||||
onPressed: openFilersModal,
|
||||
icon: const Icon(Icons.filter_list_rounded),
|
||||
tooltip: AppLocalizations.of(context)!.filters,
|
||||
if (logsProvider.loadStatus == LoadStatus.loaded) PopupMenuButton(
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
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),
|
||||
],
|
||||
|
@ -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
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -71,7 +71,7 @@ class _ClientsListState extends State<ClientsList> {
|
|||
Future refetchClients() async {
|
||||
final result = await clientsProvider.fetchClients();
|
||||
if (result == false && mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientsNotLoaded,
|
||||
color: Colors.red
|
||||
|
@ -104,21 +104,21 @@ class _ClientsListState extends State<ClientsList> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientRemovedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.content == 'client_another_list') {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAnotherList,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: type == AccessSettingsList.allowed || type == AccessSettingsList.disallowed
|
||||
? AppLocalizations.of(context)!.clientNotRemoved
|
||||
|
@ -137,21 +137,21 @@ class _ClientsListState extends State<ClientsList> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.content == 'client_another_list') {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.clientAnotherList,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: type == AccessSettingsList.allowed || type == AccessSettingsList.disallowed
|
||||
? AppLocalizations.of(context)!.clientNotRemoved
|
||||
|
|
|
@ -26,14 +26,14 @@ class AdvancedSettings extends StatelessWidget {
|
|||
final result = await function(newStatus);
|
||||
if (!context.mounted) return;
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.cannotUpdateSettings,
|
||||
color: Colors.red
|
||||
|
|
|
@ -31,7 +31,7 @@ class ColorItem extends StatelessWidget {
|
|||
child: InkWell(
|
||||
onTap: () => onChanged(numericValue),
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
overlayColor: const MaterialStatePropertyAll(Colors.grey),
|
||||
overlayColor: const WidgetStatePropertyAll(Colors.grey),
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
|
|
|
@ -9,14 +9,14 @@ class ThemeModeButton extends StatelessWidget {
|
|||
final bool? disabled;
|
||||
|
||||
const ThemeModeButton({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.value,
|
||||
required this.selected,
|
||||
required this.label,
|
||||
required this.onChanged,
|
||||
this.disabled
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -32,19 +32,19 @@ class ThemeModeButton extends StatelessWidget {
|
|||
? () => onChanged(value)
|
||||
: null,
|
||||
style: ButtonStyle(
|
||||
elevation: MaterialStateProperty.all(0),
|
||||
shape: MaterialStateProperty.all(
|
||||
elevation: WidgetStateProperty.all(0),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
)
|
||||
),
|
||||
backgroundColor: MaterialStateProperty.all(
|
||||
backgroundColor: WidgetStateProperty.all(
|
||||
value == selected
|
||||
? disabled == null || disabled == false
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: greyBackgroundColor
|
||||
: disabled == null || disabled == false
|
||||
? Theme.of(context).colorScheme.surfaceVariant
|
||||
? Theme.of(context).colorScheme.surfaceTint.withOpacity(0.1)
|
||||
: greyBackgroundColor,
|
||||
)
|
||||
),
|
||||
|
|
|
@ -5,9 +5,9 @@ class DeleteStaticLeaseModal extends StatelessWidget {
|
|||
final void Function() onConfirm;
|
||||
|
||||
const DeleteStaticLeaseModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.onConfirm
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -221,14 +221,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
|||
if (!mounted) return;
|
||||
processModal.close();
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsNotSaved,
|
||||
color: Colors.red
|
||||
|
@ -245,14 +245,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
|||
processModal.close();
|
||||
if (result.successful == true) {
|
||||
clearAll();
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.configRestored,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.configNotRestored,
|
||||
color: Colors.red
|
||||
|
@ -276,14 +276,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
|||
data.dhcpStatus!.leases = [];
|
||||
dhcpProvider.setDhcpData(data);
|
||||
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.leasesRestored,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.leasesNotRestored,
|
||||
color: Colors.red
|
||||
|
|
|
@ -43,14 +43,14 @@ class DhcpLeases extends StatelessWidget {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.staticLeaseDeleted,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.staticLeaseNotDeleted,
|
||||
color: Colors.red
|
||||
|
@ -67,28 +67,28 @@ class DhcpLeases extends StatelessWidget {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.staticLeaseCreated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.content == "already_exists") {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.staticLeaseExists,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.content == "server_not_configured") {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.serverNotConfigured,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.staticLeaseNotCreated,
|
||||
color: Colors.red
|
||||
|
|
|
@ -80,21 +80,21 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.statusCode == 400) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.someValueNotValid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
@ -197,7 +197,7 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
|||
)
|
||||
],
|
||||
),
|
||||
)).toList(),
|
||||
)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
|
@ -86,21 +86,21 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful== false && result.statusCode == 400) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.someValueNotValid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
@ -139,14 +139,14 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
|||
void clearCache() async {
|
||||
final result = await clearDnsCache(context, serversProvider.selectedServer!);
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsCacheCleared,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsCacheNotCleared,
|
||||
color: Colors.red
|
||||
|
|
|
@ -66,14 +66,14 @@ class _DnsSettingsState extends State<DnsSettings> {
|
|||
void clearCache() async {
|
||||
final result = await clearDnsCache(context, serversProvider.selectedServer!);
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsCacheCleared,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsCacheNotCleared,
|
||||
color: Colors.red
|
||||
|
|
|
@ -183,21 +183,21 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.statusCode == 400) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.someValueNotValid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -91,21 +91,21 @@ class _FallbackDnsScreenState extends State<FallbackDnsScreen> {
|
|||
|
||||
if (!context.mounted) return;
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.statusCode == 400) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.someValueNotValid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -112,21 +112,21 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.statusCode == 400) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.someValueNotValid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -152,21 +152,21 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else if (result.successful == false && result.statusCode == 400) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.someValueNotValid,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -5,9 +5,9 @@ class DeleteDnsRewrite extends StatelessWidget {
|
|||
final void Function() onConfirm;
|
||||
|
||||
const DeleteDnsRewrite({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.onConfirm
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -67,14 +67,14 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsRewriteRuleDeleted,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsRewriteRuleNotDeleted,
|
||||
color: Colors.red
|
||||
|
@ -91,14 +91,14 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsRewriteRuleAdded,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsRewriteRuleNotAdded,
|
||||
color: Colors.red
|
||||
|
@ -115,14 +115,14 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsRewriteRuleUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.dnsRewriteRuleNotUpdated,
|
||||
color: Colors.red
|
||||
|
@ -169,7 +169,7 @@ class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
|
|||
onRefresh: () async {
|
||||
final result = await rewriteRulesProvider.fetchRules();
|
||||
if (result == false) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.rewriteRulesNotLoaded,
|
||||
color: Colors.red
|
||||
|
|
|
@ -5,9 +5,9 @@ class EncryptionErrorModal extends StatelessWidget {
|
|||
final String error;
|
||||
|
||||
const EncryptionErrorModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.error,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -12,7 +12,7 @@ class EncryptionTextField extends StatelessWidget {
|
|||
final String? helperText;
|
||||
|
||||
const EncryptionTextField({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.enabled,
|
||||
required this.controller,
|
||||
required this.icon,
|
||||
|
@ -22,7 +22,7 @@ class EncryptionTextField extends StatelessWidget {
|
|||
this.keyboardType,
|
||||
this.multiline,
|
||||
this.helperText,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -233,14 +233,14 @@ class _EncryptionSettingsState extends State<EncryptionSettings> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.encryptionConfigSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.encryptionConfigNotSaved,
|
||||
color: Colors.red
|
||||
|
@ -282,14 +282,14 @@ class _EncryptionSettingsState extends State<EncryptionSettings> {
|
|||
processModal.close();
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.configurationResetSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.configurationResetError,
|
||||
color: Colors.red
|
||||
|
|
|
@ -5,9 +5,9 @@ class ErrorMessageEncryption extends StatelessWidget {
|
|||
final String errorMessage;
|
||||
|
||||
const ErrorMessageEncryption({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.errorMessage,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -6,10 +6,10 @@ class EncryptionMasterSwitch extends StatelessWidget {
|
|||
final void Function(bool) onChange;
|
||||
|
||||
const EncryptionMasterSwitch({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChange
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -8,10 +8,10 @@ class Status extends StatelessWidget {
|
|||
final String label;
|
||||
|
||||
const Status({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.valid,
|
||||
required this.label
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:install_referrer/install_referrer.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:store_checker/store_checker.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/settings/settings.dart';
|
||||
|
@ -49,14 +49,14 @@ class _GeneralSettingsState extends State<GeneralSettings> {
|
|||
}) async {
|
||||
final result = await function(newStatus);
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.cannotUpdateSettings,
|
||||
color: Colors.red
|
||||
|
@ -253,14 +253,7 @@ class _GeneralSettingsState extends State<GeneralSettings> {
|
|||
right: 10
|
||||
)
|
||||
),
|
||||
if (
|
||||
!(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
|
||||
))
|
||||
) ...[
|
||||
if (!(Platform.isAndroid || Platform.isIOS) || (Platform.isAndroid && (appConfigProvider.installationSource == InstallationAppReferrer.androidManually ))) ...[
|
||||
SectionLabel(label: AppLocalizations.of(context)!.application),
|
||||
CustomListTile(
|
||||
icon: Icons.system_update_rounded,
|
||||
|
|
|
@ -43,14 +43,14 @@ class _TopItemsListSettingsState extends State<TopItemsListSettings> with Ticker
|
|||
final result = await appConfigProvider.setHomeTopItemsOrder(persistHomeTopItemsList);
|
||||
if (!context.mounted) return;
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsSaved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsNotSaved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -102,17 +102,17 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
|
||||
processModal.close();
|
||||
|
||||
if (!mounted) return;
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.logsCleared,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.logsNotCleared,
|
||||
color: Colors.red
|
||||
|
@ -135,17 +135,17 @@ class _LogsSettingsState extends State<LogsSettings> {
|
|||
|
||||
processModal.close();
|
||||
|
||||
if (!mounted) return;
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.logsConfigUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.logsConfigNotUpdated,
|
||||
color: Colors.red
|
||||
|
|
|
@ -90,7 +90,7 @@ class _SafeSearchSettingsScreenState extends State<SafeSearchSettingsScreen> {
|
|||
processModal.close();
|
||||
|
||||
if (result == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
|
||||
color: Colors.green,
|
||||
|
@ -98,7 +98,7 @@ class _SafeSearchSettingsScreenState extends State<SafeSearchSettingsScreen> {
|
|||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.settingsNotSaved,
|
||||
color: Colors.red,
|
||||
|
|
|
@ -148,14 +148,14 @@ class _StatisticsSettingsState extends State<StatisticsSettings> {
|
|||
if (!context.mounted) return;
|
||||
|
||||
if (result.successful == true) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.statisticsConfigUpdated,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.statisticsConfigNotUpdated,
|
||||
color: Colors.red
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class AutoUpdateUnavailableModal extends StatelessWidget {
|
||||
const AutoUpdateUnavailableModal({Key? key}) : super(key: key);
|
||||
const AutoUpdateUnavailableModal({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -41,7 +41,7 @@ class UpdateScreen extends StatelessWidget {
|
|||
|
||||
if (result.successful == true) {
|
||||
serversProvider.recheckPeriodServerUpdated();
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.requestStartUpdateSuccessful,
|
||||
color: Colors.green,
|
||||
|
@ -49,7 +49,7 @@ class UpdateScreen extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.requestStartUpdateFailed,
|
||||
color: Colors.red,
|
||||
|
@ -203,7 +203,7 @@ class UpdateScreen extends StatelessWidget {
|
|||
body: Column(
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
child: SafeArea(
|
||||
child: headerPortrait()
|
||||
)
|
||||
|
|
|
@ -88,7 +88,7 @@ class _UpdateScreenState extends State<UpdateScreen> {
|
|||
if (!context.mounted) return;
|
||||
if (result.successful == true) {
|
||||
serversProvider.recheckPeriodServerUpdated();
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.requestStartUpdateSuccessful,
|
||||
color: Colors.green,
|
||||
|
@ -96,7 +96,7 @@ class _UpdateScreenState extends State<UpdateScreen> {
|
|||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.requestStartUpdateFailed,
|
||||
color: Colors.red,
|
||||
|
@ -220,7 +220,7 @@ class _Header extends SliverPersistentHeaderDelegate {
|
|||
return LayoutBuilder(
|
||||
builder: (context, constraints) => Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
|
|
|
@ -206,14 +206,14 @@ class ApiClientV2 {
|
|||
}
|
||||
|
||||
Future<ApiResponse> getLogs({
|
||||
required int count,
|
||||
int? count,
|
||||
int? offset,
|
||||
DateTime? olderThan,
|
||||
String? responseStatus,
|
||||
String? search
|
||||
}) async {
|
||||
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
|
||||
);
|
||||
if (result.successful == true) {
|
||||
|
|
|
@ -157,7 +157,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
|||
if (result != AuthStatus.success) {
|
||||
cancelConnecting();
|
||||
if (mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: getErrorMessage(result),
|
||||
color: Colors.red
|
||||
|
@ -206,7 +206,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
|||
if (serverCreated != null) {
|
||||
if (mounted) setState(() => isConnecting = false);
|
||||
if (mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionNotCreated,
|
||||
color: Colors.red
|
||||
|
@ -256,7 +256,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
|||
if (result != AuthStatus.success) {
|
||||
cancelConnecting();
|
||||
if (mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: getErrorMessage(result),
|
||||
color: Colors.red
|
||||
|
@ -306,7 +306,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
|||
)
|
||||
);
|
||||
if (mounted) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionNotCreated,
|
||||
color: Colors.red
|
||||
|
@ -419,16 +419,22 @@ class _AddServerModalState extends State<AddServerModal> {
|
|||
colors: SegmentedButtonSlideColors(
|
||||
barColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
|
||||
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,
|
||||
fontSize: 14,
|
||||
height: 40,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
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(
|
||||
margin: const EdgeInsets.only(
|
||||
|
|
|
@ -13,7 +13,7 @@ class FormTextField extends StatelessWidget {
|
|||
final bool isConnecting;
|
||||
|
||||
const FormTextField({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.controller,
|
||||
this.error,
|
||||
|
@ -24,7 +24,7 @@ class FormTextField extends StatelessWidget {
|
|||
this.hintText,
|
||||
this.helperText,
|
||||
required this.isConnecting
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -15,12 +15,12 @@ class CustomCombinedLineChart extends StatelessWidget {
|
|||
final bool daysInterval;
|
||||
|
||||
const CustomCombinedLineChart({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.inputData,
|
||||
required this.context,
|
||||
required this.dates,
|
||||
required this.daysInterval
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
LineChartData mainData(Map<String, dynamic> data, ThemeMode selectedTheme) {
|
||||
String chartDate(DateTime date) {
|
||||
|
@ -55,11 +55,11 @@ class CustomCombinedLineChart extends StatelessWidget {
|
|||
}
|
||||
|
||||
return LineChartData(
|
||||
gridData: FlGridData(
|
||||
gridData: const FlGridData(
|
||||
show: false,
|
||||
drawVerticalLine: false,
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
titlesData: const FlTitlesData(
|
||||
show: false,
|
||||
),
|
||||
borderData: FlBorderData(
|
||||
|
@ -73,7 +73,7 @@ class CustomCombinedLineChart extends StatelessWidget {
|
|||
barWidth: 2,
|
||||
isStrokeCapRound: true,
|
||||
preventCurveOverShooting: true,
|
||||
dotData: FlDotData(
|
||||
dotData: const FlDotData(
|
||||
show: false,
|
||||
),
|
||||
belowBarData: BarAreaData(
|
||||
|
|
|
@ -8,12 +8,12 @@ class ConfirmActionModal extends StatelessWidget {
|
|||
final void Function() onConfirm;
|
||||
|
||||
const ConfirmActionModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.message,
|
||||
required this.onConfirm
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -9,14 +9,14 @@ class CustomCheckboxListTile extends StatelessWidget {
|
|||
final EdgeInsets? padding;
|
||||
|
||||
const CustomCheckboxListTile({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
required this.title,
|
||||
this.disabled,
|
||||
this.subtitle,
|
||||
this.padding
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -14,7 +14,7 @@ class CustomListTile extends StatelessWidget {
|
|||
final Color? color;
|
||||
|
||||
const CustomListTile({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.subtitleWidget,
|
||||
|
@ -26,7 +26,7 @@ class CustomListTile extends StatelessWidget {
|
|||
this.disabled,
|
||||
this.onHover,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -7,12 +7,12 @@ class CustomRadio extends StatelessWidget {
|
|||
final Color backgroundColor;
|
||||
|
||||
const CustomRadio({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.groupValue,
|
||||
this.onChange,
|
||||
required this.backgroundColor,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -11,14 +11,14 @@ class CustomRadioListTile extends StatelessWidget {
|
|||
final void Function(String) onChanged;
|
||||
|
||||
const CustomRadioListTile({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.groupValue,
|
||||
required this.value,
|
||||
required this.radioBackgroundColor,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
required this.onChanged,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -7,12 +7,12 @@ class CustomRadioToggle extends StatelessWidget {
|
|||
final void Function(String) onTap;
|
||||
|
||||
const CustomRadioToggle({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.groupSelected,
|
||||
required this.value,
|
||||
required this.label,
|
||||
required this.onTap,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
110
lib/widgets/floating_search_bar.dart
Normal file
110
lib/widgets/floating_search_bar.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,13 +13,13 @@ class CustomLineChart extends StatelessWidget {
|
|||
final BuildContext context;
|
||||
|
||||
const CustomLineChart({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.data,
|
||||
required this.color,
|
||||
required this.dates,
|
||||
required this.daysInterval,
|
||||
required this.context
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
String chartDate(DateTime date) {
|
||||
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) {
|
||||
return LineChartData(
|
||||
gridData: FlGridData(
|
||||
gridData: const FlGridData(
|
||||
show: false,
|
||||
drawVerticalLine: false,
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
titlesData: const FlTitlesData(
|
||||
show: false,
|
||||
),
|
||||
borderData: FlBorderData(
|
||||
|
@ -73,7 +73,7 @@ class CustomLineChart extends StatelessWidget {
|
|||
barWidth: 2,
|
||||
isStrokeCapRound: true,
|
||||
preventCurveOverShooting: true,
|
||||
dotData: FlDotData(
|
||||
dotData: const FlDotData(
|
||||
show: false,
|
||||
),
|
||||
belowBarData: BarAreaData(
|
||||
|
|
|
@ -11,9 +11,9 @@ class CustomMenuBar extends StatelessWidget {
|
|||
final Widget child;
|
||||
|
||||
const CustomMenuBar({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.child
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -7,12 +7,12 @@ class OptionBox extends StatelessWidget {
|
|||
final String label;
|
||||
|
||||
const OptionBox({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.optionsValue,
|
||||
required this.itemValue,
|
||||
required this.onTap,
|
||||
required this.label,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -4,9 +4,9 @@ class ProcessDialog extends StatelessWidget {
|
|||
final String message;
|
||||
|
||||
const ProcessDialog({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.message,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -5,10 +5,10 @@ class SectionLabel extends StatelessWidget {
|
|||
final EdgeInsets? padding;
|
||||
|
||||
const SectionLabel({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.label,
|
||||
this.padding
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -13,9 +13,9 @@ class DeleteModal extends StatelessWidget {
|
|||
final Server serverToDelete;
|
||||
|
||||
const DeleteModal({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.serverToDelete,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -34,14 +34,14 @@ class DeleteModal extends StatelessWidget {
|
|||
appConfigProvider.setSelectedScreen(0);
|
||||
}
|
||||
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionRemoved,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionCannotBeRemoved,
|
||||
color: Colors.red
|
||||
|
|
|
@ -50,14 +50,15 @@ void showDeleteModal({
|
|||
required BuildContext context,
|
||||
required Server server
|
||||
}) async {
|
||||
await Future.delayed(const Duration(seconds: 0), () => {
|
||||
await Future.delayed(const Duration(seconds: 0), () {
|
||||
if (!context.mounted) return;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeleteModal(
|
||||
serverToDelete: server,
|
||||
),
|
||||
barrierDismissible: false
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,7 @@ void connectToServer({
|
|||
process.close();
|
||||
if (!context.mounted) return;
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.cannotConnect,
|
||||
color: Colors.red
|
||||
|
@ -150,14 +151,14 @@ void setDefaultServer({
|
|||
if (!context.mounted) return;
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
|
||||
if (result == null) {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionDefaultSuccessfully,
|
||||
color: Colors.green
|
||||
);
|
||||
}
|
||||
else {
|
||||
showSnacbkar(
|
||||
showSnackbar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionDefaultFailed,
|
||||
color: Colors.red
|
||||
|
|
|
@ -16,13 +16,13 @@ class ServersList extends StatelessWidget {
|
|||
final double breakingWidth;
|
||||
|
||||
const ServersList({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.context,
|
||||
required this.controllers,
|
||||
required this.onChange,
|
||||
required this.scrollController,
|
||||
required this.breakingWidth
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue