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
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:store_checker/store_checker.dart';
import 'package:flutter/services.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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/models/github_release.dart';
import 'package:adguard_home_manager/functions/check_app_updates.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/config/app_screens.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class Base extends StatefulWidget {
final AppConfigProvider appConfigProvider;
const Base({
Key? key,
required this.appConfigProvider,
}) : super(key: key);
const Base({Key? key}) : super(key: key);
@override
State<Base> createState() => _BaseState();
@ -41,35 +30,6 @@ class Base extends StatefulWidget {
class _BaseState extends State<Base> with WidgetsBindingObserver {
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
void initState() {
WidgetsBinding.instance.addObserver(this);
@ -77,9 +37,15 @@ class _BaseState extends State<Base> with WidgetsBindingObserver {
super.initState();
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(
context: context,
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 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 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";
}

View file

@ -3,19 +3,23 @@ import 'dart:io';
import 'package:adguard_home_manager/models/github_release.dart';
String? getAppUpdateDownloadLink(GitHubRelease gitHubRelease) {
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.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 {
try {
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;
}
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 {
return null;
}
} catch (e) {
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: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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
Future<bool> clearDnsCache(BuildContext context, Server server) async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
final ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.clearingDnsCache);
final result = await resetDnsCache(server: server);
final result = await serversProvider.apiClient!.resetDnsCache();
processModal.close();

View file

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

View file

@ -13,4 +13,17 @@ String convertTimestampLocalTimezone(DateTime timestamp, String format) {
String formatTimeOfDay(TimeOfDay timestamp, String format) {
DateFormat f = DateFormat(format);
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",
"combinedChart": "Combined chart",
"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",
"combinedChart": "Gráfico combinado",
"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/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/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/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 {
WidgetsFlutterBinding.ensureInitialized();
@ -41,9 +46,15 @@ void main() async {
await dotenv.load(fileName: '.env');
AppConfigProvider appConfigProvider = AppConfigProvider();
ServersProvider serversProvider = ServersProvider();
LogsProvider logsProvider = LogsProvider();
final AppConfigProvider appConfigProvider = AppConfigProvider();
final ServersProvider serversProvider = ServersProvider();
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();
if (Platform.isAndroid) {
@ -73,6 +84,69 @@ void main() async {
PackageInfo appInfo = await PackageInfo.fromPlatform();
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 (
(
kReleaseMode &&
@ -87,41 +161,11 @@ void main() async {
options.dsn = dotenv.env['SENTRY_DSN'];
options.sendDefaultPii = false;
},
appRunner: () => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: ((context) => serversProvider)
),
ChangeNotifierProvider(
create: ((context) => appConfigProvider)
),
ChangeNotifierProvider(
create: ((context) => logsProvider)
),
],
child: const Main(),
)
)
appRunner: () => startApp()
);
}
else {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: ((context) => serversProvider)
),
ChangeNotifierProvider(
create: ((context) => appConfigProvider)
),
ChangeNotifierProvider(
create: ((context) => logsProvider)
),
],
child: const Main(),
)
);
startApp();
}
}
@ -163,15 +207,15 @@ class _MainState extends State<Main> {
builder: (lightDynamic, darkDynamic) => MaterialApp(
title: 'AdGuard Home Manager',
theme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
? appConfigProvider.useDynamicColor == true
? lightTheme(lightDynamic)
: lightThemeOldVersions(colors[appConfigProvider.staticColor])
: lightThemeOldVersions(colors[appConfigProvider.staticColor]),
darkTheme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
? appConfigProvider.useDynamicColor == true
? darkTheme(darkDynamic)
: darkThemeOldVersions(colors[appConfigProvider.staticColor])
: darkThemeOldVersions(colors[appConfigProvider.staticColor]),
? appConfigProvider.useDynamicColor == true
? lightTheme(lightDynamic)
: lightThemeOldVersions(colors[appConfigProvider.staticColor])
: lightThemeOldVersions(colors[appConfigProvider.staticColor]),
darkTheme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
? appConfigProvider.useDynamicColor == true
? darkTheme(darkDynamic)
: darkThemeOldVersions(colors[appConfigProvider.staticColor])
: darkThemeOldVersions(colors[appConfigProvider.staticColor]),
themeMode: appConfigProvider.selectedTheme,
debugShowCheckedModeBanner: false,
localizationsDelegates: const [
@ -195,7 +239,7 @@ class _MainState extends State<Main> {
child: child!,
);
},
home: Base(appConfigProvider: appConfigProvider),
home: const Base(),
),
);
}

View file

@ -11,12 +11,10 @@ class BlockedServicesFromApi {
}
class BlockedServices {
int loadStatus = 0;
List<BlockedService>? services;
List<BlockedService> services;
BlockedServices({
this.loadStatus = 0,
this.services
required 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/safe_search.dart';
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;
final List<AutoClient> autoClientsData;
final List<AutoClient> autoClients;
final List<String> supportedTags;
ClientsAllowedBlocked? clientsAllowedBlocked;
ClientsData({
Clients({
required this.clients,
required this.autoClientsData,
required this.autoClients,
required this.supportedTags,
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))) : [],
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)) : [],
);
Map<String, dynamic> 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)),
};
}

View file

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

View file

@ -1,20 +1,4 @@
import 'dart:convert';
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;
String upstreamDnsFile;
List<String> bootstrapDns;
@ -34,9 +18,9 @@ class DnsInfoData {
List<String> localPtrUpstreams;
String blockingIpv4;
String blockingIpv6;
List<String> defaultLocalPtrUpstreams;
DnsInfoData({
DnsInfo({
required this.upstreamDns,
required this.upstreamDnsFile,
required this.bootstrapDns,
@ -59,7 +43,7 @@ class DnsInfoData {
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)) : [],
upstreamDnsFile: json["upstream_dns_file"],
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 {
LoadStatus loadStatus = LoadStatus.loading;
FilteringData? data;
Filtering({
required this.loadStatus,
this.data
});
}
class FilteringData {
final List<Filter> filters;
final List<Filter> whitelistFilters;
List<String> userRules;
@ -24,7 +6,7 @@ class FilteringData {
int interval;
bool enabled;
FilteringData({
Filtering({
required this.filters,
required this.whitelistFilters,
required this.userRules,
@ -33,7 +15,7 @@ class FilteringData {
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))) : [],
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() : [],

View file

@ -1,29 +1,13 @@
import 'dart:convert';
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 answer;
RewriteRulesData({
RewriteRules({
required this.domain,
required this.answer,
});
factory RewriteRulesData.fromJson(Map<String, dynamic> json) => RewriteRulesData(
factory RewriteRules.fromJson(Map<String, dynamic> json) => RewriteRules(
domain: json["domain"],
answer: json["answer"],
);

View file

@ -1,7 +1,9 @@
import 'dart:convert';
import 'package:adguard_home_manager/constants/enums.dart';
class ServerInfo {
int loadStatus = 0;
LoadStatus loadStatus = LoadStatus.loading;
ServerInfoData? data;
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';
class ServerStatus {
int loadStatus;
ServerStatusData? data;
ServerStatus({
required this.loadStatus,
this.data
});
}
class ServerStatusData {
final DnsStatistics stats;
final List<Client> clients;
final FilteringStatus filteringStatus;
@ -31,7 +22,7 @@ class ServerStatusData {
bool? safeSearchYandex;
bool? safeSearchYoutube;
ServerStatusData({
ServerStatus({
required this.stats,
required this.clients,
required this.filteringStatus,
@ -51,7 +42,7 @@ class ServerStatusData {
required this.safeSearchYoutube
});
factory ServerStatusData.fromJson(Map<String, dynamic> json) => ServerStatusData(
factory ServerStatus.fromJson(Map<String, dynamic> json) => ServerStatus(
stats: DnsStatistics.fromJson(json['stats']),
clients: json["clients"] != null ? List<Client>.from(json["clients"].map((x) => Client.fromJson(x))) : [],
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;
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: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/clients.dart';
import 'package:adguard_home_manager/models/logs.dart';
class LogsProvider with ChangeNotifier {
int _loadStatus = 0;
ServersProvider? _serversProvider;
update(ServersProvider? provider) {
_serversProvider = provider;
}
LoadStatus _loadStatus = LoadStatus.loading;
LogsData? _logsData;
List<AutoClient>? _clients;
int _clientsLoadStatus = 0;
DateTime? _logsOlderThan;
String _selectedResultStatus = 'all';
@ -18,13 +25,15 @@ class LogsProvider with ChangeNotifier {
int _logsQuantity = 100;
int _offset = 0;
bool _isLoadingMore = false;
AppliedFiters _appliedFilters = AppliedFiters(
selectedResultStatus: 'all',
searchText: null,
clients: null
);
int get loadStatus {
LoadStatus get loadStatus {
return _loadStatus;
}
@ -60,16 +69,15 @@ class LogsProvider with ChangeNotifier {
return _selectedClients;
}
int get clientsLoadStatus {
return _clientsLoadStatus;
}
AppliedFiters get appliedFilters {
return _appliedFilters;
}
bool get isLoadingMore {
return _isLoadingMore;
}
void setLoadStatus(int value) {
void setLoadStatus(LoadStatus value) {
_loadStatus = value;
notifyListeners();
}
@ -83,11 +91,6 @@ class LogsProvider with ChangeNotifier {
_clients = clients;
notifyListeners();
}
void setClientsLoadStatus(int status) {
_clientsLoadStatus = status;
notifyListeners();
}
void setLogsOlderThan(DateTime? value) {
_logsOlderThan = value;
@ -130,4 +133,136 @@ class LogsProvider with ChangeNotifier {
_appliedFilters = value;
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: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/update_available.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/services/db/queries.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
@ -24,51 +14,16 @@ class ServersProvider with ChangeNotifier {
List<Server> _serversList = [];
Server? _selectedServer;
final ServerStatus _serverStatus = ServerStatus(
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
);
ApiClient? _apiClient;
final UpdateAvailable _updateAvailable = UpdateAvailable(
loadStatus: LoadStatus.loading,
data: null,
);
FilteringStatus? _filteringStatus;
ApiClient? get apiClient {
return _apiClient;
}
List<Server> get serversList {
return _serversList;
@ -78,54 +33,6 @@ class ServersProvider with ChangeNotifier {
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 {
return _updateAvailable;
}
@ -144,151 +51,6 @@ class ServersProvider with ChangeNotifier {
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) {
_updateAvailable.loadStatus = status;
if (notify == true) {
@ -301,6 +63,11 @@ class ServersProvider with ChangeNotifier {
notifyListeners();
}
void setApiClient(ApiClient client) {
_apiClient = client;
notifyListeners();
}
Future<dynamic> createServer(Server server) async {
final saved = await saveServerQuery(_dbInstance!, server);
if (saved == null) {
@ -360,6 +127,11 @@ class ServersProvider with ChangeNotifier {
}
}).toList();
_serversList = newServers;
if (selectedServer != null &&server.id == selectedServer!.id) {
_apiClient = ApiClient(server: server);
}
notifyListeners();
return null;
}
@ -372,6 +144,7 @@ class ServersProvider with ChangeNotifier {
final result = await removeServerQuery(_dbInstance!, server.id);
if (result == true) {
_selectedServer = null;
_apiClient = null;
List<Server> newServers = _serversList.where((s) => s.id != server.id).toList();
_serversList = newServers;
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 {
setUpdateAvailableLoadStatus(LoadStatus.loading, true);
final result = await checkServerUpdates(server: server);
final result = await _apiClient!.checkServerUpdates();
if (result['result'] == 'success') {
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') {
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) {
Server? defaultServer;
for (var server in data) {
final Server serverObj = Server(
id: server['id'],
@ -574,20 +212,21 @@ class ServersProvider with ChangeNotifier {
);
_serversList.add(serverObj);
if (convertFromIntToBool(server['defaultServer']) == true) {
_selectedServer = 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;
}
defaultServer = serverObj;
}
}
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/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/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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class AddedList extends StatefulWidget {
final ScrollController scrollController;
final LoadStatus loadStatus;
final List<Client> data;
final Future Function() fetchClients;
final void Function(Client) onClientSelected;
final Client? selectedClient;
final bool splitView;
@ -38,9 +34,7 @@ class AddedList extends StatefulWidget {
const AddedList({
Key? key,
required this.scrollController,
required this.loadStatus,
required this.data,
required this.fetchClients,
required this.onClientSelected,
this.selectedClient,
required this.splitView
@ -76,7 +70,8 @@ class _AddedListState extends State<AddedList> {
@override
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 width = MediaQuery.of(context).size.width;
@ -85,31 +80,11 @@ class _AddedListState extends State<AddedList> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await postUpdateClient(server: serversProvider.selectedServer!, data: {
'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')
});
final result = await clientsProvider.editClient(client);
processModal.close();
if (result['result'] == 'success') {
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);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
@ -117,8 +92,6 @@ class _AddedListState extends State<AddedList> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotUpdated,
@ -131,19 +104,14 @@ class _AddedListState extends State<AddedList> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.removingClient);
final result = await postDeleteClient(server: serversProvider.selectedServer!, name: client.name);
final result = await clientsProvider.deleteClient(client);
processModal.close();
if (result['result'] == 'success') {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients = clientsData.clients.where((c) => c.name != client.name).toList();
serversProvider.setClientsData(clientsData);
if (result == true) {
if (widget.splitView == true) {
SplitView.of(context).popUntil(0);
}
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
@ -151,15 +119,13 @@ class _AddedListState extends State<AddedList> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotDeleted,
color: Colors.red
);
}
}
}
void openClientModal(Client client) {
if (width > 900 || !(Platform.isAndroid | Platform.isIOS)) {
@ -168,7 +134,7 @@ class _AddedListState extends State<AddedList> {
context: context,
builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient,
client: client,
dialog: true,
@ -180,7 +146,7 @@ class _AddedListState extends State<AddedList> {
fullscreenDialog: true,
builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient,
client: client,
dialog: false,
@ -240,7 +206,7 @@ class _AddedListState extends State<AddedList> {
onLongPress: openOptionsModal,
onEdit: openClientModal,
splitView: widget.splitView,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
noData: SizedBox(
width: double.maxFinite,
@ -260,7 +226,7 @@ class _AddedListState extends State<AddedList> {
),
const SizedBox(height: 30),
TextButton.icon(
onPressed: widget.fetchClients,
onPressed: () => clientsProvider.fetchClients(updateLoading: true),
icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh),
)
@ -290,8 +256,10 @@ class _AddedListState extends State<AddedList> {
],
),
),
loadStatus: widget.loadStatus,
onRefresh: widget.fetchClients,
loadStatus: statusProvider.loadStatus == LoadStatus.loading || clientsProvider.loadStatus == LoadStatus.loading
? LoadStatus.loading
: clientsProvider.loadStatus,
onRefresh: () => clientsProvider.fetchClients(updateLoading: false),
fab: const ClientsFab(),
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/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';
class ClientScreen extends StatefulWidget {
@ -130,7 +131,8 @@ class _ClientScreenState extends State<ClientScreen> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
void createClient() {
final Client client = Client(
@ -200,7 +202,7 @@ class _ClientScreenState extends State<ClientScreen> {
context: context,
builder: (context) => TagsModal(
selectedTags: selectedTags,
tags: serversProvider.clients.data!.supportedTags,
tags: clientsProvider.clients!.supportedTags,
onConfirm: (selected) => setState(() => selectedTags = selected),
)
);
@ -506,7 +508,7 @@ class _ClientScreenState extends State<ClientScreen> {
),
if (
serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
@ -531,7 +533,7 @@ class _ClientScreenState extends State<ClientScreen> {
),
if (
serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == 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/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/models/server.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/providers/servers_provider.dart';
class Clients extends StatelessWidget {
class Clients extends StatefulWidget {
const Clients({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
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,
);
}
State<Clients> createState() => _ClientsState();
}
class ClientsWidget extends StatefulWidget {
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 {
class _ClientsState extends State<Clients> with TickerProviderStateMixin {
late TabController tabController;
final ScrollController scrollController = ScrollController();
bool searchMode = false;
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
void initState() {
fetchClients();
final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
clientsProvider.fetchClients(updateLoading: true);
super.initState();
tabController = TabController(
initialIndex: 0,
length: 2,
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) {
@ -98,6 +54,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
@override
Widget build(BuildContext 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;
@ -137,10 +94,8 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
children: [
ClientsList(
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.filteredActiveClients : [],
fetchClients: fetchClients,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.filteredActiveClients : [],
onClientSelected: (client) => Navigator.push(context, MaterialPageRoute(
builder: (context) => LogsListClient(
ip: client.ip,
@ -153,10 +108,8 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
),
AddedList(
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.filteredAddedClients : [],
fetchClients: fetchClients,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.filteredAddedClients : [],
onClientSelected: (client) => Navigator.push(context, MaterialPageRoute(
builder: (context) => LogsListClient(
ip: client.ids[0],
@ -190,7 +143,6 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
child: ClientsDesktopView(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
fetchClients: fetchClients,
)
);
}
@ -203,7 +155,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
title: Text(AppLocalizations.of(context)!.clients),
centerTitle: false,
actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded) ...[
if (clientsProvider.loadStatus == LoadStatus.loaded) ...[
IconButton(
onPressed: () => {
Navigator.push(context, MaterialPageRoute(
@ -240,7 +192,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
setState(() {
searchMode = false;
searchController.text = "";
serversProvider.setSearchTermClients(null);
clientsProvider.setSearchTermClients(null);
});
},
icon: const Icon(Icons.arrow_back_rounded)
@ -249,13 +201,13 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
Expanded(
child: TextField(
controller: searchController,
onChanged: (value) => serversProvider.setSearchTermClients(value),
onChanged: (value) => clientsProvider.setSearchTermClients(value),
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: () {
setState(() {
searchController.text = "";
serversProvider.setSearchTermClients(null);
clientsProvider.setSearchTermClients(null);
});
},
icon: const Icon(Icons.clear_rounded)
@ -281,7 +233,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
centerTitle: false,
forceElevated: innerBoxIsScrolled,
actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded && searchMode == false) ...[
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
IconButton(
onPressed: () => setState(() => searchMode = true),
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/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/models/clients.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 {
final ServersProvider serversProvider;
final AppConfigProvider appConfigProvider;
final Future Function() fetchClients;
const ClientsDesktopView({
Key? key,
required this.serversProvider,
required this.appConfigProvider,
required this.fetchClients
}) : super(key: key);
@override
@ -55,6 +54,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
PreferredSizeWidget tabBar() {
@ -92,10 +92,8 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
children: [
ClientsList(
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.filteredActiveClients : [],
fetchClients: widget.fetchClients,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.filteredActiveClients : [],
onClientSelected: (client) => setState(() {
selectedAddedClient = null;
selectedActiveClient = client;
@ -114,10 +112,8 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
),
AddedList(
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.filteredAddedClients : [],
fetchClients: widget.fetchClients,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.filteredAddedClients : [],
onClientSelected: (client) => setState(() {
selectedActiveClient = null;
selectedAddedClient = client;
@ -146,7 +142,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
setState(() {
searchMode = false;
searchController.text = "";
serversProvider.setSearchTermClients(null);
clientsProvider.setSearchTermClients(null);
});
},
icon: const Icon(Icons.arrow_back_rounded)
@ -155,13 +151,13 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
Expanded(
child: TextField(
controller: searchController,
onChanged: (value) => serversProvider.setSearchTermClients(value),
onChanged: (value) => clientsProvider.setSearchTermClients(value),
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: () {
setState(() {
searchController.text = "";
serversProvider.setSearchTermClients(null);
clientsProvider.setSearchTermClients(null);
});
},
icon: const Icon(Icons.clear_rounded)
@ -195,7 +191,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
title: title(),
centerTitle: false,
actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded && searchMode == false) ...[
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
IconButton(
onPressed: () => setState(() => searchMode = true),
icon: const Icon(Icons.search),
@ -226,7 +222,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
centerTitle: false,
forceElevated: innerBoxIsScrolled,
actions: [
if (serversProvider.clients.loadStatus == LoadStatus.loaded && searchMode == false) ...[
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
IconButton(
onPressed: () => setState(() => searchMode = true),
icon: const Icon(Icons.search),

View file

@ -1,18 +1,17 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/clients/active_client_tile.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/constants/enums.dart';
class ClientsList extends StatelessWidget {
final ScrollController scrollController;
final LoadStatus loadStatus;
final List<AutoClient> data;
final Future Function() fetchClients;
final void Function(AutoClient) onClientSelected;
final AutoClient? selectedClient;
final bool splitView;
@ -21,9 +20,7 @@ class ClientsList extends StatelessWidget {
const ClientsList({
Key? key,
required this.scrollController,
required this.loadStatus,
required this.data,
required this.fetchClients,
required this.onClientSelected,
this.selectedClient,
required this.splitView,
@ -32,6 +29,8 @@ class ClientsList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final clientsProvider = Provider.of<ClientsProvider>(context);
return CustomTabContentList(
listPadding: splitView == true
? const EdgeInsets.only(top: 8)
@ -79,7 +78,7 @@ class ClientsList extends StatelessWidget {
),
const SizedBox(height: 30),
TextButton.icon(
onPressed: fetchClients,
onPressed: () => clientsProvider.fetchClients(updateLoading: false),
icon: const Icon(Icons.refresh_rounded),
label: Text(AppLocalizations.of(context)!.refresh)
)
@ -110,8 +109,8 @@ class ClientsList extends StatelessWidget {
],
),
),
loadStatus: loadStatus,
onRefresh: fetchClients
loadStatus: clientsProvider.loadStatus,
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/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/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/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
class ClientsFab extends StatelessWidget {
@ -22,8 +20,9 @@ class ClientsFab extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(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;
@ -31,24 +30,11 @@ class ClientsFab extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await postAddClient(
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')
);
final result = await clientsProvider.addClient(client);
processModal.close();
if (result['result'] == 'success') {
ClientsData clientsData = serversProvider.clients.data!;
clientsData.clients.add(client);
serversProvider.setClientsData(clientsData);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientAddedSuccessfully,
@ -56,8 +42,6 @@ class ClientsFab extends StatelessWidget {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotAdded,
@ -73,7 +57,7 @@ class ClientsFab extends StatelessWidget {
context: context,
builder: (BuildContext context) => ClientScreen(
onConfirm: confirmAddClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
dialog: true,
)
);
@ -83,7 +67,7 @@ class ClientsFab extends StatelessWidget {
fullscreenDialog: true,
builder: (BuildContext context) => ClientScreen(
onConfirm: confirmAddClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
dialog: false,
)
));

View file

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:async/async.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/logs/log_tile.dart';
@ -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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
class LogsListClient extends StatefulWidget {
final String ip;
@ -53,6 +53,8 @@ class _LogsListClientState extends State<LogsListClient> {
String? responseStatus,
String? searchText,
}) async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
int offst = inOffset ?? offset;
if (loadingMore != null && loadingMore == true) {
@ -62,8 +64,7 @@ class _LogsListClientState extends State<LogsListClient> {
if (cancelableRequest != null) cancelableRequest!.cancel();
cancelableRequest = CancelableOperation.fromFuture(
getLogs(
server: widget.serversProvider.selectedServer!,
serversProvider.apiClient!.getLogs(
count: logsQuantity,
offset: offst,
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/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/services/http_requests.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/snackbar.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/widgets/section_label.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
class SearchClients extends StatelessWidget {
class SearchClients extends StatefulWidget {
const SearchClients({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
return SearchClientsWidget(
serversProvider: serversProvider,
);
}
State<SearchClients> createState() => _SearchClientsState();
}
class SearchClientsWidget extends StatefulWidget {
final ServersProvider serversProvider;
const SearchClientsWidget({
Key? key,
required this.serversProvider,
}) : super(key: key);
@override
State<SearchClientsWidget> createState() => _SearchClientsWidgetState();
}
class _SearchClientsWidgetState extends State<SearchClientsWidget> {
class _SearchClientsState extends State<SearchClients> {
late ScrollController scrollController;
final TextEditingController searchController = TextEditingController();
@ -86,11 +68,13 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
@override
void initState() {
final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
scrollController = ScrollController()..addListener(scrollListener);
setState(() {
clients = widget.serversProvider.clients.data!.clients;
autoClients = widget.serversProvider.clients.data!.autoClientsData;
clients = clientsProvider.clients!.clients;
autoClients = clientsProvider.clients!.autoClients;
});
super.initState();
@ -98,7 +82,8 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
@override
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 width = MediaQuery.of(context).size.width;
@ -107,19 +92,11 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.removingClient);
final result = await postDeleteClient(server: serversProvider.selectedServer!, name: client.name);
final result = await clientsProvider.deleteClient(client);
processModal.close();
if (result['result'] == 'success') {
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);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientDeletedSuccessfully,
@ -127,44 +104,23 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotDeleted,
color: Colors.red
);
}
}
}
void confirmEditClient(Client client) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingClient);
final result = await postUpdateClient(server: serversProvider.selectedServer!, data: {
'name': client.name,
'data': client.toJson()
});
final result = await clientsProvider.editClient(client);
processModal.close();
if (result['result'] == 'success') {
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);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientUpdatedSuccessfully,
@ -172,8 +128,6 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.clientNotUpdated,
@ -189,7 +143,7 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
context: context,
builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient,
client: client,
dialog: true,
@ -201,7 +155,7 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
fullscreenDialog: true,
builder: (BuildContext context) => ClientScreen(
onConfirm: confirmEditClient,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
onDelete: deleteClient,
client: client,
dialog: false,
@ -356,7 +310,7 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
Icons.search_rounded,
size: 19,
color: serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true

View file

@ -2,11 +2,10 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.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/servers_provider.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';
class ServicesModal extends StatelessWidget {
class ServicesModal extends StatefulWidget {
final List<String> blockedServices;
final void Function(List<String>) onConfirm;
@ -17,56 +16,20 @@ class ServicesModal extends StatelessWidget {
}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return ServicesModalWidget(
blockedServices: blockedServices,
onConfirm: onConfirm,
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
State<ServicesModal> createState() => _ServicesModalStateWidget();
}
class ServicesModalWidget extends StatefulWidget {
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> {
class _ServicesModalStateWidget extends State<ServicesModal> {
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
void initState() {
if (widget.serversProvider.blockedServicesList.loadStatus != 1) {
loadBlockedServices();
final filteringProvider = Provider.of<FilteringProvider>(context, listen: false);
if (filteringProvider.blockedServicesLoadStatus != LoadStatus.loaded) {
filteringProvider.getBlockedServices();
}
blockedServices = widget.blockedServices;
@ -88,11 +51,11 @@ class _ServicesModalStateWidget extends State<ServicesModalWidget> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(context);
Widget content() {
switch (serversProvider.blockedServicesList.loadStatus) {
case 0:
switch (filteringProvider.blockedServicesLoadStatus) {
case LoadStatus.loading:
return Padding(
padding: const EdgeInsets.all(24),
child: SizedBox(
@ -116,34 +79,34 @@ class _ServicesModalStateWidget extends State<ServicesModalWidget> {
),
);
case 1:
case LoadStatus.loaded:
return SizedBox(
width: double.minPositive,
height: MediaQuery.of(context).size.height*0.5,
child: ListView.builder(
shrinkWrap: true,
itemCount: serversProvider.blockedServicesList.services!.length,
itemCount: filteringProvider.blockedServices!.services.length,
itemBuilder: (context, index) => CheckboxListTile(
title: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
serversProvider.blockedServicesList.services![index].name,
filteringProvider.blockedServices!.services[index].name,
style: TextStyle(
fontWeight: FontWeight.normal,
color: Theme.of(context).colorScheme.onSurface
),
),
),
value: blockedServices.contains(serversProvider.blockedServicesList.services![index].id),
value: blockedServices.contains(filteringProvider.blockedServices!.services[index].id),
checkboxShape: RoundedRectangleBorder(
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(
padding: const EdgeInsets.all(24),
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_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/services/http_requests.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/constants/enums.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class AddFiltersButton extends StatelessWidget {
final String type;
@ -29,7 +26,7 @@ class AddFiltersButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
@ -38,18 +35,11 @@ class AddFiltersButton extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingRule);
final List<String> newRules = serversProvider.filtering.data!.userRules;
newRules.add(rule);
final result = await setCustomRules(server: serversProvider.selectedServer!, rules: newRules);
final result = await filteringProvider.addCustomRule(rule);
processModal.close();
if (result['result'] == 'success') {
FilteringData filteringData = serversProvider.filtering.data!;
filteringData.userRules = newRules;
serversProvider.setFilteringData(filteringData);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleAddedSuccessfully,
@ -57,8 +47,6 @@ class AddFiltersButton extends StatelessWidget {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotAdded,
@ -95,58 +83,25 @@ class AddFiltersButton extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.addingList);
final result1 = await addFilteringList(server: serversProvider.selectedServer!, data: {
'name': name,
'url': url,
'whitelist': type == 'whitelist' ? true : false
});
final result = await filteringProvider.addList(name: name, url: url, type: type);
if (result1['result'] == 'success') {
if (result1['data'].toString().contains("OK")) {
final result2 = await getFiltering(server: serversProvider.selectedServer!);
final items = result1['data'].toString().split(' ')[1];
processModal.close();
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();
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
);
}
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: "${AppLocalizations.of(context)!.listAdded} ${result['data']}.",
color: Colors.green
);
}
else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains("Couldn't fetch filter from url")) {
processModal.close();
appConfigProvider.addLog(result1['log']);
else if (result['success'] == false && result['error'] == 'invalid_url') {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listUrlInvalid,
color: Colors.red
);
}
else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains('Filter URL already added')) {
processModal.close();
appConfigProvider.addLog(result1['log']);
else if (result['success'] == false && result['error'] == 'url_exists') {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listAlreadyAdded,
@ -154,9 +109,6 @@ class AddFiltersButton extends StatelessWidget {
);
}
else {
processModal.close();
appConfigProvider.addLog(result1['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
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/functions/snackbar.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/servers_provider.dart';
class BlockedServicesScreen extends StatelessWidget {
class BlockedServicesScreen extends StatefulWidget {
final bool dialog;
const BlockedServicesScreen({
@ -20,63 +20,28 @@ class BlockedServicesScreen extends StatelessWidget {
}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return BlockedServicesScreenWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
dialog: dialog,
);
}
State<BlockedServicesScreen> createState() => _BlockedServicesScreenStateWidget();
}
class BlockedServicesScreenWidget extends StatefulWidget {
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> {
class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreen> {
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
void initState() {
if (widget.serversProvider.blockedServicesList.loadStatus != 1) {
loadBlockedServices();
final filteringProvider = Provider.of<FilteringProvider>(context, listen: false);
if (filteringProvider.blockedServicesLoadStatus != LoadStatus.loaded) {
filteringProvider.loadBlockedServices(showLoading: true);
}
values = widget.serversProvider.filtering.data!.blockedServices;
values = filteringProvider.filtering!.blockedServices;
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void updateValues(bool value, BlockedService item) {
@ -96,13 +61,11 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updating);
final result = await setBlockedServices(server: serversProvider.selectedServer!, data: values);
final result = await filteringProvider.updateBlockedServices(values);
processModal.close();
if (result['result'] == 'success') {
serversProvider.setBlockedServices(values);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.blockedServicesUpdated,
@ -119,8 +82,8 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
}
Widget body() {
switch (serversProvider.blockedServicesList.loadStatus) {
case 0:
switch (filteringProvider.blockedServicesLoadStatus) {
case LoadStatus.loading:
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
width: double.maxFinite,
@ -142,15 +105,15 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
),
);
case 1:
case LoadStatus.loaded:
return ListView.builder(
itemCount: serversProvider.blockedServicesList.services!.length,
itemCount: filteringProvider.blockedServices!.services.length,
itemBuilder: (context, index) => Material(
color: Colors.transparent,
child: InkWell(
onTap: () => updateValues(
values.contains(serversProvider.blockedServicesList.services![index].id),
serversProvider.blockedServicesList.services![index]
values.contains(filteringProvider.blockedServices!.services[index].id),
filteringProvider.blockedServices!.services[index]
),
child: Padding(
padding: const EdgeInsets.only(
@ -163,17 +126,17 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
serversProvider.blockedServicesList.services![index].name,
filteringProvider.blockedServices!.services[index].name,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface
),
),
Checkbox(
value: values.contains(serversProvider.blockedServicesList.services![index].id),
value: values.contains(filteringProvider.blockedServices!.services[index].id),
onChanged: (value) => updateValues(
value!,
serversProvider.blockedServicesList.services![index]
filteringProvider.blockedServices!.services[index]
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)
@ -186,7 +149,7 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
)
);
case 2:
case LoadStatus.error:
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
width: double.maxFinite,
@ -281,7 +244,16 @@ class _BlockedServicesScreenStateWidget extends State<BlockedServicesScreenWidge
],
),
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()
),
);

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/functions/get_filtered_status.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class CheckHostModal extends StatefulWidget {
@ -57,11 +56,11 @@ class _CheckHostModalState extends State<CheckHostModal> {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void checkHost() async {
setState(() => resultWidget = checking());
final result = await serversProvider.apiClient!.checkHostFiltered(host: domainController.text);
if (mounted) {
setState(() => resultWidget = checking());
final result = await checkHostFiltered(server: serversProvider.selectedServer!, host: domainController.text);
if (result['result'] == 'success') {
final status = getFilteredStatus(context, appConfigProvider, result['data']['reason'], true);
if (mounted) {
@ -98,26 +97,24 @@ class _CheckHostModalState extends State<CheckHostModal> {
}
}
else {
if (mounted) {
setState(() => resultWidget = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.cancel,
size: 18,
setState(() => resultWidget = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.cancel,
size: 18,
color: Colors.red,
),
const SizedBox(width: 10),
Text(
AppLocalizations.of(context)!.check,
style: const TextStyle(
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/rendering.dart';
import 'package:provider/provider.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/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/providers/filtering_provider.dart';
class CustomRulesList extends StatefulWidget {
final LoadStatus loadStatus;
final ScrollController scrollController;
final List<String> data;
final Future<void> Function() fetchData;
final void Function(String) onRemoveCustomRule;
const CustomRulesList({
@ -21,7 +24,6 @@ class CustomRulesList extends StatefulWidget {
required this.loadStatus,
required this.scrollController,
required this.data,
required this.fetchData,
required this.onRemoveCustomRule
}) : super(key: key);
@ -55,6 +57,9 @@ class _CustomRulesListState extends State<CustomRulesList> {
@override
Widget build(BuildContext context) {
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
bool checkIfComment(String value) {
final regex = RegExp(r'^(!|#).*$');
if (regex.hasMatch(value)) {
@ -155,7 +160,16 @@ class _CustomRulesListState extends State<CustomRulesList> {
),
const SizedBox(height: 30),
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),
label: Text(AppLocalizations.of(context)!.refresh),
)
@ -186,7 +200,16 @@ class _CustomRulesListState extends State<CustomRulesList> {
),
),
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(
type: 'custom_rule',
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/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/providers/filtering_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/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/providers/servers_provider.dart';
class Filters extends StatelessWidget {
class Filters extends StatefulWidget {
const Filters({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return FiltersWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider
);
}
State<Filters> createState() => _FiltersState();
}
class FiltersWidget extends StatefulWidget {
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);
}
}
}
class _FiltersState extends State<Filters> {
List<AutoClient> generateClientsList(List<AutoClient> clients, List<String> ips) {
return clients.where((client) => ips.contains(client.ip)).toList();
}
@override
void initState() {
fetchFilters();
final filteringProvider = Provider.of<FilteringProvider>(context, listen: false);
filteringProvider.fetchFilters(showLoading: true);
super.initState();
}
@override
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 width = MediaQuery.of(context).size.width;
void fetchUpdateLists() async {
void updateLists() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingLists);
final result = await updateLists(server: serversProvider.selectedServer!);
final result = await filteringProvider.updateLists();
if (result['result'] == 'success') {
final result2 = await getFiltering(server: widget.serversProvider.selectedServer!);
processModal.close();
processModal.close();
if (mounted) {
if (result2['result'] == 'success') {
widget.serversProvider.setFilteringData(result2['data']);
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
);
}
}
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: "${result['data']['updated']} ${AppLocalizations.of(context)!.listsUpdated}",
color: Colors.green
);
}
else {
processModal.close();
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.listsNotUpdated,
@ -158,21 +100,16 @@ class _FiltersWidgetState extends State<FiltersWidget> {
void enableDisableFiltering() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(
serversProvider.serverStatus.data!.filteringEnabled == true
statusProvider.serverStatus!.filteringEnabled == true
? AppLocalizations.of(context)!.disableFiltering
: AppLocalizations.of(context)!.enableFiltering
);
final result = await updateFiltering(
server: serversProvider.selectedServer!,
enable: !serversProvider.serverStatus.data!.filteringEnabled
);
final result = await filteringProvider.enableDisableFiltering();
processModal.close();
if (result['result'] == 'success') {
serversProvider.setFilteringProtectionStatus(!serversProvider.serverStatus.data!.filteringEnabled);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.filteringStatusUpdated,
@ -192,16 +129,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.changingUpdateFrequency);
final result = await requestChangeUpdateFrequency(server: serversProvider.selectedServer!, data: {
"enabled": serversProvider.filtering.data!.enabled,
"interval": value
});
final result = await filteringProvider.changeUpdateFrequency(value);
processModal.close();
if (result['result'] == 'success') {
serversProvider.setFiltersUpdateFrequency(value);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.updateFrequencyChanged,
@ -244,17 +176,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deletingRule);
final List<String> newRules = serversProvider.filtering.data!.userRules.where((r) => r != rule).toList();
final result = await setCustomRules(server: serversProvider.selectedServer!, rules: newRules);
final result = await filteringProvider.removeCustomRule(rule);
processModal.close();
if (result['result'] == 'success') {
FilteringData filteringData = serversProvider.filtering.data!;
filteringData.userRules = newRules;
serversProvider.setFilteringData(filteringData);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleRemovedSuccessfully,
@ -262,13 +188,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.ruleNotRemoved,
color: Colors.red
);
);
}
}
@ -307,11 +231,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
}
List<Widget> actions() {
if (serversProvider.filtering.loadStatus == LoadStatus.loaded) {
if (filteringProvider.loadStatus == LoadStatus.loaded) {
return [
IconButton(
if (statusProvider.loadStatus == LoadStatus.loaded) IconButton(
onPressed: enableDisableFiltering,
tooltip: serversProvider.filtering.data!.enabled == true
tooltip: filteringProvider.filtering!.enabled == true
? AppLocalizations.of(context)!.disableFiltering
: AppLocalizations.of(context)!.enableFiltering,
icon: Stack(
@ -328,11 +252,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
color: Colors.white
),
child: Icon(
serversProvider.filtering.data!.enabled == true
filteringProvider.filtering!.enabled == true
? Icons.check_circle_rounded
: Icons.cancel,
size: 12,
color: serversProvider.filtering.data!.enabled == true
color: filteringProvider.filtering!.enabled == true
? appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary
: Colors.green
@ -353,7 +277,7 @@ class _FiltersWidgetState extends State<FiltersWidget> {
showDialog(
context: context,
builder: (context) => UpdateIntervalListsModal(
interval: serversProvider.filtering.data!.interval,
interval: filteringProvider.filtering!.interval,
onChange: setUpdateFrequency,
dialog: true,
),
@ -363,7 +287,7 @@ class _FiltersWidgetState extends State<FiltersWidget> {
showModalBottomSheet(
context: context,
builder: (context) => UpdateIntervalListsModal(
interval: serversProvider.filtering.data!.interval,
interval: filteringProvider.filtering!.interval,
onChange: setUpdateFrequency,
dialog: false,
),
@ -378,7 +302,7 @@ class _FiltersWidgetState extends State<FiltersWidget> {
PopupMenuButton(
itemBuilder: (context) => [
PopupMenuItem(
onTap: fetchUpdateLists,
onTap: updateLists,
child: Row(
children: [
const Icon(Icons.sync_rounded),
@ -422,13 +346,11 @@ class _FiltersWidgetState extends State<FiltersWidget> {
onRemoveCustomRule: openRemoveCustomRuleModal,
onOpenDetailsModal: openListDetails,
actions: actions(),
refreshData: fetchFilters,
);
}
else {
return FiltersTabsView(
appConfigProvider: appConfigProvider,
fetchFilters: fetchFilters,
appConfigProvider: appConfigProvider,
actions: actions(),
onRemoveCustomRule: openRemoveCustomRuleModal,
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/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/models/filtering.dart';
@ -21,7 +23,6 @@ class FiltersList extends StatefulWidget {
final LoadStatus loadStatus;
final ScrollController scrollController;
final List<Filter> data;
final Future<void> Function() fetchData;
final String type;
final void Function(Filter, String) onOpenDetailsScreen;
@ -30,7 +31,6 @@ class FiltersList extends StatefulWidget {
required this.loadStatus,
required this.scrollController,
required this.data,
required this.fetchData,
required this.type,
required this.onOpenDetailsScreen
}) : super(key: key);
@ -65,6 +65,7 @@ class _FiltersListState extends State<FiltersList> {
@override
Widget build(BuildContext context) {
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return CustomTabContentList(
@ -129,7 +130,16 @@ class _FiltersListState extends State<FiltersList> {
),
const SizedBox(height: 30),
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),
label: Text(AppLocalizations.of(context)!.refresh),
)
@ -160,7 +170,16 @@ class _FiltersListState extends State<FiltersList> {
),
),
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(
type: widget.type,
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/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/models/filtering.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class FiltersTabsView extends StatefulWidget {
final AppConfigProvider appConfigProvider;
final Future Function() fetchFilters;
final List<Widget> actions;
final void Function(String) onRemoveCustomRule;
final void Function(Filter, String) onOpenDetailsModal;
@ -20,7 +19,6 @@ class FiltersTabsView extends StatefulWidget {
const FiltersTabsView({
Key? key,
required this.appConfigProvider,
required this.fetchFilters,
required this.actions,
required this.onOpenDetailsModal,
required this.onRemoveCustomRule
@ -36,7 +34,6 @@ class _FiltersTabsViewState extends State<FiltersTabsView> with TickerProviderSt
@override
void initState() {
widget.fetchFilters();
super.initState();
tabController = TabController(
initialIndex: 0,
@ -48,7 +45,7 @@ class _FiltersTabsViewState extends State<FiltersTabsView> with TickerProviderSt
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(context);
return DefaultTabController(
length: 3,
@ -110,29 +107,26 @@ class _FiltersTabsViewState extends State<FiltersTabsView> with TickerProviderSt
controller: tabController,
children: [
FiltersList(
loadStatus: serversProvider.filtering.loadStatus,
loadStatus: filteringProvider.loadStatus,
scrollController: scrollController,
type: 'whitelist',
data: serversProvider.filtering.loadStatus == LoadStatus.loaded
? serversProvider.filtering.data!.whitelistFilters : [],
fetchData: widget.fetchFilters,
data: filteringProvider.loadStatus == LoadStatus.loaded
? filteringProvider.filtering!.whitelistFilters : [],
onOpenDetailsScreen: widget.onOpenDetailsModal,
),
FiltersList(
loadStatus: serversProvider.filtering.loadStatus,
loadStatus: filteringProvider.loadStatus,
scrollController: scrollController,
type: 'blacklist',
data: serversProvider.filtering.loadStatus == LoadStatus.loaded
? serversProvider.filtering.data!.filters : [],
fetchData: widget.fetchFilters,
data: filteringProvider.loadStatus == LoadStatus.loaded
? filteringProvider.filtering!.filters : [],
onOpenDetailsScreen: widget.onOpenDetailsModal,
),
CustomRulesList(
loadStatus: serversProvider.filtering.loadStatus,
loadStatus: filteringProvider.loadStatus,
scrollController: scrollController,
data: serversProvider.filtering.loadStatus == LoadStatus.loaded
? serversProvider.filtering.data!.userRules : [],
fetchData: widget.fetchFilters,
data: filteringProvider.loadStatus == LoadStatus.loaded
? filteringProvider.filtering!.userRules : [],
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/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/providers/filtering_provider.dart';
import 'package:adguard_home_manager/models/filtering.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/servers_provider.dart';
class FiltersTripleColumn extends StatelessWidget {
final void Function(String) onRemoveCustomRule;
final void Function(Filter, String) onOpenDetailsModal;
final List<Widget> actions;
final Future Function() refreshData;
const FiltersTripleColumn({
Key? key,
required this.onRemoveCustomRule,
required this.onOpenDetailsModal,
required this.actions,
required this.refreshData
}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(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) {
final allowRegex = RegExp(r'^@@.*$');
final blockRegex = RegExp(r'^\|\|.*$');
@ -84,7 +73,7 @@ class FiltersTripleColumn extends StatelessWidget {
}
Widget content() {
switch (serversProvider.filtering.loadStatus) {
switch (filteringProvider.loadStatus) {
case LoadStatus.loading:
return Row(
mainAxisAlignment: MainAxisAlignment.center,
@ -140,18 +129,18 @@ class FiltersTripleColumn extends StatelessWidget {
),
Expanded(
child: ListView.builder(
itemCount: serversProvider.filtering.data!.whitelistFilters.length,
itemCount: filteringProvider.filtering!.whitelistFilters.length,
itemBuilder: (context, index) => ListOptionsMenu(
list: serversProvider.filtering.data!.whitelistFilters[index],
list: filteringProvider.filtering!.whitelistFilters[index],
listType: 'whitelist',
child: CustomListTile(
title: serversProvider.filtering.data!.whitelistFilters[index].name,
subtitle: "${intFormat(serversProvider.filtering.data!.whitelistFilters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
title: filteringProvider.filtering!.whitelistFilters[index].name,
subtitle: "${intFormat(filteringProvider.filtering!.whitelistFilters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
trailing: Icon(
serversProvider.filtering.data!.whitelistFilters[index].enabled == true
filteringProvider.filtering!.whitelistFilters[index].enabled == true
? Icons.check_circle_rounded
: Icons.cancel,
color: serversProvider.filtering.data!.whitelistFilters[index].enabled == true
color: filteringProvider.filtering!.whitelistFilters[index].enabled == true
? appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary
: Colors.green
@ -159,7 +148,7 @@ class FiltersTripleColumn extends StatelessWidget {
? Colors.grey
: 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(
child: ListView.builder(
itemCount: serversProvider.filtering.data!.filters.length,
itemCount: filteringProvider.filtering!.filters.length,
itemBuilder: (context, index) => ListOptionsMenu(
list: serversProvider.filtering.data!.filters[index],
list: filteringProvider.filtering!.filters[index],
listType: 'blacklist',
child: CustomListTile(
title: serversProvider.filtering.data!.filters[index].name,
subtitle: "${intFormat(serversProvider.filtering.data!.filters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
title: filteringProvider.filtering!.filters[index].name,
subtitle: "${intFormat(filteringProvider.filtering!.filters[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}",
trailing: Icon(
serversProvider.filtering.data!.filters[index].enabled == true
filteringProvider.filtering!.filters[index].enabled == true
? Icons.check_circle_rounded
: Icons.cancel,
color: serversProvider.filtering.data!.filters[index].enabled == true
color: filteringProvider.filtering!.filters[index].enabled == true
? appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary
: Colors.green
@ -215,7 +204,7 @@ class FiltersTripleColumn extends StatelessWidget {
? Colors.grey
: 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(
child: ListView.builder(
itemCount: serversProvider.filtering.data!.userRules.length,
itemCount: filteringProvider.filtering!.userRules.length,
itemBuilder: (context, index) => ContextMenuArea(
builder: (context) => [
CustomListTile(
@ -261,7 +250,7 @@ class FiltersTripleColumn extends StatelessWidget {
onTap: () {
copyToClipboard(
context: context,
value: serversProvider.filtering.data!.userRules[index],
value: filteringProvider.filtering!.userRules[index],
successMessage: AppLocalizations.of(context)!.copiedClipboard,
);
Navigator.pop(context);
@ -278,17 +267,17 @@ class FiltersTripleColumn extends StatelessWidget {
icon: Icons.copy_rounded,
action: () => copyToClipboard(
context: context,
value: serversProvider.filtering.data!.userRules[index],
value: filteringProvider.filtering!.userRules[index],
successMessage: AppLocalizations.of(context)!.copiedClipboard,
)
)
]
)
),
title: serversProvider.filtering.data!.userRules[index],
subtitleWidget: generateSubtitle(serversProvider.filtering.data!.userRules[index]),
title: filteringProvider.filtering!.userRules[index],
subtitleWidget: generateSubtitle(filteringProvider.filtering!.userRules[index]),
trailing: IconButton(
onPressed: () => onRemoveCustomRule(serversProvider.filtering.data!.userRules[index]),
onPressed: () => onRemoveCustomRule(filteringProvider.filtering!.userRules[index]),
icon: const Icon(Icons.delete)
),
),
@ -340,7 +329,16 @@ class FiltersTripleColumn extends StatelessWidget {
title: Text(AppLocalizations.of(context)!.filters),
actions: [
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),
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/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/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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/models/filtering.dart';
class ListDetailsScreen extends StatefulWidget {
@ -60,22 +60,51 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
Filter? list;
try {
list = serversProvider.filtering.data != null
list = filteringProvider.filtering != null
? widget.type == 'whitelist'
? serversProvider.filtering.data!.whitelistFilters.firstWhere((l) => l.id == widget.listId)
: serversProvider.filtering.data!.filters.firstWhere((l) => l.id == widget.listId)
? filteringProvider.filtering!.whitelistFilters.firstWhere((l) => l.id == widget.listId)
: filteringProvider.filtering!.filters.firstWhere((l) => l.id == widget.listId)
: null;
} 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() {
return [
CustomListTile(
@ -174,29 +203,9 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
builder: (ctx) => AddListModal(
list: list,
type: widget.type,
onEdit: ({required Filter list, required String type}) async {
final result = await editList(
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
);
}
},
onEdit: ({required Filter list, required String type}) async => updateList(
FilteringListActions.edit
),
dialog: true,
),
)
@ -207,29 +216,9 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
builder: (ctx) => AddListModal(
list: list,
type: widget.type,
onEdit: ({required Filter list, required String type}) async {
final result = await editList(
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
);
}
},
onEdit: ({required Filter list, required String type}) async => updateList(
FilteringListActions.edit
),
dialog: false,
),
isScrollControlled: true,
@ -246,13 +235,13 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
context: context,
builder: (c) => DeleteListModal(
onConfirm: () async {
final result = await deleteList(
context: context,
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
list: list!,
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deletingList);
final result = await filteringProvider.deleteList(
listUrl: list!.url,
type: widget.type,
);
processModal.close();
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
@ -312,29 +301,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
if (list != null) Row(
children: [
IconButton(
onPressed: () async {
final result = await enableDisableList(
context: context,
serversProvider: serversProvider,
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
);
}
},
onPressed: () => updateList(
list!.enabled == true
? FilteringListActions.disable
: FilteringListActions.enable
),
icon: Icon(
list.enabled == true
? Icons.gpp_bad_rounded
@ -399,29 +370,11 @@ class _ListDetailsScreenState extends State<ListDetailsScreen> {
: -70,
right: 20,
child: FloatingActionButton(
onPressed: () async {
final result = await enableDisableList(
context: context,
serversProvider: serversProvider,
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
);
}
},
onPressed: () => updateList(
list!.enabled == true
? FilteringListActions.disable
: FilteringListActions.enable
),
child: Icon(
list.enabled == true
? 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
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:flutter/material.dart';
import 'package:contextmenu/contextmenu.dart';
import 'package:provider/provider.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/options_modal.dart';
import 'package:adguard_home_manager/functions/snackbar.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/models/menu_option.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class ListOptionsMenu extends StatelessWidget {
final Filter list;
@ -30,17 +30,27 @@ class ListOptionsMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final filteringProvider = Provider.of<FilteringProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void enableDisable() async {
final result = await enableDisableList(
context: context,
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
list: list,
listType: listType,
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: listType,
action: list.enabled == true
? FilteringListActions.disable
: FilteringListActions.enable
);
processModal.close();
if (result == true) {
showSnacbkar(
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/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/models/server.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -20,6 +22,7 @@ class HomeAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final Server? server = serversProvider.selectedServer;
@ -37,22 +40,48 @@ class HomeAppBar extends StatelessWidget {
floating: true,
centerTitle: false,
forceElevated: innerBoxScrolled,
leading: Icon(
serversProvider.selectedServer != null && serversProvider.serverStatus.data != null
? serversProvider.serverStatus.data!.generalEnabled == true
? Icons.gpp_good_rounded
: Icons.gpp_bad_rounded
: Icons.shield,
size: 30,
color: serversProvider.selectedServer != null && serversProvider.serverStatus.data != null
? serversProvider.serverStatus.data!.generalEnabled == true
? appConfigProvider.useThemeColorForStatus
? Theme.of(context).colorScheme.primary
: Colors.green
: appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
: Colors.red
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
leading: Stack(
children: [
Center(
child: Icon(
serversProvider.selectedServer != null && statusProvider.serverStatus != null
? statusProvider.serverStatus!.generalEnabled == true
? Icons.gpp_good_rounded
: Icons.gpp_bad_rounded
: Icons.shield,
size: 30,
color: serversProvider.selectedServer != null && statusProvider.serverStatus != null
? statusProvider.serverStatus!.generalEnabled == true
? appConfigProvider.useThemeColorForStatus
? Theme.of(context).colorScheme.primary
: Colors.green
: 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(
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}' : ""}"),
child: Row(
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/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';
class CombinedChartData {
@ -51,56 +51,56 @@ class CombinedHomeChart extends StatelessWidget {
@override
Widget build(BuildContext 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;
if (serversProvider.serverStatus.data != null) {
if (statusProvider.serverStatus != null) {
final data = CombinedChartData(
totalQueries: CombinedChartItem(
label: AppLocalizations.of(context)!.dnsQueries,
color: Colors.blue,
data: serversProvider.serverStatus.data!.stats.dnsQueries
data: statusProvider.serverStatus!.stats.dnsQueries
),
blockedFilters: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.blockedFiltering) != null
? removeZero(statusProvider.serverStatus!.stats.blockedFiltering) != null
? CombinedChartItem(
label: AppLocalizations.of(context)!.blockedFilters,
color: Colors.red,
data: serversProvider.serverStatus.data!.stats.blockedFiltering
data: statusProvider.serverStatus!.stats.blockedFiltering
)
: null
: CombinedChartItem(
label: AppLocalizations.of(context)!.blockedFilters,
color: Colors.red,
data: serversProvider.serverStatus.data!.stats.blockedFiltering
data: statusProvider.serverStatus!.stats.blockedFiltering
) ,
replacedSafeBrowsing: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.replacedSafebrowsing) != null
? removeZero(statusProvider.serverStatus!.stats.replacedSafebrowsing) != null
? CombinedChartItem(
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
color: Colors.green,
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing
data: statusProvider.serverStatus!.stats.replacedSafebrowsing
)
: null
: CombinedChartItem(
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
color: Colors.green,
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing
data: statusProvider.serverStatus!.stats.replacedSafebrowsing
) ,
replacedParental: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.replacedParental) != null
? removeZero(statusProvider.serverStatus!.stats.replacedParental) != null
? CombinedChartItem(
label: AppLocalizations.of(context)!.blockedAdultWebsites,
color: Colors.orange,
data: serversProvider.serverStatus.data!.stats.replacedParental
data: statusProvider.serverStatus!.stats.replacedParental
)
: null
: CombinedChartItem(
label: AppLocalizations.of(context)!.blockedAdultWebsites,
color: Colors.orange,
data: serversProvider.serverStatus.data!.stats.replacedParental
data: statusProvider.serverStatus!.stats.replacedParental
) ,
);
@ -184,29 +184,29 @@ class CombinedHomeChart extends StatelessWidget {
legend(
label: data.totalQueries.label,
color: data.totalQueries.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(statusProvider.serverStatus!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
),
const SizedBox(height: 16),
if (data.blockedFilters != null) legend(
label: data.blockedFilters!.label,
color: data.blockedFilters!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numBlockedFiltering/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
),
const SizedBox(height: 16),
if (data.replacedSafeBrowsing != null) legend(
label: data.replacedSafeBrowsing!.label,
color: data.replacedSafeBrowsing!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedSafebrowsing/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
),
const SizedBox(height: 16),
if (data.replacedParental != null) legend(
label: data.replacedParental!.label,
color: data.replacedParental!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedParental, Platform.localeName),
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(
label: data.totalQueries.label,
color: data.totalQueries.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(statusProvider.serverStatus!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
),
const SizedBox(height: 16),
if (data.blockedFilters != null) legend(
label: data.blockedFilters!.label,
color: data.blockedFilters!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numBlockedFiltering/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
),
const SizedBox(height: 16),
if (data.replacedSafeBrowsing != null) legend(
label: data.replacedSafeBrowsing!.label,
color: data.replacedSafeBrowsing!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedSafebrowsing/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
),
const SizedBox(height: 16),
if (data.replacedParental != null) legend(
label: data.replacedParental!.label,
color: data.replacedParental!.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedParental/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
),
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/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 {
const HomeFab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
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(
onPressed: openManagementBottomSheet,
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/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/services/http_requests.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@ -33,6 +33,8 @@ class _HomeState extends State<Home> {
@override
initState(){
Provider.of<StatusProvider>(context, listen: false).getServerStatus();
super.initState();
isVisible = true;
@ -54,7 +56,7 @@ class _HomeState extends State<Home> {
@override
Widget build(BuildContext 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;
@ -109,7 +111,7 @@ class _HomeState extends State<Home> {
List<Widget> listItems() {
return [
ServerStatus(serverStatus: serversProvider.serverStatus.data!),
ServerStatusWidget(serverStatus: statusProvider.serverStatus!),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
@ -124,40 +126,40 @@ class _HomeState extends State<Home> {
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.dnsQueries,
data: statusProvider.serverStatus!.stats.dnsQueries,
label: AppLocalizations.of(context)!.dnsQueries,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(statusProvider.serverStatus!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
color: Colors.blue,
),
),
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.blockedFiltering,
data: statusProvider.serverStatus!.stats.blockedFiltering,
label: AppLocalizations.of(context)!.blockedFilters,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numBlockedFiltering/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.red,
),
),
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing,
data: statusProvider.serverStatus!.stats.replacedSafebrowsing,
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedSafebrowsing/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.green,
),
),
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedParental,
data: statusProvider.serverStatus!.stats.replacedParental,
label: AppLocalizations.of(context)!.blockedAdultWebsites,
primaryValue: intFormat(serversProvider.serverStatus.data!.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}%",
primaryValue: intFormat(statusProvider.serverStatus!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${statusProvider.serverStatus!.stats.numDnsQueries > 0 ? doubleFormat((statusProvider.serverStatus!.stats.numReplacedParental/statusProvider.serverStatus!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.orange,
),
),
@ -172,7 +174,7 @@ class _HomeState extends State<Home> {
if (width <= 700) ...[
TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
Padding(
@ -187,7 +189,7 @@ class _HomeState extends State<Home> {
TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
Padding(
@ -201,7 +203,7 @@ class _HomeState extends State<Home> {
TopItems(
label: AppLocalizations.of(context)!.topClients,
data: serversProvider.serverStatus.data!.stats.topClients,
data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients',
clients: true,
),
@ -219,7 +221,7 @@ class _HomeState extends State<Home> {
),
child: TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
data: statusProvider.serverStatus!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
),
@ -232,7 +234,7 @@ class _HomeState extends State<Home> {
),
child: TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
data: statusProvider.serverStatus!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
),
@ -245,7 +247,7 @@ class _HomeState extends State<Home> {
),
child: TopItems(
label: AppLocalizations.of(context)!.topClients,
data: serversProvider.serverStatus.data!.stats.topClients,
data: statusProvider.serverStatus!.stats.topClients,
type: 'topClients',
),
),
@ -277,12 +279,8 @@ class _HomeState extends State<Home> {
builder: (context) => RefreshIndicator(
color: Theme.of(context).colorScheme.primary,
onRefresh: () async {
final result = await getServerStatus(serversProvider.selectedServer!);
if (result['result'] == 'success') {
serversProvider.setServerStatusData(result['data']);
}
else {
appConfigProvider.addLog(result['log']);
final result = await statusProvider.getServerStatus();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverStatusNotRefreshed,
@ -295,13 +293,13 @@ class _HomeState extends State<Home> {
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
if (serversProvider.serverStatus.loadStatus == 0) SliverFillRemaining(
if (statusProvider.loadStatus == LoadStatus.loading) SliverFillRemaining(
child: loading(),
),
if (serversProvider.serverStatus.loadStatus == 1) SliverList.list(
if (statusProvider.loadStatus == LoadStatus.loaded) SliverList.list(
children: listItems()
),
if (serversProvider.serverStatus.loadStatus == 2) SliverFillRemaining(
if (statusProvider.loadStatus == LoadStatus.error) SliverFillRemaining(
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/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/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class ManagementModal extends StatefulWidget {
final bool dialog;
@ -32,10 +31,6 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
late Animation<double> animation;
final ExpandableController expandableController = ExpandableController();
DateTime? currentDeadline;
Timer? countdown;
int start = 0;
@override
void initState() {
expandableController.addListener(() async {
@ -66,70 +61,21 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
@override
void dispose() {
if (countdown != null) countdown!.cancel();
animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(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({
required bool value,
required String filter,
int? time
}) async {
final result = await serversProvider.updateBlocking(
server: serversProvider.selectedServer!,
final result = await statusProvider.updateBlocking(
block: filter,
newStatus: value,
time: time
@ -164,7 +110,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
child: Icon(
Icons.keyboard_arrow_down_rounded,
size: 26,
color: serversProvider.serverStatus.data!.generalEnabled == true
color: statusProvider.serverStatus!.generalEnabled == true
? Theme.of(context).colorScheme.onSurfaceVariant
: Colors.grey,
),
@ -180,10 +126,10 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
fontSize: 18,
),
),
if (serversProvider.serverStatus.data!.timeGeneralDisabled > 0) ...[
if (statusProvider.serverStatus!.timeGeneralDisabled > 0) ...[
const SizedBox(height: 2),
if (currentDeadline != null) Text(
"${AppLocalizations.of(context)!.remainingTime}: ${generateRemainingTimeString(currentDeadline!.difference(DateTime.now()))}"
if (statusProvider.currentDeadline != null) Text(
"${AppLocalizations.of(context)!.remainingTime}: ${formatRemainingSeconds(statusProvider.remainingTime)}"
)
]
],
@ -191,8 +137,8 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
],
),
Switch(
value: serversProvider.serverStatus.data!.generalEnabled,
onChanged: serversProvider.protectionsManagementProcess.contains('general') == false
value: statusProvider.serverStatus!.generalEnabled,
onChanged: statusProvider.protectionsManagementProcess.contains('general') == false
? (value) {
if (value == false && expandableController.expanded == true && legacyMode == false) {
expandableController.toggle();
@ -216,35 +162,35 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
children: [
ActionChip(
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)
: null,
),
const SizedBox(width: 8),
ActionChip(
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)
: null,
),
const SizedBox(width: 8),
ActionChip(
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)
: null,
),
const SizedBox(width: 8),
ActionChip(
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)
: null,
),
const SizedBox(width: 8),
ActionChip(
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)
: null,
),
@ -256,7 +202,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
@ -266,7 +212,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
color: Colors.transparent,
borderRadius: BorderRadius.circular(28),
child: InkWell(
onTap: serversProvider.serverStatus.data!.generalEnabled == true && !serversProvider.protectionsManagementProcess.contains('general')
onTap: statusProvider.serverStatus!.generalEnabled == true && !statusProvider.protectionsManagementProcess.contains('general')
? () => expandableController.toggle()
: null,
borderRadius: BorderRadius.circular(28),
@ -277,7 +223,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28),
color: Theme.of(context).primaryColor.withOpacity(0.1)
color: Theme.of(context).colorScheme.primary.withOpacity(0.1)
),
child: Expandable(
theme: const ExpandableThemeData(
@ -301,9 +247,9 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
color: Colors.transparent,
borderRadius: BorderRadius.circular(28),
child: InkWell(
onTap: serversProvider.protectionsManagementProcess.contains('general') == false
onTap: statusProvider.protectionsManagementProcess.contains('general') == false
? () => updateBlocking(
value: !serversProvider.serverStatus.data!.generalEnabled,
value: !statusProvider.serverStatus!.generalEnabled,
filter: 'general_legacy'
) : null,
borderRadius: BorderRadius.circular(28),
@ -408,30 +354,30 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
smallSwitch(
AppLocalizations.of(context)!.ruleFiltering,
Icons.filter_list_rounded,
serversProvider.serverStatus.data!.filteringEnabled,
statusProvider.serverStatus!.filteringEnabled,
(value) => updateBlocking(value: value, filter: 'filtering'),
serversProvider.protectionsManagementProcess.contains('filtering')
statusProvider.protectionsManagementProcess.contains('filtering')
),
smallSwitch(
AppLocalizations.of(context)!.safeBrowsing,
Icons.vpn_lock_rounded,
serversProvider.serverStatus.data!.safeBrowsingEnabled,
statusProvider.serverStatus!.safeBrowsingEnabled,
(value) => updateBlocking(value: value, filter: 'safeBrowsing'),
serversProvider.protectionsManagementProcess.contains('safeBrowsing')
statusProvider.protectionsManagementProcess.contains('safeBrowsing')
),
smallSwitch(
AppLocalizations.of(context)!.parentalFiltering,
Icons.block,
serversProvider.serverStatus.data!.parentalControlEnabled,
statusProvider.serverStatus!.parentalControlEnabled,
(value) => updateBlocking(value: value, filter: 'parentalControl'),
serversProvider.protectionsManagementProcess.contains('parentalControl')
statusProvider.protectionsManagementProcess.contains('parentalControl')
),
smallSwitch(
AppLocalizations.of(context)!.safeSearch,
Icons.search_rounded,
serversProvider.serverStatus.data!.safeSearchEnabled,
statusProvider.serverStatus!.safeSearchEnabled,
(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';
class ServerStatus extends StatelessWidget {
final ServerStatusData serverStatus;
class ServerStatusWidget extends StatelessWidget {
final ServerStatus serverStatus;
const ServerStatus({
const ServerStatusWidget({
Key? key,
required this.serverStatus,
}) : 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/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/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/providers/logs_provider.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';
class TopItems extends StatelessWidget {
final String type;
@ -36,7 +34,7 @@ class TopItems extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
@ -58,52 +56,26 @@ class TopItems extends StatelessWidget {
final ProcessModal processModal = ProcessModal(context: context);
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') {
FilteringStatus oldStatus = serversProvider.serverStatus.data!.filteringStatus;
processModal.close();
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') {
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,
)
);
}
if (rules == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green
);
}
else {
appConfigProvider.addLog(rules['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
backgroundColor: Colors.red,
)
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: 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) {
String? name;
if (clients != null && clients == true) {
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) {
// ---- //
}
@ -241,13 +204,13 @@ class TopItems extends StatelessWidget {
List<Map<String, dynamic>> generateData() {
switch (type) {
case 'topQueriedDomains':
return serversProvider.serverStatus.data!.stats.topQueriedDomains;
return statusProvider.serverStatus!.stats.topQueriedDomains;
case 'topBlockedDomains':
return serversProvider.serverStatus.data!.stats.topBlockedDomains;
return statusProvider.serverStatus!.stats.topBlockedDomains;
case 'topClients':
return serversProvider.serverStatus.data!.stats.topClients;
return statusProvider.serverStatus!.stats.topClients;
default:
return [];

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.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';
class ClientsModal extends StatefulWidget {
@ -32,6 +33,7 @@ class _ClientsModalState extends State<ClientsModal> {
@override
Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final height = MediaQuery.of(context).size.height;
@ -86,7 +88,7 @@ class _ClientsModalState extends State<ClientsModal> {
void selectAll() {
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(
child: ListView.builder(
itemCount: logsProvider.clients!.length,
itemCount: clientsProvider.clients!.autoClients.length,
itemBuilder: (context, index) => listItem(
label: logsProvider.clients![index].ip,
label: clientsProvider.clients!.autoClients[index].ip,
onChanged: () {
if (selectedClients.contains(logsProvider.clients![index].ip)) {
if (selectedClients.contains(clientsProvider.clients!.autoClients[index].ip)) {
setState(() {
selectedClients = selectedClients.where(
(item) => item != logsProvider.clients![index].ip
(item) => item != clientsProvider.clients!.autoClients[index].ip
).toList();
});
}
else {
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,
children: [
TextButton(
onPressed: selectedClients.length == logsProvider.clients!.length
onPressed: selectedClients.length == clientsProvider.clients!.autoClients.length
? () => unselectAll()
: () => selectAll(),
child: Text(
selectedClients.length == logsProvider.clients!.length
selectedClients.length == clientsProvider.clients!.autoClients.length
? AppLocalizations.of(context)!.unselectAll
: 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/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/services/http_requests.dart';
import 'package:adguard_home_manager/functions/format_time.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';
class LogDetailsScreen extends StatelessWidget {
@ -29,13 +29,13 @@ class LogDetailsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
Filter? getList(int id) {
try {
return serversProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () {
return serversProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id);
return statusProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () {
return statusProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id);
});
} catch (_) {
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);
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') {
FilteringStatus oldStatus = serversProvider.filteringStatus!;
processModal.close();
List<String> newRules = rules['data'].userRules.where((domain) => !domain.contains(log.question.name)).toList();
if (newStatus == 'block') {
newRules.add("||${log.question.name}^");
}
else if (newStatus == 'unblock') {
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,
)
);
}
if (rules == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green
);
}
else {
appConfigProvider.addLog(rules['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
backgroundColor: Colors.red,
)
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: Colors.red
);
}
}
@ -266,7 +239,12 @@ class LogDetailsScreen extends StatelessWidget {
Row(
children: [
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(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded
@ -298,8 +276,13 @@ class LogDetailsScreen extends StatelessWidget {
centerTitle: false,
title: Text(AppLocalizations.of(context)!.logDetails),
actions: [
if (serversProvider.filteringStatus != null) IconButton(
onPressed: () => blockUnblock(log, getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'),
if (statusProvider.filteringStatus != null) IconButton(
onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? 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/models/applied_filters.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/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/providers/servers_provider.dart';
class Logs extends StatelessWidget {
class Logs extends StatefulWidget {
const Logs({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
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,
);
}
State<Logs> createState() => _LogsState();
}
class LogsWidget extends StatefulWidget {
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> {
class _LogsState extends State<Logs> {
late ScrollController scrollController;
bool isLoadingMore = false;
bool showDivider = true;
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 {
final result = await getFilteringRules(server: widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setFilteringStatus(result['data']);
}
else {
widget.appConfigProvider.addLog(result['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.couldntGetFilteringStatus),
backgroundColor: Colors.red,
)
);
}
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
final statusProvider = Provider.of<StatusProvider>(context, listen: false);
final result = await statusProvider.getFilteringRules();
if (mounted && result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
color: Colors.red
);
}
}
Future fetchClients() async {
final result = await getClients(widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.logsProvider.setClientsLoadStatus(1);
widget.logsProvider.setClients(result['data'].autoClientsData);
}
else {
widget.logsProvider.setClientsLoadStatus(2);
widget.appConfigProvider.addLog(result['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.couldntGetFilteringStatus),
backgroundColor: Colors.red,
)
);
}
final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
final result = await clientsProvider.fetchClients();
if (mounted && result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.couldntGetFilteringStatus,
color: Colors.red
);
}
}
void scrollListener() {
if (scrollController.position.extentAfter < 500 && isLoadingMore == false) {
fetchLogs(loadingMore: true);
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
if (scrollController.position.extentAfter < 500 && logsProvider.isLoadingMore == false) {
logsProvider.fetchLogs(loadingMore: true);
}
if (scrollController.position.pixels > 0) {
setState(() => showDivider = false);
@ -180,8 +81,10 @@ class _LogsWidgetState extends State<LogsWidget> {
@override
void initState() {
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
scrollController = ScrollController()..addListener(scrollListener);
fetchLogs(inOffset: 0);
logsProvider.fetchLogs(inOffset: 0);
fetchFilteringRules();
fetchClients();
super.initState();
@ -190,6 +93,7 @@ class _LogsWidgetState extends State<LogsWidget> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
@ -200,12 +104,12 @@ class _LogsWidgetState extends State<LogsWidget> {
processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = serverVersionIsAhead(
currentVersion: widget.serversProvider.serverStatus.data!.serverVersion,
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
? await updateQueryLogParameters(server: serversProvider.selectedServer!, data: data)
: await updateQueryLogParametersLegacy(server: serversProvider.selectedServer!, data: data);
? await serversProvider.apiClient!.updateQueryLogParameters(data: data)
: await serversProvider.apiClient!.updateQueryLogParametersLegacy(data: data);
processModal.close();
@ -231,7 +135,7 @@ class _LogsWidgetState extends State<LogsWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = await clearLogs(server: serversProvider.selectedServer!);
final result = await serversProvider.apiClient!.clearLogs();
processModal.close();
@ -243,8 +147,6 @@ class _LogsWidgetState extends State<LogsWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsNotCleared,
@ -289,7 +191,7 @@ class _LogsWidgetState extends State<LogsWidget> {
Widget generateBody() {
switch (logsProvider.loadStatus) {
case 0:
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -309,20 +211,20 @@ class _LogsWidgetState extends State<LogsWidget> {
),
);
case 1:
case LoadStatus.loaded:
return RefreshIndicator(
onRefresh: () async {
await fetchLogs(inOffset: 0);
await logsProvider.fetchLogs(inOffset: 0);
},
child: logsProvider.logsData!.data.isNotEmpty
? ListView.builder(
controller: scrollController,
padding: const EdgeInsets.only(top: 0),
itemCount: isLoadingMore == true
itemCount: logsProvider.isLoadingMore == true
? logsProvider.logsData!.data.length+1
: logsProvider.logsData!.data.length,
itemBuilder: (context, index) {
if (isLoadingMore == true && index == logsProvider.logsData!.data.length) {
if (logsProvider.isLoadingMore == true && index == logsProvider.logsData!.data.length) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Center(
@ -385,7 +287,7 @@ class _LogsWidgetState extends State<LogsWidget> {
)
);
case 2:
case LoadStatus.error:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -421,11 +323,11 @@ class _LogsWidgetState extends State<LogsWidget> {
centerTitle: false,
actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => fetchLogs(inOffset: 0),
onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh,
),
logsProvider.loadStatus == 1
logsProvider.loadStatus == LoadStatus.loaded
? IconButton(
onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded),
@ -442,7 +344,7 @@ class _LogsWidgetState extends State<LogsWidget> {
onConfirm: updateConfig,
onClear: clearQueries,
dialog: true,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
barrierDismissible: false
)
@ -454,7 +356,7 @@ class _LogsWidgetState extends State<LogsWidget> {
onConfirm: updateConfig,
onClear: clearQueries,
dialog: false,
serverVersion: serversProvider.serverStatus.data!.serverVersion,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
backgroundColor: Colors.transparent,
isScrollControlled: true
@ -510,7 +412,7 @@ class _LogsWidgetState extends State<LogsWidget> {
)
);
logsProvider.setSearchText(null);
fetchLogs(
logsProvider.fetchLogs(
inOffset: 0,
searchText: ''
);
@ -543,7 +445,7 @@ class _LogsWidgetState extends State<LogsWidget> {
)
);
logsProvider.setSelectedResultStatus('all');
fetchLogs(
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: 'all'
);
@ -578,7 +480,7 @@ class _LogsWidgetState extends State<LogsWidget> {
)
);
logsProvider.setSelectedClients(null);
fetchLogs(
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus
);

View file

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
@ -74,13 +73,15 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
int loadStatus = 0;
void loadData() async {
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
final result = serverVersionIsAhead(
currentVersion: widget.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
? await getQueryLogInfo(server: widget.serversProvider.selectedServer!)
: await getQueryLogInfoLegacy(server: widget.serversProvider.selectedServer!);
? await serversProvider.apiClient!.getQueryLogInfo()
: await serversProvider.apiClient!.getQueryLogInfoLegacy();
if (mounted) {
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/widgets/custom_list_tile.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/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/constants/enums.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart';
class LogsFiltersModal extends StatelessWidget {
@ -62,8 +59,7 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
@override
Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final width = MediaQuery.of(context).size.width;
@ -78,38 +74,6 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
"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() {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
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() {
return Column(
mainAxisSize: MainAxisSize.min,
@ -273,13 +198,13 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
subtitle: logsProvider.selectedClients != null
? "${logsProvider.selectedClients!.length} ${AppLocalizations.of(context)!.clientsSelected}"
: AppLocalizations.of(context)!.all,
onTap: logsProvider.clientsLoadStatus == 1
onTap: clientsProvider.loadStatus == LoadStatus.loaded
? openSelectClients
: null,
disabled: logsProvider.clientsLoadStatus != 1 ,
disabled: clientsProvider.loadStatus != LoadStatus.loaded,
icon: Icons.smartphone_rounded,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
trailing: logsProvider.clientsLoadStatus == 0
trailing: clientsProvider.loadStatus == LoadStatus.loading
? const SizedBox(
width: 20,
height: 20,
@ -287,7 +212,7 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
strokeWidth: 2,
),
)
: logsProvider.clientsLoadStatus == 2
: clientsProvider.loadStatus == LoadStatus.error
? const Icon(
Icons.error_rounded,
color: Colors.red,
@ -311,11 +236,17 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: resetFilters,
onPressed: () {
searchController.text = "";
logsProvider.requestResetFilters();
},
child: Text(AppLocalizations.of(context)!.resetFilters)
),
TextButton(
onPressed: () => filterLogs(),
onPressed: () {
Navigator.pop(context);
logsProvider.filterLogs();
},
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/constants/enums.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/servers_provider.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart';
class AccessSettings extends StatelessWidget {
class AccessSettings extends StatefulWidget {
const AccessSettings({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return AccessSettingsWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
State<AccessSettings> createState() => _AccessSettingsState();
}
class AccessSettingsWidget extends StatefulWidget {
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 {
class _AccessSettingsState extends State<AccessSettings> with TickerProviderStateMixin {
final ScrollController scrollController = ScrollController();
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
void initState() {
fetchClients();
Provider.of<ClientsProvider>(context, listen: false).fetchClients(updateLoading: true);
super.initState();
tabController = TabController(
initialIndex: 0,
@ -73,7 +33,7 @@ class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with Ticker
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
Widget body() {
return TabBarView(
@ -82,26 +42,23 @@ class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with Ticker
ClientsList(
type: 'allowed',
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.clients.data!.clientsAllowedBlocked!.allowedClients : [],
fetchClients: fetchClients
loadStatus: clientsProvider.loadStatus,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.clients!.clientsAllowedBlocked!.allowedClients : [],
),
ClientsList(
type: 'disallowed',
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.clients.data!.clientsAllowedBlocked!.disallowedClients : [],
fetchClients: fetchClients
loadStatus: clientsProvider.loadStatus,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.clients!.clientsAllowedBlocked!.disallowedClients : [],
),
ClientsList(
type: 'domains',
scrollController: scrollController,
loadStatus: serversProvider.clients.loadStatus,
data: serversProvider.clients.loadStatus == LoadStatus.loaded
? serversProvider.clients.data!.clientsAllowedBlocked!.blockedHosts : [],
fetchClients: fetchClients
loadStatus: clientsProvider.loadStatus,
data: clientsProvider.loadStatus == LoadStatus.loaded
? clientsProvider.clients!.clientsAllowedBlocked!.blockedHosts : [],
),
]
);

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

View file

@ -1,14 +1,10 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_split_view/flutter_split_view.dart';
import 'package:provider/provider.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/screens/settings/app_logs/app_logs.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
@ -20,8 +16,6 @@ class AdvancedSettings extends StatelessWidget {
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
Future updateSettings({
required bool newStatus,
required Future Function(bool) function
@ -71,29 +65,6 @@ class AdvancedSettings extends StatelessWidget {
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/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/services/http_requests.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/servers_provider.dart';
class Dhcp extends StatelessWidget {
const Dhcp({Key? key}) : super(key: key);
class DhcpScreen extends StatefulWidget {
const DhcpScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return DhcpWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider
);
}
State<DhcpScreen> createState() => _DhcpScreenState();
}
class DhcpWidget extends StatefulWidget {
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> {
class _DhcpScreenState extends State<DhcpScreen> {
NetworkInterface? selectedInterface;
bool enabled = false;
@ -74,31 +53,22 @@ class _DhcpWidgetState extends State<DhcpWidget> {
bool dataValid = false;
void loadDhcpStatus() async {
widget.serversProvider.setDhcpLoadStatus(0, false);
final result = await getDhcpData(server: widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setDhcpLoadStatus(1, true);
widget.serversProvider.setDhcpData(result['data']);
final result = await Provider.of<DhcpProvider>(context, listen: false).loadDhcpStatus();
if (mounted && result == true) {
final dhcpProvider = Provider.of<DhcpProvider>(context, listen: false);
if (dhcpProvider.dhcp != null) {
setState(() {
if (result['data'].dhcpStatus.interfaceName != '') {
selectedInterface = result['data'].networkInterfaces.firstWhere((interface) => interface.name == result['data'].dhcpStatus.interfaceName);
enabled = result['data'].dhcpStatus.enabled;
ipv4StartRangeController.text = result['data'].dhcpStatus.v4.rangeStart;
ipv4StartRangeController.text = result['data'].dhcpStatus.v4.rangeStart;
ipv4EndRangeController.text = result['data'].dhcpStatus.v4.rangeEnd;
ipv4SubnetMaskController.text = result['data'].dhcpStatus.v4.subnetMask;
ipv4GatewayController.text = result['data'].dhcpStatus.v4.gatewayIp;
ipv4LeaseTimeController.text = result['data'].dhcpStatus.v4.leaseDuration.toString();
if (dhcpProvider.dhcp!.dhcpStatus.interfaceName != '') {
selectedInterface = dhcpProvider.dhcp!.networkInterfaces.firstWhere((iface) => iface.name == dhcpProvider.dhcp!.dhcpStatus.interfaceName);
enabled = dhcpProvider.dhcp!.dhcpStatus.enabled;
ipv4StartRangeController.text = dhcpProvider.dhcp!.dhcpStatus.v4.rangeStart;
ipv4EndRangeController.text = dhcpProvider.dhcp!.dhcpStatus.v4.rangeEnd ?? '';
ipv4SubnetMaskController.text = dhcpProvider.dhcp!.dhcpStatus.v4.subnetMask ?? '';
ipv4GatewayController.text = dhcpProvider.dhcp!.dhcpStatus.v4.gatewayIp ?? '';
ipv4LeaseTimeController.text = dhcpProvider.dhcp!.dhcpStatus.v4.leaseDuration.toString();
}
});
}
else {
widget.serversProvider.setDhcpLoadStatus(2, true);
}
}
checkDataValid();
}
@ -213,6 +183,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dhcpProvider = Provider.of<DhcpProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
@ -221,22 +192,24 @@ class _DhcpWidgetState extends State<DhcpWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingSettings);
final result = await saveDhcpConfig(server: serversProvider.selectedServer!, data: {
"enabled": enabled,
"interface_name": selectedInterface!.name,
if (selectedInterface!.ipv4Addresses.isNotEmpty) "v4": {
"gateway_ip": ipv4GatewayController.text,
"subnet_mask": ipv4SubnetMaskController.text,
"range_start": ipv4StartRangeController.text,
"range_end": ipv4EndRangeController.text,
"lease_duration": ipv4LeaseTimeController.text != '' ? int.parse(ipv4LeaseTimeController.text) : null
},
if (selectedInterface!.ipv6Addresses.isNotEmpty) "v6": {
"range_start": ipv6StartRangeController.text,
"range_end": ipv6EndRangeController.text,
"lease_duration": ipv6LeaseTimeController.text != '' ? int.parse(ipv6LeaseTimeController.text) : null
final result = await serversProvider.apiClient!.saveDhcpConfig(
data: {
"enabled": enabled,
"interface_name": selectedInterface!.name,
if (selectedInterface!.ipv4Addresses.isNotEmpty) "v4": {
"gateway_ip": ipv4GatewayController.text,
"subnet_mask": ipv4SubnetMaskController.text,
"range_start": ipv4StartRangeController.text,
"range_end": ipv4EndRangeController.text,
"lease_duration": ipv4LeaseTimeController.text != '' ? int.parse(ipv4LeaseTimeController.text) : null
},
if (selectedInterface!.ipv6Addresses.isNotEmpty) "v6": {
"range_start": ipv6StartRangeController.text,
"range_end": ipv6EndRangeController.text,
"lease_duration": ipv6LeaseTimeController.text != '' ? int.parse(ipv6LeaseTimeController.text) : null
}
}
});
);
processModal.close();
@ -248,8 +221,6 @@ class _DhcpWidgetState extends State<DhcpWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved,
@ -263,7 +234,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.restoringConfig);
final result = await resetDhcpConfig(server: serversProvider.selectedServer!);
final result = await serversProvider.apiClient!.resetDhcpConfig();
processModal.close();
@ -277,8 +248,6 @@ class _DhcpWidgetState extends State<DhcpWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.configNotRestored,
@ -293,15 +262,15 @@ class _DhcpWidgetState extends State<DhcpWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.restoringLeases);
final result = await restoreAllLeases(server: serversProvider.selectedServer!);
final result = await serversProvider.apiClient!.restoreAllLeases();
processModal.close();
if (result['result'] == 'success') {
DhcpData data = serversProvider.dhcp.data!;
DhcpModel data = dhcpProvider.dhcp!;
data.dhcpStatus.staticLeases = [];
data.dhcpStatus.leases = [];
serversProvider.setDhcpData(data);
dhcpProvider.setDhcpData(data);
showSnacbkar(
appConfigProvider: appConfigProvider,
@ -310,8 +279,6 @@ class _DhcpWidgetState extends State<DhcpWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.leasesNotRestored,
@ -356,7 +323,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
showDialog(
context: context,
builder: (context) => SelectInterfaceModal(
interfaces: serversProvider.dhcp.data!.networkInterfaces,
interfaces: dhcpProvider.dhcp!.networkInterfaces,
onSelect: (interface) => setState(() {
clearAll();
selectedInterface = interface;
@ -369,7 +336,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
showModalBottomSheet(
context: context,
builder: (context) => SelectInterfaceModal(
interfaces: serversProvider.dhcp.data!.networkInterfaces,
interfaces: dhcpProvider.dhcp!.networkInterfaces,
onSelect: (i) => setState(() {
clearAll();
selectedInterface = i;
@ -383,8 +350,8 @@ class _DhcpWidgetState extends State<DhcpWidget> {
}
Widget generateBody() {
switch (serversProvider.dhcp.loadStatus) {
case 0:
switch (dhcpProvider.loadStatus) {
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -404,7 +371,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
),
);
case 1:
case LoadStatus.loaded:
if (selectedInterface != null) {
return SingleChildScrollView(
child: Wrap(
@ -683,7 +650,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.leases,
items: dhcpProvider.dhcp!.dhcpStatus.leases,
staticLeases: false,
)
));
@ -716,7 +683,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.staticLeases,
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
staticLeases: true,
)
));
@ -751,7 +718,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
if (!(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push(
DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.leases,
items: dhcpProvider.dhcp!.dhcpStatus.leases,
staticLeases: false,
)
);
@ -759,7 +726,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
else {
Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.leases,
items: dhcpProvider.dhcp!.dhcpStatus.leases,
staticLeases: false,
)
));
@ -778,7 +745,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
if (!(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push(
DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.staticLeases,
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
staticLeases: true,
)
);
@ -786,7 +753,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
else {
Navigator.push(context, MaterialPageRoute(
builder: (context) => DhcpLeases(
items: serversProvider.dhcp.data!.dhcpStatus.staticLeases,
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
staticLeases: true,
)
));
@ -840,7 +807,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
);
}
case 2:
case LoadStatus.error:
return SizedBox(
width: double.maxFinite,
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/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/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/models/dhcp.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class DhcpLeases extends StatelessWidget {
final List<Lease> items;
@ -29,7 +28,7 @@ class DhcpLeases extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dhcpProvider = Provider.of<DhcpProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
@ -38,19 +37,11 @@ class DhcpLeases extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deleting);
final result = await deleteStaticLease(server: serversProvider.selectedServer!, data: {
"mac": lease.mac,
"ip": lease.ip,
"hostname": lease.hostname
});
final result = await dhcpProvider.deleteLease(lease);
processModal.close();
if (result['result'] == 'success') {
DhcpData data = serversProvider.dhcp.data!;
data.dhcpStatus.staticLeases = data.dhcpStatus.staticLeases.where((l) => l.mac != lease.mac).toList();
serversProvider.setDhcpData(data);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseDeleted,
@ -58,7 +49,6 @@ class DhcpLeases extends StatelessWidget {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseNotDeleted,
@ -71,35 +61,25 @@ class DhcpLeases extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.creating);
final result = await createStaticLease(server: serversProvider.selectedServer!, data: {
"mac": lease.mac,
"ip": lease.ip,
"hostname": lease.hostname,
});
final result = await dhcpProvider.createLease(lease);
processModal.close();
if (result['result'] == 'success') {
DhcpData data = serversProvider.dhcp.data!;
data.dhcpStatus.staticLeases.add(lease);
serversProvider.setDhcpData(data);
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseCreated,
color: Colors.green
);
}
else if (result['result'] == 'error' && result['message'] == 'already_exists' ) {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 'already_exists' ) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseExists,
color: Colors.red
);
}
else if (result['result'] == 'error' && result['message'] == 'server_not_configured' ) {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 'server_not_configured' ) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverNotConfigured,
@ -107,7 +87,6 @@ class DhcpLeases extends StatelessWidget {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.staticLeaseNotCreated,

View file

@ -4,20 +4,13 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.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/providers/dns_provider.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/services/http_requests.dart';
class BootstrapDnsScreen extends StatefulWidget {
final ServersProvider serversProvider;
const BootstrapDnsScreen({
Key? key,
required this.serversProvider,
}) : super(key: key);
const BootstrapDnsScreen({Key? key}) : super(key: key);
@override
State<BootstrapDnsScreen> createState() => _BootstrapDnsScreenState();
@ -54,7 +47,9 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
@override
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();
controller.text = item;
bootstrapControllers.add({
@ -68,33 +63,27 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async {
ProcessModal processModal = ProcessModal(context: context);
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(),
});
processModal.close();
if (result['result'] == 'success') {
DnsInfoData data = serversProvider.dnsInfo.data!;
data.bootstrapDns = List<String>.from(bootstrapControllers.map((e) => e['controller'].text));
serversProvider.setDnsInfoData(data);
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green
);
}
else if (result['log'] != null && result['log'].statusCode == '400') {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 400) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid,
@ -102,8 +91,6 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
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/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/functions/clear_dns_cache.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/services/http_requests.dart';
class CacheConfigDnsScreen extends StatefulWidget {
final ServersProvider serversProvider;
const CacheConfigDnsScreen({
Key? key,
required this.serversProvider
}) : super(key: key);
const CacheConfigDnsScreen({Key? key}) : super(key: key);
@override
State<CacheConfigDnsScreen> createState() => _CacheConfigDnsScreenState();
@ -60,10 +53,12 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
@override
void initState() {
cacheSizeController.text = widget.serversProvider.dnsInfo.data!.cacheSize.toString();
overrideMinTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMin.toString();
overrideMaxTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMax.toString();
optimisticCache = widget.serversProvider.dnsInfo.data!.cacheOptimistic;
final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
cacheSizeController.text = dnsProvider.dnsInfo!.cacheSize.toString();
overrideMinTtlController.text = dnsProvider.dnsInfo!.cacheTtlMin.toString();
overrideMaxTtlController.text = dnsProvider.dnsInfo!.cacheTtlMax.toString();
optimisticCache = dnsProvider.dnsInfo!.cacheOptimistic;
validData = true;
super.initState();
}
@ -71,13 +66,14 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async {
ProcessModal processModal = ProcessModal(context: context);
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_ttl_min": int.parse(overrideMinTtlController.text),
"cache_ttl_max": int.parse(overrideMaxTtlController.text),
@ -86,23 +82,14 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
processModal.close();
if (result['result'] == 'success') {
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);
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green
);
}
else if (result['log'] != null && result['log'].statusCode == '400') {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 400) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid,
@ -110,8 +97,6 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigNotSaved,

View file

@ -2,6 +2,8 @@
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_split_view/flutter_split_view.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/providers/servers_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);
@override
Widget build(BuildContext context) {
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();
State<DnsSettings> createState() => _DnsSettingsState();
}
class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
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);
}
}
}
class _DnsSettingsState extends State<DnsSettings> {
@override
void initState() {
fetchData();
Provider.of<DnsProvider>(context, listen: false).fetchDnsData(showLoading: true);
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
@ -93,8 +56,8 @@ class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
}
Widget generateBody() {
switch (widget.serversProvider.dnsInfo.loadStatus) {
case 0:
switch (dnsProvider.loadStatus) {
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -115,63 +78,43 @@ class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
)
);
case 1:
case LoadStatus.loaded:
return ListView(
children: [
CustomListTile(
title: AppLocalizations.of(context)!.upstreamDns,
subtitle: AppLocalizations.of(context)!.upstreamDnsDescription,
onTap: () => navigate(
UpstreamDnsScreen(
serversProvider: serversProvider
)
),
onTap: () => navigate(const UpstreamDnsScreen()),
icon: Icons.upload_rounded,
),
CustomListTile(
title: AppLocalizations.of(context)!.bootstrapDns,
subtitle: AppLocalizations.of(context)!.bootstrapDnsDescription,
onTap: () => navigate(
BootstrapDnsScreen(
serversProvider: serversProvider
)
),
onTap: () => navigate(const BootstrapDnsScreen()),
icon: Icons.dns_rounded,
),
CustomListTile(
title: AppLocalizations.of(context)!.privateReverseDnsServers,
subtitle: AppLocalizations.of(context)!.privateReverseDnsDescription,
onTap: () => navigate(
PrivateReverseDnsServersScreen(
serversProvider: serversProvider
)
),
onTap: () => navigate(const PrivateReverseDnsServersScreen()),
icon: Icons.person_rounded,
),
CustomListTile(
title: AppLocalizations.of(context)!.dnsServerSettings,
subtitle: AppLocalizations.of(context)!.dnsServerSettingsDescription,
onTap: () => navigate(
DnsServerSettingsScreen(
serversProvider: serversProvider
)
),
onTap: () => navigate(const DnsServerSettingsScreen()),
icon: Icons.settings,
),
CustomListTile(
title: AppLocalizations.of(context)!.dnsCacheConfig,
subtitle: AppLocalizations.of(context)!.dnsCacheConfigDescription,
onTap: () => navigate(
CacheConfigDnsScreen(
serversProvider: serversProvider
)
),
onTap: () => navigate(const CacheConfigDnsScreen()),
icon: Icons.storage_rounded,
),
],
);
case 2:
case LoadStatus.error:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -226,7 +169,7 @@ class _DnsSettingsWidgetState extends State<DnsSettingsWidget> {
PopupMenuButton(
itemBuilder: (context) => [
PopupMenuItem(
onTap: () => fetchData(showRefreshIndicator: true),
onTap: () => dnsProvider.fetchDnsData(),
child: Row(
children: [
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/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/providers/dns_provider.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/services/http_requests.dart';
class DnsServerSettingsScreen extends StatefulWidget {
final ServersProvider serversProvider;
const DnsServerSettingsScreen({
Key? key,
required this.serversProvider
}) : super(key: key);
const DnsServerSettingsScreen({Key? key}) : super(key: key);
@override
State<DnsServerSettingsScreen> createState() => _DnsServerSettingsScreenState();
@ -89,56 +82,48 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
@override
void initState() {
limitRequestsController.text = widget.serversProvider.dnsInfo.data!.ratelimit.toString();
enableEdns = widget.serversProvider.dnsInfo.data!.ednsCsEnabled;
enableDnssec = widget.serversProvider.dnsInfo.data!.dnssecEnabled;
disableIpv6Resolving = widget.serversProvider.dnsInfo.data!.disableIpv6;
blockingMode = widget.serversProvider.dnsInfo.data!.blockingMode;
ipv4controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv4;
ipv6controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv6;
final dnsProvider = Provider.of<DnsProvider>(context, listen: false);
limitRequestsController.text = dnsProvider.dnsInfo!.ratelimit.toString();
enableEdns = dnsProvider.dnsInfo!.ednsCsEnabled;
enableDnssec = dnsProvider.dnsInfo!.dnssecEnabled;
disableIpv6Resolving = dnsProvider.dnsInfo!.disableIpv6;
blockingMode = dnsProvider.dnsInfo!.blockingMode;
ipv4controller.text = dnsProvider.dnsInfo!.blockingIpv4;
ipv6controller.text = dnsProvider.dnsInfo!.blockingIpv6;
isDataValid = true;
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: {
final result = await dnsProvider.saveDnsServerConfig({
"ratelimit": int.parse(limitRequestsController.text),
"edns_cs_enabled": enableEdns,
"dnssec_enabled": enableDnssec,
"disable_ipv6": disableIpv6Resolving,
"blocking_mode": blockingMode
"blocking_mode": blockingMode,
"blocking_ipv4": ipv4controller.text,
"blocking_ipv6": ipv6controller.text
});
processModal.close();
if (result['result'] == 'success') {
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);
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green
);
}
else if (result['log'] != null && result['log'].statusCode == '400') {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 400) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid,
@ -146,8 +131,6 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
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/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/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/services/http_requests.dart';
class PrivateReverseDnsServersScreen extends StatefulWidget {
final ServersProvider serversProvider;
const PrivateReverseDnsServersScreen({
Key? key,
required this.serversProvider,
}) : super(key: key);
const PrivateReverseDnsServersScreen({Key? key}) : super(key: key);
@override
State<PrivateReverseDnsServersScreen> createState() => _PrivateReverseDnsServersScreenState();
@ -69,10 +62,12 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
@override
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);
}
for (var item in widget.serversProvider.dnsInfo.data!.localPtrUpstreams) {
for (var item in dnsProvider.dnsInfo!.localPtrUpstreams) {
final controller = TextEditingController();
controller.text = item;
reverseResolversControllers = [{
@ -80,54 +75,46 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
'error': null
}];
}
if (widget.serversProvider.dnsInfo.data!.localPtrUpstreams.isNotEmpty) {
if (dnsProvider.dnsInfo!.localPtrUpstreams.isNotEmpty) {
editReverseResolvers = true;
}
usePrivateReverseDnsResolvers = widget.serversProvider.dnsInfo.data!.usePrivatePtrResolvers;
enableReverseResolve = widget.serversProvider.dnsInfo.data!.resolveClients;
usePrivateReverseDnsResolvers = dnsProvider.dnsInfo!.usePrivatePtrResolvers;
enableReverseResolve = dnsProvider.dnsInfo!.resolveClients;
validValues = true;
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveData() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await setDnsConfig(server: serversProvider.selectedServer!, data: editReverseResolvers == true
? {
"local_ptr_upstreams": List<String>.from(reverseResolversControllers.map((e) => e['controller'].text)),
"use_private_ptr_resolvers": usePrivateReverseDnsResolvers,
"resolve_clients": enableReverseResolve
} : {
"use_private_ptr_resolvers": usePrivateReverseDnsResolvers,
"resolve_clients": enableReverseResolve
});
final result = await dnsProvider.savePrivateReverseServersConfig(
editReverseResolvers == true
? {
"local_ptr_upstreams": List<String>.from(reverseResolversControllers.map((e) => e['controller'].text)),
"use_private_ptr_resolvers": usePrivateReverseDnsResolvers,
"resolve_clients": enableReverseResolve
} : {
"use_private_ptr_resolvers": usePrivateReverseDnsResolvers,
"resolve_clients": enableReverseResolve
}
);
processModal.close();
if (result['result'] == 'success') {
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);
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green
);
}
else if (result['log'] != null && result['log'].statusCode == '400') {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 400) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid,
@ -135,8 +122,6 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
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/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/providers/dns_provider.dart';
import 'package:adguard_home_manager/functions/snackbar.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 {
final ServersProvider serversProvider;
const UpstreamDnsScreen({
Key? key,
required this.serversProvider,
}) : super(key: key);
const UpstreamDnsScreen({Key? key}) : super(key: key);
@override
State<UpstreamDnsScreen> createState() => _UpstreamDnsScreenState();
@ -50,7 +43,9 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
@override
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 == '#') {
dnsServers.add({
'comment': item
@ -64,14 +59,14 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
});
}
}
upstreamMode = widget.serversProvider.dnsInfo.data!.upstreamMode;
upstreamMode = dnsProvider.dnsInfo!.upstreamMode;
validValues = true;
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final dnsProvider = Provider.of<DnsProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
@ -146,28 +141,21 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
ProcessModal processModal = ProcessModal(context: context);
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_mode": upstreamMode
});
processModal.close();
if (result['result'] == 'success') {
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);
if (result['success'] == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsConfigSaved,
color: Colors.green
);
}
else if (result['log'] != null && result['log'].statusCode == '400') {
appConfigProvider.addLog(result['log']);
else if (result['success'] == false && result['error'] == 400) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.someValueNotValid,
@ -175,8 +163,6 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
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';
class AddDnsRewriteModal extends StatefulWidget {
final void Function(RewriteRulesData) onConfirm;
final void Function(RewriteRules) onConfirm;
final bool dialog;
const AddDnsRewriteModal({
@ -143,7 +143,7 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
? () {
Navigator.pop(context);
widget.onConfirm(
RewriteRulesData(
RewriteRules(
domain: domainController.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/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/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/providers/servers_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
class DnsRewrites extends StatelessWidget {
const DnsRewrites({Key? key}) : super(key: key);
class DnsRewritesScreen extends StatefulWidget {
const DnsRewritesScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return DnsRewritesWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
State<DnsRewritesScreen> createState() => _DnsRewritesScreenState();
}
class DnsRewritesWidget extends StatefulWidget {
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);
}
}
class _DnsRewritesScreenState extends State<DnsRewritesScreen> {
@override
void initState() {
fetchData();
Provider.of<RewriteRulesProvider>(context, listen: false).fetchRules();
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final rewriteRulesProvider = Provider.of<RewriteRulesProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
void deleteDnsRewrite(RewriteRulesData rule) async {
void deleteDnsRewrite(RewriteRules rule) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.deleting);
final result = await deleteDnsRewriteRule(server: serversProvider.selectedServer!, data: {
"domain": rule.domain,
"answer": rule.answer
});
final result = await rewriteRulesProvider.deleteDnsRewrite(rule);
processModal.close();
if (result['result'] == 'success') {
List<RewriteRulesData> data = serversProvider.rewriteRules.data!;
data = data.where((item) => item.domain != rule.domain).toList();
serversProvider.setRewriteRulesData(data);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleDeleted,
@ -97,7 +53,6 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
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.open(AppLocalizations.of(context)!.addingRewrite);
final result = await addDnsRewriteRule(server: serversProvider.selectedServer!, data: {
"domain": rule.domain,
"answer": rule.answer
});
final result = await rewriteRulesProvider.addDnsRewrite(rule);
processModal.close();
if (result['result'] == 'success') {
List<RewriteRulesData> data = serversProvider.rewriteRules.data!;
data.add(rule);
serversProvider.setRewriteRulesData(data);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleAdded,
@ -129,7 +77,6 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.dnsRewriteRuleNotAdded,
@ -139,8 +86,8 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
}
Widget generateBody() {
switch (serversProvider.rewriteRules.loadStatus) {
case 0:
switch (rewriteRulesProvider.loadStatus) {
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -160,15 +107,22 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
),
);
case 1:
if (serversProvider.rewriteRules.data!.isNotEmpty) {
case LoadStatus.loaded:
if (rewriteRulesProvider.rewriteRules!.isNotEmpty) {
return RefreshIndicator(
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(
padding: const EdgeInsets.only(top: 0),
itemCount: serversProvider.rewriteRules.data!.length,
itemCount: rewriteRulesProvider.rewriteRules!.length,
itemBuilder: (context, index) => Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10),
decoration: BoxDecoration(
@ -195,7 +149,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
),
),
Text(
serversProvider.rewriteRules.data![index].domain,
rewriteRulesProvider.rewriteRules![index].domain,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface
),
@ -213,7 +167,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
),
),
Text(
serversProvider.rewriteRules.data![index].answer,
rewriteRulesProvider.rewriteRules![index].answer,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface
),
@ -227,7 +181,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
showDialog(
context: context,
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(
width: double.maxFinite,
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/functions/base64.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/servers_provider.dart';
@ -98,7 +97,7 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
void fetchData({bool? showRefreshIndicator}) async {
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 (result['result'] == 'success') {
@ -141,19 +140,21 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
Future checkValidDataApi({Map<String, dynamic>? data}) async {
setState(() => certKeyValidApi = 0);
final result = await checkEncryptionSettings(server: widget.serversProvider.selectedServer!, data: data ?? {
"enabled": enabled,
"server_name": domainNameController.text,
"force_https": redirectHttps,
"port_https": httpsPortController.text != '' ? int.parse(httpsPortController.text) : null,
"port_dns_over_tls": tlsPortController.text != '' ? int.parse(tlsPortController.text) : null,
"port_dns_over_quic": dnsOverQuicPortController.text != '' ? int.parse(dnsOverQuicPortController.text) : null,
if (certificateOption == 1) "certificate_chain": encodeBase64(certificateContentController.text),
if (privateKeyOption == 1 && usePreviouslySavedKey == false) "private_key": encodeBase64(pastePrivateKeyController.text),
"private_key_saved": usePreviouslySavedKey,
if (certificateOption == 0) "certificate_path": certificatePathController.text,
if (privateKeyOption == 0) "private_key_path": privateKeyPathController.text,
});
final result = await Provider.of<ServersProvider>(context, listen: false).apiClient!.checkEncryptionSettings(
data: data ?? {
"enabled": enabled,
"server_name": domainNameController.text,
"force_https": redirectHttps,
"port_https": httpsPortController.text != '' ? int.parse(httpsPortController.text) : null,
"port_dns_over_tls": tlsPortController.text != '' ? int.parse(tlsPortController.text) : null,
"port_dns_over_quic": dnsOverQuicPortController.text != '' ? int.parse(dnsOverQuicPortController.text) : null,
if (certificateOption == 1) "certificate_chain": encodeBase64(certificateContentController.text),
if (privateKeyOption == 1 && usePreviouslySavedKey == false) "private_key": encodeBase64(pastePrivateKeyController.text),
"private_key_saved": usePreviouslySavedKey,
if (certificateOption == 0) "certificate_path": certificatePathController.text,
if (privateKeyOption == 0) "private_key_path": privateKeyPathController.text,
}
);
if (mounted) {
if (result['result'] == 'success') {
@ -224,19 +225,21 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingConfig);
final result = await saveEncryptionSettings(server: serversProvider.selectedServer!, data: {
"enabled": enabled,
"server_name": domainNameController.text,
"force_https": redirectHttps,
"port_https": int.tryParse(httpsPortController.text),
"port_dns_over_tls": int.tryParse(tlsPortController.text),
"port_dns_over_quic": int.tryParse(dnsOverQuicPortController.text),
"certificate_chain": encodeBase64(certificateContentController.text),
"private_key": encodeBase64(pastePrivateKeyController.text),
"private_key_saved": usePreviouslySavedKey,
"certificate_path": certificatePathController.text,
"private_key_path": privateKeyPathController.text,
});
final result = await serversProvider.apiClient!.saveEncryptionSettings(
data: {
"enabled": enabled,
"server_name": domainNameController.text,
"force_https": redirectHttps,
"port_https": int.tryParse(httpsPortController.text),
"port_dns_over_tls": int.tryParse(tlsPortController.text),
"port_dns_over_quic": int.tryParse(dnsOverQuicPortController.text),
"certificate_chain": encodeBase64(certificateContentController.text),
"private_key": encodeBase64(pastePrivateKeyController.text),
"private_key_saved": usePreviouslySavedKey,
"certificate_path": certificatePathController.text,
"private_key_path": privateKeyPathController.text,
}
);
processModal.close();

View file

@ -2,20 +2,19 @@
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:provider/provider.dart';
import 'package:store_checker/store_checker.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/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/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/functions/compare_versions.dart';
class GeneralSettings extends StatefulWidget {
const GeneralSettings({Key? key}) : super(key: key);
@ -56,16 +55,16 @@ class _GeneralSettingsState extends State<GeneralSettings> {
Future checkUpdatesAvailable() async {
setState(() => appUpdatesStatus = AppUpdatesStatus.checking);
final result = await checkAppUpdatesGitHub();
if (result['result'] == 'success') {
final update = gitHubUpdateExists(appConfigProvider.getAppInfo!.version, result['body'].tagName);
if (update == true) {
appConfigProvider.setAppUpdatesAvailable(result['body']);
setState(() => appUpdatesStatus = AppUpdatesStatus.available);
}
else {
setState(() => appUpdatesStatus = AppUpdatesStatus.recheck);
}
final res = await checkAppUpdates(
currentBuildNumber: appConfigProvider.getAppInfo!.buildNumber,
setUpdateAvailable: appConfigProvider.setAppUpdatesAvailable,
installationSource: appConfigProvider.installationSource,
isBeta: appConfigProvider.getAppInfo!.version.contains('beta'),
);
if (res != null) {
setState(() => appUpdatesStatus = AppUpdatesStatus.available);
}
else {
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/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/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/servers_provider.dart';
class SafeSearchSettingsScreen extends StatelessWidget {
class SafeSearchSettingsScreen extends StatefulWidget {
const SafeSearchSettingsScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
return SafeSearchSettingsScreenWidget(
serversProvider: serversProvider,
appConfigProvider: appConfigProvider,
);
}
State<SafeSearchSettingsScreen> createState() => _SafeSearchSettingsScreenState();
}
class SafeSearchSettingsScreenWidget extends StatefulWidget {
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> {
class _SafeSearchSettingsScreenState extends State<SafeSearchSettingsScreen> {
bool generalEnabled = false;
bool bingEnabled = false;
bool duckduckgoEnabled = false;
@ -50,85 +27,66 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
bool pixabayEnabled = false;
bool yandexEnabled = false;
bool youtubeEnabled = false;
Future requestSafeSearchSettings() async {
if (mounted) {
final result = await getServerStatus(widget.serversProvider.selectedServer!);
if (mounted) {
if (result['result'] == 'success') {
widget.serversProvider.setServerStatusData(result['data']);
widget.serversProvider.setServerStatusLoad(1);
setState(() {
generalEnabled = result['data'].safeSearchEnabled;
bingEnabled = result['data'].safeSeachBing;
duckduckgoEnabled = result['data'].safeSearchDuckduckgo;
googleEnabled = result['data'].safeSearchGoogle;
pixabayEnabled = result['data'].safeSearchPixabay;
yandexEnabled = result['data'].safeSearchYandex;
youtubeEnabled = result['data'].safeSearchYoutube;
});
}
else {
widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setServerStatusLoad(2);
}
final result = await Provider.of<StatusProvider>(context, listen: false).getServerStatus();
if (mounted && result == true) {
final statusProvider = Provider.of<StatusProvider>(context, listen: false);
if (statusProvider.serverStatus != null) {
setState(() {
generalEnabled = statusProvider.serverStatus!.safeSearchEnabled;
bingEnabled = statusProvider.serverStatus!.safeSeachBing ?? false;
duckduckgoEnabled = statusProvider.serverStatus!.safeSearchDuckduckgo ?? false;
googleEnabled = statusProvider.serverStatus!.safeSearchGoogle ?? false;
pixabayEnabled = statusProvider.serverStatus!.safeSearchPixabay ?? false;
yandexEnabled = statusProvider.serverStatus!.safeSearchYandex ?? false;
youtubeEnabled = statusProvider.serverStatus!.safeSearchYoutube ?? false;
});
}
}
}
@override
void initState() {
if (widget.serversProvider.serverStatus.loadStatus == 0) {
final statusProvider = Provider.of<StatusProvider>(context, listen: false);
if (statusProvider.loadStatus == LoadStatus.loading) {
requestSafeSearchSettings();
}
else if (widget.serversProvider.serverStatus.loadStatus == 1) {
generalEnabled = widget.serversProvider.serverStatus.data!.safeSearchEnabled;
bingEnabled = widget.serversProvider.serverStatus.data!.safeSeachBing!;
duckduckgoEnabled = widget.serversProvider.serverStatus.data!.safeSearchDuckduckgo!;
googleEnabled = widget.serversProvider.serverStatus.data!.safeSearchGoogle!;
pixabayEnabled = widget.serversProvider.serverStatus.data!.safeSearchPixabay!;
yandexEnabled = widget.serversProvider.serverStatus.data!.safeSearchYandex!;
youtubeEnabled = widget.serversProvider.serverStatus.data!.safeSearchYoutube!;
else if (statusProvider.loadStatus == LoadStatus.loaded) {
generalEnabled = statusProvider.serverStatus!.safeSearchEnabled;
bingEnabled = statusProvider.serverStatus!.safeSeachBing!;
duckduckgoEnabled = statusProvider.serverStatus!.safeSearchDuckduckgo!;
googleEnabled = statusProvider.serverStatus!.safeSearchGoogle!;
pixabayEnabled = statusProvider.serverStatus!.safeSearchPixabay!;
yandexEnabled = statusProvider.serverStatus!.safeSearchYandex!;
youtubeEnabled = statusProvider.serverStatus!.safeSearchYoutube!;
}
super.initState();
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void saveConfig() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.savingSettings);
final result = await updateSafeSearchSettings(
server: serversProvider.selectedServer!,
body: {
"enabled": generalEnabled,
"bing": bingEnabled,
"duckduckgo": duckduckgoEnabled,
"google": googleEnabled,
"pixabay": pixabayEnabled,
"yandex": yandexEnabled,
"youtube": youtubeEnabled
}
);
final result = await statusProvider.updateSafeSearchConfig({
"enabled": generalEnabled,
"bing": bingEnabled,
"duckduckgo": duckduckgoEnabled,
"google": googleEnabled,
"pixabay": pixabayEnabled,
"yandex": yandexEnabled,
"youtube": youtubeEnabled
});
processModal.close();
if (result['result'] == 'success') {
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);
if (result == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsUpdatedSuccessfully,
@ -137,7 +95,6 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.settingsNotSaved,
@ -148,8 +105,8 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
}
Widget body() {
switch (serversProvider.serverStatus.loadStatus) {
case 0:
switch (statusProvider.loadStatus) {
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -170,7 +127,7 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
),
);
case 1:
case LoadStatus.loaded:
return RefreshIndicator(
onRefresh: requestSafeSearchSettings,
child: ListView(
@ -274,7 +231,7 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
),
);
case 2:
case LoadStatus.error:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -311,7 +268,7 @@ class _SafeSearchSettingsScreenWidgetState extends State<SafeSearchSettingsScree
centerTitle: false,
actions: [
IconButton(
onPressed: serversProvider.serverStatus.loadStatus == 1
onPressed: statusProvider.loadStatus == LoadStatus.loaded
? () => saveConfig()
: null,
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:flutter/material.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/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/providers/servers_provider.dart';
@ -41,20 +41,19 @@ class ServerInformationWidget extends StatefulWidget {
}
class _ServerInformationWidgetState extends State<ServerInformationWidget> {
ServerInfo serverInfo = ServerInfo(loadStatus: 0);
ServerInfo serverInfo = ServerInfo(loadStatus: LoadStatus.loading);
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 (result['result'] == 'success') {
setState(() {
serverInfo.loadStatus = 1;
serverInfo.loadStatus = LoadStatus.loaded;
serverInfo.data = result['data'];
});
}
else {
widget.appConfigProvider.addLog(result['log']);
setState(() => serverInfo.loadStatus = 2);
setState(() => serverInfo.loadStatus = LoadStatus.loaded);
}
}
}
@ -69,7 +68,7 @@ class _ServerInformationWidgetState extends State<ServerInformationWidget> {
Widget build(BuildContext context) {
Widget generateBody() {
switch (serverInfo.loadStatus) {
case 0:
case LoadStatus.loading:
return SizedBox(
width: double.maxFinite,
child: Column(
@ -93,7 +92,7 @@ class _ServerInformationWidgetState extends State<ServerInformationWidget> {
),
);
case 1:
case LoadStatus.loaded:
return ListView(
children: [
CustomListTile(
@ -145,7 +144,7 @@ class _ServerInformationWidgetState extends State<ServerInformationWidget> {
]
);
case 2:
case LoadStatus.error:
return SizedBox(
width: double.maxFinite,
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/compare_versions.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/app_config_provider.dart';
@ -67,8 +68,9 @@ class SettingsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(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;
@ -129,10 +131,14 @@ class SettingsWidget extends StatelessWidget {
],
body: ListView(
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),
if (serverVersionIsAhead(
currentVersion: serversProvider.serverStatus.data!.serverVersion,
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true) settingsTile(
@ -154,7 +160,7 @@ class SettingsWidget extends StatelessWidget {
title: AppLocalizations.of(context)!.dhcpSettings,
subtitle: AppLocalizations.of(context)!.dhcpSettingsDescription,
thisItem: 2,
screenToNavigate: const Dhcp(),
screenToNavigate: const DhcpScreen(),
),
settingsTile(
icon: Icons.dns_rounded,
@ -175,7 +181,7 @@ class SettingsWidget extends StatelessWidget {
title: AppLocalizations.of(context)!.dnsRewrites,
subtitle: AppLocalizations.of(context)!.dnsRewritesDescription,
thisItem: 5,
screenToNavigate: const DnsRewrites(),
screenToNavigate: const DnsRewritesScreen(),
),
if (serversProvider.updateAvailable.data != null) settingsTile(
icon: Icons.system_update_rounded,
@ -217,7 +223,7 @@ class SettingsWidget extends StatelessWidget {
icon: Icons.storage_rounded,
title: AppLocalizations.of(context)!.servers,
subtitle: serversProvider.selectedServer != null
? serversProvider.serverStatus.data != null
? statusProvider.serverStatus != null
? "${AppLocalizations.of(context)!.connectedTo} ${serversProvider.selectedServer!.name}"
: "${AppLocalizations.of(context)!.selectedServer} ${serversProvider.selectedServer!.name}"
: 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: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/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/open_url.dart';
@ -36,7 +35,7 @@ class UpdateScreen extends StatelessWidget {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.requestingUpdate);
final result = await requestUpdateServer(server: serversProvider.selectedServer!);
final result = await serversProvider.apiClient!.requestUpdateServer();
processModal.close();
@ -56,7 +55,6 @@ class UpdateScreen extends StatelessWidget {
color: Colors.red,
labelColor: Colors.white,
);
appConfigProvider.addLog(result['log']);
}
}
@ -92,8 +90,8 @@ class UpdateScreen extends StatelessWidget {
child: Column(
children: [
serversProvider.updateAvailable.loadStatus == LoadStatus.loading
? Column(
children: const [
? const Column(
children: [
CircularProgressIndicator(),
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/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/number_format.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 {
final String type;
@ -57,7 +56,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
@ -130,12 +129,8 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
),
body: RefreshIndicator(
onRefresh: () async {
final result = await getServerStatus(serversProvider.selectedServer!);
if (result['result'] == 'success') {
serversProvider.setServerStatusData(result['data']);
}
else {
appConfigProvider.addLog(result['log']);
final result = await statusProvider.getServerStatus();
if (result == false) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.serverStatusNotRefreshed,
@ -150,7 +145,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
String? name;
if (widget.isClient != null && widget.isClient == true) {
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) {
// ---- //
}

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/providers/logs_provider.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/servers_provider.dart';
class TopItemsModal extends StatefulWidget {
final String type;
@ -55,7 +55,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
@ -122,7 +122,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
String? name;
if (widget.isClient != null && widget.isClient == true) {
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) {
// ---- //
}

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/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/services/http_requests.dart';
import 'package:adguard_home_manager/models/app_log.dart';
@ -217,6 +219,7 @@ class _AddServerModalState extends State<AddServerModal> {
@override
Widget build(BuildContext context) {
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 mediaQuery = MediaQuery.of(context);
@ -257,13 +260,18 @@ class _AddServerModalState extends State<AddServerModal> {
}
final serverCreated = await serversProvider.createServer(serverObj);
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') {
serversProvider.setServerStatusData(serverStatus['data']);
serversProvider.setServerStatusLoad(1);
statusProvider.setServerStatusData(
data: serverStatus['data']
);
serversProvider.setApiClient(apiClient);
statusProvider.setServerStatusLoad(LoadStatus.loaded);
if (serverStatus['data'].serverVersion.contains('a') || serverStatus['data'].serverVersion.contains('b')) {
Navigator.pop(context);
widget.onUnsupportedVersion(serverStatus['data'].serverVersion);
@ -274,7 +282,7 @@ class _AddServerModalState extends State<AddServerModal> {
}
else {
appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2);
statusProvider.setServerStatusLoad(LoadStatus.error);
Navigator.pop(context);
}
}
@ -377,7 +385,8 @@ class _AddServerModalState extends State<AddServerModal> {
final serverSaved = await serversProvider.editServer(serverObj);
if (serverSaved == null) {
final version = await getServerVersion(serverObj);
final ApiClient apiClient = ApiClient(server: serverObj);
final version = await apiClient.getServerVersion();
if (
version['result'] == 'success' &&
(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 logsProvider = Provider.of<LogsProvider>(context);
List<AppScreen> screens = serversProvider.selectedServer != null
List<AppScreen> screens = serversProvider.selectedServer != null && serversProvider.apiClient != null
? screensServerConnected
: screensSelectServer;
String translatedName(String key) {
switch (key) {
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(
selectedIndex: appConfigProvider.selectedScreen,
selectedIndex: (serversProvider.selectedServer == null || serversProvider.apiClient == null) && appConfigProvider.selectedScreen > 1
? 0
: appConfigProvider.selectedScreen,
destinations: screens.map((screen) => NavigationDestination(
icon: Stack(
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/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/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/servers_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/models/menu_option.dart';
class DomainOptions extends StatelessWidget {
@ -36,59 +35,33 @@ class DomainOptions extends StatelessWidget {
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void blockUnblock(String domain, String newStatus) async {
final ProcessModal processModal = ProcessModal(context: context);
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') {
FilteringStatus oldStatus = serversProvider.serverStatus.data!.filteringStatus;
processModal.close();
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') {
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,
)
);
}
if (rules == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green
);
}
else {
appConfigProvider.addLog(rules['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
backgroundColor: Colors.red,
)
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: 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(
selectedIndex: appConfigProvider.selectedScreen,
selectedIndex: (serversProvider.selectedServer == null || serversProvider.apiClient == null) && appConfigProvider.selectedScreen > 1
? 0
: appConfigProvider.selectedScreen,
destinations: screens.map((screen) => NavigationRailDestination(
icon: 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/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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
@ -69,6 +71,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
@override
Widget build(BuildContext 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;
@ -132,18 +135,22 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
: await login(server);
if (result['result'] == 'success') {
final ApiClient apiClient = ApiClient(server: server);
serversProvider.setApiClient(apiClient);
serversProvider.setSelectedServer(server);
serversProvider.setServerStatusLoad(0);
final serverStatus = await getServerStatus(server);
statusProvider.setServerStatusLoad(LoadStatus.loading);
final serverStatus = await apiClient.getServerStatus();
if (serverStatus['result'] == 'success') {
serversProvider.setServerStatusData(serverStatus['data']);
statusProvider.setServerStatusData(
data: serverStatus['data']
);
serversProvider.checkServerUpdatesAvailable(server);
serversProvider.setServerStatusLoad(1);
statusProvider.setServerStatusLoad(LoadStatus.loaded);
}
else {
appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2);
statusProvider.setServerStatusLoad(LoadStatus.error);
}
process.close();
@ -192,7 +199,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
Icon(
Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null
? statusProvider.serverStatus != null
? Colors.green
: Colors.orange
: null,
@ -225,7 +232,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
return Icon(
Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null
? statusProvider.serverStatus != null
? Colors.green
: Colors.orange
: null,
@ -344,7 +351,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
decoration: BoxDecoration(
color: serversProvider.serverStatus.data != null
color: statusProvider.serverStatus != null
? Colors.green
: Colors.orange,
borderRadius: BorderRadius.circular(30)
@ -352,14 +359,14 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
child: Row(
children: [
Icon(
serversProvider.serverStatus.data != null
statusProvider.serverStatus != null
? Icons.check
: Icons.warning,
color: Colors.white,
),
const SizedBox(width: 10),
Text(
serversProvider.serverStatus.data != null
statusProvider.serverStatus != null
? AppLocalizations.of(context)!.connected
: AppLocalizations.of(context)!.selectedDisconnected,
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/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/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
@ -36,6 +38,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
@override
Widget build(BuildContext 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;
@ -99,18 +102,22 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
: await login(server);
if (result['result'] == 'success') {
final ApiClient apiClient = ApiClient(server: server);
serversProvider.setApiClient(apiClient);
serversProvider.setSelectedServer(server);
serversProvider.setServerStatusLoad(0);
final serverStatus = await getServerStatus(server);
statusProvider.setServerStatusLoad(LoadStatus.loading);
final serverStatus = await apiClient.getServerStatus();
if (serverStatus['result'] == 'success') {
serversProvider.setServerStatusData(serverStatus['data']);
statusProvider.setServerStatusData(
data: serverStatus['data']
);
serversProvider.checkServerUpdatesAvailable(server);
serversProvider.setServerStatusLoad(1);
statusProvider.setServerStatusLoad(LoadStatus.loaded);
}
else {
appConfigProvider.addLog(serverStatus['log']);
serversProvider.setServerStatusLoad(2);
statusProvider.setServerStatusLoad(LoadStatus.error);
}
process.close();
@ -159,7 +166,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
Icon(
Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null
? statusProvider.serverStatus != null
? Colors.green
: Colors.orange
: null,
@ -192,7 +199,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
return Icon(
Icons.storage_rounded,
color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id
? serversProvider.serverStatus.data != null
? statusProvider.serverStatus != null
? Colors.green
: Colors.orange
: null,
@ -305,13 +312,13 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
),
SizedBox(
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
? Container(
margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
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.orange,
borderRadius: BorderRadius.circular(30)
@ -319,14 +326,14 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
child: Row(
children: [
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.warning,
color: Colors.white,
),
const SizedBox(width: 10),
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)!.selectedDisconnected,
style: const TextStyle(

View file

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

View file

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