Merge branch 'beta'

This commit is contained in:
Juan Gilsanz Polo 2023-05-28 03:13:33 +02:00
commit 459e67363c
92 changed files with 4895 additions and 4757 deletions

102
.github/workflows/release-beta.yaml vendored Normal file
View file

@ -0,0 +1,102 @@
name: Compile and release beta build
on:
workflow_dispatch:
inputs:
version:
description: "Version (beta)"
required: true
default: "1.0.0-beta.1"
number:
description: "Build number"
required: true
default: "1"
jobs:
build-android:
name: Build Android .apk and .aab
runs-on: ubuntu-latest
env:
ANDROID_AAB_RELEASE_PATH: build/app/outputs/bundle/release
ANDROID_APK_RELEASE_PATH: build/app/outputs/apk/release
steps:
- uses: actions/checkout@v3
- name: Decode android/app/keystore.jks
run: echo "${{ secrets.KEYSTORE_JKS }}" | base64 --decode > android/app/keystore.jks
- name: Decode android/key.properties
run: echo "${{ secrets.KEY_PROPERTIES }}" | base64 --decode > android/key.properties
- name: Decode .env
run: echo "${{ secrets.ENV }}" | base64 --decode > .env
- name: Update version in YAML
run: sed -i 's/99.99.99+99/${{ github.event.inputs.version }}+${{ github.event.inputs.number }}/g' pubspec.yaml
- name: Update KeyStore password in gradle properties
run: sed -i 's/#{KEYSTORE_PASS}#/${{ secrets.KEYSTORE_PASS }}/g' android/key.properties
- name: Update KeyStore key password in gradle properties
run: sed -i 's/#{KEYSTORE_KEY_PASS}#/${{ secrets.KEYSTORE_KEY_PASS }}/g' android/key.properties
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '18.x'
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- run: flutter clean
- run: flutter pub get
- run: flutter build apk --release
- run: flutter build appbundle --release
- name: Rename apk
run: mv $ANDROID_APK_RELEASE_PATH/app-release.apk $ANDROID_APK_RELEASE_PATH/AdGuardHomeManager_${{ github.event.inputs.version }}_Android.apk
- name: Rename aab
run: mv $ANDROID_AAB_RELEASE_PATH/app-release.aab $ANDROID_AAB_RELEASE_PATH/AdGuardHomeManager_${{ github.event.inputs.version }}_Android.aab
- name: Copy apk to project root
run: cp $ANDROID_APK_RELEASE_PATH/AdGuardHomeManager_${{ github.event.inputs.version }}_Android.apk AdGuardHomeManager_${{ github.event.inputs.version }}_Android.apk
- name: Copy aab to project root
run: cp $ANDROID_AAB_RELEASE_PATH/AdGuardHomeManager_${{ github.event.inputs.version }}_Android.aab AdGuardHomeManager_${{ github.event.inputs.version }}_Android.aab
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: android
path: |
AdGuardHomeManager_${{ github.event.inputs.version }}_Android.aab
AdGuardHomeManager_${{ github.event.inputs.version }}_Android.apk
release-builds-github:
name: Release beta build to GitHub
runs-on: ubuntu-latest
needs: [build-android]
steps:
- uses: actions/checkout@v3
- name: Create builds directory
run: mkdir releases
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: android
path: releases/
- name: Release to GitHub
uses: ncipollo/release-action@v1
with:
artifacts: "releases/*"
token: ${{ secrets.GH_TOKEN }}
tag: '${{ github.event.inputs.version }}_(${{ github.event.inputs.number }})'
name: v${{ github.event.inputs.version }}
draft: true
prerelease: true
commit: ${{ github.sha }}
release-build-google-play:
name: Release Android beta build to the Google Play Store
runs-on: ubuntu-latest
needs: [build-android]
steps:
- uses: actions/checkout@v3
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: android
- name: Release app to Google Play
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAYSTORE_ACCOUNT_KEY }}
packageName: com.jgeek00.adguard_home_manager
releaseFiles: AdGuardHomeManager_${{ github.event.inputs.version }}_Android.aab
track: beta
status: draft
releaseName: ${{ github.event.inputs.version }}

View file

@ -1,15 +1,11 @@
// ignore_for_file: use_build_context_synchronously, depend_on_referenced_packages // ignore_for_file: use_build_context_synchronously, depend_on_referenced_packages
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:store_checker/store_checker.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart'; import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart';
@ -18,21 +14,14 @@ import 'package:adguard_home_manager/widgets/update_modal.dart';
import 'package:adguard_home_manager/widgets/navigation_rail.dart'; import 'package:adguard_home_manager/widgets/navigation_rail.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/check_app_updates.dart';
import 'package:adguard_home_manager/models/github_release.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/app_screen.dart'; import 'package:adguard_home_manager/models/app_screen.dart';
import 'package:adguard_home_manager/config/app_screens.dart'; import 'package:adguard_home_manager/config/app_screens.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
class Base extends StatefulWidget { class Base extends StatefulWidget {
final AppConfigProvider appConfigProvider; const Base({Key? key}) : super(key: key);
const Base({
Key? key,
required this.appConfigProvider,
}) : super(key: key);
@override @override
State<Base> createState() => _BaseState(); State<Base> createState() => _BaseState();
@ -41,35 +30,6 @@ class Base extends StatefulWidget {
class _BaseState extends State<Base> with WidgetsBindingObserver { class _BaseState extends State<Base> with WidgetsBindingObserver {
int selectedScreen = 0; int selectedScreen = 0;
Future<GitHubRelease?> checkInstallationSource() async {
final result = await checkAppUpdatesGitHub();
if (result['result'] == 'success') {
final update = gitHubUpdateExists(widget.appConfigProvider.getAppInfo!.version, result['body'].tagName);
if (update == true) {
widget.appConfigProvider.setAppUpdatesAvailable(result['body']);
if (Platform.isAndroid) {
if (
widget.appConfigProvider.installationSource == Source.IS_INSTALLED_FROM_LOCAL_SOURCE ||
widget.appConfigProvider.installationSource == Source.IS_INSTALLED_FROM_PLAY_PACKAGE_INSTALLER ||
widget.appConfigProvider.installationSource == Source.UNKNOWN
) {
return result['body'];
}
else {
return null;
}
}
else if (Platform.isIOS) {
return null;
}
else {
return result['body'];
}
}
}
return null;
}
@override @override
void initState() { void initState() {
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
@ -77,9 +37,15 @@ class _BaseState extends State<Base> with WidgetsBindingObserver {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
final result = await checkInstallationSource(); final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
final result = await checkAppUpdates(
currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber,
installationSource: appConfigProvider.installationSource,
setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable,
isBeta: appConfigProvider.getAppInfo!.version.contains('beta'),
);
if (result != null && widget.appConfigProvider.doNotRememberVersion != result.tagName) { if (result != null && appConfigProvider.doNotRememberVersion != result.tagName) {
await showDialog( await showDialog(
context: context, context: context,
builder: (context) => UpdateModal( builder: (context) => UpdateModal(

View file

@ -2,6 +2,6 @@ class Urls {
static const String playStore = "https://play.google.com/store/apps/details?id=com.jgeek00.adguard_home_manager"; static const String playStore = "https://play.google.com/store/apps/details?id=com.jgeek00.adguard_home_manager";
static const String gitHub = "https://github.com/JGeek00/adguard-home-manager"; static const String gitHub = "https://github.com/JGeek00/adguard-home-manager";
static const String customRuleDocs = "https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters"; static const String customRuleDocs = "https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters";
static const String checkLatestReleaseUrl = "https://api.github.com/repos/JGeek00/adguard-home-manager/releases/latest"; static const String getReleasesGitHub = "https://api.github.com/repos/JGeek00/adguard-home-manager/releases";
static const String adGuardHomeReleasesTags = "https://api.github.com/repos/AdGuardTeam/AdGuardHome/releases/tags"; static const String adGuardHomeReleasesTags = "https://api.github.com/repos/AdGuardTeam/AdGuardHome/releases/tags";
} }

View file

@ -3,19 +3,23 @@ import 'dart:io';
import 'package:adguard_home_manager/models/github_release.dart'; import 'package:adguard_home_manager/models/github_release.dart';
String? getAppUpdateDownloadLink(GitHubRelease gitHubRelease) { String? getAppUpdateDownloadLink(GitHubRelease gitHubRelease) {
if (Platform.isAndroid) { try {
return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('apk')).browserDownloadUrl; if (Platform.isAndroid) {
} return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('apk')).browserDownloadUrl;
else if (Platform.isMacOS) { }
return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('macOS')).browserDownloadUrl; // macOS package is a zip else if (Platform.isMacOS) {
} return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('macOS')).browserDownloadUrl;
else if (Platform.isWindows) { }
return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('exe')).browserDownloadUrl; else if (Platform.isWindows) {
} return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('exe')).browserDownloadUrl;
else if (Platform.isLinux) { }
return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('deb')).browserDownloadUrl; else if (Platform.isLinux) {
} return gitHubRelease.assets.firstWhere((item) => item.browserDownloadUrl.contains('deb')).browserDownloadUrl;
else { }
else {
return null;
}
} catch (e) {
return null; return null;
} }
} }

View file

@ -1,61 +0,0 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
Future<Map<String, dynamic>> blockUnblock(BuildContext context, String domain, String newStatus) async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
final ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingUserFilters);
final rules = await getFilteringRules(server: serversProvider.selectedServer!);
if (rules['result'] == 'success') {
FilteringStatus oldStatus = serversProvider.serverStatus.data!.filteringStatus;
List<String> newRules = rules['data'].userRules.where((d) => !d.contains(domain)).toList();
if (newStatus == 'block') {
newRules.add("||$domain^");
}
else if (newStatus == 'unblock') {
newRules.add("@@||$domain^");
}
FilteringStatus newObj = serversProvider.serverStatus.data!.filteringStatus;
newObj.userRules = newRules;
serversProvider.setFilteringStatus(newObj);
final result = await postFilteringRules(server: serversProvider.selectedServer!, data: {'rules': newRules});
processModal.close();
if (result['result'] == 'success') {
return {
'success': true,
'message': AppLocalizations.of(context)!.userFilteringRulesUpdated
};
}
else {
appConfigProvider.addLog(result['log']);
serversProvider.setFilteringStatus(oldStatus);
return {
'success': false,
'message': AppLocalizations.of(context)!.userFilteringRulesNotUpdated
};
}
}
else {
appConfigProvider.addLog(rules['log']);
return {
'success': false,
'message': AppLocalizations.of(context)!.userFilteringRulesNotUpdated
};
}
}

View file

@ -0,0 +1,55 @@
import 'dart:io';
import 'package:store_checker/store_checker.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/models/github_release.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
Future<GitHubRelease?> checkAppUpdates({
required String currentBuildNumber,
required void Function(GitHubRelease?) setUpdateAvailable,
required Source installationSource,
required bool isBeta
}) async {
final result = await checkAppUpdatesGitHub();
if (result['result'] == 'success') {
final update = gitHubUpdateExists(
currentBuildNumber: currentBuildNumber,
gitHubReleases: result['body'],
isBeta: isBeta
);
if (update == true) {
final release = isBeta == true
? result['body'].firstWhere((release) => release.prerelease == true)
: result['body'].firstWhere((release) => release.prerelease == false);
setUpdateAvailable(release);
if (Platform.isAndroid) {
if (
installationSource == Source.IS_INSTALLED_FROM_LOCAL_SOURCE ||
installationSource == Source.IS_INSTALLED_FROM_PLAY_PACKAGE_INSTALLER ||
installationSource == Source.UNKNOWN
) {
return release;
}
else {
return null;
}
}
else if (Platform.isIOS) {
return null;
}
else {
return release;
}
}
else {
setUpdateAvailable(null);
}
}
return null;
}

View file

@ -5,15 +5,17 @@ import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/server.dart'; import 'package:adguard_home_manager/models/server.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
Future<bool> clearDnsCache(BuildContext context, Server server) async { Future<bool> clearDnsCache(BuildContext context, Server server) async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
final ProcessModal processModal = ProcessModal(context: context); final ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.clearingDnsCache); processModal.open(AppLocalizations.of(context)!.clearingDnsCache);
final result = await resetDnsCache(server: server); final result = await serversProvider.apiClient!.resetDnsCache();
processModal.close(); processModal.close();

View file

@ -1,5 +1,7 @@
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:adguard_home_manager/models/github_release.dart';
bool compareVersions({ bool compareVersions({
required String currentVersion, required String currentVersion,
required String newVersion required String newVersion
@ -147,20 +149,36 @@ bool serverVersionIsAhead({
} }
} }
bool gitHubUpdateExists(String appVersion, String gitHubVersion) { bool gitHubUpdateExists({
final List<int> appVersionSplit = List<int>.from(appVersion.split('.').map((e) => int.parse(e))); required String currentBuildNumber,
final List<int> gitHubVersionSplit = List<int>.from(gitHubVersion.split('.').map((e) => int.parse(e))); required List<GitHubRelease> gitHubReleases,
required bool isBeta
}) {
final release = isBeta == true
? gitHubReleases.firstWhere((release) => release.prerelease == true)
: gitHubReleases.firstWhere((release) => release.prerelease == false);
final versionNumberRegex = RegExp(r'\(\d+\)');
final releaseNumberExtracted = versionNumberRegex.allMatches(release.tagName).first.group(0);
if (gitHubVersionSplit[0] > appVersionSplit[0]) { if (releaseNumberExtracted != null) {
return true; final releaseNumber = releaseNumberExtracted.replaceAll(RegExp(r'\(|\)'), '');
} try {
else if (gitHubVersionSplit[0] == appVersionSplit[0] && gitHubVersionSplit[1] > appVersionSplit[1]) { final newReleaseParsed = int.parse(releaseNumber);
return true; final currentReleaseParsed = int.parse(currentBuildNumber);
} if (newReleaseParsed > currentReleaseParsed) {
else if (gitHubVersionSplit[0] == appVersionSplit[0] && gitHubVersionSplit[1] == appVersionSplit[1] && gitHubVersionSplit[2] > appVersionSplit[2]) { return true;
return true; }
else {
return false;
}
} catch (e) {
Sentry.captureMessage("Invalid release number. Current release: $currentBuildNumber. New release: $releaseNumber");
return false;
}
} }
else { else {
Sentry.captureMessage("Invalid release number. Tagname: ${release.tagName}");
return false; return false;
} }
} }

View file

@ -13,4 +13,17 @@ String convertTimestampLocalTimezone(DateTime timestamp, String format) {
String formatTimeOfDay(TimeOfDay timestamp, String format) { String formatTimeOfDay(TimeOfDay timestamp, String format) {
DateFormat f = DateFormat(format); DateFormat f = DateFormat(format);
return f.format(DateTime(0, 0, 0, timestamp.hour, timestamp.minute)); return f.format(DateTime(0, 0, 0, timestamp.hour, timestamp.minute));
}
String formatRemainingSeconds(int seconds) {
int h, m, s;
h = seconds ~/ 3600;
m = ((seconds - h * 3600)) ~/ 60;
s = seconds - (h * 3600) - (m * 60);
String hourLeft = h.toString().length < 2 ? "0$h" : h.toString();
String minuteLeft = m.toString().length < 2 ? "0$m" : m.toString();
String secondsLeft = s.toString().length < 2 ? "0$s" : s.toString();
return "$hourLeft:$minuteLeft:$secondsLeft";
} }

View file

@ -628,5 +628,7 @@
"application": "Application", "application": "Application",
"combinedChart": "Combined chart", "combinedChart": "Combined chart",
"combinedChartDescription": "Combine all charts into one", "combinedChartDescription": "Combine all charts into one",
"statistics": "Statistics" "statistics": "Statistics",
"errorLoadFilters": "Error when loading filters.",
"clientRemovedSuccessfully": "Client removed successfully."
} }

View file

@ -628,5 +628,7 @@
"application": "Aplicación", "application": "Aplicación",
"combinedChart": "Gráfico combinado", "combinedChart": "Gráfico combinado",
"combinedChartDescription": "Combina todos los gráficos en uno solo", "combinedChartDescription": "Combina todos los gráficos en uno solo",
"statistics": "Estadísticas" "statistics": "Estadísticas",
"errorLoadFilters": "Error al cargar los filtros.",
"clientRemovedSuccessfully": "Cliente eliminado correctamente."
} }

View file

@ -17,15 +17,20 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/base.dart'; import 'package:adguard_home_manager/base.dart';
import 'package:adguard_home_manager/classes/http_override.dart';
import 'package:adguard_home_manager/services/db/database.dart';
import 'package:adguard_home_manager/constants/colors.dart';
import 'package:adguard_home_manager/config/globals.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/config/theme.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/providers/rewrite_rules_provider.dart';
import 'package:adguard_home_manager/providers/dhcp_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/constants/colors.dart';
import 'package:adguard_home_manager/config/globals.dart';
import 'package:adguard_home_manager/config/theme.dart';
import 'package:adguard_home_manager/classes/http_override.dart';
import 'package:adguard_home_manager/services/db/database.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -41,9 +46,15 @@ void main() async {
await dotenv.load(fileName: '.env'); await dotenv.load(fileName: '.env');
AppConfigProvider appConfigProvider = AppConfigProvider(); final AppConfigProvider appConfigProvider = AppConfigProvider();
ServersProvider serversProvider = ServersProvider(); final ServersProvider serversProvider = ServersProvider();
LogsProvider logsProvider = LogsProvider(); final StatusProvider statusProvider = StatusProvider();
final ClientsProvider clientsProvider = ClientsProvider();
final FilteringProvider filtersProvider = FilteringProvider();
final DhcpProvider dhcpProvider = DhcpProvider();
final RewriteRulesProvider rewriteRulesProvider = RewriteRulesProvider();
final DnsProvider dnsProvider = DnsProvider();
final LogsProvider logsProvider = LogsProvider();
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) { if (Platform.isAndroid) {
@ -73,6 +84,69 @@ void main() async {
PackageInfo appInfo = await PackageInfo.fromPlatform(); PackageInfo appInfo = await PackageInfo.fromPlatform();
appConfigProvider.setAppInfo(appInfo); appConfigProvider.setAppInfo(appInfo);
void startApp() => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: ((context) => serversProvider)
),
ChangeNotifierProvider(
create: ((context) => appConfigProvider)
),
ChangeNotifierProvider(
create: ((context) => statusProvider)
),
ChangeNotifierProvider(
create: ((context) => clientsProvider)
),
ChangeNotifierProvider(
create: ((context) => logsProvider)
),
ChangeNotifierProvider(
create: ((context) => filtersProvider)
),
ChangeNotifierProvider(
create: ((context) => dhcpProvider)
),
ChangeNotifierProvider(
create: ((context) => rewriteRulesProvider)
),
ChangeNotifierProvider(
create: ((context) => dnsProvider)
),
ChangeNotifierProxyProvider2<ServersProvider, StatusProvider, ClientsProvider>(
create: (context) => clientsProvider,
update: (context, servers, status, clients) => clients!..update(servers, status),
),
ChangeNotifierProxyProvider2<ServersProvider, StatusProvider, FilteringProvider>(
create: (context) => filtersProvider,
update: (context, servers, status, filtering) => filtering!..update(servers, status),
),
ChangeNotifierProxyProvider<ServersProvider, StatusProvider>(
create: (context) => statusProvider,
update: (context, servers, status) => status!..update(servers),
),
ChangeNotifierProxyProvider<ServersProvider, LogsProvider>(
create: (context) => logsProvider,
update: (context, servers, logs) => logs!..update(servers),
),
ChangeNotifierProxyProvider<ServersProvider, DhcpProvider>(
create: (context) => dhcpProvider,
update: (context, servers, dhcp) => dhcp!..update(servers),
),
ChangeNotifierProxyProvider<ServersProvider, RewriteRulesProvider>(
create: (context) => rewriteRulesProvider,
update: (context, servers, rewrite) => rewrite!..update(servers),
),
ChangeNotifierProxyProvider<ServersProvider, DnsProvider>(
create: (context) => dnsProvider,
update: (context, servers, dns) => dns!..update(servers),
),
],
child: const Main(),
)
);
if ( if (
( (
kReleaseMode && kReleaseMode &&
@ -87,41 +161,11 @@ void main() async {
options.dsn = dotenv.env['SENTRY_DSN']; options.dsn = dotenv.env['SENTRY_DSN'];
options.sendDefaultPii = false; options.sendDefaultPii = false;
}, },
appRunner: () => runApp( appRunner: () => startApp()
MultiProvider(
providers: [
ChangeNotifierProvider(
create: ((context) => serversProvider)
),
ChangeNotifierProvider(
create: ((context) => appConfigProvider)
),
ChangeNotifierProvider(
create: ((context) => logsProvider)
),
],
child: const Main(),
)
)
); );
} }
else { else {
runApp( startApp();
MultiProvider(
providers: [
ChangeNotifierProvider(
create: ((context) => serversProvider)
),
ChangeNotifierProvider(
create: ((context) => appConfigProvider)
),
ChangeNotifierProvider(
create: ((context) => logsProvider)
),
],
child: const Main(),
)
);
} }
} }
@ -163,15 +207,15 @@ class _MainState extends State<Main> {
builder: (lightDynamic, darkDynamic) => MaterialApp( builder: (lightDynamic, darkDynamic) => MaterialApp(
title: 'AdGuard Home Manager', title: 'AdGuard Home Manager',
theme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31 theme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
? appConfigProvider.useDynamicColor == true ? appConfigProvider.useDynamicColor == true
? lightTheme(lightDynamic) ? lightTheme(lightDynamic)
: lightThemeOldVersions(colors[appConfigProvider.staticColor]) : lightThemeOldVersions(colors[appConfigProvider.staticColor])
: lightThemeOldVersions(colors[appConfigProvider.staticColor]), : lightThemeOldVersions(colors[appConfigProvider.staticColor]),
darkTheme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31 darkTheme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
? appConfigProvider.useDynamicColor == true ? appConfigProvider.useDynamicColor == true
? darkTheme(darkDynamic) ? darkTheme(darkDynamic)
: darkThemeOldVersions(colors[appConfigProvider.staticColor]) : darkThemeOldVersions(colors[appConfigProvider.staticColor])
: darkThemeOldVersions(colors[appConfigProvider.staticColor]), : darkThemeOldVersions(colors[appConfigProvider.staticColor]),
themeMode: appConfigProvider.selectedTheme, themeMode: appConfigProvider.selectedTheme,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
localizationsDelegates: const [ localizationsDelegates: const [
@ -195,7 +239,7 @@ class _MainState extends State<Main> {
child: child!, child: child!,
); );
}, },
home: Base(appConfigProvider: appConfigProvider), home: const Base(),
), ),
); );
} }

View file

@ -11,12 +11,10 @@ class BlockedServicesFromApi {
} }
class BlockedServices { class BlockedServices {
int loadStatus = 0; List<BlockedService> services;
List<BlockedService>? services;
BlockedServices({ BlockedServices({
this.loadStatus = 0, required this.services
this.services
}); });
} }

View file

@ -1,45 +1,28 @@
import 'dart:convert';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart'; import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
import 'package:adguard_home_manager/models/safe_search.dart'; import 'package:adguard_home_manager/models/safe_search.dart';
class Clients { class Clients {
LoadStatus loadStatus;
ClientsData? data;
Clients({
required this.loadStatus,
this.data
});
}
ClientsData clientsFromJson(String str) => ClientsData.fromJson(json.decode(str));
String clientsToJson(ClientsData data) => json.encode(data.toJson());
class ClientsData {
List<Client> clients; List<Client> clients;
final List<AutoClient> autoClientsData; final List<AutoClient> autoClients;
final List<String> supportedTags; final List<String> supportedTags;
ClientsAllowedBlocked? clientsAllowedBlocked; ClientsAllowedBlocked? clientsAllowedBlocked;
ClientsData({ Clients({
required this.clients, required this.clients,
required this.autoClientsData, required this.autoClients,
required this.supportedTags, required this.supportedTags,
this.clientsAllowedBlocked this.clientsAllowedBlocked
}); });
factory ClientsData.fromJson(Map<String, dynamic> json) => ClientsData( factory Clients.fromJson(Map<String, dynamic> json) => Clients(
clients: json["clients"] != null ? List<Client>.from(json["clients"].map((x) => Client.fromJson(x))) : [], clients: json["clients"] != null ? List<Client>.from(json["clients"].map((x) => Client.fromJson(x))) : [],
autoClientsData: json["auto_clients"] != null ? List<AutoClient>.from(json["auto_clients"].map((x) => AutoClient.fromJson(x))) : [], autoClients: json["auto_clients"] != null ? List<AutoClient>.from(json["auto_clients"].map((x) => AutoClient.fromJson(x))) : [],
supportedTags: json["supported_tags"] != null ? List<String>.from(json["supported_tags"].map((x) => x)) : [], supportedTags: json["supported_tags"] != null ? List<String>.from(json["supported_tags"].map((x) => x)) : [],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"clients": List<dynamic>.from(clients.map((x) => x.toJson())), "clients": List<dynamic>.from(clients.map((x) => x.toJson())),
"auto_clients": List<dynamic>.from(autoClientsData.map((x) => x.toJson())), "auto_clients": List<dynamic>.from(autoClients.map((x) => x.toJson())),
"supported_tags": List<dynamic>.from(supportedTags.map((x) => x)), "supported_tags": List<dynamic>.from(supportedTags.map((x) => x)),
}; };
} }

View file

@ -1,20 +1,9 @@
import 'dart:convert'; import 'dart:convert';
class DhcpModel { class DhcpModel {
int loadStatus = 0;
DhcpData? data;
DhcpModel({
required this.loadStatus,
this.data,
});
}
class DhcpData {
List<NetworkInterface> networkInterfaces; List<NetworkInterface> networkInterfaces;
DhcpStatus dhcpStatus; DhcpStatus dhcpStatus;
DhcpData({ DhcpModel({
required this.networkInterfaces, required this.networkInterfaces,
required this.dhcpStatus, required this.dhcpStatus,
}); });

View file

@ -1,20 +1,4 @@
import 'dart:convert';
class DnsInfo { class DnsInfo {
int loadStatus = 0;
DnsInfoData? data;
DnsInfo({
required this.loadStatus,
this.data
});
}
DnsInfoData dnsInfoDataFromJson(String str) => DnsInfoData.fromJson(json.decode(str));
String dnsInfoDataToJson(DnsInfoData data) => json.encode(data.toJson());
class DnsInfoData {
List<String> upstreamDns; List<String> upstreamDns;
String upstreamDnsFile; String upstreamDnsFile;
List<String> bootstrapDns; List<String> bootstrapDns;
@ -34,9 +18,9 @@ class DnsInfoData {
List<String> localPtrUpstreams; List<String> localPtrUpstreams;
String blockingIpv4; String blockingIpv4;
String blockingIpv6; String blockingIpv6;
List<String> defaultLocalPtrUpstreams; List<String> defaultLocalPtrUpstreams;
DnsInfoData({
DnsInfo({
required this.upstreamDns, required this.upstreamDns,
required this.upstreamDnsFile, required this.upstreamDnsFile,
required this.bootstrapDns, required this.bootstrapDns,
@ -59,7 +43,7 @@ class DnsInfoData {
required this.defaultLocalPtrUpstreams, required this.defaultLocalPtrUpstreams,
}); });
factory DnsInfoData.fromJson(Map<String, dynamic> json) => DnsInfoData( factory DnsInfo.fromJson(Map<String, dynamic> json) => DnsInfo(
upstreamDns: json["upstream_dns"] != null ? List<String>.from(json["upstream_dns"].map((x) => x)) : [], upstreamDns: json["upstream_dns"] != null ? List<String>.from(json["upstream_dns"].map((x) => x)) : [],
upstreamDnsFile: json["upstream_dns_file"], upstreamDnsFile: json["upstream_dns_file"],
bootstrapDns: List<String>.from(json["bootstrap_dns"].map((x) => x)), bootstrapDns: List<String>.from(json["bootstrap_dns"].map((x) => x)),

View file

@ -1,22 +1,4 @@
import 'dart:convert';
import 'package:adguard_home_manager/constants/enums.dart';
FilteringData filteringFromJson(String str) => FilteringData.fromJson(json.decode(str));
String filteringToJson(FilteringData data) => json.encode(data.toJson());
class Filtering { class Filtering {
LoadStatus loadStatus = LoadStatus.loading;
FilteringData? data;
Filtering({
required this.loadStatus,
this.data
});
}
class FilteringData {
final List<Filter> filters; final List<Filter> filters;
final List<Filter> whitelistFilters; final List<Filter> whitelistFilters;
List<String> userRules; List<String> userRules;
@ -24,7 +6,7 @@ class FilteringData {
int interval; int interval;
bool enabled; bool enabled;
FilteringData({ Filtering({
required this.filters, required this.filters,
required this.whitelistFilters, required this.whitelistFilters,
required this.userRules, required this.userRules,
@ -33,7 +15,7 @@ class FilteringData {
required this.enabled, required this.enabled,
}); });
factory FilteringData.fromJson(Map<String, dynamic> json) => FilteringData( factory Filtering.fromJson(Map<String, dynamic> json) => Filtering(
filters: json["filters"] != null ? List<Filter>.from(json["filters"].map((x) => Filter.fromJson(x))) : [], filters: json["filters"] != null ? List<Filter>.from(json["filters"].map((x) => Filter.fromJson(x))) : [],
whitelistFilters: json["whitelist_filters"] != null ? List<Filter>.from(json["whitelist_filters"].map((x) => Filter.fromJson(x))) : [], whitelistFilters: json["whitelist_filters"] != null ? List<Filter>.from(json["whitelist_filters"].map((x) => Filter.fromJson(x))) : [],
userRules: json["user_rules"] != null ? List<String>.from(json["user_rules"].map((x) => x)).where((i) => i != '').toList() : [], userRules: json["user_rules"] != null ? List<String>.from(json["user_rules"].map((x) => x)).where((i) => i != '').toList() : [],

View file

@ -1,29 +1,13 @@
import 'dart:convert';
class RewriteRules { class RewriteRules {
int loadStatus = 0;
List<RewriteRulesData>? data;
RewriteRules({
required this.loadStatus,
this.data
});
}
List<RewriteRulesData> rewriteRulesDataFromJson(String str) => List<RewriteRulesData>.from(json.decode(str).map((x) => RewriteRulesData.fromJson(x)));
String rewriteRulesDataToJson(List<RewriteRulesData> data) => json.encode(List<RewriteRulesData>.from(data.map((x) => x.toJson())));
class RewriteRulesData {
final String domain; final String domain;
final String answer; final String answer;
RewriteRulesData({ RewriteRules({
required this.domain, required this.domain,
required this.answer, required this.answer,
}); });
factory RewriteRulesData.fromJson(Map<String, dynamic> json) => RewriteRulesData( factory RewriteRules.fromJson(Map<String, dynamic> json) => RewriteRules(
domain: json["domain"], domain: json["domain"],
answer: json["answer"], answer: json["answer"],
); );

View file

@ -1,7 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'package:adguard_home_manager/constants/enums.dart';
class ServerInfo { class ServerInfo {
int loadStatus = 0; LoadStatus loadStatus = LoadStatus.loading;
ServerInfoData? data; ServerInfoData? data;
ServerInfo({ ServerInfo({

View file

@ -4,15 +4,6 @@ import 'package:adguard_home_manager/models/dns_statistics.dart';
import 'package:adguard_home_manager/models/filtering_status.dart'; import 'package:adguard_home_manager/models/filtering_status.dart';
class ServerStatus { class ServerStatus {
int loadStatus;
ServerStatusData? data;
ServerStatus({
required this.loadStatus,
this.data
});
}
class ServerStatusData {
final DnsStatistics stats; final DnsStatistics stats;
final List<Client> clients; final List<Client> clients;
final FilteringStatus filteringStatus; final FilteringStatus filteringStatus;
@ -31,7 +22,7 @@ class ServerStatusData {
bool? safeSearchYandex; bool? safeSearchYandex;
bool? safeSearchYoutube; bool? safeSearchYoutube;
ServerStatusData({ ServerStatus({
required this.stats, required this.stats,
required this.clients, required this.clients,
required this.filteringStatus, required this.filteringStatus,
@ -51,7 +42,7 @@ class ServerStatusData {
required this.safeSearchYoutube required this.safeSearchYoutube
}); });
factory ServerStatusData.fromJson(Map<String, dynamic> json) => ServerStatusData( factory ServerStatus.fromJson(Map<String, dynamic> json) => ServerStatus(
stats: DnsStatistics.fromJson(json['stats']), stats: DnsStatistics.fromJson(json['stats']),
clients: json["clients"] != null ? List<Client>.from(json["clients"].map((x) => Client.fromJson(x))) : [], clients: json["clients"] != null ? List<Client>.from(json["clients"].map((x) => Client.fromJson(x))) : [],
generalEnabled: json['status']['protection_enabled'], generalEnabled: json['status']['protection_enabled'],

View file

@ -199,7 +199,7 @@ class AppConfigProvider with ChangeNotifier {
} }
} }
void setAppUpdatesAvailable(GitHubRelease value) { void setAppUpdatesAvailable(GitHubRelease? value) {
_appUpdatesAvailable = value; _appUpdatesAvailable = value;
notifyListeners(); notifyListeners();
} }

View file

@ -0,0 +1,285 @@
import 'package:flutter/material.dart';
import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/functions/maps_fns.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
import 'package:adguard_home_manager/constants/enums.dart';
class ClientsProvider with ChangeNotifier {
ServersProvider? _serversProvider;
StatusProvider? _statusProvider;
update(ServersProvider? servers, StatusProvider? status) {
_serversProvider = servers;
_statusProvider = status;
}
LoadStatus _loadStatus = LoadStatus.loading;
Clients? _clients;
String? _searchTermClients;
List<AutoClient> _filteredActiveClients = [];
List<Client> _filteredAddedClients = [];
LoadStatus get loadStatus {
return _loadStatus;
}
Clients? get clients {
return _clients;
}
String? get searchTermClients {
return _searchTermClients;
}
List<AutoClient> get filteredActiveClients {
return _filteredActiveClients;
}
List<Client> get filteredAddedClients {
return _filteredAddedClients;
}
void setClientsLoadStatus(LoadStatus status, bool notify) {
_loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
void setClientsData(Clients data, bool notify) {
_clients = data;
if (_searchTermClients != null && _searchTermClients != '') {
_filteredActiveClients = _clients!.autoClients.where(
(client) => client.ip.contains(_searchTermClients!.toLowerCase()) || (client.name != null ? client.name!.contains(_searchTermClients!.toLowerCase()) : false)
).toList();
_filteredAddedClients = _clients!.clients.where(
(client) {
isContained(String value) => value.contains(value.toLowerCase());
return client.ids.any(isContained);
}
).toList();
}
else {
_filteredActiveClients = data.autoClients;
_filteredAddedClients = data.clients;
}
if (notify == true) notifyListeners();
}
void setSearchTermClients(String? value) {
_searchTermClients = value;
if (value != null && value != '') {
if (_clients != null) {
_filteredActiveClients = _clients!.autoClients.where(
(client) => client.ip.contains(value.toLowerCase()) || (client.name != null ? client.name!.contains(value.toLowerCase()) : false)
).toList();
_filteredAddedClients = _clients!.clients.where(
(client) {
isContained(String value) => value.contains(value.toLowerCase());
return client.ids.any(isContained);
}
).toList();
}
}
else {
if (_clients != null) _filteredActiveClients = _clients!.autoClients;
if (_clients != null) _filteredAddedClients = _clients!.clients;
}
notifyListeners();
}
void setAllowedDisallowedClientsBlockedDomains(ClientsAllowedBlocked data) {
_clients?.clientsAllowedBlocked = data;
notifyListeners();
}
Future<bool> fetchClients({
bool? updateLoading
}) async {
if (updateLoading == true) {
_loadStatus = LoadStatus.loading;
}
final result = await _serversProvider!.apiClient!.getClients();
if (result['result'] == 'success') {
setClientsData(result['data'], false);
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
if (updateLoading == true) {
_loadStatus = LoadStatus.error;
notifyListeners();
}
return false;
}
}
Future<bool> deleteClient(Client client) async {
final result = await _serversProvider!.apiClient!.postDeleteClient(name: client.name);
if (result['result'] == 'success') {
Clients clientsData = clients!;
clientsData.clients = clientsData.clients.where((c) => c.name != client.name).toList();
setClientsData(clientsData, false);
notifyListeners();
return true;
}
else {
return false;
}
}
Future<bool> editClient(Client client) async {
final result = await _serversProvider!.apiClient!.postUpdateClient(
data: {
'name': client.name,
'data': serverVersionIsAhead(
currentVersion: _statusProvider!.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == false
? removePropFromMap(client.toJson(), 'safesearch_enabled')
: removePropFromMap(client.toJson(), 'safe_search')
}
);
if (result['result'] == 'success') {
Clients clientsData = clients!;
clientsData.clients = clientsData.clients.map((e) {
if (e.name == client.name) {
return client;
}
else {
return e;
}
}).toList();
setClientsData(clientsData, false);
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
Future<bool> addClient(Client client) async {
final result = await _serversProvider!.apiClient!.postAddClient(
data: serverVersionIsAhead(
currentVersion: _statusProvider!.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == false
? removePropFromMap(client.toJson(), 'safesearch_enabled')
: removePropFromMap(client.toJson(), 'safe_search')
);
if (result['result'] == 'success') {
Clients clientsData = clients!;
clientsData.clients.add(client);
setClientsData(clientsData, false);
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
Future<Map<String, dynamic>> addClientList(String item, String type) async {
Map<String, List<String>> body = {
"allowed_clients": clients!.clientsAllowedBlocked?.allowedClients ?? [],
"disallowed_clients": clients!.clientsAllowedBlocked?.disallowedClients ?? [],
"blocked_hosts": clients!.clientsAllowedBlocked?.blockedHosts ?? [],
};
if (type == 'allowed') {
body['allowed_clients']!.add(item);
}
else if (type == 'disallowed') {
body['disallowed_clients']!.add(item);
}
else if (type == 'domains') {
body['blocked_hosts']!.add(item);
}
final result = await _serversProvider!.apiClient!.requestAllowedBlockedClientsHosts(body);
if (result['result'] == 'success') {
_clients?.clientsAllowedBlocked = ClientsAllowedBlocked(
allowedClients: body['allowed_clients'] ?? [],
disallowedClients: body['disallowed_clients'] ?? [],
blockedHosts: body['blocked_hosts'] ?? [],
);
notifyListeners();
return { 'success': true };
}
else if (result['result'] == 'error' && result['message'] == 'client_another_list') {
notifyListeners();
return {
'success': false,
'error': 'client_another_list'
};
}
else {
notifyListeners();
return {
'success': false,
'error': null
};
}
}
Future<Map<String, dynamic>> removeClientList(String client, String type) async {
Map<String, List<String>> body = {
"allowed_clients": clients!.clientsAllowedBlocked?.allowedClients ?? [],
"disallowed_clients": clients!.clientsAllowedBlocked?.disallowedClients ?? [],
"blocked_hosts": clients!.clientsAllowedBlocked?.blockedHosts ?? [],
};
if (type == 'allowed') {
body['allowed_clients'] = body['allowed_clients']!.where((c) => c != client).toList();
}
else if (type == 'disallowed') {
body['disallowed_clients'] = body['disallowed_clients']!.where((c) => c != client).toList();
}
else if (type == 'domains') {
body['blocked_hosts'] = body['blocked_hosts']!.where((c) => c != client).toList();
}
final result = await _serversProvider!.apiClient!.requestAllowedBlockedClientsHosts(body);
if (result['result'] == 'success') {
_clients?.clientsAllowedBlocked = ClientsAllowedBlocked(
allowedClients: body['allowed_clients'] ?? [],
disallowedClients: body['disallowed_clients'] ?? [],
blockedHosts: body['blocked_hosts'] ?? [],
);
notifyListeners();
return { 'success': true };
}
else if (result['result'] == 'error' && result['message'] == 'client_another_list') {
notifyListeners();
return {
'success': false,
'error': 'client_another_list'
};
}
else {
notifyListeners();
return {
'success': false,
'error': null
};
}
}
}

View file

@ -0,0 +1,115 @@
import 'package:flutter/material.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/dhcp.dart';
class DhcpProvider with ChangeNotifier {
ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
LoadStatus _loadStatus = LoadStatus.loading;
DhcpModel? _dhcp;
DhcpModel? get dhcp {
return _dhcp;
}
LoadStatus get loadStatus {
return _loadStatus;
}
void setDhcpData(DhcpModel data) {
_dhcp = data;
notifyListeners();
}
void setDhcpLoadStatus(LoadStatus status, bool notify) {
_loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
Future<bool> loadDhcpStatus({
bool? showLoading
}) async {
if (showLoading == true) {
_loadStatus = LoadStatus.loading;
notifyListeners();
}
final result = await _serversProvider!.apiClient!.getDhcpData();
if (result['result'] == 'success') {
_dhcp = result['data'];
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
if (showLoading == true) {
_loadStatus = LoadStatus.error;
notifyListeners();
}
return false;
}
}
Future<bool> deleteLease(Lease lease) async {
final result = await _serversProvider!.apiClient!.deleteStaticLease(
data: {
"mac": lease.mac,
"ip": lease.ip,
"hostname": lease.hostname
}
);
if (result['result'] == 'success') {
DhcpModel data = dhcp!;
data.dhcpStatus.staticLeases = data.dhcpStatus.staticLeases.where((l) => l.mac != lease.mac).toList();
setDhcpData(data);
return true;
}
else {
notifyListeners();
return false;
}
}
Future<Map<String, dynamic>> createLease(Lease lease) async {
final result = await _serversProvider!.apiClient!.createStaticLease(
data: {
"mac": lease.mac,
"ip": lease.ip,
"hostname": lease.hostname,
}
);
if (result['result'] == 'success') {
DhcpModel data = dhcp!;
data.dhcpStatus.staticLeases.add(lease);
setDhcpData(data);
return { 'success': true };
}
else if (result['result'] == 'error' && result['message'] == 'already_exists' ) {
return {
'success': false,
'error': 'already_exists'
};
}
else if (result['result'] == 'error' && result['message'] == 'server_not_configured' ) {
return {
'success': false,
'error': 'server_not_configured'
};
}
else {
return {
'success': false,
'error': null
};
}
}
}

View file

@ -0,0 +1,199 @@
import 'package:flutter/material.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
class DnsProvider with ChangeNotifier {
ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
LoadStatus _loadStatus = LoadStatus.loading;
DnsInfo? _dnsInfo;
LoadStatus get loadStatus {
return _loadStatus;
}
DnsInfo? get dnsInfo {
return _dnsInfo;
}
void setDnsInfoData(DnsInfo data) {
_dnsInfo = data;
notifyListeners();
}
void setDnsInfoLoadStatus(LoadStatus status, bool notify) {
_loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
Future<bool> fetchDnsData({
bool? showLoading
}) async {
if (showLoading == true) {
_loadStatus = LoadStatus.loading;
}
final result = await _serversProvider!.apiClient!.getDnsInfo();
if (result['result'] == 'success') {
_dnsInfo = result['data'];
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
if (showLoading == false) {
_loadStatus = LoadStatus.loaded;
notifyListeners();
}
return false;
}
}
Future<Map<String, dynamic>> savePrivateReverseServersConfig(Map<String, dynamic> value) async {
final result = await _serversProvider!.apiClient!.setDnsConfig(
data: value
);
if (result['result'] == 'success') {
DnsInfo data = dnsInfo!;
if (value['local_ptr_upstreams'] != null) {
data.localPtrUpstreams = value['local_ptr_upsreams'];
}
data.usePrivatePtrResolvers = value['use_private_ptr_resolvers'];
data.resolveClients = value['resolve_clients'];
setDnsInfoData(data);
return { 'success': true };
}
else if (result['log'] != null && result['log'].statusCode == '400') {
return {
'success': false,
'error': 400
};
}
else {
return {
'success': false,
'error': null
};
}
}
Future<Map<String, dynamic>> saveUpstreamDnsConfig(Map<String, dynamic> value) async {
final result = await _serversProvider!.apiClient!.setDnsConfig(
data: value
);
if (result['result'] == 'success') {
DnsInfo data = dnsInfo!;
data.upstreamDns = List<String>.from(value['upstream_dns']);
data.upstreamMode = value['upstream_mode'];
setDnsInfoData(data);
return { 'success': true };
}
else if (result['log'] != null && result['log'].statusCode == '400') {
return {
'success': false,
'error': 400
};
}
else {
return {
'success': false,
'error': null
};
}
}
Future<Map<String, dynamic>> saveBootstrapDnsConfig(Map<String, dynamic> value) async {
final result = await _serversProvider!.apiClient!.setDnsConfig(
data: value
);
if (result['result'] == 'success') {
DnsInfo data = dnsInfo!;
data.bootstrapDns = List<String>.from(value['bootstrap_dns']);
setDnsInfoData(data);
return { 'success': true };
}
else if (result['log'] != null && result['log'].statusCode == '400') {
return {
'success': false,
'error': 400
};
}
else {
return {
'success': false,
'error': null
};
}
}
Future<Map<String, dynamic>> saveCacheCacheConfig(Map<String, dynamic> value) async {
final result = await _serversProvider!.apiClient!.setDnsConfig(
data: value
);
if (result['result'] == 'success') {
DnsInfo data = dnsInfo!;
data.cacheSize = value['cache_size'];
data.cacheTtlMin = value['cache_ttl_min'];
data.cacheTtlMax = value['cache_ttl_max'];
data.cacheOptimistic = value['cache_optimistic'];
setDnsInfoData(data);
return { 'success': true };
}
else if (result['log'] != null && result['log'].statusCode == '400') {
return {
'success': false,
'error': 400
};
}
else {
return {
'success': false,
'error': null
};
}
}
Future<Map<String, dynamic>> saveDnsServerConfig(Map<String, dynamic> value) async {
final result = await _serversProvider!.apiClient!.setDnsConfig(
data: value
);
if (result['result'] == 'success') {
DnsInfo data = dnsInfo!;
data.ratelimit = value['ratelimit'];
data.ednsCsEnabled = value['edns_cs_enabled'];
data.dnssecEnabled = value['dnssec_enabled'];
data.disableIpv6 = value['disable_ipv6'];
data.blockingMode = value['blocking_mode'];
data.blockingIpv4 = value['blocking_ipv4'];
data.blockingIpv6 = value['blocking_ipv6'];
setDnsInfoData(data);
return { 'success': true };
}
else if (result['log'] != null && result['log'].statusCode == '400') {
return {
'success': false,
'error': 400
};
}
else {
return {
'success': false,
'error': null
};
}
}
}

View file

@ -0,0 +1,387 @@
import 'package:flutter/material.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/blocked_services.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
enum FilteringListActions { edit, enable, disable }
class FilteringProvider with ChangeNotifier {
StatusProvider? _statusProvider;
ServersProvider? _serversProvider;
update(ServersProvider? servers, StatusProvider? status) {
_serversProvider = servers;
_statusProvider = status;
}
LoadStatus _loadStatus = LoadStatus.loading;
Filtering? _filtering;
LoadStatus _blockedServicesLoadStatus = LoadStatus.loading;
BlockedServices? _blockedServicesList;
LoadStatus get loadStatus {
return _loadStatus;
}
Filtering? get filtering {
return _filtering;
}
LoadStatus get blockedServicesLoadStatus {
return _blockedServicesLoadStatus;
}
BlockedServices? get blockedServices {
return _blockedServicesList;
}
void setFilteringData(Filtering data) {
_filtering = data;
notifyListeners();
}
void setFilteringLoadStatus(LoadStatus loadStatus, bool notify) {
_loadStatus = loadStatus;
if (notify == true) {
notifyListeners();
}
}
void setFilteringProtectionStatus(bool status, bool notify) {
_statusProvider!.setFilteringEnabledStatus(status);
_filtering!.enabled = status;
if (notify == true) notifyListeners();
}
void setFiltersUpdateFrequency(int frequency) {
if (_filtering != null) {
_filtering!.interval = frequency;
notifyListeners();
}
}
void setBlockedServices(List<String> blockedServices) {
if (_filtering != null) {
_filtering!.blockedServices = blockedServices;
notifyListeners();
}
}
void setBlockedServiceListData(List<BlockedService> data) {
_blockedServicesList = BlockedServices(services: data);
notifyListeners();
}
void setBlockedServicesListLoadStatus(LoadStatus status, bool notify) {
_blockedServicesLoadStatus = status;
if (notify == true) {
notifyListeners();
}
}
Future<bool> getBlockedServices({
bool? showLoader
}) async {
_blockedServicesLoadStatus = LoadStatus.loading;
if (showLoader == true) notifyListeners();
final result = await _serversProvider!.apiClient!.getBlockedServices();
if (result['result'] == 'success') {
_blockedServicesLoadStatus = LoadStatus.loaded;
_blockedServicesList = BlockedServices(services: result['data']);
notifyListeners();
return true;
}
else {
if (showLoader == true) {
_blockedServicesLoadStatus = LoadStatus.error;
notifyListeners();
}
return false;
}
}
Future<bool> fetchFilters({
bool? showLoading
}) async {
if (showLoading == true) {
_loadStatus = LoadStatus.loading;
}
final result = await _serversProvider!.apiClient!.getFiltering();
if (result['result'] == 'success') {
_filtering = result['data'];
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
_loadStatus = LoadStatus.error;
notifyListeners();
return false;
}
}
Future<Map<String, dynamic>> updateLists() async {
final result = await _serversProvider!.apiClient!.updateLists();
if (result['result'] == 'success') {
final result2 = await _serversProvider!.apiClient!.getFiltering();
if (result2['result'] == 'success') {
_filtering = result2['data'];
notifyListeners();
return {
"success": true,
"data": result['data']
};
}
else {
notifyListeners();
return { "success": false };
}
}
else {
notifyListeners();
return { "success": false };
}
}
Future<bool> enableDisableFiltering() async {
final newValue = !_statusProvider!.serverStatus!.filteringEnabled;
final result = await _serversProvider!.apiClient!.updateFiltering(
enable: newValue
);
if (result['result'] == 'success') {
setFilteringProtectionStatus(newValue, false);
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
Future<bool> changeUpdateFrequency(int value) async {
final result = await _serversProvider!.apiClient!.requestChangeUpdateFrequency(
data: {
"enabled": filtering!.enabled,
"interval": value
}
);
if (result['result'] == 'success') {
setFiltersUpdateFrequency(value);
return true;
}
else {
notifyListeners();
return false;
}
}
Future<bool> removeCustomRule(String rule) async {
final List<String> newRules = filtering!.userRules.where((r) => r != rule).toList();
final result = await _serversProvider!.apiClient!.setCustomRules(rules: newRules);
if (result['result'] == 'success') {
Filtering filteringData = filtering!;
filteringData.userRules = newRules;
_filtering = filteringData;
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
Future<bool> deleteList({
required String listUrl,
required String type
}) async {
final result1 = await _serversProvider!.apiClient!.deleteFilterList(
data: {
"url": listUrl,
"whitelist": type == 'whitelist' ? true : false
}
);
if (result1['result'] == 'success') {
final result2 = await _serversProvider!.apiClient!.getFiltering();
if (result2['result'] == 'success') {
_filtering = result2['data'];
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
else {
notifyListeners();
return false;
}
}
Future<bool> updateList({
required Filter list,
required String type,
required FilteringListActions action
}) async {
final result1 = await _serversProvider!.apiClient!.updateFilterList(
data: {
"data": {
"enabled": action == FilteringListActions.disable || action == FilteringListActions.enable
? !list.enabled
: list.enabled,
"name": list.name,
"url": list.url
},
"url": list.url,
"whitelist": type == 'whitelist' ? true : false
}
);
if (result1['result'] == 'success') {
final result2 = await _serversProvider!.apiClient!.getFiltering();
if (result2['result'] == 'success') {
_filtering = result2['data'];
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
else {
notifyListeners();
return false;
}
}
Future<bool> addCustomRule(String rule) async {
final List<String> newRules = filtering!.userRules;
newRules.add(rule);
final result = await _serversProvider!.apiClient!.setCustomRules(rules: newRules);
if (result['result'] == 'success') {
Filtering filteringData = filtering!;
filteringData.userRules = newRules;
_filtering = filteringData;
notifyListeners();
return true;
}
else {
notifyListeners();
return false;
}
}
Future<Map<String, dynamic>> addList({required String name, required String url, required String type}) async {
final result1 = await _serversProvider!.apiClient!.addFilteringList(
data: {
'name': name,
'url': url,
'whitelist': type == 'whitelist' ? true : false
}
);
if (result1['result'] == 'success') {
if (result1['data'].toString().contains("OK")) {
final result2 = await _serversProvider!.apiClient!.getFiltering();
final items = result1['data'].toString().split(' ')[1];
if (result2['result'] == 'success') {
_filtering = result2['data'];
notifyListeners();
return {
'success': true,
'data': items
};
}
else {
notifyListeners();
return {
'success': false,
'error': null
};
}
}
else {
notifyListeners();
return {
'success': false,
'error': null
};
}
}
else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains("Couldn't fetch filter from url")) {
notifyListeners();
return {
'success': false,
'error': 'invalid_url'
};
}
else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains('Filter URL already added')) {
notifyListeners();
return {
'success': false,
'error': 'url_exists'
};
}
else {
notifyListeners();
return {
'success': false,
'error': null
};
}
}
Future<bool> loadBlockedServices({
bool? showLoading
}) async {
if (showLoading == true) {
_blockedServicesLoadStatus = LoadStatus.loading;
}
final result = await _serversProvider!.apiClient!.getBlockedServices();
if (result['result'] == 'success') {
_blockedServicesList = BlockedServices(services: result['data']);
_blockedServicesLoadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
if (showLoading == true) _blockedServicesLoadStatus = LoadStatus.error;
notifyListeners();
return false;
}
}
Future<bool> updateBlockedServices(List<String> values) async {
final result = await _serversProvider!.apiClient!.setBlockedServices(
data: values
);
if (result['result'] == 'success') {
setBlockedServices(values);
return true;
}
else {
notifyListeners();
return false;
}
}
}

View file

@ -1,14 +1,21 @@
import 'package:adguard_home_manager/models/clients.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/applied_filters.dart'; import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/models/logs.dart';
class LogsProvider with ChangeNotifier { class LogsProvider with ChangeNotifier {
int _loadStatus = 0; ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
LoadStatus _loadStatus = LoadStatus.loading;
LogsData? _logsData; LogsData? _logsData;
List<AutoClient>? _clients; List<AutoClient>? _clients;
int _clientsLoadStatus = 0;
DateTime? _logsOlderThan; DateTime? _logsOlderThan;
String _selectedResultStatus = 'all'; String _selectedResultStatus = 'all';
@ -18,13 +25,15 @@ class LogsProvider with ChangeNotifier {
int _logsQuantity = 100; int _logsQuantity = 100;
int _offset = 0; int _offset = 0;
bool _isLoadingMore = false;
AppliedFiters _appliedFilters = AppliedFiters( AppliedFiters _appliedFilters = AppliedFiters(
selectedResultStatus: 'all', selectedResultStatus: 'all',
searchText: null, searchText: null,
clients: null clients: null
); );
int get loadStatus { LoadStatus get loadStatus {
return _loadStatus; return _loadStatus;
} }
@ -60,16 +69,15 @@ class LogsProvider with ChangeNotifier {
return _selectedClients; return _selectedClients;
} }
int get clientsLoadStatus {
return _clientsLoadStatus;
}
AppliedFiters get appliedFilters { AppliedFiters get appliedFilters {
return _appliedFilters; return _appliedFilters;
} }
bool get isLoadingMore {
return _isLoadingMore;
}
void setLoadStatus(int value) { void setLoadStatus(LoadStatus value) {
_loadStatus = value; _loadStatus = value;
notifyListeners(); notifyListeners();
} }
@ -83,11 +91,6 @@ class LogsProvider with ChangeNotifier {
_clients = clients; _clients = clients;
notifyListeners(); notifyListeners();
} }
void setClientsLoadStatus(int status) {
_clientsLoadStatus = status;
notifyListeners();
}
void setLogsOlderThan(DateTime? value) { void setLogsOlderThan(DateTime? value) {
_logsOlderThan = value; _logsOlderThan = value;
@ -130,4 +133,136 @@ class LogsProvider with ChangeNotifier {
_appliedFilters = value; _appliedFilters = value;
notifyListeners(); notifyListeners();
} }
void setIsLoadingMore(bool status) {
_isLoadingMore = status;
}
Future<bool> fetchLogs({
int? inOffset,
bool? loadingMore,
String? responseStatus,
String? searchText,
}) async {
int offst = inOffset ?? offset;
String resStatus = responseStatus ?? selectedResultStatus;
String? search = searchText ?? searchText;
if (loadingMore != null && loadingMore == true) {
_isLoadingMore = true;
notifyListeners();
}
final result = await _serversProvider!.apiClient!.getLogs(
count: logsQuantity,
offset: offst,
olderThan: logsOlderThan,
responseStatus: resStatus,
search: search
);
if (loadingMore != null && loadingMore == true) {
_isLoadingMore = false;
notifyListeners();
}
if (result['result'] == 'success') {
_offset = inOffset != null ? inOffset+logsQuantity : offset+logsQuantity;
if (loadingMore != null && loadingMore == true && logsData != null) {
LogsData newLogsData = result['data'];
newLogsData.data = [...logsData!.data, ...result['data'].data];
if (appliedFilters.clients != null) {
newLogsData.data = newLogsData.data.where(
(item) => appliedFilters.clients!.contains(item.client)
).toList();
}
_logsData = newLogsData;
}
else {
LogsData newLogsData = result['data'];
if (appliedFilters.clients != null) {
newLogsData.data = newLogsData.data.where(
(item) => appliedFilters.clients!.contains(item.client)
).toList();
}
_logsData = newLogsData;
}
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
_loadStatus = LoadStatus.error;
notifyListeners();
return false;
}
}
Future<bool> requestResetFilters() async {
_loadStatus = LoadStatus.loading;
notifyListeners();
resetFilters();
final result = await _serversProvider!.apiClient!.getLogs(
count: logsQuantity
);
_appliedFilters = AppliedFiters(
selectedResultStatus: 'all',
searchText: null,
clients: null
);
if (result['result'] == 'success') {
_logsData = result['data'];
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
_loadStatus = LoadStatus.error;
notifyListeners();
return false;
}
}
Future<bool> filterLogs() async {
_loadStatus = LoadStatus.loading;
notifyListeners();
setOffset(0);
final result = await _serversProvider!.apiClient!.getLogs(
count: logsQuantity,
olderThan: logsOlderThan,
responseStatus: selectedResultStatus,
search: searchText,
);
_appliedFilters = AppliedFiters(
selectedResultStatus: selectedResultStatus,
searchText: searchText,
clients: selectedClients
);
if (result['result'] == 'success') {
LogsData newLogsData = result['data'];
if (appliedFilters.clients != null) {
newLogsData.data = newLogsData.data.where(
(item) => appliedFilters.clients!.contains(item.client)
).toList();
}
_logsData = newLogsData;
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
_loadStatus = LoadStatus.error;
notifyListeners();
return false;
}
}
} }

View file

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/rewrite_rules.dart';
class RewriteRulesProvider with ChangeNotifier {
ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
LoadStatus _loadStatus = LoadStatus.loading;
List<RewriteRules>? _rewriteRules;
LoadStatus get loadStatus {
return _loadStatus;
}
List<RewriteRules>? get rewriteRules {
return _rewriteRules;
}
void setRewriteRulesData(List<RewriteRules> data) {
_rewriteRules = data;
notifyListeners();
}
void setRewriteRulesLoadStatus(LoadStatus status, bool notify) {
_loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
Future<bool> addDnsRewrite(RewriteRules rule) async {
final result = await _serversProvider!.apiClient!.addDnsRewriteRule(
data: {
"domain": rule.domain,
"answer": rule.answer
}
);
if (result['result'] == 'success') {
List<RewriteRules> data = rewriteRules!;
data.add(rule);
setRewriteRulesData(data);
return true;
}
else {
notifyListeners();
return false;
}
}
Future<bool> deleteDnsRewrite(RewriteRules rule) async {
final result = await _serversProvider!.apiClient!.deleteDnsRewriteRule(
data: {
"domain": rule.domain,
"answer": rule.answer
}
);
if (result['result'] == 'success') {
List<RewriteRules> data = rewriteRules!;
data = data.where((item) => item.domain != rule.domain).toList();
setRewriteRulesData(data);
return true;
}
else {
notifyListeners();
return false;
}
}
Future<bool> fetchRules({
bool? showLoading
}) async {
if (showLoading == true) {
_loadStatus = LoadStatus.loading;
}
final result = await _serversProvider!.apiClient!.getDnsRewriteRules();
if (result['result'] == 'success') {
_rewriteRules = result['data'];
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
if (showLoading == true) {
_loadStatus = LoadStatus.error;
notifyListeners();
}
return false;
}
}
}

View file

@ -1,19 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/models/dhcp.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
import 'package:adguard_home_manager/models/rewrite_rules.dart';
import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
import 'package:adguard_home_manager/models/blocked_services.dart';
import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/models/server_status.dart';
import 'package:adguard_home_manager/models/server.dart'; import 'package:adguard_home_manager/models/server.dart';
import 'package:adguard_home_manager/models/update_available.dart'; import 'package:adguard_home_manager/models/update_available.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/functions/time_server_disabled.dart';
import 'package:adguard_home_manager/functions/conversions.dart'; import 'package:adguard_home_manager/functions/conversions.dart';
import 'package:adguard_home_manager/services/db/queries.dart'; import 'package:adguard_home_manager/services/db/queries.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
@ -24,51 +14,16 @@ class ServersProvider with ChangeNotifier {
List<Server> _serversList = []; List<Server> _serversList = [];
Server? _selectedServer; Server? _selectedServer;
final ServerStatus _serverStatus = ServerStatus( ApiClient? _apiClient;
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error
data: null
); // serverStatus != null means server is connected
List<String> _protectionsManagementProcess = []; // protections that are currenty being enabled or disabled
final Clients _clients = Clients(
loadStatus: LoadStatus.loading,
data: null
);
String? _searchTermClients;
List<AutoClient> _filteredActiveClients = [];
List<Client> _filteredAddedClients = [];
final Filtering _filtering = Filtering(
loadStatus: LoadStatus.loading,
data: null
);
final DhcpModel _dhcp = DhcpModel(
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error
data: null
);
final RewriteRules _rewriteRules = RewriteRules(
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error
data: null
);
final DnsInfo _dnsInfo = DnsInfo(
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error
data: null
);
final BlockedServices _blockedServicesList = BlockedServices(
loadStatus: 0,
services: null
);
final UpdateAvailable _updateAvailable = UpdateAvailable( final UpdateAvailable _updateAvailable = UpdateAvailable(
loadStatus: LoadStatus.loading, loadStatus: LoadStatus.loading,
data: null, data: null,
); );
FilteringStatus? _filteringStatus; ApiClient? get apiClient {
return _apiClient;
}
List<Server> get serversList { List<Server> get serversList {
return _serversList; return _serversList;
@ -78,54 +33,6 @@ class ServersProvider with ChangeNotifier {
return _selectedServer; return _selectedServer;
} }
ServerStatus get serverStatus {
return _serverStatus;
}
List<String> get protectionsManagementProcess {
return _protectionsManagementProcess;
}
Clients get clients {
return _clients;
}
String? get searchTermClients {
return _searchTermClients;
}
List<AutoClient> get filteredActiveClients {
return _filteredActiveClients;
}
List<Client> get filteredAddedClients {
return _filteredAddedClients;
}
FilteringStatus? get filteringStatus {
return _filteringStatus;
}
Filtering get filtering {
return _filtering;
}
DhcpModel get dhcp {
return _dhcp;
}
RewriteRules get rewriteRules {
return _rewriteRules;
}
DnsInfo get dnsInfo {
return _dnsInfo;
}
BlockedServices get blockedServicesList {
return _blockedServicesList;
}
UpdateAvailable get updateAvailable { UpdateAvailable get updateAvailable {
return _updateAvailable; return _updateAvailable;
} }
@ -144,151 +51,6 @@ class ServersProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void setServerStatusData(ServerStatusData data) {
_serverStatus.data = data;
notifyListeners();
}
void setServerStatusLoad(int status) {
_serverStatus.loadStatus = status;
notifyListeners();
}
void setClientsLoadStatus(LoadStatus status, bool notify) {
_clients.loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
void setClientsData(ClientsData data) {
_clients.data = data;
if (_searchTermClients != null && _searchTermClients != '') {
_filteredActiveClients = _clients.data!.autoClientsData.where(
(client) => client.ip.contains(_searchTermClients!.toLowerCase()) || (client.name != null ? client.name!.contains(_searchTermClients!.toLowerCase()) : false)
).toList();
_filteredAddedClients = _clients.data!.clients.where(
(client) {
isContained(String value) => value.contains(value.toLowerCase());
return client.ids.any(isContained);
}
).toList();
}
else {
_filteredActiveClients = data.autoClientsData;
_filteredAddedClients = data.clients;
}
notifyListeners();
}
void setSearchTermClients(String? value) {
_searchTermClients = value;
if (value != null && value != '') {
if (_clients.data != null) {
_filteredActiveClients = _clients.data!.autoClientsData.where(
(client) => client.ip.contains(value.toLowerCase()) || (client.name != null ? client.name!.contains(value.toLowerCase()) : false)
).toList();
_filteredAddedClients = _clients.data!.clients.where(
(client) {
isContained(String value) => value.contains(value.toLowerCase());
return client.ids.any(isContained);
}
).toList();
}
}
else {
if (_clients.data != null) _filteredActiveClients = _clients.data!.autoClientsData;
if (_clients.data != null) _filteredAddedClients = _clients.data!.clients;
}
notifyListeners();
}
void setAllowedDisallowedClientsBlockedDomains(ClientsAllowedBlocked data) {
_clients.data?.clientsAllowedBlocked = data;
notifyListeners();
}
void setFilteringStatus(FilteringStatus status) {
_filteringStatus = status;
notifyListeners();
}
void setFilteringData(FilteringData data) {
_filtering.data = data;
notifyListeners();
}
void setFilteringLoadStatus(LoadStatus loadStatus, bool notify) {
_filtering.loadStatus = loadStatus;
if (notify == true) {
notifyListeners();
}
}
void setFilteringProtectionStatus(bool status) {
_serverStatus.data!.filteringEnabled = status;
_filtering.data!.enabled = status;
notifyListeners();
}
void setFiltersUpdateFrequency(int frequency) {
_filtering.data!.interval = frequency;
notifyListeners();
}
void setBlockedServices(List<String> blockedServices) {
_filtering.data!.blockedServices = blockedServices;
notifyListeners();
}
void setDhcpData(DhcpData data) {
_dhcp.data = data;
notifyListeners();
}
void setDhcpLoadStatus(int status, bool notify) {
_dhcp.loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
void setRewriteRulesData(List<RewriteRulesData> data) {
_rewriteRules.data = data;
notifyListeners();
}
void setRewriteRulesLoadStatus(int status, bool notify) {
_rewriteRules.loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
void setDnsInfoData(DnsInfoData data) {
_dnsInfo.data = data;
notifyListeners();
}
void setDnsInfoLoadStatus(int status, bool notify) {
_dnsInfo.loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
void setBlockedServiceListData(List<BlockedService> data) {
_blockedServicesList.services = data;
notifyListeners();
}
void setBlockedServicesListLoadStatus(int status, bool notify) {
_blockedServicesList.loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
void setUpdateAvailableLoadStatus(LoadStatus status, bool notify) { void setUpdateAvailableLoadStatus(LoadStatus status, bool notify) {
_updateAvailable.loadStatus = status; _updateAvailable.loadStatus = status;
if (notify == true) { if (notify == true) {
@ -301,6 +63,11 @@ class ServersProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void setApiClient(ApiClient client) {
_apiClient = client;
notifyListeners();
}
Future<dynamic> createServer(Server server) async { Future<dynamic> createServer(Server server) async {
final saved = await saveServerQuery(_dbInstance!, server); final saved = await saveServerQuery(_dbInstance!, server);
if (saved == null) { if (saved == null) {
@ -360,6 +127,11 @@ class ServersProvider with ChangeNotifier {
} }
}).toList(); }).toList();
_serversList = newServers; _serversList = newServers;
if (selectedServer != null &&server.id == selectedServer!.id) {
_apiClient = ApiClient(server: server);
}
notifyListeners(); notifyListeners();
return null; return null;
} }
@ -372,6 +144,7 @@ class ServersProvider with ChangeNotifier {
final result = await removeServerQuery(_dbInstance!, server.id); final result = await removeServerQuery(_dbInstance!, server.id);
if (result == true) { if (result == true) {
_selectedServer = null; _selectedServer = null;
_apiClient = null;
List<Server> newServers = _serversList.where((s) => s.id != server.id).toList(); List<Server> newServers = _serversList.where((s) => s.id != server.id).toList();
_serversList = newServers; _serversList = newServers;
notifyListeners(); notifyListeners();
@ -382,155 +155,12 @@ class ServersProvider with ChangeNotifier {
} }
} }
Future<dynamic> updateBlocking({
required Server server,
required String block,
required bool newStatus,
int? time
}) async {
switch (block) {
case 'general':
_protectionsManagementProcess.add('general');
notifyListeners();
final result = await updateGeneralProtection(
server: server,
enable: newStatus,
time: time
);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'general').toList();
if (result['result'] == 'success') {
_serverStatus.data!.generalEnabled = newStatus;
if (time != null) {
_serverStatus.data!.timeGeneralDisabled = time;
_serverStatus.data!.disabledUntil = generateTimeDeadline(time);
}
else {
_serverStatus.data!.timeGeneralDisabled = 0;
_serverStatus.data!.disabledUntil = null;
}
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'general_legacy':
_protectionsManagementProcess.add('general');
notifyListeners();
final result = await updateGeneralProtectionLegacy(server, newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'general').toList();
if (result['result'] == 'success') {
_serverStatus.data!.generalEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'filtering':
_protectionsManagementProcess.add('filtering');
notifyListeners();
final result = await updateFiltering(
server: server,
enable: newStatus,
);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'filtering').toList();
if (result['result'] == 'success') {
_serverStatus.data!.filteringEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'safeSearch':
_protectionsManagementProcess.add('safeSearch');
notifyListeners();
final result = serverVersionIsAhead(
currentVersion: serverStatus.data!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
? await updateSafeSearchSettings(server: server, body: { 'enabled': newStatus })
: await updateSafeSearchLegacy(server, newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'safeSearch').toList();
if (result['result'] == 'success') {
_serverStatus.data!.safeSearchEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'safeBrowsing':
_protectionsManagementProcess.add('safeBrowsing');
notifyListeners();
final result = await updateSafeBrowsing(server, newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'safeBrowsing').toList();
if (result['result'] == 'success') {
_serverStatus.data!.safeBrowsingEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'parentalControl':
_protectionsManagementProcess.add('parentalControl');
notifyListeners();
final result = await updateParentalControl(server, newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'parentalControl').toList();
if (result['result'] == 'success') {
_serverStatus.data!.parentalControlEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
default:
return false;
}
}
void checkServerUpdatesAvailable(Server server) async { void checkServerUpdatesAvailable(Server server) async {
setUpdateAvailableLoadStatus(LoadStatus.loading, true); setUpdateAvailableLoadStatus(LoadStatus.loading, true);
final result = await checkServerUpdates(server: server); final result = await _apiClient!.checkServerUpdates();
if (result['result'] == 'success') { if (result['result'] == 'success') {
UpdateAvailableData data = UpdateAvailableData.fromJson(result['data']); UpdateAvailableData data = UpdateAvailableData.fromJson(result['data']);
final gitHubResult = await getUpdateChangelog(server: server, releaseTag: data.newVersion ?? data.currentVersion); final gitHubResult = await _apiClient!.getUpdateChangelog(releaseTag: data.newVersion ?? data.currentVersion);
if (gitHubResult['result'] == 'success') { if (gitHubResult['result'] == 'success') {
data.changelog = gitHubResult['body']; data.changelog = gitHubResult['body'];
} }
@ -556,8 +186,16 @@ class ServersProvider with ChangeNotifier {
} }
} }
void saveFromDb(List<Map<String, dynamic>>? data) async { Future initializateServer(Server server) async {
final serverStatus = await _apiClient!.getServerStatus();
if (serverStatus['result'] == 'success') {
checkServerUpdatesAvailable(server); // Do not await
}
}
Future saveFromDb(List<Map<String, dynamic>>? data) async {
if (data != null) { if (data != null) {
Server? defaultServer;
for (var server in data) { for (var server in data) {
final Server serverObj = Server( final Server serverObj = Server(
id: server['id'], id: server['id'],
@ -574,20 +212,21 @@ class ServersProvider with ChangeNotifier {
); );
_serversList.add(serverObj); _serversList.add(serverObj);
if (convertFromIntToBool(server['defaultServer']) == true) { if (convertFromIntToBool(server['defaultServer']) == true) {
_selectedServer = serverObj; defaultServer = serverObj;
_serverStatus.loadStatus = 0;
final serverStatus = await getServerStatus(serverObj);
if (serverStatus['result'] == 'success') {
_serverStatus.data = serverStatus['data'];
_serverStatus.loadStatus = 1;
checkServerUpdatesAvailable(serverObj); // Do not await
}
else {
_serverStatus.loadStatus = 2;
}
} }
} }
notifyListeners();
if (defaultServer != null) {
_selectedServer = defaultServer;
_apiClient = ApiClient(server: defaultServer);
initializateServer(defaultServer);
}
}
else {
notifyListeners();
return null;
} }
notifyListeners();
} }
} }

View file

@ -0,0 +1,347 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:adguard_home_manager/models/server_status.dart';
import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/functions/time_server_disabled.dart';
class StatusProvider with ChangeNotifier {
ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
LoadStatus _loadStatus = LoadStatus.loading;
ServerStatus? _serverStatus; // serverStatus != null means server is connected
List<String> _protectionsManagementProcess = []; // protections that are currenty being enabled or disabled
FilteringStatus? _filteringStatus;
// Countdown
DateTime? _currentDeadline;
Timer? _countdown;
int _remaining = 0;
LoadStatus get loadStatus {
return _loadStatus;
}
ServerStatus? get serverStatus {
return _serverStatus;
}
List<String> get protectionsManagementProcess {
return _protectionsManagementProcess;
}
FilteringStatus? get filteringStatus {
return _filteringStatus;
}
int get remainingTime {
return _remaining;
}
DateTime? get currentDeadline {
return _currentDeadline;
}
void setServerStatusData({
required ServerStatus data,
}) {
_serverStatus = data;
if (
(_countdown == null ||( _countdown != null && _countdown!.isActive == false)) &&
data.disabledUntil != null
) {
startCountdown(data.disabledUntil!);
}
notifyListeners();
}
void setServerStatusLoad(LoadStatus status) {
_loadStatus = status;
notifyListeners();
}
void setFilteringStatus(FilteringStatus status) {
_filteringStatus = status;
notifyListeners();
}
void startCountdown(DateTime deadline) {
stopCountdown();
_currentDeadline = deadline;
_remaining = deadline.difference(DateTime.now()).inSeconds+1;
_countdown = Timer.periodic(
const Duration(seconds: 1),
(Timer timer) async {
if (_remaining == 0) {
timer.cancel();
notifyListeners();
getServerStatus();
}
else {
_remaining = _remaining - 1;
notifyListeners();
}
},
);
}
void stopCountdown() {
if (_countdown != null && _countdown!.isActive) {
_countdown!.cancel();
_countdown = null;
_remaining = 0;
_currentDeadline = null;
}
}
Future<dynamic> updateBlocking({
required String block,
required bool newStatus,
int? time
}) async {
switch (block) {
case 'general':
_protectionsManagementProcess.add('general');
notifyListeners();
final result = await _serversProvider!.apiClient!.updateGeneralProtection(
enable: newStatus,
time: time
);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'general').toList();
if (result['result'] == 'success') {
_serverStatus!.generalEnabled = newStatus;
if (time != null) {
final deadline = generateTimeDeadline(time);
_serverStatus!.timeGeneralDisabled = time;
_serverStatus!.disabledUntil = deadline;
startCountdown(deadline);
}
else {
_serverStatus!.timeGeneralDisabled = 0;
_serverStatus!.disabledUntil = null;
stopCountdown();
}
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'general_legacy':
_protectionsManagementProcess.add('general');
notifyListeners();
final result = await _serversProvider!.apiClient!.updateGeneralProtectionLegacy(newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'general').toList();
if (result['result'] == 'success') {
_serverStatus!.generalEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'filtering':
_protectionsManagementProcess.add('filtering');
notifyListeners();
final result = await _serversProvider!.apiClient!.updateFiltering(
enable: newStatus,
);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'filtering').toList();
if (result['result'] == 'success') {
_serverStatus!.filteringEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'safeSearch':
_protectionsManagementProcess.add('safeSearch');
notifyListeners();
final result = serverVersionIsAhead(
currentVersion: serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
? await _serversProvider!.apiClient!.updateSafeSearchSettings(body: { 'enabled': newStatus })
: await _serversProvider!.apiClient!.updateSafeSearchLegacy(newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'safeSearch').toList();
if (result['result'] == 'success') {
_serverStatus!.safeSearchEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'safeBrowsing':
_protectionsManagementProcess.add('safeBrowsing');
notifyListeners();
final result = await _serversProvider!.apiClient!.updateSafeBrowsing(newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'safeBrowsing').toList();
if (result['result'] == 'success') {
_serverStatus!.safeBrowsingEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
case 'parentalControl':
_protectionsManagementProcess.add('parentalControl');
notifyListeners();
final result = await _serversProvider!.apiClient!.updateParentalControl(newStatus);
_protectionsManagementProcess = _protectionsManagementProcess.where((e) => e != 'parentalControl').toList();
if (result['result'] == 'success') {
_serverStatus!.parentalControlEnabled = newStatus;
notifyListeners();
return null;
}
else {
notifyListeners();
return result['log'];
}
default:
return false;
}
}
void setFilteringEnabledStatus(bool status) {
_serverStatus!.filteringEnabled = status;
}
Future<bool> getFilteringRules() async {
final result = await _serversProvider!.apiClient!.getFilteringRules();
if (result['result'] == 'success') {
_filteringStatus = result['data'];
notifyListeners();
return true;
}
else {
return false;
}
}
Future<bool> getServerStatus({
bool? withLoadingIndicator
}) async {
if (withLoadingIndicator == true) {
_loadStatus = LoadStatus.loading;
}
final result = await _serversProvider!.apiClient!.getServerStatus();
if (result['result'] == 'success') {
setServerStatusData(
data: result['data']
);
_loadStatus = LoadStatus.loaded;
notifyListeners();
return true;
}
else {
if (withLoadingIndicator == true) _loadStatus = LoadStatus.error;
notifyListeners();
return false;
}
}
Future<bool> blockUnblockDomain({
required String domain,
required String newStatus
}) async {
final rules = await _serversProvider!.apiClient!.getFilteringRules();
if (rules['result'] == 'success') {
FilteringStatus oldStatus = serverStatus!.filteringStatus;
List<String> newRules = rules['data'].userRules.where((d) => !d.contains(domain)).toList();
if (newStatus == 'block') {
newRules.add("||$domain^");
}
else if (newStatus == 'unblock') {
newRules.add("@@||$domain^");
}
FilteringStatus newObj = serverStatus!.filteringStatus;
newObj.userRules = newRules;
_filteringStatus = newObj;
final result = await _serversProvider!.apiClient!.postFilteringRules(data: {'rules': newRules});
if (result['result'] == 'success') {
return true;
}
else {
_filteringStatus = oldStatus;
return false;
}
}
else {
return false;
}
}
Future<bool> updateSafeSearchConfig(Map<String, bool> status) async {
final result = await _serversProvider!.apiClient!.updateSafeSearchSettings(
body: status
);
if (result['result'] == 'success') {
ServerStatus data = serverStatus!;
data.safeSearchEnabled = status['enabled'] ?? false;
data.safeSeachBing = status['bing'] ?? false;
data.safeSearchDuckduckgo = status['duckduckgo'] ?? false;
data.safeSearchGoogle = status['google'] ?? false;
data.safeSearchPixabay = status['pixabay'] ?? false;
data.safeSearchYandex = status['yandex'] ?? false;
data.safeSearchYoutube = status['youtube'] ?? false;
setServerStatusData(data: data);
return true;
}
else {
notifyListeners();
return false;
}
}
}

View file

@ -17,20 +17,16 @@ import 'package:adguard_home_manager/screens/clients/options_modal.dart';
import 'package:adguard_home_manager/widgets/tab_content_list.dart'; import 'package:adguard_home_manager/widgets/tab_content_list.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/maps_fns.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class AddedList extends StatefulWidget { class AddedList extends StatefulWidget {
final ScrollController scrollController; final ScrollController scrollController;
final LoadStatus loadStatus;
final List<Client> data; final List<Client> data;
final Future Function() fetchClients;
final void Function(Client) onClientSelected; final void Function(Client) onClientSelected;
final Client? selectedClient; final Client? selectedClient;
final bool splitView; final bool splitView;
@ -38,9 +34,7 @@ class AddedList extends StatefulWidget {
const AddedList({ const AddedList({
Key? key, Key? key,
required this.scrollController, required this.scrollController,
required this.loadStatus,
required this.data, required this.data,
required this.fetchClients,
required this.onClientSelected, required this.onClientSelected,
this.selectedClient, this.selectedClient,
required this.splitView required this.splitView
@ -76,7 +70,8 @@ class _AddedListState extends State<AddedList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -85,31 +80,11 @@ class _AddedListState extends State<AddedList> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingClient); processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await postUpdateClient(server: serversProvider.selectedServer!, data: { final result = await clientsProvider.editClient(client);
'name': client.name,
'data': serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == false
? removePropFromMap(client.toJson(), 'safesearch_enabled')
: removePropFromMap(client.toJson(), 'safe_search')
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients = clientsData.clients.map((e) {
if (e.name == client.name) {
return client;
}
else {
return e;
}
}).toList();
serversProvider.setClientsData(clientsData);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully, label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
@ -117,8 +92,6 @@ class _AddedListState extends State<AddedList> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotUpdated, label: AppLocalizations.of(context)!.clientNotUpdated,
@ -131,19 +104,14 @@ class _AddedListState extends State<AddedList> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.removingClient); processModal.open(AppLocalizations.of(context)!.removingClient);
final result = await postDeleteClient(server: serversProvider.selectedServer!, name: client.name); final result = await clientsProvider.deleteClient(client);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients = clientsData.clients.where((c) => c.name != client.name).toList();
serversProvider.setClientsData(clientsData);
if (widget.splitView == true) { if (widget.splitView == true) {
SplitView.of(context).popUntil(0); SplitView.of(context).popUntil(0);
} }
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientDeletedSuccessfully, label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
@ -151,15 +119,13 @@ class _AddedListState extends State<AddedList> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotDeleted, label: AppLocalizations.of(context)!.clientNotDeleted,
color: Colors.red color: Colors.red
); );
} }
} }
void openClientModal(Client client) { void openClientModal(Client client) {
if (width > 900 || !(Platform.isAndroid | Platform.isIOS)) { if (width > 900 || !(Platform.isAndroid | Platform.isIOS)) {
@ -168,7 +134,7 @@ class _AddedListState extends State<AddedList> {
context: context, context: context,
builder: (BuildContext context) => ClientScreen( builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient, onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient, onDelete: deleteClient,
client: client, client: client,
dialog: true, dialog: true,
@ -180,7 +146,7 @@ class _AddedListState extends State<AddedList> {
fullscreenDialog: true, fullscreenDialog: true,
builder: (BuildContext context) => ClientScreen( builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient, onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient, onDelete: deleteClient,
client: client, client: client,
dialog: false, dialog: false,
@ -240,7 +206,7 @@ class _AddedListState extends State<AddedList> {
onLongPress: openOptionsModal, onLongPress: openOptionsModal,
onEdit: openClientModal, onEdit: openClientModal,
splitView: widget.splitView, splitView: widget.splitView,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
), ),
noData: SizedBox( noData: SizedBox(
width: double.maxFinite, width: double.maxFinite,
@ -260,7 +226,7 @@ class _AddedListState extends State<AddedList> {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
TextButton.icon( TextButton.icon(
onPressed: widget.fetchClients, onPressed: () => clientsProvider.fetchClients(updateLoading: true),
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh), label: Text(AppLocalizations.of(context)!.refresh),
) )
@ -290,8 +256,10 @@ class _AddedListState extends State<AddedList> {
], ],
), ),
), ),
loadStatus: widget.loadStatus, loadStatus: statusProvider.loadStatus == LoadStatus.loading || clientsProvider.loadStatus == LoadStatus.loading
onRefresh: widget.fetchClients, ? LoadStatus.loading
: clientsProvider.loadStatus,
onRefresh: () => clientsProvider.fetchClients(updateLoading: false),
fab: const ClientsFab(), fab: const ClientsFab(),
fabVisible: isVisible, fabVisible: isVisible,
); );

View file

@ -11,7 +11,8 @@ import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/models/safe_search.dart'; import 'package:adguard_home_manager/models/safe_search.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
class ClientScreen extends StatefulWidget { class ClientScreen extends StatefulWidget {
@ -130,7 +131,8 @@ class _ClientScreenState extends State<ClientScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final clientsProvider = Provider.of<ClientsProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
void createClient() { void createClient() {
final Client client = Client( final Client client = Client(
@ -200,7 +202,7 @@ class _ClientScreenState extends State<ClientScreen> {
context: context, context: context,
builder: (context) => TagsModal( builder: (context) => TagsModal(
selectedTags: selectedTags, selectedTags: selectedTags,
tags: serversProvider.clients.data!.supportedTags, tags: clientsProvider.clients!.supportedTags,
onConfirm: (selected) => setState(() => selectedTags = selected), onConfirm: (selected) => setState(() => selectedTags = selected),
) )
); );
@ -506,7 +508,7 @@ class _ClientScreenState extends State<ClientScreen> {
), ),
if ( if (
serverVersionIsAhead( serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion, currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == true ) == true
@ -531,7 +533,7 @@ class _ClientScreenState extends State<ClientScreen> {
), ),
if ( if (
serverVersionIsAhead( serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion, currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == false ) == false

View file

@ -11,84 +11,40 @@ import 'package:adguard_home_manager/screens/clients/logs_list_client.dart';
import 'package:adguard_home_manager/screens/clients/clients_desktop_view.dart'; import 'package:adguard_home_manager/screens/clients/clients_desktop_view.dart';
import 'package:adguard_home_manager/screens/clients/added_list.dart'; import 'package:adguard_home_manager/screens/clients/added_list.dart';
import 'package:adguard_home_manager/models/app_log.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/models/server.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
class Clients extends StatelessWidget { class Clients extends StatefulWidget {
const Clients({Key? key}) : super(key: key); const Clients({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<Clients> createState() => _ClientsState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return ClientsWidget(
server: serversProvider.selectedServer!,
setLoadingStatus: serversProvider.setClientsLoadStatus,
setClientsData: serversProvider.setClientsData,
setSelectedClientsTab: appConfigProvider.setSelectedClientsTab,
addLog: appConfigProvider.addLog,
);
}
} }
class ClientsWidget extends StatefulWidget { class _ClientsState extends State<Clients> with TickerProviderStateMixin {
final Server server;
final void Function(LoadStatus, bool) setLoadingStatus;
final void Function(ClientsData) setClientsData;
final void Function(int) setSelectedClientsTab;
final void Function(AppLog) addLog;
const ClientsWidget({
Key? key,
required this.server,
required this.setLoadingStatus,
required this.setClientsData,
required this.setSelectedClientsTab,
required this.addLog,
}) : super(key: key);
@override
State<ClientsWidget> createState() => _ClientsWidgetState();
}
class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateMixin {
late TabController tabController; late TabController tabController;
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
bool searchMode = false; bool searchMode = false;
final TextEditingController searchController = TextEditingController(); final TextEditingController searchController = TextEditingController();
Future fetchClients() async {
widget.setLoadingStatus(LoadStatus.loading, false);
final result = await getClients(widget.server);
if (mounted) {
if (result['result'] == 'success') {
widget.setClientsData(result['data']);
widget.setLoadingStatus(LoadStatus.loaded, true);
}
else {
widget.addLog(result['log']);
widget.setLoadingStatus(LoadStatus.error, true);
}
}
}
@override @override
void initState() { void initState() {
fetchClients(); final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
clientsProvider.fetchClients(updateLoading: true);
super.initState(); super.initState();
tabController = TabController( tabController = TabController(
initialIndex: 0, initialIndex: 0,
length: 2, length: 2,
vsync: this, vsync: this,
); );
tabController.addListener(() => widget.setSelectedClientsTab(tabController.index)); tabController.addListener(
() => Provider.of<AppConfigProvider>(context, listen: false).setSelectedClientsTab(tabController.index)
);
} }
List<AutoClient> generateClientsList(List<AutoClient> clients, List<String> ips) { List<AutoClient> generateClientsList(List<AutoClient> clients, List<String> ips) {
@ -98,6 +54,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -137,10 +94,8 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
children: [ children: [
ClientsList( ClientsList(
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, data: clientsProvider.loadStatus == LoadStatus.loaded
data: serversProvider.clients.loadStatus == LoadStatus.loaded ? clientsProvider.filteredActiveClients : [],
? serversProvider.filteredActiveClients : [],
fetchClients: fetchClients,
onClientSelected: (client) => Navigator.push(context, MaterialPageRoute( onClientSelected: (client) => Navigator.push(context, MaterialPageRoute(
builder: (context) => LogsListClient( builder: (context) => LogsListClient(
ip: client.ip, ip: client.ip,
@ -153,10 +108,8 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
), ),
AddedList( AddedList(
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, data: clientsProvider.loadStatus == LoadStatus.loaded
data: serversProvider.clients.loadStatus == LoadStatus.loaded ? clientsProvider.filteredAddedClients : [],
? serversProvider.filteredAddedClients : [],
fetchClients: fetchClients,
onClientSelected: (client) => Navigator.push(context, MaterialPageRoute( onClientSelected: (client) => Navigator.push(context, MaterialPageRoute(
builder: (context) => LogsListClient( builder: (context) => LogsListClient(
ip: client.ids[0], ip: client.ids[0],
@ -190,7 +143,6 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
child: ClientsDesktopView( child: ClientsDesktopView(
serversProvider: serversProvider, serversProvider: serversProvider,
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
fetchClients: fetchClients,
) )
); );
} }
@ -203,7 +155,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
title: Text(AppLocalizations.of(context)!.clients), title: Text(AppLocalizations.of(context)!.clients),
centerTitle: false, centerTitle: false,
actions: [ actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded) ...[ if (clientsProvider.loadStatus == LoadStatus.loaded) ...[
IconButton( IconButton(
onPressed: () => { onPressed: () => {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
@ -240,7 +192,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
setState(() { setState(() {
searchMode = false; searchMode = false;
searchController.text = ""; searchController.text = "";
serversProvider.setSearchTermClients(null); clientsProvider.setSearchTermClients(null);
}); });
}, },
icon: const Icon(Icons.arrow_back_rounded) icon: const Icon(Icons.arrow_back_rounded)
@ -249,13 +201,13 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
Expanded( Expanded(
child: TextField( child: TextField(
controller: searchController, controller: searchController,
onChanged: (value) => serversProvider.setSearchTermClients(value), onChanged: (value) => clientsProvider.setSearchTermClients(value),
decoration: InputDecoration( decoration: InputDecoration(
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
searchController.text = ""; searchController.text = "";
serversProvider.setSearchTermClients(null); clientsProvider.setSearchTermClients(null);
}); });
}, },
icon: const Icon(Icons.clear_rounded) icon: const Icon(Icons.clear_rounded)
@ -281,7 +233,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
centerTitle: false, centerTitle: false,
forceElevated: innerBoxIsScrolled, forceElevated: innerBoxIsScrolled,
actions: [ actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded && searchMode == false) ...[ if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
IconButton( IconButton(
onPressed: () => setState(() => searchMode = true), onPressed: () => setState(() => searchMode = true),
icon: const Icon(Icons.search), icon: const Icon(Icons.search),

View file

@ -10,6 +10,7 @@ import 'package:adguard_home_manager/screens/clients/added_list.dart';
import 'package:adguard_home_manager/screens/clients/clients_list.dart'; import 'package:adguard_home_manager/screens/clients/clients_list.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -18,13 +19,11 @@ import 'package:adguard_home_manager/providers/servers_provider.dart';
class ClientsDesktopView extends StatefulWidget { class ClientsDesktopView extends StatefulWidget {
final ServersProvider serversProvider; final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider; final AppConfigProvider appConfigProvider;
final Future Function() fetchClients;
const ClientsDesktopView({ const ClientsDesktopView({
Key? key, Key? key,
required this.serversProvider, required this.serversProvider,
required this.appConfigProvider, required this.appConfigProvider,
required this.fetchClients
}) : super(key: key); }) : super(key: key);
@override @override
@ -55,6 +54,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
PreferredSizeWidget tabBar() { PreferredSizeWidget tabBar() {
@ -92,10 +92,8 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
children: [ children: [
ClientsList( ClientsList(
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, data: clientsProvider.loadStatus == LoadStatus.loaded
data: serversProvider.clients.loadStatus == LoadStatus.loaded ? clientsProvider.filteredActiveClients : [],
? serversProvider.filteredActiveClients : [],
fetchClients: widget.fetchClients,
onClientSelected: (client) => setState(() { onClientSelected: (client) => setState(() {
selectedAddedClient = null; selectedAddedClient = null;
selectedActiveClient = client; selectedActiveClient = client;
@ -114,10 +112,8 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
), ),
AddedList( AddedList(
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, data: clientsProvider.loadStatus == LoadStatus.loaded
data: serversProvider.clients.loadStatus == LoadStatus.loaded ? clientsProvider.filteredAddedClients : [],
? serversProvider.filteredAddedClients : [],
fetchClients: widget.fetchClients,
onClientSelected: (client) => setState(() { onClientSelected: (client) => setState(() {
selectedActiveClient = null; selectedActiveClient = null;
selectedAddedClient = client; selectedAddedClient = client;
@ -146,7 +142,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
setState(() { setState(() {
searchMode = false; searchMode = false;
searchController.text = ""; searchController.text = "";
serversProvider.setSearchTermClients(null); clientsProvider.setSearchTermClients(null);
}); });
}, },
icon: const Icon(Icons.arrow_back_rounded) icon: const Icon(Icons.arrow_back_rounded)
@ -155,13 +151,13 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
Expanded( Expanded(
child: TextField( child: TextField(
controller: searchController, controller: searchController,
onChanged: (value) => serversProvider.setSearchTermClients(value), onChanged: (value) => clientsProvider.setSearchTermClients(value),
decoration: InputDecoration( decoration: InputDecoration(
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
searchController.text = ""; searchController.text = "";
serversProvider.setSearchTermClients(null); clientsProvider.setSearchTermClients(null);
}); });
}, },
icon: const Icon(Icons.clear_rounded) icon: const Icon(Icons.clear_rounded)
@ -195,7 +191,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
title: title(), title: title(),
centerTitle: false, centerTitle: false,
actions: [ actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded && searchMode == false) ...[ if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
IconButton( IconButton(
onPressed: () => setState(() => searchMode = true), onPressed: () => setState(() => searchMode = true),
icon: const Icon(Icons.search), icon: const Icon(Icons.search),
@ -226,7 +222,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
centerTitle: false, centerTitle: false,
forceElevated: innerBoxIsScrolled, forceElevated: innerBoxIsScrolled,
actions: [ actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded && searchMode == false) ...[ if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
IconButton( IconButton(
onPressed: () => setState(() => searchMode = true), onPressed: () => setState(() => searchMode = true),
icon: const Icon(Icons.search), icon: const Icon(Icons.search),

View file

@ -1,18 +1,17 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/clients/active_client_tile.dart'; import 'package:adguard_home_manager/screens/clients/active_client_tile.dart';
import 'package:adguard_home_manager/widgets/tab_content_list.dart'; import 'package:adguard_home_manager/widgets/tab_content_list.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/constants/enums.dart';
class ClientsList extends StatelessWidget { class ClientsList extends StatelessWidget {
final ScrollController scrollController; final ScrollController scrollController;
final LoadStatus loadStatus;
final List<AutoClient> data; final List<AutoClient> data;
final Future Function() fetchClients;
final void Function(AutoClient) onClientSelected; final void Function(AutoClient) onClientSelected;
final AutoClient? selectedClient; final AutoClient? selectedClient;
final bool splitView; final bool splitView;
@ -21,9 +20,7 @@ class ClientsList extends StatelessWidget {
const ClientsList({ const ClientsList({
Key? key, Key? key,
required this.scrollController, required this.scrollController,
required this.loadStatus,
required this.data, required this.data,
required this.fetchClients,
required this.onClientSelected, required this.onClientSelected,
this.selectedClient, this.selectedClient,
required this.splitView, required this.splitView,
@ -32,6 +29,8 @@ class ClientsList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final clientsProvider = Provider.of<ClientsProvider>(context);
return CustomTabContentList( return CustomTabContentList(
listPadding: splitView == true listPadding: splitView == true
? const EdgeInsets.only(top: 8) ? const EdgeInsets.only(top: 8)
@ -79,7 +78,7 @@ class ClientsList extends StatelessWidget {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
TextButton.icon( TextButton.icon(
onPressed: fetchClients, onPressed: () => clientsProvider.fetchClients(updateLoading: false),
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh) label: Text(AppLocalizations.of(context)!.refresh)
) )
@ -110,8 +109,8 @@ class ClientsList extends StatelessWidget {
], ],
), ),
), ),
loadStatus: loadStatus, loadStatus: clientsProvider.loadStatus,
onRefresh: fetchClients onRefresh: () => clientsProvider.fetchClients(updateLoading: false),
); );
} }
} }

View file

@ -9,12 +9,10 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/clients/client_screen.dart'; import 'package:adguard_home_manager/screens/clients/client_screen.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/functions/maps_fns.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
class ClientsFab extends StatelessWidget { class ClientsFab extends StatelessWidget {
@ -22,8 +20,9 @@ class ClientsFab extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -31,24 +30,11 @@ class ClientsFab extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingClient); processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await postAddClient( final result = await clientsProvider.addClient(client);
server: serversProvider.selectedServer!,
data: serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == false
? removePropFromMap(client.toJson(), 'safesearch_enabled')
: removePropFromMap(client.toJson(), 'safe_search')
);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients.add(client);
serversProvider.setClientsData(clientsData);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully, label: AppLocalizations.of(context)!.clientAddedSuccessfully,
@ -56,8 +42,6 @@ class ClientsFab extends StatelessWidget {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotAdded, label: AppLocalizations.of(context)!.clientNotAdded,
@ -73,7 +57,7 @@ class ClientsFab extends StatelessWidget {
context: context, context: context,
builder: (BuildContext context) => ClientScreen( builder: (BuildContext context) => ClientScreen(
onConfirm: confirmAddClient, onConfirm: confirmAddClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
dialog: true, dialog: true,
) )
); );
@ -83,7 +67,7 @@ class ClientsFab extends StatelessWidget {
fullscreenDialog: true, fullscreenDialog: true,
builder: (BuildContext context) => ClientScreen( builder: (BuildContext context) => ClientScreen(
onConfirm: confirmAddClient, onConfirm: confirmAddClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
dialog: false, dialog: false,
) )
)); ));

View file

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:async/async.dart'; import 'package:async/async.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/logs/log_tile.dart'; import 'package:adguard_home_manager/screens/logs/log_tile.dart';
@ -10,7 +11,6 @@ import 'package:adguard_home_manager/screens/logs/log_details_screen.dart';
import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class LogsListClient extends StatefulWidget { class LogsListClient extends StatefulWidget {
final String ip; final String ip;
@ -53,6 +53,8 @@ class _LogsListClientState extends State<LogsListClient> {
String? responseStatus, String? responseStatus,
String? searchText, String? searchText,
}) async { }) async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
int offst = inOffset ?? offset; int offst = inOffset ?? offset;
if (loadingMore != null && loadingMore == true) { if (loadingMore != null && loadingMore == true) {
@ -62,8 +64,7 @@ class _LogsListClientState extends State<LogsListClient> {
if (cancelableRequest != null) cancelableRequest!.cancel(); if (cancelableRequest != null) cancelableRequest!.cancel();
cancelableRequest = CancelableOperation.fromFuture( cancelableRequest = CancelableOperation.fromFuture(
getLogs( serversProvider.apiClient!.getLogs(
server: widget.serversProvider.selectedServer!,
count: logsQuantity, count: logsQuantity,
offset: offst, offset: offst,
search: '"${widget.ip}"' search: '"${widget.ip}"'

View file

@ -11,43 +11,25 @@ import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
import 'package:adguard_home_manager/screens/clients/client_screen.dart'; import 'package:adguard_home_manager/screens/clients/client_screen.dart';
import 'package:adguard_home_manager/screens/clients/options_modal.dart'; import 'package:adguard_home_manager/screens/clients/options_modal.dart';
import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/widgets/section_label.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class SearchClients extends StatelessWidget { class SearchClients extends StatefulWidget {
const SearchClients({Key? key}) : super(key: key); const SearchClients({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<SearchClients> createState() => _SearchClientsState();
final serversProvider = Provider.of<ServersProvider>(context);
return SearchClientsWidget(
serversProvider: serversProvider,
);
}
} }
class SearchClientsWidget extends StatefulWidget { class _SearchClientsState extends State<SearchClients> {
final ServersProvider serversProvider;
const SearchClientsWidget({
Key? key,
required this.serversProvider,
}) : super(key: key);
@override
State<SearchClientsWidget> createState() => _SearchClientsWidgetState();
}
class _SearchClientsWidgetState extends State<SearchClientsWidget> {
late ScrollController scrollController; late ScrollController scrollController;
final TextEditingController searchController = TextEditingController(); final TextEditingController searchController = TextEditingController();
@ -86,11 +68,13 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
@override @override
void initState() { void initState() {
final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
scrollController = ScrollController()..addListener(scrollListener); scrollController = ScrollController()..addListener(scrollListener);
setState(() { setState(() {
clients = widget.serversProvider.clients.data!.clients; clients = clientsProvider.clients!.clients;
autoClients = widget.serversProvider.clients.data!.autoClientsData; autoClients = clientsProvider.clients!.autoClients;
}); });
super.initState(); super.initState();
@ -98,7 +82,8 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -107,19 +92,11 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.removingClient); processModal.open(AppLocalizations.of(context)!.removingClient);
final result = await postDeleteClient(server: serversProvider.selectedServer!, name: client.name); final result = await clientsProvider.deleteClient(client);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients = clientsData.clients.where((c) => c.name != client.name).toList();
serversProvider.setClientsData(clientsData);
setState(() {
clients = clientsData.clients;
});
search(searchController.text);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientDeletedSuccessfully, label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
@ -127,44 +104,23 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotDeleted, label: AppLocalizations.of(context)!.clientNotDeleted,
color: Colors.red color: Colors.red
); );
} }
} }
void confirmEditClient(Client client) async { void confirmEditClient(Client client) async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingClient); processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await postUpdateClient(server: serversProvider.selectedServer!, data: { final result = await clientsProvider.editClient(client);
'name': client.name,
'data': client.toJson()
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients = clientsData.clients.map((e) {
if (e.name == client.name) {
return client;
}
else {
return e;
}
}).toList();
serversProvider.setClientsData(clientsData);
setState(() {
clients = clientsData.clients;
});
search(searchController.text);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully, label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
@ -172,8 +128,6 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotUpdated, label: AppLocalizations.of(context)!.clientNotUpdated,
@ -189,7 +143,7 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
context: context, context: context,
builder: (BuildContext context) => ClientScreen( builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient, onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient, onDelete: deleteClient,
client: client, client: client,
dialog: true, dialog: true,
@ -201,7 +155,7 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
fullscreenDialog: true, fullscreenDialog: true,
builder: (BuildContext context) => ClientScreen( builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient, onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient, onDelete: deleteClient,
client: client, client: client,
dialog: false, dialog: false,
@ -356,7 +310,7 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
Icons.search_rounded, Icons.search_rounded,
size: 19, size: 19,
color: serverVersionIsAhead( color: serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion, currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == true ) == true

View file

@ -2,11 +2,10 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class ServicesModal extends StatelessWidget { class ServicesModal extends StatefulWidget {
final List<String> blockedServices; final List<String> blockedServices;
final void Function(List<String>) onConfirm; final void Function(List<String>) onConfirm;
@ -17,56 +16,20 @@ class ServicesModal extends StatelessWidget {
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { State<ServicesModal> createState() => _ServicesModalStateWidget();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return ServicesModalWidget(
blockedServices: blockedServices,
onConfirm: onConfirm,
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
} }
class ServicesModalWidget extends StatefulWidget { class _ServicesModalStateWidget extends State<ServicesModal> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
final List<String> blockedServices;
final void Function(List<String>) onConfirm;
const ServicesModalWidget({
Key? key,
required this.blockedServices,
required this.onConfirm,
required this.serversProvider,
required this.appConfigProvider
}) : super(key: key);
@override
State<ServicesModalWidget> createState() => _ServicesModalStateWidget();
}
class _ServicesModalStateWidget extends State<ServicesModalWidget> {
List<String> blockedServices = []; List<String> blockedServices = [];
Future loadBlockedServices() async {
final result = await getBlockedServices(server: widget.serversProvider.selectedServer!);
if (result['result'] == 'success') {
widget.serversProvider.setBlockedServicesListLoadStatus(1, true);
widget.serversProvider.setBlockedServiceListData(result['data']);
}
else {
widget.serversProvider.setBlockedServicesListLoadStatus(2, true);
widget.appConfigProvider.addLog(result['log']);
}
}
@override @override
void initState() { void initState() {
if (widget.serversProvider.blockedServicesList.loadStatus != 1) { final filteringProvider = Provider.of<FilteringProvider>(context, listen: false);
loadBlockedServices();
if (filteringProvider.blockedServicesLoadStatus != LoadStatus.loaded) {
filteringProvider.getBlockedServices();
} }
blockedServices = widget.blockedServices; blockedServices = widget.blockedServices;
@ -88,11 +51,11 @@ class _ServicesModalStateWidget extends State<ServicesModalWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
Widget content() { Widget content() {
switch (serversProvider.blockedServicesList.loadStatus) { switch (filteringProvider.blockedServicesLoadStatus) {
case 0: case LoadStatus.loading:
return Padding( return Padding(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: SizedBox( child: SizedBox(
@ -116,34 +79,34 @@ class _ServicesModalStateWidget extends State<ServicesModalWidget> {
), ),
); );
case 1: case LoadStatus.loaded:
return SizedBox( return SizedBox(
width: double.minPositive, width: double.minPositive,
height: MediaQuery.of(context).size.height*0.5, height: MediaQuery.of(context).size.height*0.5,
child: ListView.builder( child: ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: serversProvider.blockedServicesList.services!.length, itemCount: filteringProvider.blockedServices!.services.length,
itemBuilder: (context, index) => CheckboxListTile( itemBuilder: (context, index) => CheckboxListTile(
title: Padding( title: Padding(
padding: const EdgeInsets.only(left: 10), padding: const EdgeInsets.only(left: 10),
child: Text( child: Text(
serversProvider.blockedServicesList.services![index].name, filteringProvider.blockedServices!.services[index].name,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: Theme.of(context).colorScheme.onSurface color: Theme.of(context).colorScheme.onSurface
), ),
), ),
), ),
value: blockedServices.contains(serversProvider.blockedServicesList.services![index].id), value: blockedServices.contains(filteringProvider.blockedServices!.services[index].id),
checkboxShape: RoundedRectangleBorder( checkboxShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5) borderRadius: BorderRadius.circular(5)
), ),
onChanged: (value) => checkUncheckService(value!, serversProvider.blockedServicesList.services![index].id) onChanged: (value) => checkUncheckService(value!, filteringProvider.blockedServices!.services[index].id)
) )
), ),
); );
case 2: case LoadStatus.error:
return Padding( return Padding(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: SizedBox( child: SizedBox(

View file

@ -9,13 +9,10 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/add_custom_rule.dart'; import 'package:adguard_home_manager/screens/filters/add_custom_rule.dart';
import 'package:adguard_home_manager/screens/filters/add_list_modal.dart'; import 'package:adguard_home_manager/screens/filters/add_list_modal.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class AddFiltersButton extends StatelessWidget { class AddFiltersButton extends StatelessWidget {
final String type; final String type;
@ -29,7 +26,7 @@ class AddFiltersButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -38,18 +35,11 @@ class AddFiltersButton extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingRule); processModal.open(AppLocalizations.of(context)!.addingRule);
final List<String> newRules = serversProvider.filtering.data!.userRules; final result = await filteringProvider.addCustomRule(rule);
newRules.add(rule);
final result = await setCustomRules(server: serversProvider.selectedServer!, rules: newRules);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
FilteringData filteringData = serversProvider.filtering.data!;
filteringData.userRules = newRules;
serversProvider.setFilteringData(filteringData);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleAddedSuccessfully, label: AppLocalizations.of(context)!.ruleAddedSuccessfully,
@ -57,8 +47,6 @@ class AddFiltersButton extends StatelessWidget {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotAdded, label: AppLocalizations.of(context)!.ruleNotAdded,
@ -95,58 +83,25 @@ class AddFiltersButton extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingList); processModal.open(AppLocalizations.of(context)!.addingList);
final result1 = await addFilteringList(server: serversProvider.selectedServer!, data: { final result = await filteringProvider.addList(name: name, url: url, type: type);
'name': name,
'url': url,
'whitelist': type == 'whitelist' ? true : false
});
if (result1['result'] == 'success') { processModal.close();
if (result1['data'].toString().contains("OK")) {
final result2 = await getFiltering(server: serversProvider.selectedServer!);
final items = result1['data'].toString().split(' ')[1];
if (result2['result'] == 'success') { if (result['success'] == true) {
serversProvider.setFilteringData(result2['data']); showSnacbkar(
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true); appConfigProvider: appConfigProvider,
} label: "${AppLocalizations.of(context)!.listAdded} ${result['data']}.",
else { color: Colors.green
appConfigProvider.addLog(result2['log']); );
serversProvider.setFilteringLoadStatus(LoadStatus.error, true);
}
processModal.close();
showSnacbkar(
appConfigProvider: appConfigProvider,
label: "${AppLocalizations.of(context)!.listAdded} $items.",
color: Colors.green
);
}
else {
processModal.close();
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listNotAdded,
color: Colors.red
);
}
} }
else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains("Couldn't fetch filter from url")) { else if (result['success'] == false && result['error'] == 'invalid_url') {
processModal.close();
appConfigProvider.addLog(result1['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listUrlInvalid, label: AppLocalizations.of(context)!.listUrlInvalid,
color: Colors.red color: Colors.red
); );
} }
else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains('Filter URL already added')) { else if (result['success'] == false && result['error'] == 'url_exists') {
processModal.close();
appConfigProvider.addLog(result1['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listAlreadyAdded, label: AppLocalizations.of(context)!.listAlreadyAdded,
@ -154,9 +109,6 @@ class AddFiltersButton extends StatelessWidget {
); );
} }
else { else {
processModal.close();
appConfigProvider.addLog(result1['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listNotAdded, label: AppLocalizations.of(context)!.listNotAdded,

View file

@ -7,11 +7,11 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/models/blocked_services.dart'; import 'package:adguard_home_manager/models/blocked_services.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class BlockedServicesScreen extends StatelessWidget { class BlockedServicesScreen extends StatefulWidget {
final bool dialog; final bool dialog;
const BlockedServicesScreen({ const BlockedServicesScreen({
@ -20,63 +20,28 @@ class BlockedServicesScreen extends StatelessWidget {
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { State<BlockedServicesScreen> createState() => _BlockedServicesScreenStateWidget();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return BlockedServicesScreenWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
dialog: dialog,
);
}
} }
class BlockedServicesScreenWidget extends StatefulWidget { class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
final bool dialog;
const BlockedServicesScreenWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider,
required this.dialog
}) : super(key: key);
@override
State<BlockedServicesScreenWidget> createState() => _BlockedServicesScreenStateWidget();
}
class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidget> {
List<String> values = []; List<String> values = [];
Future loadBlockedServices() async {
final result = await getBlockedServices(server: widget.serversProvider.selectedServer!);
if (result['result'] == 'success') {
widget.serversProvider.setBlockedServicesListLoadStatus(1, true);
widget.serversProvider.setBlockedServiceListData(result['data']);
}
else {
widget.serversProvider.setBlockedServicesListLoadStatus(2, true);
widget.appConfigProvider.addLog(result['log']);
}
}
@override @override
void initState() { void initState() {
if (widget.serversProvider.blockedServicesList.loadStatus != 1) { final filteringProvider = Provider.of<FilteringProvider>(context, listen: false);
loadBlockedServices();
if (filteringProvider.blockedServicesLoadStatus != LoadStatus.loaded) {
filteringProvider.loadBlockedServices(showLoading: true);
} }
values = widget.serversProvider.filtering.data!.blockedServices; values = filteringProvider.filtering!.blockedServices;
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void updateValues(bool value, BlockedService item) { void updateValues(bool value, BlockedService item) {
@ -96,13 +61,11 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updating); processModal.open(AppLocalizations.of(context)!.updating);
final result = await setBlockedServices(server: serversProvider.selectedServer!, data: values); final result = await filteringProvider.updateBlockedServices(values);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
serversProvider.setBlockedServices(values);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.blockedServicesUpdated, label: AppLocalizations.of(context)!.blockedServicesUpdated,
@ -119,8 +82,8 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
} }
Widget body() { Widget body() {
switch (serversProvider.blockedServicesList.loadStatus) { switch (filteringProvider.blockedServicesLoadStatus) {
case 0: case LoadStatus.loading:
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
width: double.maxFinite, width: double.maxFinite,
@ -142,15 +105,15 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
), ),
); );
case 1: case LoadStatus.loaded:
return ListView.builder( return ListView.builder(
itemCount: serversProvider.blockedServicesList.services!.length, itemCount: filteringProvider.blockedServices!.services.length,
itemBuilder: (context, index) => Material( itemBuilder: (context, index) => Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
onTap: () => updateValues( onTap: () => updateValues(
values.contains(serversProvider.blockedServicesList.services![index].id), values.contains(filteringProvider.blockedServices!.services[index].id),
serversProvider.blockedServicesList.services![index] filteringProvider.blockedServices!.services[index]
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
@ -163,17 +126,17 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
serversProvider.blockedServicesList.services![index].name, filteringProvider.blockedServices!.services[index].name,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: Theme.of(context).colorScheme.onSurface color: Theme.of(context).colorScheme.onSurface
), ),
), ),
Checkbox( Checkbox(
value: values.contains(serversProvider.blockedServicesList.services![index].id), value: values.contains(filteringProvider.blockedServices!.services[index].id),
onChanged: (value) => updateValues( onChanged: (value) => updateValues(
value!, value!,
serversProvider.blockedServicesList.services![index] filteringProvider.blockedServices!.services[index]
), ),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5) borderRadius: BorderRadius.circular(5)
@ -186,7 +149,7 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
) )
); );
case 2: case LoadStatus.error:
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
width: double.maxFinite, width: double.maxFinite,
@ -281,7 +244,16 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
], ],
), ),
body: RefreshIndicator( body: RefreshIndicator(
onRefresh: loadBlockedServices, onRefresh: () async {
final result = await filteringProvider.loadBlockedServices();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.blockedServicesListNotLoaded,
color: Colors.red
);
}
},
child: body() child: body()
), ),
); );

View file

@ -6,7 +6,6 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/get_filtered_status.dart'; import 'package:adguard_home_manager/functions/get_filtered_status.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
class CheckHostModal extends StatefulWidget { class CheckHostModal extends StatefulWidget {
@ -57,11 +56,11 @@ class _CheckHostModalState extends State<CheckHostModal> {
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void checkHost() async { void checkHost() async {
setState(() => resultWidget = checking());
final result = await serversProvider.apiClient!.checkHostFiltered(host: domainController.text);
if (mounted) { if (mounted) {
setState(() => resultWidget = checking());
final result = await checkHostFiltered(server: serversProvider.selectedServer!, host: domainController.text);
if (result['result'] == 'success') { if (result['result'] == 'success') {
final status = getFilteredStatus(context, appConfigProvider, result['data']['reason'], true); final status = getFilteredStatus(context, appConfigProvider, result['data']['reason'], true);
if (mounted) { if (mounted) {
@ -98,26 +97,24 @@ class _CheckHostModalState extends State<CheckHostModal> {
} }
} }
else { else {
if (mounted) { setState(() => resultWidget = Row(
setState(() => resultWidget = Row( mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [
children: [ const Icon(
const Icon( Icons.cancel,
Icons.cancel, size: 18,
size: 18, color: Colors.red,
),
const SizedBox(width: 10),
Text(
AppLocalizations.of(context)!.check,
style: const TextStyle(
color: Colors.red, color: Colors.red,
fontWeight: FontWeight.w500
), ),
const SizedBox(width: 10), )
Text( ],
AppLocalizations.of(context)!.check, ));
style: const TextStyle(
color: Colors.red,
fontWeight: FontWeight.w500
),
)
],
));
}
} }
} }
} }

View file

@ -2,18 +2,21 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/add_button.dart'; import 'package:adguard_home_manager/screens/filters/add_button.dart';
import 'package:adguard_home_manager/widgets/tab_content_list.dart'; import 'package:adguard_home_manager/widgets/tab_content_list.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
class CustomRulesList extends StatefulWidget { class CustomRulesList extends StatefulWidget {
final LoadStatus loadStatus; final LoadStatus loadStatus;
final ScrollController scrollController; final ScrollController scrollController;
final List<String> data; final List<String> data;
final Future<void> Function() fetchData;
final void Function(String) onRemoveCustomRule; final void Function(String) onRemoveCustomRule;
const CustomRulesList({ const CustomRulesList({
@ -21,7 +24,6 @@ class CustomRulesList extends StatefulWidget {
required this.loadStatus, required this.loadStatus,
required this.scrollController, required this.scrollController,
required this.data, required this.data,
required this.fetchData,
required this.onRemoveCustomRule required this.onRemoveCustomRule
}) : super(key: key); }) : super(key: key);
@ -55,6 +57,9 @@ class _CustomRulesListState extends State<CustomRulesList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
bool checkIfComment(String value) { bool checkIfComment(String value) {
final regex = RegExp(r'^(!|#).*$'); final regex = RegExp(r'^(!|#).*$');
if (regex.hasMatch(value)) { if (regex.hasMatch(value)) {
@ -155,7 +160,16 @@ class _CustomRulesListState extends State<CustomRulesList> {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
TextButton.icon( TextButton.icon(
onPressed: widget.fetchData, onPressed: () async {
final result = await filteringProvider.fetchFilters();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red
);
}
},
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh), label: Text(AppLocalizations.of(context)!.refresh),
) )
@ -186,7 +200,16 @@ class _CustomRulesListState extends State<CustomRulesList> {
), ),
), ),
loadStatus: widget.loadStatus, loadStatus: widget.loadStatus,
onRefresh: widget.fetchData, onRefresh: () async {
final result = await filteringProvider.fetchFilters();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red
);
}
},
fab: AddFiltersButton( fab: AddFiltersButton(
type: 'custom_rule', type: 'custom_rule',
widget: (fn) => FloatingActionButton( widget: (fn) => FloatingActionButton(

View file

@ -15,115 +15,57 @@ import 'package:adguard_home_manager/screens/filters/blocked_services_screen.dar
import 'package:adguard_home_manager/screens/filters/update_interval_lists_modal.dart'; import 'package:adguard_home_manager/screens/filters/update_interval_lists_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/models/filtering.dart'; import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/clients.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class Filters extends StatelessWidget { class Filters extends StatefulWidget {
const Filters({Key? key}) : super(key: key); const Filters({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<Filters> createState() => _FiltersState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return FiltersWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider
);
}
} }
class FiltersWidget extends StatefulWidget { class _FiltersState extends State<Filters> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const FiltersWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider
}) : super(key: key);
@override
State<FiltersWidget> createState() => _FiltersWidgetState();
}
class _FiltersWidgetState extends State<FiltersWidget> {
Future fetchFilters() async {
widget.serversProvider.setFilteringLoadStatus(LoadStatus.loading, false);
final result = await getFiltering(server: widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setFilteringData(result['data']);
widget.serversProvider.setFilteringLoadStatus(LoadStatus.loaded, false);
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setFilteringLoadStatus(LoadStatus.error, false);
}
}
}
List<AutoClient> generateClientsList(List<AutoClient> clients, List<String> ips) { List<AutoClient> generateClientsList(List<AutoClient> clients, List<String> ips) {
return clients.where((client) => ips.contains(client.ip)).toList(); return clients.where((client) => ips.contains(client.ip)).toList();
} }
@override @override
void initState() { void initState() {
fetchFilters(); final filteringProvider = Provider.of<FilteringProvider>(context, listen: false);
filteringProvider.fetchFilters(showLoading: true);
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
void fetchUpdateLists() async { void updateLists() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingLists); processModal.open(AppLocalizations.of(context)!.updatingLists);
final result = await updateLists(server: serversProvider.selectedServer!); final result = await filteringProvider.updateLists();
if (result['result'] == 'success') { processModal.close();
final result2 = await getFiltering(server: widget.serversProvider.selectedServer!);
processModal.close(); if (result['success'] == true) {
showSnacbkar(
if (mounted) { appConfigProvider: appConfigProvider,
if (result2['result'] == 'success') { label: "${result['data']['updated']} ${AppLocalizations.of(context)!.listsUpdated}",
widget.serversProvider.setFilteringData(result2['data']); color: Colors.green
);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: "${result['data']['updated']} ${AppLocalizations.of(context)!.listsUpdated}",
color: Colors.green
);
}
else {
widget.appConfigProvider.addLog(result2['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listsNotLoaded,
color: Colors.red
);
}
}
} }
else { else {
processModal.close();
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listsNotUpdated, label: AppLocalizations.of(context)!.listsNotUpdated,
@ -158,21 +100,16 @@ class _FiltersWidgetState extends State<FiltersWidget> {
void enableDisableFiltering() async { void enableDisableFiltering() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open( processModal.open(
serversProvider.serverStatus.data!.filteringEnabled == true statusProvider.serverStatus!.filteringEnabled == true
? AppLocalizations.of(context)!.disableFiltering ? AppLocalizations.of(context)!.disableFiltering
: AppLocalizations.of(context)!.enableFiltering : AppLocalizations.of(context)!.enableFiltering
); );
final result = await updateFiltering( final result = await filteringProvider.enableDisableFiltering();
server: serversProvider.selectedServer!,
enable: !serversProvider.serverStatus.data!.filteringEnabled
);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
serversProvider.setFilteringProtectionStatus(!serversProvider.serverStatus.data!.filteringEnabled);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.filteringStatusUpdated, label: AppLocalizations.of(context)!.filteringStatusUpdated,
@ -192,16 +129,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.changingUpdateFrequency); processModal.open(AppLocalizations.of(context)!.changingUpdateFrequency);
final result = await requestChangeUpdateFrequency(server: serversProvider.selectedServer!, data: { final result = await filteringProvider.changeUpdateFrequency(value);
"enabled": serversProvider.filtering.data!.enabled,
"interval": value
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
serversProvider.setFiltersUpdateFrequency(value);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.updateFrequencyChanged, label: AppLocalizations.of(context)!.updateFrequencyChanged,
@ -244,17 +176,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deletingRule); processModal.open(AppLocalizations.of(context)!.deletingRule);
final List<String> newRules = serversProvider.filtering.data!.userRules.where((r) => r != rule).toList(); final result = await filteringProvider.removeCustomRule(rule);
final result = await setCustomRules(server: serversProvider.selectedServer!, rules: newRules);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
FilteringData filteringData = serversProvider.filtering.data!;
filteringData.userRules = newRules;
serversProvider.setFilteringData(filteringData);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleRemovedSuccessfully, label: AppLocalizations.of(context)!.ruleRemovedSuccessfully,
@ -262,13 +188,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotRemoved, label: AppLocalizations.of(context)!.ruleNotRemoved,
color: Colors.red color: Colors.red
); );
} }
} }
@ -307,11 +231,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
} }
List<Widget> actions() { List<Widget> actions() {
if (serversProvider.filtering.loadStatus == LoadStatus.loaded) { if (filteringProvider.loadStatus == LoadStatus.loaded) {
return [ return [
IconButton( if (statusProvider.loadStatus == LoadStatus.loaded) IconButton(
onPressed: enableDisableFiltering, onPressed: enableDisableFiltering,
tooltip: serversProvider.filtering.data!.enabled == true tooltip: filteringProvider.filtering!.enabled == true
? AppLocalizations.of(context)!.disableFiltering ? AppLocalizations.of(context)!.disableFiltering
: AppLocalizations.of(context)!.enableFiltering, : AppLocalizations.of(context)!.enableFiltering,
icon: Stack( icon: Stack(
@ -328,11 +252,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
color: Colors.white color: Colors.white
), ),
child: Icon( child: Icon(
serversProvider.filtering.data!.enabled == true filteringProvider.filtering!.enabled == true
? Icons.check_circle_rounded ? Icons.check_circle_rounded
: Icons.cancel, : Icons.cancel,
size: 12, size: 12,
color: serversProvider.filtering.data!.enabled == true color: filteringProvider.filtering!.enabled == true
? appConfigProvider.useThemeColorForStatus == true ? appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Colors.green : Colors.green
@ -353,7 +277,7 @@ class _FiltersWidgetState extends State<FiltersWidget> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => UpdateIntervalListsModal( builder: (context) => UpdateIntervalListsModal(
interval: serversProvider.filtering.data!.interval, interval: filteringProvider.filtering!.interval,
onChange: setUpdateFrequency, onChange: setUpdateFrequency,
dialog: true, dialog: true,
), ),
@ -363,7 +287,7 @@ class _FiltersWidgetState extends State<FiltersWidget> {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: (context) => UpdateIntervalListsModal( builder: (context) => UpdateIntervalListsModal(
interval: serversProvider.filtering.data!.interval, interval: filteringProvider.filtering!.interval,
onChange: setUpdateFrequency, onChange: setUpdateFrequency,
dialog: false, dialog: false,
), ),
@ -378,7 +302,7 @@ class _FiltersWidgetState extends State<FiltersWidget> {
PopupMenuButton( PopupMenuButton(
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem( PopupMenuItem(
onTap: fetchUpdateLists, onTap: updateLists,
child: Row( child: Row(
children: [ children: [
const Icon(Icons.sync_rounded), const Icon(Icons.sync_rounded),
@ -422,13 +346,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
onRemoveCustomRule: openRemoveCustomRuleModal, onRemoveCustomRule: openRemoveCustomRuleModal,
onOpenDetailsModal: openListDetails, onOpenDetailsModal: openListDetails,
actions: actions(), actions: actions(),
refreshData: fetchFilters,
); );
} }
else { else {
return FiltersTabsView( return FiltersTabsView(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
fetchFilters: fetchFilters,
actions: actions(), actions: actions(),
onRemoveCustomRule: openRemoveCustomRuleModal, onRemoveCustomRule: openRemoveCustomRuleModal,
onOpenDetailsModal: openListDetails, onOpenDetailsModal: openListDetails,

View file

@ -14,6 +14,8 @@ import 'package:adguard_home_manager/widgets/tab_content_list.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/models/filtering.dart'; import 'package:adguard_home_manager/models/filtering.dart';
@ -21,7 +23,6 @@ class FiltersList extends StatefulWidget {
final LoadStatus loadStatus; final LoadStatus loadStatus;
final ScrollController scrollController; final ScrollController scrollController;
final List<Filter> data; final List<Filter> data;
final Future<void> Function() fetchData;
final String type; final String type;
final void Function(Filter, String) onOpenDetailsScreen; final void Function(Filter, String) onOpenDetailsScreen;
@ -30,7 +31,6 @@ class FiltersList extends StatefulWidget {
required this.loadStatus, required this.loadStatus,
required this.scrollController, required this.scrollController,
required this.data, required this.data,
required this.fetchData,
required this.type, required this.type,
required this.onOpenDetailsScreen required this.onOpenDetailsScreen
}) : super(key: key); }) : super(key: key);
@ -65,6 +65,7 @@ class _FiltersListState extends State<FiltersList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
return CustomTabContentList( return CustomTabContentList(
@ -129,7 +130,16 @@ class _FiltersListState extends State<FiltersList> {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
TextButton.icon( TextButton.icon(
onPressed: widget.fetchData, onPressed: () async {
final result = await filteringProvider.fetchFilters();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red
);
}
},
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh), label: Text(AppLocalizations.of(context)!.refresh),
) )
@ -160,7 +170,16 @@ class _FiltersListState extends State<FiltersList> {
), ),
), ),
loadStatus: widget.loadStatus, loadStatus: widget.loadStatus,
onRefresh: widget.fetchData, onRefresh: () async {
final result = await filteringProvider.fetchFilters();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red
);
}
},
fab: AddFiltersButton( fab: AddFiltersButton(
type: widget.type, type: widget.type,
widget: (fn) => FloatingActionButton( widget: (fn) => FloatingActionButton(

View file

@ -5,14 +5,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/custom_rules_list.dart'; import 'package:adguard_home_manager/screens/filters/custom_rules_list.dart';
import 'package:adguard_home_manager/screens/filters/filters_list.dart'; import 'package:adguard_home_manager/screens/filters/filters_list.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/filtering.dart'; import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class FiltersTabsView extends StatefulWidget { class FiltersTabsView extends StatefulWidget {
final AppConfigProvider appConfigProvider; final AppConfigProvider appConfigProvider;
final Future Function() fetchFilters;
final List<Widget> actions; final List<Widget> actions;
final void Function(String) onRemoveCustomRule; final void Function(String) onRemoveCustomRule;
final void Function(Filter, String) onOpenDetailsModal; final void Function(Filter, String) onOpenDetailsModal;
@ -20,7 +19,6 @@ class FiltersTabsView extends StatefulWidget {
const FiltersTabsView({ const FiltersTabsView({
Key? key, Key? key,
required this.appConfigProvider, required this.appConfigProvider,
required this.fetchFilters,
required this.actions, required this.actions,
required this.onOpenDetailsModal, required this.onOpenDetailsModal,
required this.onRemoveCustomRule required this.onRemoveCustomRule
@ -36,7 +34,6 @@ class _FiltersTabsViewState extends State<FiltersTabsView> with TickerProviderSt
@override @override
void initState() { void initState() {
widget.fetchFilters();
super.initState(); super.initState();
tabController = TabController( tabController = TabController(
initialIndex: 0, initialIndex: 0,
@ -48,7 +45,7 @@ class _FiltersTabsViewState extends State<FiltersTabsView> with TickerProviderSt
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
return DefaultTabController( return DefaultTabController(
length: 3, length: 3,
@ -110,29 +107,26 @@ class _FiltersTabsViewState extends State<FiltersTabsView> with TickerProviderSt
controller: tabController, controller: tabController,
children: [ children: [
FiltersList( FiltersList(
loadStatus: serversProvider.filtering.loadStatus, loadStatus: filteringProvider.loadStatus,
scrollController: scrollController, scrollController: scrollController,
type: 'whitelist', type: 'whitelist',
data: serversProvider.filtering.loadStatus == LoadStatus.loaded data: filteringProvider.loadStatus == LoadStatus.loaded
? serversProvider.filtering.data!.whitelistFilters : [], ? filteringProvider.filtering!.whitelistFilters : [],
fetchData: widget.fetchFilters,
onOpenDetailsScreen: widget.onOpenDetailsModal, onOpenDetailsScreen: widget.onOpenDetailsModal,
), ),
FiltersList( FiltersList(
loadStatus: serversProvider.filtering.loadStatus, loadStatus: filteringProvider.loadStatus,
scrollController: scrollController, scrollController: scrollController,
type: 'blacklist', type: 'blacklist',
data: serversProvider.filtering.loadStatus == LoadStatus.loaded data: filteringProvider.loadStatus == LoadStatus.loaded
? serversProvider.filtering.data!.filters : [], ? filteringProvider.filtering!.filters : [],
fetchData: widget.fetchFilters,
onOpenDetailsScreen: widget.onOpenDetailsModal, onOpenDetailsScreen: widget.onOpenDetailsModal,
), ),
CustomRulesList( CustomRulesList(
loadStatus: serversProvider.filtering.loadStatus, loadStatus: filteringProvider.loadStatus,
scrollController: scrollController, scrollController: scrollController,
data: serversProvider.filtering.loadStatus == LoadStatus.loaded data: filteringProvider.loadStatus == LoadStatus.loaded
? serversProvider.filtering.data!.userRules : [], ? filteringProvider.filtering!.userRules : [],
fetchData: widget.fetchFilters,
onRemoveCustomRule: widget.onRemoveCustomRule, onRemoveCustomRule: widget.onRemoveCustomRule,
), ),
] ]

View file

@ -14,41 +14,30 @@ import 'package:adguard_home_manager/widgets/options_modal.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/models/menu_option.dart'; import 'package:adguard_home_manager/models/menu_option.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/copy_clipboard.dart'; import 'package:adguard_home_manager/functions/copy_clipboard.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/models/filtering.dart'; import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class FiltersTripleColumn extends StatelessWidget { class FiltersTripleColumn extends StatelessWidget {
final void Function(String) onRemoveCustomRule; final void Function(String) onRemoveCustomRule;
final void Function(Filter, String) onOpenDetailsModal; final void Function(Filter, String) onOpenDetailsModal;
final List<Widget> actions; final List<Widget> actions;
final Future Function() refreshData;
const FiltersTripleColumn({ const FiltersTripleColumn({
Key? key, Key? key,
required this.onRemoveCustomRule, required this.onRemoveCustomRule,
required this.onOpenDetailsModal, required this.onOpenDetailsModal,
required this.actions, required this.actions,
required this.refreshData
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
bool checkIfComment(String value) {
final regex = RegExp(r'^(!|#).*$');
if (regex.hasMatch(value)) {
return true;
}
else {
return false;
}
}
Widget? generateSubtitle(String rule) { Widget? generateSubtitle(String rule) {
final allowRegex = RegExp(r'^@@.*$'); final allowRegex = RegExp(r'^@@.*$');
final blockRegex = RegExp(r'^\|\|.*$'); final blockRegex = RegExp(r'^\|\|.*$');
@ -84,7 +73,7 @@ class FiltersTripleColumn extends StatelessWidget {
} }
Widget content() { Widget content() {
switch (serversProvider.filtering.loadStatus) { switch (filteringProvider.loadStatus) {
case LoadStatus.loading: case LoadStatus.loading:
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -140,18 +129,18 @@ class FiltersTripleColumn extends StatelessWidget {
), ),
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: serversProvider.filtering.data!.whitelistFilters.length, itemCount: filteringProvider.filtering!.whitelistFilters.length,
itemBuilder: (context, index) => ListOptionsMenu( itemBuilder: (context, index) => ListOptionsMenu(
list: serversProvider.filtering.data!.whitelistFilters[index], list: filteringProvider.filtering!.whitelistFilters[index],
listType: 'whitelist', listType: 'whitelist',
child: CustomListTile( child: CustomListTile(
title: serversProvider.filtering.data!.whitelistFilters[index].name, title: filteringProvider.filtering!.whitelistFilters[index].name,
subtitle: "${intFormat(serversProvider.filtering.data!.whitelistFilters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}", subtitle: "${intFormat(filteringProvider.filtering!.whitelistFilters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
trailing: Icon( trailing: Icon(
serversProvider.filtering.data!.whitelistFilters[index].enabled == true filteringProvider.filtering!.whitelistFilters[index].enabled == true
? Icons.check_circle_rounded ? Icons.check_circle_rounded
: Icons.cancel, : Icons.cancel,
color: serversProvider.filtering.data!.whitelistFilters[index].enabled == true color: filteringProvider.filtering!.whitelistFilters[index].enabled == true
? appConfigProvider.useThemeColorForStatus == true ? appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Colors.green : Colors.green
@ -159,7 +148,7 @@ class FiltersTripleColumn extends StatelessWidget {
? Colors.grey ? Colors.grey
: Colors.red : Colors.red
), ),
onTap: () => onOpenDetailsModal(serversProvider.filtering.data!.whitelistFilters[index], 'whitelist'), onTap: () => onOpenDetailsModal(filteringProvider.filtering!.whitelistFilters[index], 'whitelist'),
), ),
), ),
), ),
@ -196,18 +185,18 @@ class FiltersTripleColumn extends StatelessWidget {
), ),
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: serversProvider.filtering.data!.filters.length, itemCount: filteringProvider.filtering!.filters.length,
itemBuilder: (context, index) => ListOptionsMenu( itemBuilder: (context, index) => ListOptionsMenu(
list: serversProvider.filtering.data!.filters[index], list: filteringProvider.filtering!.filters[index],
listType: 'blacklist', listType: 'blacklist',
child: CustomListTile( child: CustomListTile(
title: serversProvider.filtering.data!.filters[index].name, title: filteringProvider.filtering!.filters[index].name,
subtitle: "${intFormat(serversProvider.filtering.data!.filters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}", subtitle: "${intFormat(filteringProvider.filtering!.filters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
trailing: Icon( trailing: Icon(
serversProvider.filtering.data!.filters[index].enabled == true filteringProvider.filtering!.filters[index].enabled == true
? Icons.check_circle_rounded ? Icons.check_circle_rounded
: Icons.cancel, : Icons.cancel,
color: serversProvider.filtering.data!.filters[index].enabled == true color: filteringProvider.filtering!.filters[index].enabled == true
? appConfigProvider.useThemeColorForStatus == true ? appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Colors.green : Colors.green
@ -215,7 +204,7 @@ class FiltersTripleColumn extends StatelessWidget {
? Colors.grey ? Colors.grey
: Colors.red : Colors.red
), ),
onTap: () => onOpenDetailsModal(serversProvider.filtering.data!.filters[index], 'blacklist'), onTap: () => onOpenDetailsModal(filteringProvider.filtering!.filters[index], 'blacklist'),
), ),
), ),
), ),
@ -252,7 +241,7 @@ class FiltersTripleColumn extends StatelessWidget {
), ),
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: serversProvider.filtering.data!.userRules.length, itemCount: filteringProvider.filtering!.userRules.length,
itemBuilder: (context, index) => ContextMenuArea( itemBuilder: (context, index) => ContextMenuArea(
builder: (context) => [ builder: (context) => [
CustomListTile( CustomListTile(
@ -261,7 +250,7 @@ class FiltersTripleColumn extends StatelessWidget {
onTap: () { onTap: () {
copyToClipboard( copyToClipboard(
context: context, context: context,
value: serversProvider.filtering.data!.userRules[index], value: filteringProvider.filtering!.userRules[index],
successMessage: AppLocalizations.of(context)!.copiedClipboard, successMessage: AppLocalizations.of(context)!.copiedClipboard,
); );
Navigator.pop(context); Navigator.pop(context);
@ -278,17 +267,17 @@ class FiltersTripleColumn extends StatelessWidget {
icon: Icons.copy_rounded, icon: Icons.copy_rounded,
action: () => copyToClipboard( action: () => copyToClipboard(
context: context, context: context,
value: serversProvider.filtering.data!.userRules[index], value: filteringProvider.filtering!.userRules[index],
successMessage: AppLocalizations.of(context)!.copiedClipboard, successMessage: AppLocalizations.of(context)!.copiedClipboard,
) )
) )
] ]
) )
), ),
title: serversProvider.filtering.data!.userRules[index], title: filteringProvider.filtering!.userRules[index],
subtitleWidget: generateSubtitle(serversProvider.filtering.data!.userRules[index]), subtitleWidget: generateSubtitle(filteringProvider.filtering!.userRules[index]),
trailing: IconButton( trailing: IconButton(
onPressed: () => onRemoveCustomRule(serversProvider.filtering.data!.userRules[index]), onPressed: () => onRemoveCustomRule(filteringProvider.filtering!.userRules[index]),
icon: const Icon(Icons.delete) icon: const Icon(Icons.delete)
), ),
), ),
@ -340,7 +329,16 @@ class FiltersTripleColumn extends StatelessWidget {
title: Text(AppLocalizations.of(context)!.filters), title: Text(AppLocalizations.of(context)!.filters),
actions: [ actions: [
IconButton( IconButton(
onPressed: refreshData, onPressed: () async {
final result = await filteringProvider.fetchFilters();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.errorLoadFilters,
color: Colors.red
);
}
},
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh, tooltip: AppLocalizations.of(context)!.refresh,
), ),

View file

@ -9,13 +9,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/add_list_modal.dart'; import 'package:adguard_home_manager/screens/filters/add_list_modal.dart';
import 'package:adguard_home_manager/screens/filters/delete_list_modal.dart'; import 'package:adguard_home_manager/screens/filters/delete_list_modal.dart';
import 'package:adguard_home_manager/screens/filters/list_functions.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/functions/format_time.dart'; import 'package:adguard_home_manager/functions/format_time.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/filtering.dart'; import 'package:adguard_home_manager/models/filtering.dart';
class ListDetailsScreen extends StatefulWidget { class ListDetailsScreen extends StatefulWidget {
@ -60,22 +60,51 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
Filter? list; Filter? list;
try { try {
list = serversProvider.filtering.data != null list = filteringProvider.filtering != null
? widget.type == 'whitelist' ? widget.type == 'whitelist'
? serversProvider.filtering.data!.whitelistFilters.firstWhere((l) => l.id == widget.listId) ? filteringProvider.filtering!.whitelistFilters.firstWhere((l) => l.id == widget.listId)
: serversProvider.filtering.data!.filters.firstWhere((l) => l.id == widget.listId) : filteringProvider.filtering!.filters.firstWhere((l) => l.id == widget.listId)
: null; : null;
} catch (e) { } catch (e) {
// ------- // // ------- //
} }
void updateList(FilteringListActions action) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(
list!.enabled == true
? AppLocalizations.of(context)!.disablingList
: AppLocalizations.of(context)!.enablingList,
);
final result = await filteringProvider.updateList(
list: list,
type: widget.type,
action: action
);
processModal.close();
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red
);
}
}
List<Widget> content() { List<Widget> content() {
return [ return [
CustomListTile( CustomListTile(
@ -174,29 +203,9 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
builder: (ctx) => AddListModal( builder: (ctx) => AddListModal(
list: list, list: list,
type: widget.type, type: widget.type,
onEdit: ({required Filter list, required String type}) async { onEdit: ({required Filter list, required String type}) async => updateList(
final result = await editList( FilteringListActions.edit
context: context, ),
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
list: list,
type: widget.type
);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red
);
}
},
dialog: true, dialog: true,
), ),
) )
@ -207,29 +216,9 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
builder: (ctx) => AddListModal( builder: (ctx) => AddListModal(
list: list, list: list,
type: widget.type, type: widget.type,
onEdit: ({required Filter list, required String type}) async { onEdit: ({required Filter list, required String type}) async => updateList(
final result = await editList( FilteringListActions.edit
context: context, ),
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
list: list,
type: widget.type
);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red
);
}
},
dialog: false, dialog: false,
), ),
isScrollControlled: true, isScrollControlled: true,
@ -246,13 +235,13 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
context: context, context: context,
builder: (c) => DeleteListModal( builder: (c) => DeleteListModal(
onConfirm: () async { onConfirm: () async {
final result = await deleteList( ProcessModal processModal = ProcessModal(context: context);
context: context, processModal.open(AppLocalizations.of(context)!.deletingList);
serversProvider: serversProvider, final result = await filteringProvider.deleteList(
appConfigProvider: appConfigProvider, listUrl: list!.url,
list: list!,
type: widget.type, type: widget.type,
); );
processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
@ -312,29 +301,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
if (list != null) Row( if (list != null) Row(
children: [ children: [
IconButton( IconButton(
onPressed: () async { onPressed: () => updateList(
final result = await enableDisableList( list!.enabled == true
context: context, ? FilteringListActions.disable
serversProvider: serversProvider, : FilteringListActions.enable
appConfigProvider: appConfigProvider, ),
list: list!,
listType: widget.type,
);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red
);
}
},
icon: Icon( icon: Icon(
list.enabled == true list.enabled == true
? Icons.gpp_bad_rounded ? Icons.gpp_bad_rounded
@ -399,29 +370,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
: -70, : -70,
right: 20, right: 20,
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () async { onPressed: () => updateList(
final result = await enableDisableList( list!.enabled == true
context: context, ? FilteringListActions.disable
serversProvider: serversProvider, : FilteringListActions.enable
appConfigProvider: appConfigProvider, ),
list: list!,
listType: widget.type,
);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataUpdated,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listDataNotUpdated,
color: Colors.red
);
}
},
child: Icon( child: Icon(
list.enabled == true list.enabled == true
? Icons.gpp_bad_rounded ? Icons.gpp_bad_rounded

View file

@ -1,141 +0,0 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
Future<bool> enableDisableList({
required BuildContext context,
required ServersProvider serversProvider,
required AppConfigProvider appConfigProvider,
required Filter list,
required String listType,
}) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(
list.enabled == true
? AppLocalizations.of(context)!.disablingList
: AppLocalizations.of(context)!.enablingList,
);
final result = await updateFilterList(server: serversProvider.selectedServer!, data: {
"data": {
"enabled": !list.enabled,
"name": list.name,
"url": list.url
},
"url": list.url,
"whitelist": listType == 'whitelist' ? true : false
});
processModal.close();
if (result['result'] == 'success') {
final result2 = await getFiltering(server: serversProvider.selectedServer!);
if (result2['result'] == 'success') {
serversProvider.setFilteringData(result2['data']);
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
}
else {
appConfigProvider.addLog(result2['log']);
serversProvider.setFilteringLoadStatus(LoadStatus.error, true);
}
return true;
}
else {
appConfigProvider.addLog(result['log']);
return false;
}
}
Future<bool> editList({
required BuildContext context,
required ServersProvider serversProvider,
required AppConfigProvider appConfigProvider,
required Filter list,
required String type
}) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingListData);
final result1 = await updateFilterList(server: serversProvider.selectedServer!, data: {
"data": {
"enabled": list.enabled,
"name": list.name,
"url": list.url
},
"url": list.url,
"whitelist": type == 'whitelist' ? true : false
});
if (result1['result'] == 'success') {
final result2 = await getFiltering(server: serversProvider.selectedServer!);
if (result2['result'] == 'success') {
serversProvider.setFilteringData(result2['data']);
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
}
else {
appConfigProvider.addLog(result2['log']);
serversProvider.setFilteringLoadStatus(LoadStatus.error, true);
}
processModal.close();
return true;
}
else {
processModal.close();
appConfigProvider.addLog(result1['log']);
return false;
}
}
Future<bool> deleteList({
required BuildContext context,
required ServersProvider serversProvider,
required AppConfigProvider appConfigProvider,
required Filter list,
required String type
}) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deletingList);
final result1 = await deleteFilterList(server: serversProvider.selectedServer!, data: {
"url": list.url,
"whitelist": type == 'whitelist' ? true : false
});
if (result1['result'] == 'success') {
final result2 = await getFiltering(server: serversProvider.selectedServer!);
if (result2['result'] == 'success') {
serversProvider.setFilteringData(result2['data']);
serversProvider.setFilteringLoadStatus(LoadStatus.loaded, true);
}
else {
appConfigProvider.addLog(result2['log']);
serversProvider.setFilteringLoadStatus(LoadStatus.loading, true);
}
processModal.close();
return true;
}
else {
processModal.close();
appConfigProvider.addLog(result1['log']);
return false;
}
}

View file

@ -1,20 +1,20 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:contextmenu/contextmenu.dart'; import 'package:contextmenu/contextmenu.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/list_functions.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/widgets/options_modal.dart'; import 'package:adguard_home_manager/widgets/options_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/filtering.dart'; import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/filtering_provider.dart';
import 'package:adguard_home_manager/functions/copy_clipboard.dart'; import 'package:adguard_home_manager/functions/copy_clipboard.dart';
import 'package:adguard_home_manager/models/menu_option.dart'; import 'package:adguard_home_manager/models/menu_option.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class ListOptionsMenu extends StatelessWidget { class ListOptionsMenu extends StatelessWidget {
final Filter list; final Filter list;
@ -30,17 +30,27 @@ class ListOptionsMenu extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void enableDisable() async { void enableDisable() async {
final result = await enableDisableList( ProcessModal processModal = ProcessModal(context: context);
context: context, processModal.open(
serversProvider: serversProvider, list.enabled == true
appConfigProvider: appConfigProvider, ? AppLocalizations.of(context)!.disablingList
list: list, : AppLocalizations.of(context)!.enablingList
listType: listType,
); );
final result = await filteringProvider.updateList(
list: list,
type: listType,
action: list.enabled == true
? FilteringListActions.disable
: FilteringListActions.enable
);
processModal.close();
if (result == true) { if (result == true) {
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,

View file

@ -4,6 +4,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/servers/servers.dart'; import 'package:adguard_home_manager/screens/servers/servers.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/models/server.dart'; import 'package:adguard_home_manager/models/server.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -20,6 +22,7 @@ class HomeAppBar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final Server? server = serversProvider.selectedServer; final Server? server = serversProvider.selectedServer;
@ -37,22 +40,48 @@ class HomeAppBar extends StatelessWidget {
floating: true, floating: true,
centerTitle: false, centerTitle: false,
forceElevated: innerBoxScrolled, forceElevated: innerBoxScrolled,
leading: Icon( leading: Stack(
serversProvider.selectedServer != null && serversProvider.serverStatus.data != null children: [
? serversProvider.serverStatus.data!.generalEnabled == true Center(
? Icons.gpp_good_rounded child: Icon(
: Icons.gpp_bad_rounded serversProvider.selectedServer != null && statusProvider.serverStatus != null
: Icons.shield, ? statusProvider.serverStatus!.generalEnabled == true
size: 30, ? Icons.gpp_good_rounded
color: serversProvider.selectedServer != null && serversProvider.serverStatus.data != null : Icons.gpp_bad_rounded
? serversProvider.serverStatus.data!.generalEnabled == true : Icons.shield,
? appConfigProvider.useThemeColorForStatus size: 30,
? Theme.of(context).colorScheme.primary color: serversProvider.selectedServer != null && statusProvider.serverStatus != null
: Colors.green ? statusProvider.serverStatus!.generalEnabled == true
: appConfigProvider.useThemeColorForStatus == true ? appConfigProvider.useThemeColorForStatus
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38) ? Theme.of(context).colorScheme.primary
: Colors.red : Colors.green
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38) : appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
: Colors.red
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
),
),
if (statusProvider.remainingTime > 0) Positioned(
bottom: 15,
right: 15,
child: Stack(
children: [
Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Theme.of(context).colorScheme.surface
),
child: Icon(
Icons.timer_rounded,
size: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
)
],
), ),
title: Column( title: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -95,7 +124,7 @@ class HomeAppBar extends StatelessWidget {
], ],
), ),
), ),
if (serversProvider.selectedServer != null && serversProvider.serverStatus.loadStatus == 1) PopupMenuItem( if (serversProvider.selectedServer != null && statusProvider.loadStatus == LoadStatus.loaded) PopupMenuItem(
onTap: () => openUrl("${server!.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}"), onTap: () => openUrl("${server!.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}"),
child: Row( child: Row(
children: [ children: [

View file

@ -7,7 +7,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/combined_line_chart.dart'; import 'package:adguard_home_manager/widgets/combined_line_chart.dart';
import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
class CombinedChartData { class CombinedChartData {
@ -51,56 +51,56 @@ class CombinedHomeChart extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
if (serversProvider.serverStatus.data != null) { if (statusProvider.serverStatus != null) {
final data = CombinedChartData( final data = CombinedChartData(
totalQueries: CombinedChartItem( totalQueries: CombinedChartItem(
label: AppLocalizations.of(context)!.dnsQueries, label: AppLocalizations.of(context)!.dnsQueries,
color: Colors.blue, color: Colors.blue,
data: serversProvider.serverStatus.data!.stats.dnsQueries data: statusProvider.serverStatus!.stats.dnsQueries
), ),
blockedFilters: appConfigProvider.hideZeroValues == true blockedFilters: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.blockedFiltering) != null ? removeZero(statusProvider.serverStatus!.stats.blockedFiltering) != null
? CombinedChartItem( ? CombinedChartItem(
label: AppLocalizations.of(context)!.blockedFilters, label: AppLocalizations.of(context)!.blockedFilters,
color: Colors.red, color: Colors.red,
data: serversProvider.serverStatus.data!.stats.blockedFiltering data: statusProvider.serverStatus!.stats.blockedFiltering
) )
: null : null
: CombinedChartItem( : CombinedChartItem(
label: AppLocalizations.of(context)!.blockedFilters, label: AppLocalizations.of(context)!.blockedFilters,
color: Colors.red, color: Colors.red,
data: serversProvider.serverStatus.data!.stats.blockedFiltering data: statusProvider.serverStatus!.stats.blockedFiltering
) , ) ,
replacedSafeBrowsing: appConfigProvider.hideZeroValues == true replacedSafeBrowsing: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.replacedSafebrowsing) != null ? removeZero(statusProvider.serverStatus!.stats.replacedSafebrowsing) != null
? CombinedChartItem( ? CombinedChartItem(
label: AppLocalizations.of(context)!.malwarePhisingBlocked, label: AppLocalizations.of(context)!.malwarePhisingBlocked,
color: Colors.green, color: Colors.green,
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing data: statusProvider.serverStatus!.stats.replacedSafebrowsing
) )
: null : null
: CombinedChartItem( : CombinedChartItem(
label: AppLocalizations.of(context)!.malwarePhisingBlocked, label: AppLocalizations.of(context)!.malwarePhisingBlocked,
color: Colors.green, color: Colors.green,
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing data: statusProvider.serverStatus!.stats.replacedSafebrowsing
) , ) ,
replacedParental: appConfigProvider.hideZeroValues == true replacedParental: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.replacedParental) != null ? removeZero(statusProvider.serverStatus!.stats.replacedParental) != null
? CombinedChartItem( ? CombinedChartItem(
label: AppLocalizations.of(context)!.blockedAdultWebsites, label: AppLocalizations.of(context)!.blockedAdultWebsites,
color: Colors.orange, color: Colors.orange,
data: serversProvider.serverStatus.data!.stats.replacedParental data: statusProvider.serverStatus!.stats.replacedParental
) )
: null : null
: CombinedChartItem( : CombinedChartItem(
label: AppLocalizations.of(context)!.blockedAdultWebsites, label: AppLocalizations.of(context)!.blockedAdultWebsites,
color: Colors.orange, color: Colors.orange,
data: serversProvider.serverStatus.data!.stats.replacedParental data: statusProvider.serverStatus!.stats.replacedParental
) , ) ,
); );
@ -184,29 +184,29 @@ class CombinedHomeChart extends StatelessWidget {
legend( legend(
label: data.totalQueries.label, label: data.totalQueries.label,
color: data.totalQueries.color, color: data.totalQueries.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms", secondaryValue: "${doubleFormat(statusProvider.serverStatus!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (data.blockedFilters != null) legend( if (data.blockedFilters != null) legend(
label: data.blockedFilters!.label, label: data.blockedFilters!.label,
color: data.blockedFilters!.color, color: data.blockedFilters!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numBlockedFiltering, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numBlockedFiltering/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numBlockedFiltering/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (data.replacedSafeBrowsing != null) legend( if (data.replacedSafeBrowsing != null) legend(
label: data.replacedSafeBrowsing!.label, label: data.replacedSafeBrowsing!.label,
color: data.replacedSafeBrowsing!.color, color: data.replacedSafeBrowsing!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedSafebrowsing/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (data.replacedParental != null) legend( if (data.replacedParental != null) legend(
label: data.replacedParental!.label, label: data.replacedParental!.label,
color: data.replacedParental!.color, color: data.replacedParental!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedParental, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedParental/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedParental/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
), ),
], ],
), ),
@ -247,29 +247,29 @@ class CombinedHomeChart extends StatelessWidget {
legend( legend(
label: data.totalQueries.label, label: data.totalQueries.label,
color: data.totalQueries.color, color: data.totalQueries.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms", secondaryValue: "${doubleFormat(statusProvider.serverStatus!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (data.blockedFilters != null) legend( if (data.blockedFilters != null) legend(
label: data.blockedFilters!.label, label: data.blockedFilters!.label,
color: data.blockedFilters!.color, color: data.blockedFilters!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numBlockedFiltering, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numBlockedFiltering/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numBlockedFiltering/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (data.replacedSafeBrowsing != null) legend( if (data.replacedSafeBrowsing != null) legend(
label: data.replacedSafeBrowsing!.label, label: data.replacedSafeBrowsing!.label,
color: data.replacedSafeBrowsing!.color, color: data.replacedSafeBrowsing!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedSafebrowsing/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
if (data.replacedParental != null) legend( if (data.replacedParental != null) legend(
label: data.replacedParental!.label, label: data.replacedParental!.label,
color: data.replacedParental!.color, color: data.replacedParental!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedParental, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedParental/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedParental/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
], ],

View file

@ -3,14 +3,15 @@ import 'package:flutter/material.dart';
import 'package:adguard_home_manager/screens/home/management_modal.dart'; import 'package:adguard_home_manager/screens/home/management_modal.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart';
class HomeFab extends StatelessWidget { class HomeFab extends StatelessWidget {
const HomeFab({Key? key}) : super(key: key); const HomeFab({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -35,7 +36,7 @@ class HomeFab extends StatelessWidget {
} }
} }
return serversProvider.serverStatus.loadStatus == 1 return statusProvider.loadStatus == LoadStatus.loaded
? FloatingActionButton( ? FloatingActionButton(
onPressed: openManagementBottomSheet, onPressed: openManagementBottomSheet,
child: const Icon(Icons.shield_rounded), child: const Icon(Icons.shield_rounded),

View file

@ -15,10 +15,10 @@ import 'package:adguard_home_manager/screens/home/top_items.dart';
import 'package:adguard_home_manager/screens/home/chart.dart'; import 'package:adguard_home_manager/screens/home/chart.dart';
import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class Home extends StatefulWidget { class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key); const Home({Key? key}) : super(key: key);
@ -33,6 +33,8 @@ class _HomeState extends State<Home> {
@override @override
initState(){ initState(){
Provider.of<StatusProvider>(context, listen: false).getServerStatus();
super.initState(); super.initState();
isVisible = true; isVisible = true;
@ -54,7 +56,7 @@ class _HomeState extends State<Home> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -109,7 +111,7 @@ class _HomeState extends State<Home> {
List<Widget> listItems() { List<Widget> listItems() {
return [ return [
ServerStatus(serverStatus: serversProvider.serverStatus.data!), ServerStatusWidget(serverStatus: statusProvider.serverStatus!),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider( child: Divider(
@ -124,40 +126,40 @@ class _HomeState extends State<Home> {
FractionallySizedBox( FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1, widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart( child: HomeChart(
data: serversProvider.serverStatus.data!.stats.dnsQueries, data: statusProvider.serverStatus!.stats.dnsQueries,
label: AppLocalizations.of(context)!.dnsQueries, label: AppLocalizations.of(context)!.dnsQueries,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms", secondaryValue: "${doubleFormat(statusProvider.serverStatus!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
color: Colors.blue, color: Colors.blue,
), ),
), ),
FractionallySizedBox( FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1, widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart( child: HomeChart(
data: serversProvider.serverStatus.data!.stats.blockedFiltering, data: statusProvider.serverStatus!.stats.blockedFiltering,
label: AppLocalizations.of(context)!.blockedFilters, label: AppLocalizations.of(context)!.blockedFilters,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numBlockedFiltering, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numBlockedFiltering/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numBlockedFiltering/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.red, color: Colors.red,
), ),
), ),
FractionallySizedBox( FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1, widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart( child: HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing, data: statusProvider.serverStatus!.stats.replacedSafebrowsing,
label: AppLocalizations.of(context)!.malwarePhisingBlocked, label: AppLocalizations.of(context)!.malwarePhisingBlocked,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedSafebrowsing/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.green, color: Colors.green,
), ),
), ),
FractionallySizedBox( FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1, widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart( child: HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedParental, data: statusProvider.serverStatus!.stats.replacedParental,
label: AppLocalizations.of(context)!.blockedAdultWebsites, label: AppLocalizations.of(context)!.blockedAdultWebsites,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedParental, Platform.localeName), primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedParental/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%", secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedParental/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.orange, color: Colors.orange,
), ),
), ),
@ -172,7 +174,7 @@ class _HomeState extends State<Home> {
if (width <= 700) ...[ if (width <= 700) ...[
TopItems( TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains, label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains, data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains', type: 'topQueriedDomains',
), ),
Padding( Padding(
@ -187,7 +189,7 @@ class _HomeState extends State<Home> {
TopItems( TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains, label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains, data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains', type: 'topBlockedDomains',
), ),
Padding( Padding(
@ -201,7 +203,7 @@ class _HomeState extends State<Home> {
TopItems( TopItems(
label: AppLocalizations.of(context)!.topClients, label: AppLocalizations.of(context)!.topClients,
data: serversProvider.serverStatus.data!.stats.topClients, data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients', type: 'topClients',
clients: true, clients: true,
), ),
@ -219,7 +221,7 @@ class _HomeState extends State<Home> {
), ),
child: TopItems( child: TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains, label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains, data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains', type: 'topQueriedDomains',
), ),
), ),
@ -232,7 +234,7 @@ class _HomeState extends State<Home> {
), ),
child: TopItems( child: TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains, label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains, data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains', type: 'topBlockedDomains',
), ),
), ),
@ -245,7 +247,7 @@ class _HomeState extends State<Home> {
), ),
child: TopItems( child: TopItems(
label: AppLocalizations.of(context)!.topClients, label: AppLocalizations.of(context)!.topClients,
data: serversProvider.serverStatus.data!.stats.topClients, data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients', type: 'topClients',
), ),
), ),
@ -277,12 +279,8 @@ class _HomeState extends State<Home> {
builder: (context) => RefreshIndicator( builder: (context) => RefreshIndicator(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
onRefresh: () async { onRefresh: () async {
final result = await getServerStatus(serversProvider.selectedServer!); final result = await statusProvider.getServerStatus();
if (result['result'] == 'success') { if (result == false) {
serversProvider.setServerStatusData(result['data']);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverStatusNotRefreshed, label: AppLocalizations.of(context)!.serverStatusNotRefreshed,
@ -295,13 +293,13 @@ class _HomeState extends State<Home> {
SliverOverlapInjector( SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
), ),
if (serversProvider.serverStatus.loadStatus == 0) SliverFillRemaining( if (statusProvider.loadStatus == LoadStatus.loading) SliverFillRemaining(
child: loading(), child: loading(),
), ),
if (serversProvider.serverStatus.loadStatus == 1) SliverList.list( if (statusProvider.loadStatus == LoadStatus.loaded) SliverList.list(
children: listItems() children: listItems()
), ),
if (serversProvider.serverStatus.loadStatus == 2) SliverFillRemaining( if (statusProvider.loadStatus == LoadStatus.error) SliverFillRemaining(
child: loadError(), child: loadError(),
), ),
], ],

View file

@ -10,10 +10,9 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/functions/time_server_disabled.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/functions/format_time.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class ManagementModal extends StatefulWidget { class ManagementModal extends StatefulWidget {
final bool dialog; final bool dialog;
@ -32,10 +31,6 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
late Animation<double> animation; late Animation<double> animation;
final ExpandableController expandableController = ExpandableController(); final ExpandableController expandableController = ExpandableController();
DateTime? currentDeadline;
Timer? countdown;
int start = 0;
@override @override
void initState() { void initState() {
expandableController.addListener(() async { expandableController.addListener(() async {
@ -66,70 +61,21 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
@override @override
void dispose() { void dispose() {
if (countdown != null) countdown!.cancel();
animationController.dispose(); animationController.dispose();
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void startTimer(DateTime deadline) {
setState(() {
currentDeadline = deadline;
start = deadline.difference(DateTime.now()).inSeconds+1;
});
const oneSec = Duration(seconds: 1);
countdown = Timer.periodic(
oneSec,
(Timer timer) async {
if (start == 0) {
setState(() {
timer.cancel();
});
final result = await getServerStatus(serversProvider.selectedServer!);
if (result['result'] == 'success') {
serversProvider.setServerStatusData(result['data']);
}
} else {
setState(() {
start = start - 1;
});
}
},
);
}
if (
serversProvider.serverStatus.data != null &&
serversProvider.serverStatus.data!.disabledUntil != null &&
serversProvider.serverStatus.data!.disabledUntil != currentDeadline
) {
startTimer(serversProvider.serverStatus.data!.disabledUntil!);
}
if (
serversProvider.serverStatus.data != null &&
serversProvider.serverStatus.data!.generalEnabled == true
) {
setState(() {
start = 0;
currentDeadline = null;
if (countdown != null) countdown!.cancel();
countdown = null;
});
}
void updateBlocking({ void updateBlocking({
required bool value, required bool value,
required String filter, required String filter,
int? time int? time
}) async { }) async {
final result = await serversProvider.updateBlocking( final result = await statusProvider.updateBlocking(
server: serversProvider.selectedServer!,
block: filter, block: filter,
newStatus: value, newStatus: value,
time: time time: time
@ -164,7 +110,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
child: Icon( child: Icon(
Icons.keyboard_arrow_down_rounded, Icons.keyboard_arrow_down_rounded,
size: 26, size: 26,
color: serversProvider.serverStatus.data!.generalEnabled == true color: statusProvider.serverStatus!.generalEnabled == true
? Theme.of(context).colorScheme.onSurfaceVariant ? Theme.of(context).colorScheme.onSurfaceVariant
: Colors.grey, : Colors.grey,
), ),
@ -180,10 +126,10 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
fontSize: 18, fontSize: 18,
), ),
), ),
if (serversProvider.serverStatus.data!.timeGeneralDisabled > 0) ...[ if (statusProvider.serverStatus!.timeGeneralDisabled > 0) ...[
const SizedBox(height: 2), const SizedBox(height: 2),
if (currentDeadline != null) Text( if (statusProvider.currentDeadline != null) Text(
"${AppLocalizations.of(context)!.remainingTime}: ${generateRemainingTimeString(currentDeadline!.difference(DateTime.now()))}" "${AppLocalizations.of(context)!.remainingTime}: ${formatRemainingSeconds(statusProvider.remainingTime)}"
) )
] ]
], ],
@ -191,8 +137,8 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
], ],
), ),
Switch( Switch(
value: serversProvider.serverStatus.data!.generalEnabled, value: statusProvider.serverStatus!.generalEnabled,
onChanged: serversProvider.protectionsManagementProcess.contains('general') == false onChanged: statusProvider.protectionsManagementProcess.contains('general') == false
? (value) { ? (value) {
if (value == false && expandableController.expanded == true && legacyMode == false) { if (value == false && expandableController.expanded == true && legacyMode == false) {
expandableController.toggle(); expandableController.toggle();
@ -216,35 +162,35 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
children: [ children: [
ActionChip( ActionChip(
label: Text(AppLocalizations.of(context)!.seconds(30)), label: Text(AppLocalizations.of(context)!.seconds(30)),
onPressed: serversProvider.protectionsManagementProcess.contains('general') == false && serversProvider.serverStatus.data!.generalEnabled == true onPressed: statusProvider.protectionsManagementProcess.contains('general') == false && statusProvider.serverStatus!.generalEnabled == true
? () => disableWithCountdown(29000) ? () => disableWithCountdown(29000)
: null, : null,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionChip( ActionChip(
label: Text(AppLocalizations.of(context)!.minute(1)), label: Text(AppLocalizations.of(context)!.minute(1)),
onPressed: serversProvider.protectionsManagementProcess.contains('general') == false && serversProvider.serverStatus.data!.generalEnabled == true onPressed: statusProvider.protectionsManagementProcess.contains('general') == false && statusProvider.serverStatus!.generalEnabled == true
? () => disableWithCountdown(59000) ? () => disableWithCountdown(59000)
: null, : null,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionChip( ActionChip(
label: Text(AppLocalizations.of(context)!.minutes(10)), label: Text(AppLocalizations.of(context)!.minutes(10)),
onPressed: serversProvider.protectionsManagementProcess.contains('general') == false && serversProvider.serverStatus.data!.generalEnabled == true onPressed: statusProvider.protectionsManagementProcess.contains('general') == false && statusProvider.serverStatus!.generalEnabled == true
? () => disableWithCountdown(599000) ? () => disableWithCountdown(599000)
: null, : null,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionChip( ActionChip(
label: Text(AppLocalizations.of(context)!.hour(1)), label: Text(AppLocalizations.of(context)!.hour(1)),
onPressed: serversProvider.protectionsManagementProcess.contains('general') == false && serversProvider.serverStatus.data!.generalEnabled == true onPressed: statusProvider.protectionsManagementProcess.contains('general') == false && statusProvider.serverStatus!.generalEnabled == true
? () => disableWithCountdown(3599000) ? () => disableWithCountdown(3599000)
: null, : null,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionChip( ActionChip(
label: Text(AppLocalizations.of(context)!.hours(24)), label: Text(AppLocalizations.of(context)!.hours(24)),
onPressed: serversProvider.protectionsManagementProcess.contains('general') == false && serversProvider.serverStatus.data!.generalEnabled == true onPressed: statusProvider.protectionsManagementProcess.contains('general') == false && statusProvider.serverStatus!.generalEnabled == true
? () => disableWithCountdown(86399000) ? () => disableWithCountdown(86399000)
: null, : null,
), ),
@ -256,7 +202,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24), padding: const EdgeInsets.symmetric(horizontal: 24),
child: serverVersionIsAhead( child: serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion, currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == true ) == true
@ -266,7 +212,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(28), borderRadius: BorderRadius.circular(28),
child: InkWell( child: InkWell(
onTap: serversProvider.serverStatus.data!.generalEnabled == true && !serversProvider.protectionsManagementProcess.contains('general') onTap: statusProvider.serverStatus!.generalEnabled == true && !statusProvider.protectionsManagementProcess.contains('general')
? () => expandableController.toggle() ? () => expandableController.toggle()
: null, : null,
borderRadius: BorderRadius.circular(28), borderRadius: BorderRadius.circular(28),
@ -277,7 +223,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28), borderRadius: BorderRadius.circular(28),
color: Theme.of(context).primaryColor.withOpacity(0.1) color: Theme.of(context).colorScheme.primary.withOpacity(0.1)
), ),
child: Expandable( child: Expandable(
theme: const ExpandableThemeData( theme: const ExpandableThemeData(
@ -301,9 +247,9 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(28), borderRadius: BorderRadius.circular(28),
child: InkWell( child: InkWell(
onTap: serversProvider.protectionsManagementProcess.contains('general') == false onTap: statusProvider.protectionsManagementProcess.contains('general') == false
? () => updateBlocking( ? () => updateBlocking(
value: !serversProvider.serverStatus.data!.generalEnabled, value: !statusProvider.serverStatus!.generalEnabled,
filter: 'general_legacy' filter: 'general_legacy'
) : null, ) : null,
borderRadius: BorderRadius.circular(28), borderRadius: BorderRadius.circular(28),
@ -408,30 +354,30 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
smallSwitch( smallSwitch(
AppLocalizations.of(context)!.ruleFiltering, AppLocalizations.of(context)!.ruleFiltering,
Icons.filter_list_rounded, Icons.filter_list_rounded,
serversProvider.serverStatus.data!.filteringEnabled, statusProvider.serverStatus!.filteringEnabled,
(value) => updateBlocking(value: value, filter: 'filtering'), (value) => updateBlocking(value: value, filter: 'filtering'),
serversProvider.protectionsManagementProcess.contains('filtering') statusProvider.protectionsManagementProcess.contains('filtering')
), ),
smallSwitch( smallSwitch(
AppLocalizations.of(context)!.safeBrowsing, AppLocalizations.of(context)!.safeBrowsing,
Icons.vpn_lock_rounded, Icons.vpn_lock_rounded,
serversProvider.serverStatus.data!.safeBrowsingEnabled, statusProvider.serverStatus!.safeBrowsingEnabled,
(value) => updateBlocking(value: value, filter: 'safeBrowsing'), (value) => updateBlocking(value: value, filter: 'safeBrowsing'),
serversProvider.protectionsManagementProcess.contains('safeBrowsing') statusProvider.protectionsManagementProcess.contains('safeBrowsing')
), ),
smallSwitch( smallSwitch(
AppLocalizations.of(context)!.parentalFiltering, AppLocalizations.of(context)!.parentalFiltering,
Icons.block, Icons.block,
serversProvider.serverStatus.data!.parentalControlEnabled, statusProvider.serverStatus!.parentalControlEnabled,
(value) => updateBlocking(value: value, filter: 'parentalControl'), (value) => updateBlocking(value: value, filter: 'parentalControl'),
serversProvider.protectionsManagementProcess.contains('parentalControl') statusProvider.protectionsManagementProcess.contains('parentalControl')
), ),
smallSwitch( smallSwitch(
AppLocalizations.of(context)!.safeSearch, AppLocalizations.of(context)!.safeSearch,
Icons.search_rounded, Icons.search_rounded,
serversProvider.serverStatus.data!.safeSearchEnabled, statusProvider.serverStatus!.safeSearchEnabled,
(value) => updateBlocking(value: value, filter: 'safeSearch'), (value) => updateBlocking(value: value, filter: 'safeSearch'),
serversProvider.protectionsManagementProcess.contains('safeSearch') statusProvider.protectionsManagementProcess.contains('safeSearch')
), ),
]; ];
} }

View file

@ -5,10 +5,10 @@ import 'package:adguard_home_manager/screens/home/status_box.dart';
import 'package:adguard_home_manager/models/server_status.dart'; import 'package:adguard_home_manager/models/server_status.dart';
class ServerStatus extends StatelessWidget { class ServerStatusWidget extends StatelessWidget {
final ServerStatusData serverStatus; final ServerStatus serverStatus;
const ServerStatus({ const ServerStatusWidget({
Key? key, Key? key,
required this.serverStatus, required this.serverStatus,
}) : super(key: key); }) : super(key: key);

View file

@ -9,16 +9,14 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/domain_options.dart'; import 'package:adguard_home_manager/widgets/domain_options.dart';
import 'package:adguard_home_manager/screens/top_items/top_items_modal.dart'; import 'package:adguard_home_manager/screens/top_items/top_items_modal.dart';
import 'package:adguard_home_manager/widgets/options_modal.dart';
import 'package:adguard_home_manager/screens/top_items/top_items.dart'; import 'package:adguard_home_manager/screens/top_items/top_items.dart';
import 'package:adguard_home_manager/models/applied_filters.dart'; import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/models/menu_option.dart'; import 'package:adguard_home_manager/models/menu_option.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
class TopItems extends StatelessWidget { class TopItems extends StatelessWidget {
final String type; final String type;
@ -36,7 +34,7 @@ class TopItems extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
@ -58,52 +56,26 @@ class TopItems extends StatelessWidget {
final ProcessModal processModal = ProcessModal(context: context); final ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingUserFilters); processModal.open(AppLocalizations.of(context)!.savingUserFilters);
final rules = await getFilteringRules(server: serversProvider.selectedServer!); final rules = await statusProvider.blockUnblockDomain(
domain: domain,
newStatus: newStatus
);
if (rules['result'] == 'success') { processModal.close();
FilteringStatus oldStatus = serversProvider.serverStatus.data!.filteringStatus;
List<String> newRules = rules['data'].userRules.where((d) => !d.contains(domain)).toList(); if (rules == true) {
if (newStatus == 'block') { showSnacbkar(
newRules.add("||$domain^"); appConfigProvider: appConfigProvider,
} label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
else if (newStatus == 'unblock') { color: Colors.green
newRules.add("@@||$domain^"); );
}
FilteringStatus newObj = serversProvider.serverStatus.data!.filteringStatus;
newObj.userRules = newRules;
serversProvider.setFilteringStatus(newObj);
final result = await postFilteringRules(server: serversProvider.selectedServer!, data: {'rules': newRules});
processModal.close();
if (result['result'] == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesUpdated),
backgroundColor: Colors.green,
)
);
}
else {
appConfigProvider.addLog(result['log']);
serversProvider.setFilteringStatus(oldStatus);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
backgroundColor: Colors.red,
)
);
}
} }
else { else {
appConfigProvider.addLog(rules['log']); showSnacbkar(
ScaffoldMessenger.of(context).showSnackBar( appConfigProvider: appConfigProvider,
SnackBar( label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated), color: Colors.red
backgroundColor: Colors.red,
)
); );
} }
} }
@ -141,20 +113,11 @@ class TopItems extends StatelessWidget {
]; ];
} }
void openOptionsModal(String domain, String type) {
showDialog(
context: context,
builder: (context) => OptionsModal(
options: generateOptions(domain),
)
);
}
Widget rowItem(Map<String, dynamic> item) { Widget rowItem(Map<String, dynamic> item) {
String? name; String? name;
if (clients != null && clients == true) { if (clients != null && clients == true) {
try { try {
name = serversProvider.serverStatus.data!.clients.firstWhere((c) => c.ids.contains(item.keys.toList()[0])).name; name = statusProvider.serverStatus!.clients.firstWhere((c) => c.ids.contains(item.keys.toList()[0])).name;
} catch (e) { } catch (e) {
// ---- // // ---- //
} }
@ -241,13 +204,13 @@ class TopItems extends StatelessWidget {
List<Map<String, dynamic>> generateData() { List<Map<String, dynamic>> generateData() {
switch (type) { switch (type) {
case 'topQueriedDomains': case 'topQueriedDomains':
return serversProvider.serverStatus.data!.stats.topQueriedDomains; return statusProvider.serverStatus!.stats.topQueriedDomains;
case 'topBlockedDomains': case 'topBlockedDomains':
return serversProvider.serverStatus.data!.stats.topBlockedDomains; return statusProvider.serverStatus!.stats.topBlockedDomains;
case 'topClients': case 'topClients':
return serversProvider.serverStatus.data!.stats.topClients; return statusProvider.serverStatus!.stats.topClients;
default: default:
return []; return [];

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
class ClientsModal extends StatefulWidget { class ClientsModal extends StatefulWidget {
@ -32,6 +33,7 @@ class _ClientsModalState extends State<ClientsModal> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final height = MediaQuery.of(context).size.height; final height = MediaQuery.of(context).size.height;
@ -86,7 +88,7 @@ class _ClientsModalState extends State<ClientsModal> {
void selectAll() { void selectAll() {
setState(() { setState(() {
selectedClients = logsProvider.clients!.map((item) => item.ip).toList(); selectedClients = clientsProvider.clients!.autoClients.map((item) => item.ip).toList();
}); });
} }
@ -126,20 +128,20 @@ class _ClientsModalState extends State<ClientsModal> {
), ),
Flexible( Flexible(
child: ListView.builder( child: ListView.builder(
itemCount: logsProvider.clients!.length, itemCount: clientsProvider.clients!.autoClients.length,
itemBuilder: (context, index) => listItem( itemBuilder: (context, index) => listItem(
label: logsProvider.clients![index].ip, label: clientsProvider.clients!.autoClients[index].ip,
onChanged: () { onChanged: () {
if (selectedClients.contains(logsProvider.clients![index].ip)) { if (selectedClients.contains(clientsProvider.clients!.autoClients[index].ip)) {
setState(() { setState(() {
selectedClients = selectedClients.where( selectedClients = selectedClients.where(
(item) => item != logsProvider.clients![index].ip (item) => item != clientsProvider.clients!.autoClients[index].ip
).toList(); ).toList();
}); });
} }
else { else {
setState(() { setState(() {
selectedClients.add(logsProvider.clients![index].ip); selectedClients.add(clientsProvider.clients!.autoClients[index].ip);
}); });
} }
} }
@ -152,11 +154,11 @@ class _ClientsModalState extends State<ClientsModal> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
TextButton( TextButton(
onPressed: selectedClients.length == logsProvider.clients!.length onPressed: selectedClients.length == clientsProvider.clients!.autoClients.length
? () => unselectAll() ? () => unselectAll()
: () => selectAll(), : () => selectAll(),
child: Text( child: Text(
selectedClients.length == logsProvider.clients!.length selectedClients.length == clientsProvider.clients!.autoClients.length
? AppLocalizations.of(context)!.unselectAll ? AppLocalizations.of(context)!.unselectAll
: AppLocalizations.of(context)!.selectAll : AppLocalizations.of(context)!.selectAll
) )

View file

@ -10,11 +10,11 @@ import 'package:adguard_home_manager/screens/logs/log_list_tile.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/get_filtered_status.dart'; import 'package:adguard_home_manager/functions/get_filtered_status.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/functions/format_time.dart'; import 'package:adguard_home_manager/functions/format_time.dart';
import 'package:adguard_home_manager/models/filtering_status.dart'; import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
class LogDetailsScreen extends StatelessWidget { class LogDetailsScreen extends StatelessWidget {
@ -29,13 +29,13 @@ class LogDetailsScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
Filter? getList(int id) { Filter? getList(int id) {
try { try {
return serversProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () { return statusProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () {
return serversProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id); return statusProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id);
}); });
} catch (_) { } catch (_) {
return null; return null;
@ -53,56 +53,29 @@ class LogDetailsScreen extends StatelessWidget {
); );
} }
void blockUnblock(Log log, String newStatus) async { void blockUnblock(String domain, String newStatus) async {
final ProcessModal processModal = ProcessModal(context: context); final ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingUserFilters); processModal.open(AppLocalizations.of(context)!.savingUserFilters);
final rules = await getFilteringRules(server: serversProvider.selectedServer!); final rules = await statusProvider.blockUnblockDomain(
domain: domain,
newStatus: newStatus
);
if (rules['result'] == 'success') { processModal.close();
FilteringStatus oldStatus = serversProvider.filteringStatus!;
List<String> newRules = rules['data'].userRules.where((domain) => !domain.contains(log.question.name)).toList(); if (rules == true) {
if (newStatus == 'block') { showSnacbkar(
newRules.add("||${log.question.name}^"); appConfigProvider: appConfigProvider,
} label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
else if (newStatus == 'unblock') { color: Colors.green
newRules.add("@@||${log.question.name}^"); );
}
FilteringStatus newObj = serversProvider.filteringStatus!;
newObj.userRules = newRules;
serversProvider.setFilteringStatus(newObj);
final result = await postFilteringRules(server: serversProvider.selectedServer!, data: {'rules': newRules});
processModal.close();
if (result['result'] == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesUpdated),
backgroundColor: Colors.green,
)
);
}
else {
appConfigProvider.addLog(result['log']);
serversProvider.setFilteringStatus(oldStatus);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
backgroundColor: Colors.red,
)
);
}
} }
else { else {
appConfigProvider.addLog(rules['log']); showSnacbkar(
ScaffoldMessenger.of(context).showSnackBar( appConfigProvider: appConfigProvider,
SnackBar( label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated), color: Colors.red
backgroundColor: Colors.red,
)
); );
} }
} }
@ -266,7 +239,12 @@ class LogDetailsScreen extends StatelessWidget {
Row( Row(
children: [ children: [
IconButton( IconButton(
onPressed: () => blockUnblock(log, getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'), onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
icon: Icon( icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded ? Icons.check_circle_rounded
@ -298,8 +276,13 @@ class LogDetailsScreen extends StatelessWidget {
centerTitle: false, centerTitle: false,
title: Text(AppLocalizations.of(context)!.logDetails), title: Text(AppLocalizations.of(context)!.logDetails),
actions: [ actions: [
if (serversProvider.filteringStatus != null) IconButton( if (statusProvider.filteringStatus != null) IconButton(
onPressed: () => blockUnblock(log, getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'), onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
icon: Icon( icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded ? Icons.check_circle_rounded

View file

@ -15,160 +15,61 @@ import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/applied_filters.dart'; import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
class Logs extends StatelessWidget { class Logs extends StatefulWidget {
const Logs({Key? key}) : super(key: key); const Logs({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<Logs> createState() => _LogsState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
return LogsWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
logsProvider: logsProvider,
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: logsProvider.appliedFilters.searchText,
);
}
} }
class LogsWidget extends StatefulWidget { class _LogsState extends State<Logs> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
final LogsProvider logsProvider;
final String selectedResultStatus;
final String? searchText;
const LogsWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider,
required this.logsProvider,
required this.selectedResultStatus,
required this.searchText,
}) : super(key: key);
@override
State<LogsWidget> createState() => _LogsWidgetState();
}
class _LogsWidgetState extends State<LogsWidget> {
late ScrollController scrollController; late ScrollController scrollController;
bool isLoadingMore = false;
bool showDivider = true; bool showDivider = true;
Log? selectedLog; Log? selectedLog;
Future fetchLogs({
int? inOffset,
bool? loadingMore,
String? responseStatus,
String? searchText,
}) async {
int offst = inOffset ?? widget.logsProvider.offset;
String resStatus = responseStatus ?? widget.selectedResultStatus;
String? search = searchText ?? widget.searchText;
if (loadingMore != null && loadingMore == true) {
setState(() => isLoadingMore = true);
}
final result = await getLogs(
server: widget.serversProvider.selectedServer!,
count: widget.logsProvider.logsQuantity,
offset: offst,
olderThan: widget.logsProvider.logsOlderThan,
responseStatus: resStatus,
search: search
);
if (loadingMore != null && loadingMore == true) {
setState(() => isLoadingMore = false);
}
if (mounted) {
if (result['result'] == 'success') {
widget.logsProvider.setOffset(inOffset != null ? inOffset+widget.logsProvider.logsQuantity : widget.logsProvider.offset+widget.logsProvider.logsQuantity);
if (loadingMore != null && loadingMore == true && widget.logsProvider.logsData != null) {
LogsData newLogsData = result['data'];
newLogsData.data = [...widget.logsProvider.logsData!.data, ...result['data'].data];
if (widget.logsProvider.appliedFilters.clients != null) {
newLogsData.data = newLogsData.data.where(
(item) => widget.logsProvider.appliedFilters.clients!.contains(item.client)
).toList();
}
widget.logsProvider.setLogsData(newLogsData);
}
else {
LogsData newLogsData = result['data'];
if (widget.logsProvider.appliedFilters.clients != null) {
newLogsData.data = newLogsData.data.where(
(item) => widget.logsProvider.appliedFilters.clients!.contains(item.client)
).toList();
}
widget.logsProvider.setLogsData(newLogsData);
}
widget.logsProvider.setLoadStatus(1);
}
else {
widget.logsProvider.setLoadStatus(2);
widget.appConfigProvider.addLog(result['log']);
}
}
}
void fetchFilteringRules() async { void fetchFilteringRules() async {
final result = await getFilteringRules(server: widget.serversProvider.selectedServer!); final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
if (mounted) { final statusProvider = Provider.of<StatusProvider>(context, listen: false);
if (result['result'] == 'success') {
widget.serversProvider.setFilteringStatus(result['data']); final result = await statusProvider.getFilteringRules();
} if (mounted && result == false) {
else { showSnacbkar(
widget.appConfigProvider.addLog(result['log']); appConfigProvider: appConfigProvider,
ScaffoldMessenger.of(context).showSnackBar( label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
SnackBar( color: Colors.red
content: Text(AppLocalizations.of(context)!.couldntGetFilteringStatus), );
backgroundColor: Colors.red,
)
);
}
} }
} }
Future fetchClients() async { Future fetchClients() async {
final result = await getClients(widget.serversProvider.selectedServer!); final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
if (mounted) { final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
if (result['result'] == 'success') {
widget.logsProvider.setClientsLoadStatus(1); final result = await clientsProvider.fetchClients();
widget.logsProvider.setClients(result['data'].autoClientsData); if (mounted && result == false) {
} showSnacbkar(
else { appConfigProvider: appConfigProvider,
widget.logsProvider.setClientsLoadStatus(2); label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
widget.appConfigProvider.addLog(result['log']); color: Colors.red
ScaffoldMessenger.of(context).showSnackBar( );
SnackBar(
content: Text(AppLocalizations.of(context)!.couldntGetFilteringStatus),
backgroundColor: Colors.red,
)
);
}
} }
} }
void scrollListener() { void scrollListener() {
if (scrollController.position.extentAfter < 500 && isLoadingMore == false) { final logsProvider = Provider.of<LogsProvider>(context, listen: false);
fetchLogs(loadingMore: true);
if (scrollController.position.extentAfter < 500 && logsProvider.isLoadingMore == false) {
logsProvider.fetchLogs(loadingMore: true);
} }
if (scrollController.position.pixels > 0) { if (scrollController.position.pixels > 0) {
setState(() => showDivider = false); setState(() => showDivider = false);
@ -180,8 +81,10 @@ class _LogsWidgetState extends State<LogsWidget> {
@override @override
void initState() { void initState() {
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
scrollController = ScrollController()..addListener(scrollListener); scrollController = ScrollController()..addListener(scrollListener);
fetchLogs(inOffset: 0); logsProvider.fetchLogs(inOffset: 0);
fetchFilteringRules(); fetchFilteringRules();
fetchClients(); fetchClients();
super.initState(); super.initState();
@ -190,6 +93,7 @@ class _LogsWidgetState extends State<LogsWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
@ -200,12 +104,12 @@ class _LogsWidgetState extends State<LogsWidget> {
processModal.open(AppLocalizations.of(context)!.updatingSettings); processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = serverVersionIsAhead( final result = serverVersionIsAhead(
currentVersion: widget.serversProvider.serverStatus.data!.serverVersion, currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == true ) == true
? await updateQueryLogParameters(server: serversProvider.selectedServer!, data: data) ? await serversProvider.apiClient!.updateQueryLogParameters(data: data)
: await updateQueryLogParametersLegacy(server: serversProvider.selectedServer!, data: data); : await serversProvider.apiClient!.updateQueryLogParametersLegacy(data: data);
processModal.close(); processModal.close();
@ -231,7 +135,7 @@ class _LogsWidgetState extends State<LogsWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingSettings); processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = await clearLogs(server: serversProvider.selectedServer!); final result = await serversProvider.apiClient!.clearLogs();
processModal.close(); processModal.close();
@ -243,8 +147,6 @@ class _LogsWidgetState extends State<LogsWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsNotCleared, label: AppLocalizations.of(context)!.logsNotCleared,
@ -289,7 +191,7 @@ class _LogsWidgetState extends State<LogsWidget> {
Widget generateBody() { Widget generateBody() {
switch (logsProvider.loadStatus) { switch (logsProvider.loadStatus) {
case 0: case LoadStatus.loading:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -309,20 +211,20 @@ class _LogsWidgetState extends State<LogsWidget> {
), ),
); );
case 1: case LoadStatus.loaded:
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
await fetchLogs(inOffset: 0); await logsProvider.fetchLogs(inOffset: 0);
}, },
child: logsProvider.logsData!.data.isNotEmpty child: logsProvider.logsData!.data.isNotEmpty
? ListView.builder( ? ListView.builder(
controller: scrollController, controller: scrollController,
padding: const EdgeInsets.only(top: 0), padding: const EdgeInsets.only(top: 0),
itemCount: isLoadingMore == true itemCount: logsProvider.isLoadingMore == true
? logsProvider.logsData!.data.length+1 ? logsProvider.logsData!.data.length+1
: logsProvider.logsData!.data.length, : logsProvider.logsData!.data.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (isLoadingMore == true && index == logsProvider.logsData!.data.length) { if (logsProvider.isLoadingMore == true && index == logsProvider.logsData!.data.length) {
return const Padding( return const Padding(
padding: EdgeInsets.symmetric(vertical: 20), padding: EdgeInsets.symmetric(vertical: 20),
child: Center( child: Center(
@ -385,7 +287,7 @@ class _LogsWidgetState extends State<LogsWidget> {
) )
); );
case 2: case LoadStatus.error:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -421,11 +323,11 @@ class _LogsWidgetState extends State<LogsWidget> {
centerTitle: false, centerTitle: false,
actions: [ actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton( if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => fetchLogs(inOffset: 0), onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh, tooltip: AppLocalizations.of(context)!.refresh,
), ),
logsProvider.loadStatus == 1 logsProvider.loadStatus == LoadStatus.loaded
? IconButton( ? IconButton(
onPressed: openFilersModal, onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded), icon: const Icon(Icons.filter_list_rounded),
@ -442,7 +344,7 @@ class _LogsWidgetState extends State<LogsWidget> {
onConfirm: updateConfig, onConfirm: updateConfig,
onClear: clearQueries, onClear: clearQueries,
dialog: true, dialog: true,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
), ),
barrierDismissible: false barrierDismissible: false
) )
@ -454,7 +356,7 @@ class _LogsWidgetState extends State<LogsWidget> {
onConfirm: updateConfig, onConfirm: updateConfig,
onClear: clearQueries, onClear: clearQueries,
dialog: false, dialog: false,
serverVersion: serversProvider.serverStatus.data!.serverVersion, serverVersion: statusProvider.serverStatus!.serverVersion,
), ),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
isScrollControlled: true isScrollControlled: true
@ -510,7 +412,7 @@ class _LogsWidgetState extends State<LogsWidget> {
) )
); );
logsProvider.setSearchText(null); logsProvider.setSearchText(null);
fetchLogs( logsProvider.fetchLogs(
inOffset: 0, inOffset: 0,
searchText: '' searchText: ''
); );
@ -543,7 +445,7 @@ class _LogsWidgetState extends State<LogsWidget> {
) )
); );
logsProvider.setSelectedResultStatus('all'); logsProvider.setSelectedResultStatus('all');
fetchLogs( logsProvider.fetchLogs(
inOffset: 0, inOffset: 0,
responseStatus: 'all' responseStatus: 'all'
); );
@ -578,7 +480,7 @@ class _LogsWidgetState extends State<LogsWidget> {
) )
); );
logsProvider.setSelectedClients(null); logsProvider.setSelectedClients(null);
fetchLogs( logsProvider.fetchLogs(
inOffset: 0, inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus responseStatus: logsProvider.appliedFilters.selectedResultStatus
); );

View file

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -74,13 +73,15 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
int loadStatus = 0; int loadStatus = 0;
void loadData() async { void loadData() async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
final result = serverVersionIsAhead( final result = serverVersionIsAhead(
currentVersion: widget.serverVersion, currentVersion: widget.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == true ) == true
? await getQueryLogInfo(server: widget.serversProvider.selectedServer!) ? await serversProvider.apiClient!.getQueryLogInfo()
: await getQueryLogInfoLegacy(server: widget.serversProvider.selectedServer!); : await serversProvider.apiClient!.getQueryLogInfoLegacy();
if (mounted) { if (mounted) {
if (result['result'] == 'success') { if (result['result'] == 'success') {

View file

@ -10,11 +10,8 @@ import 'package:adguard_home_manager/screens/logs/clients_modal.dart';
import 'package:adguard_home_manager/screens/logs/filter_status_modal.dart'; import 'package:adguard_home_manager/screens/logs/filter_status_modal.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
class LogsFiltersModal extends StatelessWidget { class LogsFiltersModal extends StatelessWidget {
@ -62,8 +59,7 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
final serversProvider = Provider.of<ServersProvider>(context); final clientsProvider = Provider.of<ClientsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -78,38 +74,6 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
"safe_search": AppLocalizations.of(context)!.blockedSafeSearchRow, "safe_search": AppLocalizations.of(context)!.blockedSafeSearchRow,
}; };
void resetFilters() async {
setState(() {
searchController.text = '';
});
logsProvider.setLoadStatus(0);
logsProvider.resetFilters();
final result = await getLogs(
server: serversProvider.selectedServer!,
count: logsProvider.logsQuantity
);
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: 'all',
searchText: null,
clients: null
)
);
if (result['result'] == 'success') {
logsProvider.setLogsData(result['data']);
logsProvider.setLoadStatus(1);
}
else {
appConfigProvider.addLog(result['log']);
logsProvider.setLoadStatus(2);
}
}
void openSelectFilterStatus() { void openSelectFilterStatus() {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) { if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog( showDialog(
@ -158,45 +122,6 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
} }
} }
void filterLogs() async {
Navigator.pop(context);
logsProvider.setLoadStatus(0);
logsProvider.setOffset(0);
final result = await getLogs(
server: serversProvider.selectedServer!,
count: logsProvider.logsQuantity,
olderThan: logsProvider.logsOlderThan,
responseStatus: logsProvider.selectedResultStatus,
search: logsProvider.searchText,
);
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.selectedResultStatus,
searchText: logsProvider.searchText,
clients: logsProvider.selectedClients
)
);
if (result['result'] == 'success') {
LogsData newLogsData = result['data'];
if (widget.logsProvider.appliedFilters.clients != null) {
newLogsData.data = newLogsData.data.where(
(item) => widget.logsProvider.appliedFilters.clients!.contains(item.client)
).toList();
}
logsProvider.setLogsData(newLogsData);
logsProvider.setLoadStatus(1);
}
else {
appConfigProvider.addLog(result['log']);
logsProvider.setLoadStatus(2);
}
}
Widget content() { Widget content() {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -273,13 +198,13 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
subtitle: logsProvider.selectedClients != null subtitle: logsProvider.selectedClients != null
? "${logsProvider.selectedClients!.length} ${AppLocalizations.of(context)!.clientsSelected}" ? "${logsProvider.selectedClients!.length} ${AppLocalizations.of(context)!.clientsSelected}"
: AppLocalizations.of(context)!.all, : AppLocalizations.of(context)!.all,
onTap: logsProvider.clientsLoadStatus == 1 onTap: clientsProvider.loadStatus == LoadStatus.loaded
? openSelectClients ? openSelectClients
: null, : null,
disabled: logsProvider.clientsLoadStatus != 1 , disabled: clientsProvider.loadStatus != LoadStatus.loaded,
icon: Icons.smartphone_rounded, icon: Icons.smartphone_rounded,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
trailing: logsProvider.clientsLoadStatus == 0 trailing: clientsProvider.loadStatus == LoadStatus.loading
? const SizedBox( ? const SizedBox(
width: 20, width: 20,
height: 20, height: 20,
@ -287,7 +212,7 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
strokeWidth: 2, strokeWidth: 2,
), ),
) )
: logsProvider.clientsLoadStatus == 2 : clientsProvider.loadStatus == LoadStatus.error
? const Icon( ? const Icon(
Icons.error_rounded, Icons.error_rounded,
color: Colors.red, color: Colors.red,
@ -311,11 +236,17 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
TextButton( TextButton(
onPressed: resetFilters, onPressed: () {
searchController.text = "";
logsProvider.requestResetFilters();
},
child: Text(AppLocalizations.of(context)!.resetFilters) child: Text(AppLocalizations.of(context)!.resetFilters)
), ),
TextButton( TextButton(
onPressed: () => filterLogs(), onPressed: () {
Navigator.pop(context);
logsProvider.filterLogs();
},
child: Text(AppLocalizations.of(context)!.apply) child: Text(AppLocalizations.of(context)!.apply)
), ),
], ],

View file

@ -7,62 +7,22 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/access_settings/clients_list.dart'; import 'package:adguard_home_manager/screens/settings/access_settings/clients_list.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class AccessSettings extends StatelessWidget { class AccessSettings extends StatefulWidget {
const AccessSettings({Key? key}) : super(key: key); const AccessSettings({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<AccessSettings> createState() => _AccessSettingsState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return AccessSettingsWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
} }
class AccessSettingsWidget extends StatefulWidget { class _AccessSettingsState extends State<AccessSettings> with TickerProviderStateMixin {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const AccessSettingsWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider,
}) : super(key: key);
@override
State<AccessSettingsWidget> createState() => _AccessSettingsWidgetState();
}
class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with TickerProviderStateMixin {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
late TabController tabController; late TabController tabController;
Future fetchClients() async {
widget.serversProvider.setClientsLoadStatus(LoadStatus.loading, false);
final result = await getClients(widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setClientsData(result['data']);
widget.serversProvider.setClientsLoadStatus(LoadStatus.loaded, true);
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setClientsLoadStatus(LoadStatus.error, true);
}
}
}
@override @override
void initState() { void initState() {
fetchClients(); Provider.of<ClientsProvider>(context, listen: false).fetchClients(updateLoading: true);
super.initState(); super.initState();
tabController = TabController( tabController = TabController(
initialIndex: 0, initialIndex: 0,
@ -73,7 +33,7 @@ class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with Ticker
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final clientsProvider = Provider.of<ClientsProvider>(context);
Widget body() { Widget body() {
return TabBarView( return TabBarView(
@ -82,26 +42,23 @@ class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with Ticker
ClientsList( ClientsList(
type: 'allowed', type: 'allowed',
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, loadStatus: clientsProvider.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded data: clientsProvider.loadStatus == LoadStatus.loaded
? serversProvider.clients.data!.clientsAllowedBlocked!.allowedClients : [], ? clientsProvider.clients!.clientsAllowedBlocked!.allowedClients : [],
fetchClients: fetchClients
), ),
ClientsList( ClientsList(
type: 'disallowed', type: 'disallowed',
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, loadStatus: clientsProvider.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded data: clientsProvider.loadStatus == LoadStatus.loaded
? serversProvider.clients.data!.clientsAllowedBlocked!.disallowedClients : [], ? clientsProvider.clients!.clientsAllowedBlocked!.disallowedClients : [],
fetchClients: fetchClients
), ),
ClientsList( ClientsList(
type: 'domains', type: 'domains',
scrollController: scrollController, scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus, loadStatus: clientsProvider.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded data: clientsProvider.loadStatus == LoadStatus.loaded
? serversProvider.clients.data!.clientsAllowedBlocked!.blockedHosts : [], ? clientsProvider.clients!.clientsAllowedBlocked!.blockedHosts : [],
fetchClients: fetchClients
), ),
] ]
); );

View file

@ -13,10 +13,8 @@ import 'package:adguard_home_manager/widgets/tab_content_list.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
class ClientsList extends StatefulWidget { class ClientsList extends StatefulWidget {
@ -24,7 +22,6 @@ class ClientsList extends StatefulWidget {
final ScrollController scrollController; final ScrollController scrollController;
final LoadStatus loadStatus; final LoadStatus loadStatus;
final List<String> data; final List<String> data;
final Future Function() fetchClients;
const ClientsList({ const ClientsList({
Key? key, Key? key,
@ -32,7 +29,6 @@ class ClientsList extends StatefulWidget {
required this.scrollController, required this.scrollController,
required this.loadStatus, required this.loadStatus,
required this.data, required this.data,
required this.fetchClients
}) : super(key: key); }) : super(key: key);
@override @override
@ -67,16 +63,27 @@ class _ClientsListState extends State<ClientsList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
Future refetchClients() async {
final result = await clientsProvider.fetchClients();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientsNotLoaded,
color: Colors.red
);
}
}
void confirmRemoveItem(String client, String type) async { void confirmRemoveItem(String client, String type) async {
Map<String, List<String>> body = { Map<String, List<String>> body = {
"allowed_clients": serversProvider.clients.data!.clientsAllowedBlocked?.allowedClients ?? [], "allowed_clients": clientsProvider.clients!.clientsAllowedBlocked?.allowedClients ?? [],
"disallowed_clients": serversProvider.clients.data!.clientsAllowedBlocked?.disallowedClients ?? [], "disallowed_clients": clientsProvider.clients!.clientsAllowedBlocked?.disallowedClients ?? [],
"blocked_hosts": serversProvider.clients.data!.clientsAllowedBlocked?.blockedHosts ?? [], "blocked_hosts": clientsProvider.clients!.clientsAllowedBlocked?.blockedHosts ?? [],
}; };
if (type == 'allowed') { if (type == 'allowed') {
@ -92,20 +99,18 @@ class _ClientsListState extends State<ClientsList> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.removingClient); processModal.open(AppLocalizations.of(context)!.removingClient);
final result = await requestAllowedBlockedClientsHosts(serversProvider.selectedServer!, body); final result = await clientsProvider.removeClientList(client, type);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
serversProvider.setAllowedDisallowedClientsBlockedDomains( showSnacbkar(
ClientsAllowedBlocked( appConfigProvider: appConfigProvider,
allowedClients: body['allowed_clients'] ?? [], label: AppLocalizations.of(context)!.clientRemovedSuccessfully,
disallowedClients: body['disallowed_clients'] ?? [], color: Colors.green
blockedHosts: body['blocked_hosts'] ?? [],
)
); );
} }
else if (result['result'] == 'error' && result['message'] == 'client_another_list') { else if (result['success'] == false && result['error'] == 'client_another_list') {
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAnotherList, label: AppLocalizations.of(context)!.clientAnotherList,
@ -113,50 +118,32 @@ class _ClientsListState extends State<ClientsList> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotRemoved, label: type == 'allowed' || type == 'blocked'
? AppLocalizations.of(context)!.clientNotRemoved
: AppLocalizations.of(context)!.domainNotAdded,
color: Colors.red color: Colors.red
); );
} }
} }
void confirmAddItem(String item, String type) async { void confirmAddItem(String item, String type) async {
Map<String, List<String>> body = {
"allowed_clients": serversProvider.clients.data!.clientsAllowedBlocked?.allowedClients ?? [],
"disallowed_clients": serversProvider.clients.data!.clientsAllowedBlocked?.disallowedClients ?? [],
"blocked_hosts": serversProvider.clients.data!.clientsAllowedBlocked?.blockedHosts ?? [],
};
if (type == 'allowed') {
body['allowed_clients']!.add(item);
}
else if (type == 'disallowed') {
body['disallowed_clients']!.add(item);
}
else if (type == 'domains') {
body['blocked_hosts']!.add(item);
}
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.removingClient); processModal.open(AppLocalizations.of(context)!.removingClient);
final result = await requestAllowedBlockedClientsHosts(serversProvider.selectedServer!, body); final result = await clientsProvider.addClientList(item, type);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
serversProvider.setAllowedDisallowedClientsBlockedDomains( showSnacbkar(
ClientsAllowedBlocked( appConfigProvider: appConfigProvider,
allowedClients: body['allowed_clients'] ?? [], label: AppLocalizations.of(context)!.clientAddedSuccessfully,
disallowedClients: body['disallowed_clients'] ?? [], color: Colors.green
blockedHosts: body['blocked_hosts'] ?? [],
)
); );
} }
else if (result['result'] == 'error' && result['message'] == 'client_another_list') { else if (result['success'] == false && result['error'] == 'client_another_list') {
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAnotherList, label: AppLocalizations.of(context)!.clientAnotherList,
@ -164,8 +151,6 @@ class _ClientsListState extends State<ClientsList> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: type == 'allowed' || type == 'blocked' label: type == 'allowed' || type == 'blocked'
@ -325,7 +310,7 @@ class _ClientsListState extends State<ClientsList> {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
TextButton.icon( TextButton.icon(
onPressed: widget.fetchClients, onPressed: refetchClients,
icon: const Icon(Icons.refresh_rounded), icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh), label: Text(AppLocalizations.of(context)!.refresh),
) )
@ -359,7 +344,7 @@ class _ClientsListState extends State<ClientsList> {
), ),
), ),
loadStatus: widget.loadStatus, loadStatus: widget.loadStatus,
onRefresh: widget.fetchClients, onRefresh: refetchClients,
refreshIndicatorOffset: 0, refreshIndicatorOffset: 0,
fab: FloatingActionButton( fab: FloatingActionButton(
onPressed: () { onPressed: () {

View file

@ -1,14 +1,10 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_split_view/flutter_split_view.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/screens/settings/app_logs/app_logs.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
@ -20,8 +16,6 @@ class AdvancedSettings extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
Future updateSettings({ Future updateSettings({
required bool newStatus, required bool newStatus,
required Future Function(bool) function required Future Function(bool) function
@ -71,29 +65,6 @@ class AdvancedSettings extends StatelessWidget {
right: 10 right: 10
) )
), ),
CustomListTile(
icon: Icons.list_rounded,
title: AppLocalizations.of(context)!.logs,
subtitle: AppLocalizations.of(context)!.checkAppLogs,
onTap: () => {
if (width > 900 || !(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push(const AppLogs())
}
else {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const AppLogs()
)
)
}
},
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
left: 20,
right: 10
)
),
], ],
) )
); );

View file

@ -13,42 +13,21 @@ import 'package:adguard_home_manager/screens/settings/dhcp/dhcp_leases.dart';
import 'package:adguard_home_manager/screens/settings/dhcp/select_interface_modal.dart'; import 'package:adguard_home_manager/screens/settings/dhcp/select_interface_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/dhcp_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/dhcp.dart'; import 'package:adguard_home_manager/models/dhcp.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
class Dhcp extends StatelessWidget { class DhcpScreen extends StatefulWidget {
const Dhcp({Key? key}) : super(key: key); const DhcpScreen({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<DhcpScreen> createState() => _DhcpScreenState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return DhcpWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider
);
}
} }
class DhcpWidget extends StatefulWidget { class _DhcpScreenState extends State<DhcpScreen> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const DhcpWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider
}) : super(key: key);
@override
State<DhcpWidget> createState() => _DhcpWidgetState();
}
class _DhcpWidgetState extends State<DhcpWidget> {
NetworkInterface? selectedInterface; NetworkInterface? selectedInterface;
bool enabled = false; bool enabled = false;
@ -74,31 +53,22 @@ class _DhcpWidgetState extends State<DhcpWidget> {
bool dataValid = false; bool dataValid = false;
void loadDhcpStatus() async { void loadDhcpStatus() async {
widget.serversProvider.setDhcpLoadStatus(0, false); final result = await Provider.of<DhcpProvider>(context, listen: false).loadDhcpStatus();
if (mounted && result == true) {
final result = await getDhcpData(server: widget.serversProvider.selectedServer!); final dhcpProvider = Provider.of<DhcpProvider>(context, listen: false);
if (dhcpProvider.dhcp != null) {
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setDhcpLoadStatus(1, true);
widget.serversProvider.setDhcpData(result['data']);
setState(() { setState(() {
if (result['data'].dhcpStatus.interfaceName != '') { if (dhcpProvider.dhcp!.dhcpStatus.interfaceName != '') {
selectedInterface = result['data'].networkInterfaces.firstWhere((interface) => interface.name == result['data'].dhcpStatus.interfaceName); selectedInterface = dhcpProvider.dhcp!.networkInterfaces.firstWhere((iface) => iface.name == dhcpProvider.dhcp!.dhcpStatus.interfaceName);
enabled = dhcpProvider.dhcp!.dhcpStatus.enabled;
enabled = result['data'].dhcpStatus.enabled; ipv4StartRangeController.text = dhcpProvider.dhcp!.dhcpStatus.v4.rangeStart;
ipv4StartRangeController.text = result['data'].dhcpStatus.v4.rangeStart; ipv4EndRangeController.text = dhcpProvider.dhcp!.dhcpStatus.v4.rangeEnd ?? '';
ipv4StartRangeController.text = result['data'].dhcpStatus.v4.rangeStart; ipv4SubnetMaskController.text = dhcpProvider.dhcp!.dhcpStatus.v4.subnetMask ?? '';
ipv4EndRangeController.text = result['data'].dhcpStatus.v4.rangeEnd; ipv4GatewayController.text = dhcpProvider.dhcp!.dhcpStatus.v4.gatewayIp ?? '';
ipv4SubnetMaskController.text = result['data'].dhcpStatus.v4.subnetMask; ipv4LeaseTimeController.text = dhcpProvider.dhcp!.dhcpStatus.v4.leaseDuration.toString();
ipv4GatewayController.text = result['data'].dhcpStatus.v4.gatewayIp;
ipv4LeaseTimeController.text = result['data'].dhcpStatus.v4.leaseDuration.toString();
} }
}); });
} }
else {
widget.serversProvider.setDhcpLoadStatus(2, true);
}
} }
checkDataValid(); checkDataValid();
} }
@ -213,6 +183,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final dhcpProvider = Provider.of<DhcpProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -221,22 +192,24 @@ class _DhcpWidgetState extends State<DhcpWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingSettings); processModal.open(AppLocalizations.of(context)!.savingSettings);
final result = await saveDhcpConfig(server: serversProvider.selectedServer!, data: { final result = await serversProvider.apiClient!.saveDhcpConfig(
"enabled": enabled, data: {
"interface_name": selectedInterface!.name, "enabled": enabled,
if (selectedInterface!.ipv4Addresses.isNotEmpty) "v4": { "interface_name": selectedInterface!.name,
"gateway_ip": ipv4GatewayController.text, if (selectedInterface!.ipv4Addresses.isNotEmpty) "v4": {
"subnet_mask": ipv4SubnetMaskController.text, "gateway_ip": ipv4GatewayController.text,
"range_start": ipv4StartRangeController.text, "subnet_mask": ipv4SubnetMaskController.text,
"range_end": ipv4EndRangeController.text, "range_start": ipv4StartRangeController.text,
"lease_duration": ipv4LeaseTimeController.text != '' ? int.parse(ipv4LeaseTimeController.text) : null "range_end": ipv4EndRangeController.text,
}, "lease_duration": ipv4LeaseTimeController.text != '' ? int.parse(ipv4LeaseTimeController.text) : null
if (selectedInterface!.ipv6Addresses.isNotEmpty) "v6": { },
"range_start": ipv6StartRangeController.text, if (selectedInterface!.ipv6Addresses.isNotEmpty) "v6": {
"range_end": ipv6EndRangeController.text, "range_start": ipv6StartRangeController.text,
"lease_duration": ipv6LeaseTimeController.text != '' ? int.parse(ipv6LeaseTimeController.text) : null "range_end": ipv6EndRangeController.text,
"lease_duration": ipv6LeaseTimeController.text != '' ? int.parse(ipv6LeaseTimeController.text) : null
}
} }
}); );
processModal.close(); processModal.close();
@ -248,8 +221,6 @@ class _DhcpWidgetState extends State<DhcpWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved, label: AppLocalizations.of(context)!.settingsNotSaved,
@ -263,7 +234,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.restoringConfig); processModal.open(AppLocalizations.of(context)!.restoringConfig);
final result = await resetDhcpConfig(server: serversProvider.selectedServer!); final result = await serversProvider.apiClient!.resetDhcpConfig();
processModal.close(); processModal.close();
@ -277,8 +248,6 @@ class _DhcpWidgetState extends State<DhcpWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.configNotRestored, label: AppLocalizations.of(context)!.configNotRestored,
@ -293,15 +262,15 @@ class _DhcpWidgetState extends State<DhcpWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.restoringLeases); processModal.open(AppLocalizations.of(context)!.restoringLeases);
final result = await restoreAllLeases(server: serversProvider.selectedServer!); final result = await serversProvider.apiClient!.restoreAllLeases();
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['result'] == 'success') {
DhcpData data = serversProvider.dhcp.data!; DhcpModel data = dhcpProvider.dhcp!;
data.dhcpStatus.staticLeases = []; data.dhcpStatus.staticLeases = [];
data.dhcpStatus.leases = []; data.dhcpStatus.leases = [];
serversProvider.setDhcpData(data); dhcpProvider.setDhcpData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
@ -310,8 +279,6 @@ class _DhcpWidgetState extends State<DhcpWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.leasesNotRestored, label: AppLocalizations.of(context)!.leasesNotRestored,
@ -356,7 +323,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => SelectInterfaceModal( builder: (context) => SelectInterfaceModal(
interfaces: serversProvider.dhcp.data!.networkInterfaces, interfaces: dhcpProvider.dhcp!.networkInterfaces,
onSelect: (interface) => setState(() { onSelect: (interface) => setState(() {
clearAll(); clearAll();
selectedInterface = interface; selectedInterface = interface;
@ -369,7 +336,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: (context) => SelectInterfaceModal( builder: (context) => SelectInterfaceModal(
interfaces: serversProvider.dhcp.data!.networkInterfaces, interfaces: dhcpProvider.dhcp!.networkInterfaces,
onSelect: (i) => setState(() { onSelect: (i) => setState(() {
clearAll(); clearAll();
selectedInterface = i; selectedInterface = i;
@ -383,8 +350,8 @@ class _DhcpWidgetState extends State<DhcpWidget> {
} }
Widget generateBody() { Widget generateBody() {
switch (serversProvider.dhcp.loadStatus) { switch (dhcpProvider.loadStatus) {
case 0: case LoadStatus.loading:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -404,7 +371,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
), ),
); );
case 1: case LoadStatus.loaded:
if (selectedInterface != null) { if (selectedInterface != null) {
return SingleChildScrollView( return SingleChildScrollView(
child: Wrap( child: Wrap(
@ -683,7 +650,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
onTap: () { onTap: () {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases( builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.leases, items: dhcpProvider.dhcp!.dhcpStatus.leases,
staticLeases: false, staticLeases: false,
) )
)); ));
@ -716,7 +683,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
onTap: () { onTap: () {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases( builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.staticLeases, items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
staticLeases: true, staticLeases: true,
) )
)); ));
@ -751,7 +718,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
if (!(Platform.isAndroid || Platform.isIOS)) { if (!(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push( SplitView.of(context).push(
DhcpLeases( DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.leases, items: dhcpProvider.dhcp!.dhcpStatus.leases,
staticLeases: false, staticLeases: false,
) )
); );
@ -759,7 +726,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
else { else {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases( builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.leases, items: dhcpProvider.dhcp!.dhcpStatus.leases,
staticLeases: false, staticLeases: false,
) )
)); ));
@ -778,7 +745,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
if (!(Platform.isAndroid || Platform.isIOS)) { if (!(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push( SplitView.of(context).push(
DhcpLeases( DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.staticLeases, items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
staticLeases: true, staticLeases: true,
) )
); );
@ -786,7 +753,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
else { else {
Navigator.push(context, MaterialPageRoute( Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases( builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.staticLeases, items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
staticLeases: true, staticLeases: true,
) )
)); ));
@ -840,7 +807,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
); );
} }
case 2: case LoadStatus.error:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(

View file

@ -10,12 +10,11 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/dhcp/delete_static_lease_modal.dart'; import 'package:adguard_home_manager/screens/settings/dhcp/delete_static_lease_modal.dart';
import 'package:adguard_home_manager/screens/settings/dhcp/add_static_lease_modal.dart'; import 'package:adguard_home_manager/screens/settings/dhcp/add_static_lease_modal.dart';
import 'package:adguard_home_manager/providers/dhcp_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/dhcp.dart'; import 'package:adguard_home_manager/models/dhcp.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class DhcpLeases extends StatelessWidget { class DhcpLeases extends StatelessWidget {
final List<Lease> items; final List<Lease> items;
@ -29,7 +28,7 @@ class DhcpLeases extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final dhcpProvider = Provider.of<DhcpProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -38,19 +37,11 @@ class DhcpLeases extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deleting); processModal.open(AppLocalizations.of(context)!.deleting);
final result = await deleteStaticLease(server: serversProvider.selectedServer!, data: { final result = await dhcpProvider.deleteLease(lease);
"mac": lease.mac,
"ip": lease.ip,
"hostname": lease.hostname
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
DhcpData data = serversProvider.dhcp.data!;
data.dhcpStatus.staticLeases = data.dhcpStatus.staticLeases.where((l) => l.mac != lease.mac).toList();
serversProvider.setDhcpData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseDeleted, label: AppLocalizations.of(context)!.staticLeaseDeleted,
@ -58,7 +49,6 @@ class DhcpLeases extends StatelessWidget {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseNotDeleted, label: AppLocalizations.of(context)!.staticLeaseNotDeleted,
@ -71,35 +61,25 @@ class DhcpLeases extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.creating); processModal.open(AppLocalizations.of(context)!.creating);
final result = await createStaticLease(server: serversProvider.selectedServer!, data: { final result = await dhcpProvider.createLease(lease);
"mac": lease.mac,
"ip": lease.ip,
"hostname": lease.hostname,
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
DhcpData data = serversProvider.dhcp.data!;
data.dhcpStatus.staticLeases.add(lease);
serversProvider.setDhcpData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseCreated, label: AppLocalizations.of(context)!.staticLeaseCreated,
color: Colors.green color: Colors.green
); );
} }
else if (result['result'] == 'error' && result['message'] == 'already_exists' ) { else if (result['success'] == false && result['error'] == 'already_exists' ) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseExists, label: AppLocalizations.of(context)!.staticLeaseExists,
color: Colors.red color: Colors.red
); );
} }
else if (result['result'] == 'error' && result['message'] == 'server_not_configured' ) { else if (result['success'] == false && result['error'] == 'server_not_configured' ) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverNotConfigured, label: AppLocalizations.of(context)!.serverNotConfigured,
@ -107,7 +87,6 @@ class DhcpLeases extends StatelessWidget {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseNotCreated, label: AppLocalizations.of(context)!.staticLeaseNotCreated,

View file

@ -4,20 +4,13 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class BootstrapDnsScreen extends StatefulWidget { class BootstrapDnsScreen extends StatefulWidget {
final ServersProvider serversProvider; const BootstrapDnsScreen({Key? key}) : super(key: key);
const BootstrapDnsScreen({
Key? key,
required this.serversProvider,
}) : super(key: key);
@override @override
State<BootstrapDnsScreen> createState() => _BootstrapDnsScreenState(); State<BootstrapDnsScreen> createState() => _BootstrapDnsScreenState();
@ -54,7 +47,9 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
@override @override
void initState() { void initState() {
for (var item in widget.serversProvider.dnsInfo.data!.bootstrapDns) { final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
for (var item in dnsProvider.dnsInfo!.bootstrapDns) {
final controller = TextEditingController(); final controller = TextEditingController();
controller.text = item; controller.text = item;
bootstrapControllers.add({ bootstrapControllers.add({
@ -68,33 +63,27 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async { void saveData() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig); processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: { final result = await dnsProvider.saveBootstrapDnsConfig({
"bootstrap_dns": bootstrapControllers.map((e) => e['controller'].text).toList(), "bootstrap_dns": bootstrapControllers.map((e) => e['controller'].text).toList(),
}); });
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
DnsInfoData data = serversProvider.dnsInfo.data!;
data.bootstrapDns = List<String>.from(bootstrapControllers.map((e) => e['controller'].text));
serversProvider.setDnsInfoData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result['log'] != null && result['log'].statusCode == '400') { else if (result['success'] == false && result['error'] == 400) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
@ -102,8 +91,6 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,

View file

@ -8,21 +8,14 @@ import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
import 'package:adguard_home_manager/screens/settings/dns/clear_dns_cache_dialog.dart'; import 'package:adguard_home_manager/screens/settings/dns/clear_dns_cache_dialog.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/clear_dns_cache.dart'; import 'package:adguard_home_manager/functions/clear_dns_cache.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class CacheConfigDnsScreen extends StatefulWidget { class CacheConfigDnsScreen extends StatefulWidget {
final ServersProvider serversProvider; const CacheConfigDnsScreen({Key? key}) : super(key: key);
const CacheConfigDnsScreen({
Key? key,
required this.serversProvider
}) : super(key: key);
@override @override
State<CacheConfigDnsScreen> createState() => _CacheConfigDnsScreenState(); State<CacheConfigDnsScreen> createState() => _CacheConfigDnsScreenState();
@ -60,10 +53,12 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
@override @override
void initState() { void initState() {
cacheSizeController.text = widget.serversProvider.dnsInfo.data!.cacheSize.toString(); final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
overrideMinTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMin.toString();
overrideMaxTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMax.toString(); cacheSizeController.text = dnsProvider.dnsInfo!.cacheSize.toString();
optimisticCache = widget.serversProvider.dnsInfo.data!.cacheOptimistic; overrideMinTtlController.text = dnsProvider.dnsInfo!.cacheTtlMin.toString();
overrideMaxTtlController.text = dnsProvider.dnsInfo!.cacheTtlMax.toString();
optimisticCache = dnsProvider.dnsInfo!.cacheOptimistic;
validData = true; validData = true;
super.initState(); super.initState();
} }
@ -71,13 +66,14 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async { void saveData() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig); processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: { final result = await dnsProvider.saveCacheCacheConfig({
"cache_size": int.parse(cacheSizeController.text), "cache_size": int.parse(cacheSizeController.text),
"cache_ttl_min": int.parse(overrideMinTtlController.text), "cache_ttl_min": int.parse(overrideMinTtlController.text),
"cache_ttl_max": int.parse(overrideMaxTtlController.text), "cache_ttl_max": int.parse(overrideMaxTtlController.text),
@ -86,23 +82,14 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
DnsInfoData data = serversProvider.dnsInfo.data!;
data.cacheSize = int.parse(cacheSizeController.text);
data.cacheTtlMin = int.parse(overrideMinTtlController.text);
data.cacheTtlMax = int.parse(overrideMaxTtlController.text);
data.cacheOptimistic = optimisticCache;
serversProvider.setDnsInfoData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result['log'] != null && result['log'].statusCode == '400') { else if (result['success'] == false && result['error'] == 400) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
@ -110,8 +97,6 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,

View file

@ -2,6 +2,8 @@
import 'dart:io'; import 'dart:io';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_split_view/flutter_split_view.dart'; import 'package:flutter_split_view/flutter_split_view.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -19,64 +21,25 @@ import 'package:adguard_home_manager/functions/clear_dns_cache.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class DnsSettings extends StatelessWidget { class DnsSettings extends StatefulWidget {
const DnsSettings({Key? key}) : super(key: key); const DnsSettings({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<DnsSettings> createState() => _DnsSettingsState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return DnsSettingsWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
}
class DnsSettingsWidget extends StatefulWidget {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const DnsSettingsWidget({
required this.serversProvider,
required this.appConfigProvider,
Key? key
}) : super(key: key);
@override
State<DnsSettingsWidget> createState() => _DnsSettingsWidgetState();
} }
class _DnsSettingsWidgetState extends State<DnsSettingsWidget> { class _DnsSettingsState extends State<DnsSettings> {
void fetchData({bool? showRefreshIndicator}) async {
widget.serversProvider.setDnsInfoLoadStatus(0, showRefreshIndicator ?? false);
final result = await getDnsInfo(server: widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setDnsInfoData(result['data']);
widget.serversProvider.setDnsInfoLoadStatus(1, true);
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setDnsInfoLoadStatus(2, true);
}
}
}
@override @override
void initState() { void initState() {
fetchData(); Provider.of<DnsProvider>(context, listen: false).fetchDnsData(showLoading: true);
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -93,8 +56,8 @@ class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
} }
Widget generateBody() { Widget generateBody() {
switch (widget.serversProvider.dnsInfo.loadStatus) { switch (dnsProvider.loadStatus) {
case 0: case LoadStatus.loading:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -115,63 +78,43 @@ class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
) )
); );
case 1: case LoadStatus.loaded:
return ListView( return ListView(
children: [ children: [
CustomListTile( CustomListTile(
title: AppLocalizations.of(context)!.upstreamDns, title: AppLocalizations.of(context)!.upstreamDns,
subtitle: AppLocalizations.of(context)!.upstreamDnsDescription, subtitle: AppLocalizations.of(context)!.upstreamDnsDescription,
onTap: () => navigate( onTap: () => navigate(const UpstreamDnsScreen()),
UpstreamDnsScreen(
serversProvider: serversProvider
)
),
icon: Icons.upload_rounded, icon: Icons.upload_rounded,
), ),
CustomListTile( CustomListTile(
title: AppLocalizations.of(context)!.bootstrapDns, title: AppLocalizations.of(context)!.bootstrapDns,
subtitle: AppLocalizations.of(context)!.bootstrapDnsDescription, subtitle: AppLocalizations.of(context)!.bootstrapDnsDescription,
onTap: () => navigate( onTap: () => navigate(const BootstrapDnsScreen()),
BootstrapDnsScreen(
serversProvider: serversProvider
)
),
icon: Icons.dns_rounded, icon: Icons.dns_rounded,
), ),
CustomListTile( CustomListTile(
title: AppLocalizations.of(context)!.privateReverseDnsServers, title: AppLocalizations.of(context)!.privateReverseDnsServers,
subtitle: AppLocalizations.of(context)!.privateReverseDnsDescription, subtitle: AppLocalizations.of(context)!.privateReverseDnsDescription,
onTap: () => navigate( onTap: () => navigate(const PrivateReverseDnsServersScreen()),
PrivateReverseDnsServersScreen(
serversProvider: serversProvider
)
),
icon: Icons.person_rounded, icon: Icons.person_rounded,
), ),
CustomListTile( CustomListTile(
title: AppLocalizations.of(context)!.dnsServerSettings, title: AppLocalizations.of(context)!.dnsServerSettings,
subtitle: AppLocalizations.of(context)!.dnsServerSettingsDescription, subtitle: AppLocalizations.of(context)!.dnsServerSettingsDescription,
onTap: () => navigate( onTap: () => navigate(const DnsServerSettingsScreen()),
DnsServerSettingsScreen(
serversProvider: serversProvider
)
),
icon: Icons.settings, icon: Icons.settings,
), ),
CustomListTile( CustomListTile(
title: AppLocalizations.of(context)!.dnsCacheConfig, title: AppLocalizations.of(context)!.dnsCacheConfig,
subtitle: AppLocalizations.of(context)!.dnsCacheConfigDescription, subtitle: AppLocalizations.of(context)!.dnsCacheConfigDescription,
onTap: () => navigate( onTap: () => navigate(const CacheConfigDnsScreen()),
CacheConfigDnsScreen(
serversProvider: serversProvider
)
),
icon: Icons.storage_rounded, icon: Icons.storage_rounded,
), ),
], ],
); );
case 2: case LoadStatus.error:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -226,7 +169,7 @@ class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
PopupMenuButton( PopupMenuButton(
itemBuilder: (context) => [ itemBuilder: (context) => [
PopupMenuItem( PopupMenuItem(
onTap: () => fetchData(showRefreshIndicator: true), onTap: () => dnsProvider.fetchDnsData(),
child: Row( child: Row(
children: [ children: [
const Icon(Icons.refresh_rounded), const Icon(Icons.refresh_rounded),

View file

@ -8,20 +8,13 @@ import 'package:adguard_home_manager/widgets/custom_radio_list_tile.dart';
import 'package:adguard_home_manager/widgets/section_label.dart'; import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class DnsServerSettingsScreen extends StatefulWidget { class DnsServerSettingsScreen extends StatefulWidget {
final ServersProvider serversProvider; const DnsServerSettingsScreen({Key? key}) : super(key: key);
const DnsServerSettingsScreen({
Key? key,
required this.serversProvider
}) : super(key: key);
@override @override
State<DnsServerSettingsScreen> createState() => _DnsServerSettingsScreenState(); State<DnsServerSettingsScreen> createState() => _DnsServerSettingsScreenState();
@ -89,56 +82,48 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
@override @override
void initState() { void initState() {
limitRequestsController.text = widget.serversProvider.dnsInfo.data!.ratelimit.toString(); final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
enableEdns = widget.serversProvider.dnsInfo.data!.ednsCsEnabled;
enableDnssec = widget.serversProvider.dnsInfo.data!.dnssecEnabled; limitRequestsController.text = dnsProvider.dnsInfo!.ratelimit.toString();
disableIpv6Resolving = widget.serversProvider.dnsInfo.data!.disableIpv6; enableEdns = dnsProvider.dnsInfo!.ednsCsEnabled;
blockingMode = widget.serversProvider.dnsInfo.data!.blockingMode; enableDnssec = dnsProvider.dnsInfo!.dnssecEnabled;
ipv4controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv4; disableIpv6Resolving = dnsProvider.dnsInfo!.disableIpv6;
ipv6controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv6; blockingMode = dnsProvider.dnsInfo!.blockingMode;
ipv4controller.text = dnsProvider.dnsInfo!.blockingIpv4;
ipv6controller.text = dnsProvider.dnsInfo!.blockingIpv6;
isDataValid = true; isDataValid = true;
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async { void saveData() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig); processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: { final result = await dnsProvider.saveDnsServerConfig({
"ratelimit": int.parse(limitRequestsController.text), "ratelimit": int.parse(limitRequestsController.text),
"edns_cs_enabled": enableEdns, "edns_cs_enabled": enableEdns,
"dnssec_enabled": enableDnssec, "dnssec_enabled": enableDnssec,
"disable_ipv6": disableIpv6Resolving, "disable_ipv6": disableIpv6Resolving,
"blocking_mode": blockingMode "blocking_mode": blockingMode,
"blocking_ipv4": ipv4controller.text,
"blocking_ipv6": ipv6controller.text
}); });
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
DnsInfoData data = serversProvider.dnsInfo.data!;
data.ratelimit = int.parse(limitRequestsController.text);
data.ednsCsEnabled = enableEdns;
data.dnssecEnabled = enableDnssec;
data.disableIpv6 = disableIpv6Resolving;
data.blockingMode = blockingMode;
data.blockingIpv4 = ipv4controller.text;
data.blockingIpv6 = ipv6controller.text;
serversProvider.setDnsInfoData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result['log'] != null && result['log'].statusCode == '400') { else if (result['success'] == false && result['error'] == 400) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
@ -146,8 +131,6 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,

View file

@ -6,20 +6,13 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class PrivateReverseDnsServersScreen extends StatefulWidget { class PrivateReverseDnsServersScreen extends StatefulWidget {
final ServersProvider serversProvider; const PrivateReverseDnsServersScreen({Key? key}) : super(key: key);
const PrivateReverseDnsServersScreen({
Key? key,
required this.serversProvider,
}) : super(key: key);
@override @override
State<PrivateReverseDnsServersScreen> createState() => _PrivateReverseDnsServersScreenState(); State<PrivateReverseDnsServersScreen> createState() => _PrivateReverseDnsServersScreenState();
@ -69,10 +62,12 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
@override @override
void initState() { void initState() {
for (var item in widget.serversProvider.dnsInfo.data!.defaultLocalPtrUpstreams) { final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
for (var item in dnsProvider.dnsInfo!.defaultLocalPtrUpstreams) {
defaultReverseResolvers.add(item); defaultReverseResolvers.add(item);
} }
for (var item in widget.serversProvider.dnsInfo.data!.localPtrUpstreams) { for (var item in dnsProvider.dnsInfo!.localPtrUpstreams) {
final controller = TextEditingController(); final controller = TextEditingController();
controller.text = item; controller.text = item;
reverseResolversControllers = [{ reverseResolversControllers = [{
@ -80,54 +75,46 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
'error': null 'error': null
}]; }];
} }
if (widget.serversProvider.dnsInfo.data!.localPtrUpstreams.isNotEmpty) { if (dnsProvider.dnsInfo!.localPtrUpstreams.isNotEmpty) {
editReverseResolvers = true; editReverseResolvers = true;
} }
usePrivateReverseDnsResolvers = widget.serversProvider.dnsInfo.data!.usePrivatePtrResolvers; usePrivateReverseDnsResolvers = dnsProvider.dnsInfo!.usePrivatePtrResolvers;
enableReverseResolve = widget.serversProvider.dnsInfo.data!.resolveClients; enableReverseResolve = dnsProvider.dnsInfo!.resolveClients;
validValues = true; validValues = true;
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async { void saveData() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig); processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: editReverseResolvers == true final result = await dnsProvider.savePrivateReverseServersConfig(
? { editReverseResolvers == true
"local_ptr_upstreams": List<String>.from(reverseResolversControllers.map((e) => e['controller'].text)), ? {
"use_private_ptr_resolvers": usePrivateReverseDnsResolvers, "local_ptr_upstreams": List<String>.from(reverseResolversControllers.map((e) => e['controller'].text)),
"resolve_clients": enableReverseResolve "use_private_ptr_resolvers": usePrivateReverseDnsResolvers,
} : { "resolve_clients": enableReverseResolve
"use_private_ptr_resolvers": usePrivateReverseDnsResolvers, } : {
"resolve_clients": enableReverseResolve "use_private_ptr_resolvers": usePrivateReverseDnsResolvers,
}); "resolve_clients": enableReverseResolve
}
);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
DnsInfoData data = serversProvider.dnsInfo.data!;
if (editReverseResolvers == true) {
data.localPtrUpstreams = List<String>.from(reverseResolversControllers.map((e) => e['controller'].text));
}
data.usePrivatePtrResolvers = usePrivateReverseDnsResolvers;
data.resolveClients = enableReverseResolve;
serversProvider.setDnsInfoData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result['log'] != null && result['log'].statusCode == '400') { else if (result['success'] == false && result['error'] == 400) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
@ -135,8 +122,6 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,

View file

@ -10,20 +10,13 @@ import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/screens/settings/dns/comment_modal.dart'; import 'package:adguard_home_manager/screens/settings/dns/comment_modal.dart';
import 'package:adguard_home_manager/widgets/custom_radio_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_radio_list_tile.dart';
import 'package:adguard_home_manager/models/dns_info.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/dns_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class UpstreamDnsScreen extends StatefulWidget { class UpstreamDnsScreen extends StatefulWidget {
final ServersProvider serversProvider; const UpstreamDnsScreen({Key? key}) : super(key: key);
const UpstreamDnsScreen({
Key? key,
required this.serversProvider,
}) : super(key: key);
@override @override
State<UpstreamDnsScreen> createState() => _UpstreamDnsScreenState(); State<UpstreamDnsScreen> createState() => _UpstreamDnsScreenState();
@ -50,7 +43,9 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
@override @override
void initState() { void initState() {
for (var item in widget.serversProvider.dnsInfo.data!.upstreamDns) { final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
for (var item in dnsProvider.dnsInfo!.upstreamDns) {
if (item == '#') { if (item == '#') {
dnsServers.add({ dnsServers.add({
'comment': item 'comment': item
@ -64,14 +59,14 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
}); });
} }
} }
upstreamMode = widget.serversProvider.dnsInfo.data!.upstreamMode; upstreamMode = dnsProvider.dnsInfo!.upstreamMode;
validValues = true; validValues = true;
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -146,28 +141,21 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig); processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: { final result = await dnsProvider.saveUpstreamDnsConfig({
"upstream_dns": dnsServers.map((e) => e['controller'] != null ? e['controller'].text : e['comment']).toList(), "upstream_dns": dnsServers.map((e) => e['controller'] != null ? e['controller'].text : e['comment']).toList(),
"upstream_mode": upstreamMode "upstream_mode": upstreamMode
}); });
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result['success'] == true) {
DnsInfoData data = serversProvider.dnsInfo.data!;
data.upstreamDns = List<String>.from(dnsServers.map((e) => e['controller'] != null ? e['controller'].text : e['comment']));
data.upstreamMode = upstreamMode;
serversProvider.setDnsInfoData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved, label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green color: Colors.green
); );
} }
else if (result['log'] != null && result['log'].statusCode == '400') { else if (result['success'] == false && result['error'] == 400) {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid, label: AppLocalizations.of(context)!.someValueNotValid,
@ -175,8 +163,6 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved, label: AppLocalizations.of(context)!.dnsConfigNotSaved,

View file

@ -6,7 +6,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/models/rewrite_rules.dart'; import 'package:adguard_home_manager/models/rewrite_rules.dart';
class AddDnsRewriteModal extends StatefulWidget { class AddDnsRewriteModal extends StatefulWidget {
final void Function(RewriteRulesData) onConfirm; final void Function(RewriteRules) onConfirm;
final bool dialog; final bool dialog;
const AddDnsRewriteModal({ const AddDnsRewriteModal({
@ -143,7 +143,7 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
? () { ? () {
Navigator.pop(context); Navigator.pop(context);
widget.onConfirm( widget.onConfirm(
RewriteRulesData( RewriteRules(
domain: domainController.text, domain: domainController.text,
answer: answerController.text answer: answerController.text
) )

View file

@ -9,87 +9,43 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/dns_rewrites/add_dns_rewrite_modal.dart'; import 'package:adguard_home_manager/screens/settings/dns_rewrites/add_dns_rewrite_modal.dart';
import 'package:adguard_home_manager/screens/settings/dns_rewrites/delete_dns_rewrite.dart'; import 'package:adguard_home_manager/screens/settings/dns_rewrites/delete_dns_rewrite.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/rewrite_rules_provider.dart';
import 'package:adguard_home_manager/models/rewrite_rules.dart'; import 'package:adguard_home_manager/models/rewrite_rules.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
class DnsRewrites extends StatelessWidget { class DnsRewritesScreen extends StatefulWidget {
const DnsRewrites({Key? key}) : super(key: key); const DnsRewritesScreen({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<DnsRewritesScreen> createState() => _DnsRewritesScreenState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return DnsRewritesWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
} }
class DnsRewritesWidget extends StatefulWidget { class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const DnsRewritesWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider
}) : super(key: key);
@override
State<DnsRewritesWidget> createState() => _DnsRewritesWidgetState();
}
class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
Future fetchData() async {
widget.serversProvider.setRewriteRulesLoadStatus(0, false);
final result = await getDnsRewriteRules(server: widget.serversProvider.selectedServer!);
if (result['result'] == 'success') {
widget.serversProvider.setRewriteRulesData(result['data']);
widget.serversProvider.setRewriteRulesLoadStatus(1, true);
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setRewriteRulesLoadStatus(2, true);
}
}
@override @override
void initState() { void initState() {
fetchData(); Provider.of<RewriteRulesProvider>(context, listen: false).fetchRules();
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final rewriteRulesProvider = Provider.of<RewriteRulesProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
void deleteDnsRewrite(RewriteRulesData rule) async { void deleteDnsRewrite(RewriteRules rule) async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deleting); processModal.open(AppLocalizations.of(context)!.deleting);
final result = await deleteDnsRewriteRule(server: serversProvider.selectedServer!, data: { final result = await rewriteRulesProvider.deleteDnsRewrite(rule);
"domain": rule.domain,
"answer": rule.answer
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
List<RewriteRulesData> data = serversProvider.rewriteRules.data!;
data = data.where((item) => item.domain != rule.domain).toList();
serversProvider.setRewriteRulesData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleDeleted, label: AppLocalizations.of(context)!.dnsRewriteRuleDeleted,
@ -97,7 +53,6 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleNotDeleted, label: AppLocalizations.of(context)!.dnsRewriteRuleNotDeleted,
@ -106,22 +61,15 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
} }
} }
void addDnsRewrite(RewriteRulesData rule) async { void addDnsRewrite(RewriteRules rule) async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingRewrite); processModal.open(AppLocalizations.of(context)!.addingRewrite);
final result = await addDnsRewriteRule(server: serversProvider.selectedServer!, data: { final result = await rewriteRulesProvider.addDnsRewrite(rule);
"domain": rule.domain,
"answer": rule.answer
});
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
List<RewriteRulesData> data = serversProvider.rewriteRules.data!;
data.add(rule);
serversProvider.setRewriteRulesData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleAdded, label: AppLocalizations.of(context)!.dnsRewriteRuleAdded,
@ -129,7 +77,6 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleNotAdded, label: AppLocalizations.of(context)!.dnsRewriteRuleNotAdded,
@ -139,8 +86,8 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
} }
Widget generateBody() { Widget generateBody() {
switch (serversProvider.rewriteRules.loadStatus) { switch (rewriteRulesProvider.loadStatus) {
case 0: case LoadStatus.loading:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -160,15 +107,22 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
), ),
); );
case 1: case LoadStatus.loaded:
if (serversProvider.rewriteRules.data!.isNotEmpty) { if (rewriteRulesProvider.rewriteRules!.isNotEmpty) {
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
await fetchData(); final result = await rewriteRulesProvider.fetchRules();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.rewriteRulesNotLoaded,
color: Colors.red
);
}
}, },
child: ListView.builder( child: ListView.builder(
padding: const EdgeInsets.only(top: 0), padding: const EdgeInsets.only(top: 0),
itemCount: serversProvider.rewriteRules.data!.length, itemCount: rewriteRulesProvider.rewriteRules!.length,
itemBuilder: (context, index) => Container( itemBuilder: (context, index) => Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -195,7 +149,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
), ),
), ),
Text( Text(
serversProvider.rewriteRules.data![index].domain, rewriteRulesProvider.rewriteRules![index].domain,
style: TextStyle( style: TextStyle(
color: Theme.of(context).colorScheme.onSurface color: Theme.of(context).colorScheme.onSurface
), ),
@ -213,7 +167,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
), ),
), ),
Text( Text(
serversProvider.rewriteRules.data![index].answer, rewriteRulesProvider.rewriteRules![index].answer,
style: TextStyle( style: TextStyle(
color: Theme.of(context).colorScheme.onSurface color: Theme.of(context).colorScheme.onSurface
), ),
@ -227,7 +181,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => DeleteDnsRewrite( builder: (context) => DeleteDnsRewrite(
onConfirm: () => deleteDnsRewrite(serversProvider.rewriteRules.data![index]) onConfirm: () => deleteDnsRewrite(rewriteRulesProvider.rewriteRules![index])
) )
) )
}, },
@ -251,7 +205,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
); );
} }
case 2: case LoadStatus.error:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(

View file

@ -16,7 +16,6 @@ import 'package:adguard_home_manager/screens/settings/encryption/error_message.d
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/base64.dart'; import 'package:adguard_home_manager/functions/base64.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -98,7 +97,7 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
void fetchData({bool? showRefreshIndicator}) async { void fetchData({bool? showRefreshIndicator}) async {
setState(() => loadStatus = 0); setState(() => loadStatus = 0);
final result = await getEncryptionSettings(server: widget.serversProvider.selectedServer!); final result = await Provider.of<ServersProvider>(context, listen: false).apiClient!.getEncryptionSettings();
if (mounted) { if (mounted) {
if (result['result'] == 'success') { if (result['result'] == 'success') {
@ -141,19 +140,21 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
Future checkValidDataApi({Map<String, dynamic>? data}) async { Future checkValidDataApi({Map<String, dynamic>? data}) async {
setState(() => certKeyValidApi = 0); setState(() => certKeyValidApi = 0);
final result = await checkEncryptionSettings(server: widget.serversProvider.selectedServer!, data: data ?? { final result = await Provider.of<ServersProvider>(context, listen: false).apiClient!.checkEncryptionSettings(
"enabled": enabled, data: data ?? {
"server_name": domainNameController.text, "enabled": enabled,
"force_https": redirectHttps, "server_name": domainNameController.text,
"port_https": httpsPortController.text != '' ? int.parse(httpsPortController.text) : null, "force_https": redirectHttps,
"port_dns_over_tls": tlsPortController.text != '' ? int.parse(tlsPortController.text) : null, "port_https": httpsPortController.text != '' ? int.parse(httpsPortController.text) : null,
"port_dns_over_quic": dnsOverQuicPortController.text != '' ? int.parse(dnsOverQuicPortController.text) : null, "port_dns_over_tls": tlsPortController.text != '' ? int.parse(tlsPortController.text) : null,
if (certificateOption == 1) "certificate_chain": encodeBase64(certificateContentController.text), "port_dns_over_quic": dnsOverQuicPortController.text != '' ? int.parse(dnsOverQuicPortController.text) : null,
if (privateKeyOption == 1 && usePreviouslySavedKey == false) "private_key": encodeBase64(pastePrivateKeyController.text), if (certificateOption == 1) "certificate_chain": encodeBase64(certificateContentController.text),
"private_key_saved": usePreviouslySavedKey, if (privateKeyOption == 1 && usePreviouslySavedKey == false) "private_key": encodeBase64(pastePrivateKeyController.text),
if (certificateOption == 0) "certificate_path": certificatePathController.text, "private_key_saved": usePreviouslySavedKey,
if (privateKeyOption == 0) "private_key_path": privateKeyPathController.text, if (certificateOption == 0) "certificate_path": certificatePathController.text,
}); if (privateKeyOption == 0) "private_key_path": privateKeyPathController.text,
}
);
if (mounted) { if (mounted) {
if (result['result'] == 'success') { if (result['result'] == 'success') {
@ -224,19 +225,21 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig); processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await saveEncryptionSettings(server: serversProvider.selectedServer!, data: { final result = await serversProvider.apiClient!.saveEncryptionSettings(
"enabled": enabled, data: {
"server_name": domainNameController.text, "enabled": enabled,
"force_https": redirectHttps, "server_name": domainNameController.text,
"port_https": int.tryParse(httpsPortController.text), "force_https": redirectHttps,
"port_dns_over_tls": int.tryParse(tlsPortController.text), "port_https": int.tryParse(httpsPortController.text),
"port_dns_over_quic": int.tryParse(dnsOverQuicPortController.text), "port_dns_over_tls": int.tryParse(tlsPortController.text),
"certificate_chain": encodeBase64(certificateContentController.text), "port_dns_over_quic": int.tryParse(dnsOverQuicPortController.text),
"private_key": encodeBase64(pastePrivateKeyController.text), "certificate_chain": encodeBase64(certificateContentController.text),
"private_key_saved": usePreviouslySavedKey, "private_key": encodeBase64(pastePrivateKeyController.text),
"certificate_path": certificatePathController.text, "private_key_saved": usePreviouslySavedKey,
"private_key_path": privateKeyPathController.text, "certificate_path": certificatePathController.text,
}); "private_key_path": privateKeyPathController.text,
}
);
processModal.close(); processModal.close();

View file

@ -2,20 +2,19 @@
import 'dart:io'; import 'dart:io';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:store_checker/store_checker.dart'; import 'package:store_checker/store_checker.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/widgets/section_label.dart';
import 'package:adguard_home_manager/functions/check_app_updates.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/functions/app_update_download_link.dart'; import 'package:adguard_home_manager/functions/app_update_download_link.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
class GeneralSettings extends StatefulWidget { class GeneralSettings extends StatefulWidget {
const GeneralSettings({Key? key}) : super(key: key); const GeneralSettings({Key? key}) : super(key: key);
@ -56,16 +55,16 @@ class _GeneralSettingsState extends State<GeneralSettings> {
Future checkUpdatesAvailable() async { Future checkUpdatesAvailable() async {
setState(() => appUpdatesStatus = AppUpdatesStatus.checking); setState(() => appUpdatesStatus = AppUpdatesStatus.checking);
final result = await checkAppUpdatesGitHub();
if (result['result'] == 'success') { final res = await checkAppUpdates(
final update = gitHubUpdateExists(appConfigProvider.getAppInfo!.version, result['body'].tagName); currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber,
if (update == true) { setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable,
appConfigProvider.setAppUpdatesAvailable(result['body']); installationSource: appConfigProvider.installationSource,
setState(() => appUpdatesStatus = AppUpdatesStatus.available); isBeta: appConfigProvider.getAppInfo!.version.contains('beta'),
} );
else {
setState(() => appUpdatesStatus = AppUpdatesStatus.recheck); if (res != null) {
} setState(() => appUpdatesStatus = AppUpdatesStatus.available);
} }
else { else {
setState(() => appUpdatesStatus = AppUpdatesStatus.recheck); setState(() => appUpdatesStatus = AppUpdatesStatus.recheck);

View file

@ -7,42 +7,19 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/custom_checkbox_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_checkbox_list_tile.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/server_status.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class SafeSearchSettingsScreen extends StatelessWidget { class SafeSearchSettingsScreen extends StatefulWidget {
const SafeSearchSettingsScreen({Key? key}) : super(key: key); const SafeSearchSettingsScreen({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { State<SafeSearchSettingsScreen> createState() => _SafeSearchSettingsScreenState();
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return SafeSearchSettingsScreenWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
} }
class SafeSearchSettingsScreenWidget extends StatefulWidget { class _SafeSearchSettingsScreenState extends State<SafeSearchSettingsScreen> {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
const SafeSearchSettingsScreenWidget({
Key? key,
required this.serversProvider,
required this.appConfigProvider
}) : super(key: key);
@override
State<SafeSearchSettingsScreenWidget> createState() => _SafeSearchSettingsScreenWidgetState();
}
class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScreenWidget> {
bool generalEnabled = false; bool generalEnabled = false;
bool bingEnabled = false; bool bingEnabled = false;
bool duckduckgoEnabled = false; bool duckduckgoEnabled = false;
@ -50,85 +27,66 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
bool pixabayEnabled = false; bool pixabayEnabled = false;
bool yandexEnabled = false; bool yandexEnabled = false;
bool youtubeEnabled = false; bool youtubeEnabled = false;
Future requestSafeSearchSettings() async { Future requestSafeSearchSettings() async {
if (mounted) { final result = await Provider.of<StatusProvider>(context, listen: false).getServerStatus();
final result = await getServerStatus(widget.serversProvider.selectedServer!); if (mounted && result == true) {
if (mounted) { final statusProvider = Provider.of<StatusProvider>(context, listen: false);
if (result['result'] == 'success') { if (statusProvider.serverStatus != null) {
widget.serversProvider.setServerStatusData(result['data']); setState(() {
widget.serversProvider.setServerStatusLoad(1); generalEnabled = statusProvider.serverStatus!.safeSearchEnabled;
setState(() { bingEnabled = statusProvider.serverStatus!.safeSeachBing ?? false;
generalEnabled = result['data'].safeSearchEnabled; duckduckgoEnabled = statusProvider.serverStatus!.safeSearchDuckduckgo ?? false;
bingEnabled = result['data'].safeSeachBing; googleEnabled = statusProvider.serverStatus!.safeSearchGoogle ?? false;
duckduckgoEnabled = result['data'].safeSearchDuckduckgo; pixabayEnabled = statusProvider.serverStatus!.safeSearchPixabay ?? false;
googleEnabled = result['data'].safeSearchGoogle; yandexEnabled = statusProvider.serverStatus!.safeSearchYandex ?? false;
pixabayEnabled = result['data'].safeSearchPixabay; youtubeEnabled = statusProvider.serverStatus!.safeSearchYoutube ?? false;
yandexEnabled = result['data'].safeSearchYandex; });
youtubeEnabled = result['data'].safeSearchYoutube;
});
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setServerStatusLoad(2);
}
} }
} }
} }
@override @override
void initState() { void initState() {
if (widget.serversProvider.serverStatus.loadStatus == 0) { final statusProvider = Provider.of<StatusProvider>(context, listen: false);
if (statusProvider.loadStatus == LoadStatus.loading) {
requestSafeSearchSettings(); requestSafeSearchSettings();
} }
else if (widget.serversProvider.serverStatus.loadStatus == 1) { else if (statusProvider.loadStatus == LoadStatus.loaded) {
generalEnabled = widget.serversProvider.serverStatus.data!.safeSearchEnabled; generalEnabled = statusProvider.serverStatus!.safeSearchEnabled;
bingEnabled = widget.serversProvider.serverStatus.data!.safeSeachBing!; bingEnabled = statusProvider.serverStatus!.safeSeachBing!;
duckduckgoEnabled = widget.serversProvider.serverStatus.data!.safeSearchDuckduckgo!; duckduckgoEnabled = statusProvider.serverStatus!.safeSearchDuckduckgo!;
googleEnabled = widget.serversProvider.serverStatus.data!.safeSearchGoogle!; googleEnabled = statusProvider.serverStatus!.safeSearchGoogle!;
pixabayEnabled = widget.serversProvider.serverStatus.data!.safeSearchPixabay!; pixabayEnabled = statusProvider.serverStatus!.safeSearchPixabay!;
yandexEnabled = widget.serversProvider.serverStatus.data!.safeSearchYandex!; yandexEnabled = statusProvider.serverStatus!.safeSearchYandex!;
youtubeEnabled = widget.serversProvider.serverStatus.data!.safeSearchYoutube!; youtubeEnabled = statusProvider.serverStatus!.safeSearchYoutube!;
} }
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveConfig() async { void saveConfig() async {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingSettings); processModal.open(AppLocalizations.of(context)!.savingSettings);
final result = await updateSafeSearchSettings( final result = await statusProvider.updateSafeSearchConfig({
server: serversProvider.selectedServer!, "enabled": generalEnabled,
body: { "bing": bingEnabled,
"enabled": generalEnabled, "duckduckgo": duckduckgoEnabled,
"bing": bingEnabled, "google": googleEnabled,
"duckduckgo": duckduckgoEnabled, "pixabay": pixabayEnabled,
"google": googleEnabled, "yandex": yandexEnabled,
"pixabay": pixabayEnabled, "youtube": youtubeEnabled
"yandex": yandexEnabled, });
"youtube": youtubeEnabled
}
);
processModal.close(); processModal.close();
if (result['result'] == 'success') { if (result == true) {
ServerStatusData data = serversProvider.serverStatus.data!;
data.safeSearchEnabled = generalEnabled;
data.safeSeachBing = bingEnabled;
data.safeSearchDuckduckgo = duckduckgoEnabled;
data.safeSearchGoogle = googleEnabled;
data.safeSearchPixabay = pixabayEnabled;
data.safeSearchYandex = yandexEnabled;
data.safeSearchYoutube = youtubeEnabled;
serversProvider.setServerStatusData(data);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully, label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
@ -137,7 +95,6 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
); );
} }
else { else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved, label: AppLocalizations.of(context)!.settingsNotSaved,
@ -148,8 +105,8 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
} }
Widget body() { Widget body() {
switch (serversProvider.serverStatus.loadStatus) { switch (statusProvider.loadStatus) {
case 0: case LoadStatus.loading:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -170,7 +127,7 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
), ),
); );
case 1: case LoadStatus.loaded:
return RefreshIndicator( return RefreshIndicator(
onRefresh: requestSafeSearchSettings, onRefresh: requestSafeSearchSettings,
child: ListView( child: ListView(
@ -274,7 +231,7 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
), ),
); );
case 2: case LoadStatus.error:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -311,7 +268,7 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
centerTitle: false, centerTitle: false,
actions: [ actions: [
IconButton( IconButton(
onPressed: serversProvider.serverStatus.loadStatus == 1 onPressed: statusProvider.loadStatus == LoadStatus.loaded
? () => saveConfig() ? () => saveConfig()
: null, : null,
icon: const Icon(Icons.save_rounded), icon: const Icon(Icons.save_rounded),

View file

@ -1,3 +1,4 @@
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -7,7 +8,6 @@ import 'package:adguard_home_manager/screens/settings/server_info/dns_addresses_
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/server_info.dart'; import 'package:adguard_home_manager/models/server_info.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -41,20 +41,19 @@ class ServerInformationWidget extends StatefulWidget {
} }
class _ServerInformationWidgetState extends State<ServerInformationWidget> { class _ServerInformationWidgetState extends State<ServerInformationWidget> {
ServerInfo serverInfo = ServerInfo(loadStatus: 0); ServerInfo serverInfo = ServerInfo(loadStatus: LoadStatus.loading);
void fetchServerInfo() async { void fetchServerInfo() async {
final result = await getServerInfo(server: widget.serversProvider.selectedServer!); final result = await Provider.of<ServersProvider>(context, listen: false).apiClient!.getServerInfo();
if (mounted) { if (mounted) {
if (result['result'] == 'success') { if (result['result'] == 'success') {
setState(() { setState(() {
serverInfo.loadStatus = 1; serverInfo.loadStatus = LoadStatus.loaded;
serverInfo.data = result['data']; serverInfo.data = result['data'];
}); });
} }
else { else {
widget.appConfigProvider.addLog(result['log']); setState(() => serverInfo.loadStatus = LoadStatus.loaded);
setState(() => serverInfo.loadStatus = 2);
} }
} }
} }
@ -69,7 +68,7 @@ class _ServerInformationWidgetState extends State<ServerInformationWidget> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget generateBody() { Widget generateBody() {
switch (serverInfo.loadStatus) { switch (serverInfo.loadStatus) {
case 0: case LoadStatus.loading:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(
@ -93,7 +92,7 @@ class _ServerInformationWidgetState extends State<ServerInformationWidget> {
), ),
); );
case 1: case LoadStatus.loaded:
return ListView( return ListView(
children: [ children: [
CustomListTile( CustomListTile(
@ -145,7 +144,7 @@ class _ServerInformationWidgetState extends State<ServerInformationWidget> {
] ]
); );
case 2: case LoadStatus.error:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: Column(

View file

@ -27,6 +27,7 @@ import 'package:adguard_home_manager/constants/strings.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart'; import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/constants/urls.dart'; import 'package:adguard_home_manager/constants/urls.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
@ -67,8 +68,9 @@ class SettingsWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -129,10 +131,14 @@ class SettingsWidget extends StatelessWidget {
], ],
body: ListView( body: ListView(
children: [ children: [
if (serversProvider.selectedServer != null && serversProvider.serverStatus.data != null) ...[ if (
serversProvider.selectedServer != null &&
statusProvider.serverStatus != null &&
serversProvider.apiClient != null
) ...[
SectionLabel(label: AppLocalizations.of(context)!.serverSettings), SectionLabel(label: AppLocalizations.of(context)!.serverSettings),
if (serverVersionIsAhead( if (serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion, currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28', referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33' referenceVersionBeta: 'v0.108.0-b.33'
) == true) settingsTile( ) == true) settingsTile(
@ -154,7 +160,7 @@ class SettingsWidget extends StatelessWidget {
title: AppLocalizations.of(context)!.dhcpSettings, title: AppLocalizations.of(context)!.dhcpSettings,
subtitle: AppLocalizations.of(context)!.dhcpSettingsDescription, subtitle: AppLocalizations.of(context)!.dhcpSettingsDescription,
thisItem: 2, thisItem: 2,
screenToNavigate: const Dhcp(), screenToNavigate: const DhcpScreen(),
), ),
settingsTile( settingsTile(
icon: Icons.dns_rounded, icon: Icons.dns_rounded,
@ -175,7 +181,7 @@ class SettingsWidget extends StatelessWidget {
title: AppLocalizations.of(context)!.dnsRewrites, title: AppLocalizations.of(context)!.dnsRewrites,
subtitle: AppLocalizations.of(context)!.dnsRewritesDescription, subtitle: AppLocalizations.of(context)!.dnsRewritesDescription,
thisItem: 5, thisItem: 5,
screenToNavigate: const DnsRewrites(), screenToNavigate: const DnsRewritesScreen(),
), ),
if (serversProvider.updateAvailable.data != null) settingsTile( if (serversProvider.updateAvailable.data != null) settingsTile(
icon: Icons.system_update_rounded, icon: Icons.system_update_rounded,
@ -217,7 +223,7 @@ class SettingsWidget extends StatelessWidget {
icon: Icons.storage_rounded, icon: Icons.storage_rounded,
title: AppLocalizations.of(context)!.servers, title: AppLocalizations.of(context)!.servers,
subtitle: serversProvider.selectedServer != null subtitle: serversProvider.selectedServer != null
? serversProvider.serverStatus.data != null ? statusProvider.serverStatus != null
? "${AppLocalizations.of(context)!.connectedTo} ${serversProvider.selectedServer!.name}" ? "${AppLocalizations.of(context)!.connectedTo} ${serversProvider.selectedServer!.name}"
: "${AppLocalizations.of(context)!.selectedServer} ${serversProvider.selectedServer!.name}" : "${AppLocalizations.of(context)!.selectedServer} ${serversProvider.selectedServer!.name}"
: AppLocalizations.of(context)!.noServerSelected, : AppLocalizations.of(context)!.noServerSelected,

View file

@ -10,7 +10,6 @@ import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/open_url.dart'; import 'package:adguard_home_manager/functions/open_url.dart';
@ -36,7 +35,7 @@ class UpdateScreen extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context); ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.requestingUpdate); processModal.open(AppLocalizations.of(context)!.requestingUpdate);
final result = await requestUpdateServer(server: serversProvider.selectedServer!); final result = await serversProvider.apiClient!.requestUpdateServer();
processModal.close(); processModal.close();
@ -56,7 +55,6 @@ class UpdateScreen extends StatelessWidget {
color: Colors.red, color: Colors.red,
labelColor: Colors.white, labelColor: Colors.white,
); );
appConfigProvider.addLog(result['log']);
} }
} }
@ -92,8 +90,8 @@ class UpdateScreen extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
serversProvider.updateAvailable.loadStatus == LoadStatus.loading serversProvider.updateAvailable.loadStatus == LoadStatus.loading
? Column( ? const Column(
children: const [ children: [
CircularProgressIndicator(), CircularProgressIndicator(),
SizedBox(height: 4) SizedBox(height: 4)
], ],

View file

@ -12,11 +12,10 @@ import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/models/applied_filters.dart'; import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class TopItemsScreen extends StatefulWidget { class TopItemsScreen extends StatefulWidget {
final String type; final String type;
@ -57,7 +56,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
@ -130,12 +129,8 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
), ),
body: RefreshIndicator( body: RefreshIndicator(
onRefresh: () async { onRefresh: () async {
final result = await getServerStatus(serversProvider.selectedServer!); final result = await statusProvider.getServerStatus();
if (result['result'] == 'success') { if (result == false) {
serversProvider.setServerStatusData(result['data']);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar( showSnacbkar(
appConfigProvider: appConfigProvider, appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverStatusNotRefreshed, label: AppLocalizations.of(context)!.serverStatusNotRefreshed,
@ -150,7 +145,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
String? name; String? name;
if (widget.isClient != null && widget.isClient == true) { if (widget.isClient != null && widget.isClient == true) {
try { try {
name = serversProvider.serverStatus.data!.clients.firstWhere((c) => c.ids.contains(screenData[index].keys.toList()[0])).name; name = statusProvider.serverStatus!.clients.firstWhere((c) => c.ids.contains(screenData[index].keys.toList()[0])).name;
} catch (e) { } catch (e) {
// ---- // // ---- //
} }

View file

@ -13,8 +13,8 @@ import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/models/applied_filters.dart'; import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class TopItemsModal extends StatefulWidget { class TopItemsModal extends StatefulWidget {
final String type; final String type;
@ -55,7 +55,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
@ -122,7 +122,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
String? name; String? name;
if (widget.isClient != null && widget.isClient == true) { if (widget.isClient != null && widget.isClient == true) {
try { try {
name = serversProvider.serverStatus.data!.clients.firstWhere((c) => c.ids.contains(screenData[index].keys.toList()[0])).name; name = statusProvider.serverStatus!.clients.firstWhere((c) => c.ids.contains(screenData[index].keys.toList()[0])).name;
} catch (e) { } catch (e) {
// ---- // // ---- //
} }

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/functions/base64.dart'; import 'package:adguard_home_manager/functions/base64.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/app_log.dart'; import 'package:adguard_home_manager/models/app_log.dart';
@ -217,6 +219,7 @@ class _AddServerModalState extends State<AddServerModal> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context, listen: false); final serversProvider = Provider.of<ServersProvider>(context, listen: false);
final statusProvider = Provider.of<StatusProvider>(context, listen: false);
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false); final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
final mediaQuery = MediaQuery.of(context); final mediaQuery = MediaQuery.of(context);
@ -257,13 +260,18 @@ class _AddServerModalState extends State<AddServerModal> {
} }
final serverCreated = await serversProvider.createServer(serverObj); final serverCreated = await serversProvider.createServer(serverObj);
if (serverCreated == null) { if (serverCreated == null) {
serversProvider.setServerStatusLoad(0); statusProvider.setServerStatusLoad(LoadStatus.loading);
final ApiClient apiClient = ApiClient(server: serverObj);
final serverStatus = await getServerStatus(serverObj); final serverStatus = await apiClient.getServerStatus();
if (serverStatus['result'] == 'success') { if (serverStatus['result'] == 'success') {
serversProvider.setServerStatusData(serverStatus['data']); statusProvider.setServerStatusData(
serversProvider.setServerStatusLoad(1); data: serverStatus['data']
);
serversProvider.setApiClient(apiClient);
statusProvider.setServerStatusLoad(LoadStatus.loaded);
if (serverStatus['data'].serverVersion.contains('a') || serverStatus['data'].serverVersion.contains('b')) { if (serverStatus['data'].serverVersion.contains('a') || serverStatus['data'].serverVersion.contains('b')) {
Navigator.pop(context); Navigator.pop(context);
widget.onUnsupportedVersion(serverStatus['data'].serverVersion); widget.onUnsupportedVersion(serverStatus['data'].serverVersion);
@ -274,7 +282,7 @@ class _AddServerModalState extends State<AddServerModal> {
} }
else { else {
appConfigProvider.addLog(serverStatus['log']); appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2); statusProvider.setServerStatusLoad(LoadStatus.error);
Navigator.pop(context); Navigator.pop(context);
} }
} }
@ -377,7 +385,8 @@ class _AddServerModalState extends State<AddServerModal> {
final serverSaved = await serversProvider.editServer(serverObj); final serverSaved = await serversProvider.editServer(serverObj);
if (serverSaved == null) { if (serverSaved == null) {
final version = await getServerVersion(serverObj); final ApiClient apiClient = ApiClient(server: serverObj);
final version = await apiClient.getServerVersion();
if ( if (
version['result'] == 'success' && version['result'] == 'success' &&
(version['data'].contains('a') || version['data'].contains('b')) // alpha or beta (version['data'].contains('a') || version['data'].contains('b')) // alpha or beta

View file

@ -17,11 +17,10 @@ class BottomNavBar extends StatelessWidget {
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
List<AppScreen> screens = serversProvider.selectedServer != null List<AppScreen> screens = serversProvider.selectedServer != null && serversProvider.apiClient != null
? screensServerConnected ? screensServerConnected
: screensSelectServer; : screensSelectServer;
String translatedName(String key) { String translatedName(String key) {
switch (key) { switch (key) {
case 'home': case 'home':
@ -47,8 +46,14 @@ class BottomNavBar extends StatelessWidget {
} }
} }
if ((serversProvider.selectedServer == null || serversProvider.apiClient == null) && appConfigProvider.selectedScreen > 1) {
appConfigProvider.setSelectedScreen(0);
}
return NavigationBar( return NavigationBar(
selectedIndex: appConfigProvider.selectedScreen, selectedIndex: (serversProvider.selectedServer == null || serversProvider.apiClient == null) && appConfigProvider.selectedScreen > 1
? 0
: appConfigProvider.selectedScreen,
destinations: screens.map((screen) => NavigationDestination( destinations: screens.map((screen) => NavigationDestination(
icon: Stack( icon: Stack(
children: [ children: [

View file

@ -9,11 +9,10 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/options_modal.dart'; import 'package:adguard_home_manager/widgets/options_modal.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/filtering_status.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/menu_option.dart'; import 'package:adguard_home_manager/models/menu_option.dart';
class DomainOptions extends StatelessWidget { class DomainOptions extends StatelessWidget {
@ -36,59 +35,33 @@ class DomainOptions extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
void blockUnblock(String domain, String newStatus) async { void blockUnblock(String domain, String newStatus) async {
final ProcessModal processModal = ProcessModal(context: context); final ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingUserFilters); processModal.open(AppLocalizations.of(context)!.savingUserFilters);
final rules = await getFilteringRules(server: serversProvider.selectedServer!); final rules = await statusProvider.blockUnblockDomain(
domain: domain,
newStatus: newStatus
);
if (rules['result'] == 'success') { processModal.close();
FilteringStatus oldStatus = serversProvider.serverStatus.data!.filteringStatus;
List<String> newRules = rules['data'].userRules.where((d) => !d.contains(domain)).toList(); if (rules == true) {
if (newStatus == 'block') { showSnacbkar(
newRules.add("||$domain^"); appConfigProvider: appConfigProvider,
} label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
else if (newStatus == 'unblock') { color: Colors.green
newRules.add("@@||$domain^"); );
}
FilteringStatus newObj = serversProvider.serverStatus.data!.filteringStatus;
newObj.userRules = newRules;
serversProvider.setFilteringStatus(newObj);
final result = await postFilteringRules(server: serversProvider.selectedServer!, data: {'rules': newRules});
processModal.close();
if (result['result'] == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesUpdated),
backgroundColor: Colors.green,
)
);
}
else {
appConfigProvider.addLog(result['log']);
serversProvider.setFilteringStatus(oldStatus);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
backgroundColor: Colors.red,
)
);
}
} }
else { else {
appConfigProvider.addLog(rules['log']); showSnacbkar(
ScaffoldMessenger.of(context).showSnackBar( appConfigProvider: appConfigProvider,
SnackBar( label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated), color: Colors.red
backgroundColor: Colors.red,
)
); );
} }
} }

View file

@ -46,8 +46,14 @@ class SideNavigationRail extends StatelessWidget {
} }
} }
if ((serversProvider.selectedServer == null || serversProvider.apiClient == null) && appConfigProvider.selectedScreen > 1) {
appConfigProvider.setSelectedScreen(0);
}
return NavigationRail( return NavigationRail(
selectedIndex: appConfigProvider.selectedScreen, selectedIndex: (serversProvider.selectedServer == null || serversProvider.apiClient == null) && appConfigProvider.selectedScreen > 1
? 0
: appConfigProvider.selectedScreen,
destinations: screens.map((screen) => NavigationRailDestination( destinations: screens.map((screen) => NavigationRailDestination(
icon: Icon( icon: Icon(
screen.icon, screen.icon,

View file

@ -11,6 +11,8 @@ import 'package:adguard_home_manager/widgets/servers_list/delete_modal.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/models/app_log.dart'; import 'package:adguard_home_manager/models/app_log.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/services/http_requests.dart';
@ -69,6 +71,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -132,18 +135,22 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
: await login(server); : await login(server);
if (result['result'] == 'success') { if (result['result'] == 'success') {
final ApiClient apiClient = ApiClient(server: server);
serversProvider.setApiClient(apiClient);
serversProvider.setSelectedServer(server); serversProvider.setSelectedServer(server);
serversProvider.setServerStatusLoad(0); statusProvider.setServerStatusLoad(LoadStatus.loading);
final serverStatus = await getServerStatus(server); final serverStatus = await apiClient.getServerStatus();
if (serverStatus['result'] == 'success') { if (serverStatus['result'] == 'success') {
serversProvider.setServerStatusData(serverStatus['data']); statusProvider.setServerStatusData(
data: serverStatus['data']
);
serversProvider.checkServerUpdatesAvailable(server); serversProvider.checkServerUpdatesAvailable(server);
serversProvider.setServerStatusLoad(1); statusProvider.setServerStatusLoad(LoadStatus.loaded);
} }
else { else {
appConfigProvider.addLog(serverStatus['log']); appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2); statusProvider.setServerStatusLoad(LoadStatus.error);
} }
process.close(); process.close();
@ -192,7 +199,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
Icon( Icon(
Icons.storage_rounded, Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null ? statusProvider.serverStatus != null
? Colors.green ? Colors.green
: Colors.orange : Colors.orange
: null, : null,
@ -225,7 +232,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
return Icon( return Icon(
Icons.storage_rounded, Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null ? statusProvider.serverStatus != null
? Colors.green ? Colors.green
: Colors.orange : Colors.orange
: null, : null,
@ -344,7 +351,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
margin: const EdgeInsets.only(right: 12), margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: serversProvider.serverStatus.data != null color: statusProvider.serverStatus != null
? Colors.green ? Colors.green
: Colors.orange, : Colors.orange,
borderRadius: BorderRadius.circular(30) borderRadius: BorderRadius.circular(30)
@ -352,14 +359,14 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
child: Row( child: Row(
children: [ children: [
Icon( Icon(
serversProvider.serverStatus.data != null statusProvider.serverStatus != null
? Icons.check ? Icons.check
: Icons.warning, : Icons.warning,
color: Colors.white, color: Colors.white,
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
serversProvider.serverStatus.data != null statusProvider.serverStatus != null
? AppLocalizations.of(context)!.connected ? AppLocalizations.of(context)!.connected
: AppLocalizations.of(context)!.selectedDisconnected, : AppLocalizations.of(context)!.selectedDisconnected,
style: const TextStyle( style: const TextStyle(

View file

@ -10,6 +10,8 @@ import 'package:adguard_home_manager/widgets/servers_list/delete_modal.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/models/app_log.dart'; import 'package:adguard_home_manager/models/app_log.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/services/http_requests.dart';
@ -36,6 +38,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context); final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context); final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width; final width = MediaQuery.of(context).size.width;
@ -99,18 +102,22 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
: await login(server); : await login(server);
if (result['result'] == 'success') { if (result['result'] == 'success') {
final ApiClient apiClient = ApiClient(server: server);
serversProvider.setApiClient(apiClient);
serversProvider.setSelectedServer(server); serversProvider.setSelectedServer(server);
serversProvider.setServerStatusLoad(0); statusProvider.setServerStatusLoad(LoadStatus.loading);
final serverStatus = await getServerStatus(server); final serverStatus = await apiClient.getServerStatus();
if (serverStatus['result'] == 'success') { if (serverStatus['result'] == 'success') {
serversProvider.setServerStatusData(serverStatus['data']); statusProvider.setServerStatusData(
data: serverStatus['data']
);
serversProvider.checkServerUpdatesAvailable(server); serversProvider.checkServerUpdatesAvailable(server);
serversProvider.setServerStatusLoad(1); statusProvider.setServerStatusLoad(LoadStatus.loaded);
} }
else { else {
appConfigProvider.addLog(serverStatus['log']); appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2); statusProvider.setServerStatusLoad(LoadStatus.error);
} }
process.close(); process.close();
@ -159,7 +166,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
Icon( Icon(
Icons.storage_rounded, Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null ? statusProvider.serverStatus != null
? Colors.green ? Colors.green
: Colors.orange : Colors.orange
: null, : null,
@ -192,7 +199,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
return Icon( return Icon(
Icons.storage_rounded, Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null ? statusProvider.serverStatus != null
? Colors.green ? Colors.green
: Colors.orange : Colors.orange
: null, : null,
@ -305,13 +312,13 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
), ),
SizedBox( SizedBox(
child: serversProvider.selectedServer != null && child: serversProvider.selectedServer != null &&
serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null && serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && statusProvider.serverStatus != null &&
serversProvider.selectedServer?.id == server.id serversProvider.selectedServer?.id == server.id
? Container( ? Container(
margin: const EdgeInsets.only(right: 12), margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && statusProvider.serverStatus != null
? Colors.green ? Colors.green
: Colors.orange, : Colors.orange,
borderRadius: BorderRadius.circular(30) borderRadius: BorderRadius.circular(30)
@ -319,14 +326,14 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
child: Row( child: Row(
children: [ children: [
Icon( Icon(
serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && statusProvider.serverStatus != null
? Icons.check ? Icons.check
: Icons.warning, : Icons.warning,
color: Colors.white, color: Colors.white,
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && serversProvider.serverStatus.data != null serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id && statusProvider.serverStatus != null
? AppLocalizations.of(context)!.connected ? AppLocalizations.of(context)!.connected
: AppLocalizations.of(context)!.selectedDisconnected, : AppLocalizations.of(context)!.selectedDisconnected,
style: const TextStyle( style: const TextStyle(

View file

@ -60,7 +60,7 @@ class _UpdateModalState extends State<UpdateModal> {
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
"${AppLocalizations.of(context)!.newVersion}: ${widget.gitHubRelease.tagName}", "${AppLocalizations.of(context)!.newVersion}: ${widget.gitHubRelease.name.replaceAll('v', '')}",
style: TextStyle( style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant color: Theme.of(context).colorScheme.onSurfaceVariant
), ),
@ -101,7 +101,9 @@ class _UpdateModalState extends State<UpdateModal> {
), ),
actions: [ actions: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: downloadLink != null
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.end,
children: [ children: [
if (downloadLink != null) TextButton( if (downloadLink != null) TextButton(
onPressed: () { onPressed: () {

View file

@ -421,7 +421,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 61; CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 38Z3B9TJTR; DEVELOPMENT_TEAM = 38Z3B9TJTR;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "AdGuard Home Manager"; INFOPLIST_KEY_CFBundleDisplayName = "AdGuard Home Manager";
@ -429,7 +429,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 2.3.2; MARKETING_VERSION = 2.4.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.jgeek00.adguard-home-manager"; PRODUCT_BUNDLE_IDENTIFIER = "com.jgeek00.adguard-home-manager";
PRODUCT_COPYRIGHT = "Copyright © 2023 JGeek00. All rights reserved."; PRODUCT_COPYRIGHT = "Copyright © 2023 JGeek00. All rights reserved.";
PRODUCT_NAME = "AdGuard Home Manager"; PRODUCT_NAME = "AdGuard Home Manager";
@ -554,7 +554,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 61; CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 38Z3B9TJTR; DEVELOPMENT_TEAM = 38Z3B9TJTR;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "AdGuard Home Manager"; INFOPLIST_KEY_CFBundleDisplayName = "AdGuard Home Manager";
@ -562,7 +562,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 2.3.2; MARKETING_VERSION = 2.4.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.jgeek00.adguard-home-manager"; PRODUCT_BUNDLE_IDENTIFIER = "com.jgeek00.adguard-home-manager";
PRODUCT_COPYRIGHT = "Copyright © 2023 JGeek00. All rights reserved."; PRODUCT_COPYRIGHT = "Copyright © 2023 JGeek00. All rights reserved.";
PRODUCT_NAME = "AdGuard Home Manager"; PRODUCT_NAME = "AdGuard Home Manager";
@ -581,7 +581,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 61; CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 38Z3B9TJTR; DEVELOPMENT_TEAM = 38Z3B9TJTR;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "AdGuard Home Manager"; INFOPLIST_KEY_CFBundleDisplayName = "AdGuard Home Manager";
@ -589,7 +589,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 2.3.2; MARKETING_VERSION = 2.4.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.jgeek00.adguard-home-manager"; PRODUCT_BUNDLE_IDENTIFIER = "com.jgeek00.adguard-home-manager";
PRODUCT_COPYRIGHT = "Copyright © 2023 JGeek00. All rights reserved."; PRODUCT_COPYRIGHT = "Copyright © 2023 JGeek00. All rights reserved.";
PRODUCT_NAME = "AdGuard Home Manager"; PRODUCT_NAME = "AdGuard Home Manager";