mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-21 14:29:12 +00:00
308 lines
No EOL
12 KiB
Dart
308 lines
No EOL
12 KiB
Dart
// 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/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/functions/desktop_mode.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';
|
|
|
|
class DnsServerSettingsScreen extends StatefulWidget {
|
|
const DnsServerSettingsScreen({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
State<DnsServerSettingsScreen> createState() => _DnsServerSettingsScreenState();
|
|
}
|
|
|
|
class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
|
final TextEditingController limitRequestsController = TextEditingController();
|
|
String? limitRequestsError;
|
|
bool enableEdns = false;
|
|
bool enableDnssec = false;
|
|
bool disableIpv6Resolving = false;
|
|
|
|
String blockingMode = "default";
|
|
|
|
final TextEditingController ipv4controller = TextEditingController();
|
|
String? ipv4error;
|
|
final TextEditingController ipv6controller = TextEditingController();
|
|
String? ipv6error;
|
|
|
|
bool isDataValid = false;
|
|
|
|
void validateIpv4(String value) {
|
|
RegExp ipAddress = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$');
|
|
if (ipAddress.hasMatch(value) == true) {
|
|
setState(() => ipv4error = null);
|
|
}
|
|
else {
|
|
setState(() => ipv4error = AppLocalizations.of(context)!.invalidIp);
|
|
}
|
|
validateData();
|
|
}
|
|
|
|
void validateIpv6(String value) {
|
|
RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)');
|
|
if (ipAddress.hasMatch(value) == true) {
|
|
setState(() => ipv6error = null);
|
|
}
|
|
else {
|
|
setState(() => ipv6error = AppLocalizations.of(context)!.invalidIp);
|
|
}
|
|
validateData();
|
|
}
|
|
|
|
void validateData() {
|
|
if (
|
|
limitRequestsController.text != '' &&
|
|
limitRequestsError == null &&
|
|
(
|
|
blockingMode != 'custom_ip' ||
|
|
(
|
|
blockingMode == 'custom_ip' &&
|
|
ipv4controller.text != '' &&
|
|
ipv4error == null &&
|
|
ipv6controller.text != '' &&
|
|
ipv6error == null
|
|
)
|
|
) == true
|
|
) {
|
|
setState(() => isDataValid = true);
|
|
}
|
|
else {
|
|
setState(() => isDataValid = false);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
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 dnsProvider = Provider.of<DnsProvider>(context);
|
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
|
final width = MediaQuery.of(context).size.width;
|
|
|
|
void saveData() async {
|
|
ProcessModal processModal = ProcessModal(context: context);
|
|
processModal.open(AppLocalizations.of(context)!.savingConfig);
|
|
|
|
final result = await dnsProvider.saveDnsServerConfig({
|
|
"ratelimit": int.parse(limitRequestsController.text),
|
|
"edns_cs_enabled": enableEdns,
|
|
"dnssec_enabled": enableDnssec,
|
|
"disable_ipv6": disableIpv6Resolving,
|
|
"blocking_mode": blockingMode,
|
|
"blocking_ipv4": ipv4controller.text,
|
|
"blocking_ipv6": ipv6controller.text
|
|
});
|
|
|
|
processModal.close();
|
|
|
|
if (result['success'] == true) {
|
|
showSnacbkar(
|
|
appConfigProvider: appConfigProvider,
|
|
label: AppLocalizations.of(context)!.dnsConfigSaved,
|
|
color: Colors.green
|
|
);
|
|
}
|
|
else if (result['success'] == false && result['error'] == 400) {
|
|
showSnacbkar(
|
|
appConfigProvider: appConfigProvider,
|
|
label: AppLocalizations.of(context)!.someValueNotValid,
|
|
color: Colors.red
|
|
);
|
|
}
|
|
else {
|
|
showSnacbkar(
|
|
appConfigProvider: appConfigProvider,
|
|
label: AppLocalizations.of(context)!.dnsConfigNotSaved,
|
|
color: Colors.red
|
|
);
|
|
}
|
|
}
|
|
|
|
void updateBlockingMode(String mode) {
|
|
if (mode != 'custom_ip') {
|
|
ipv4controller.text = '';
|
|
ipv4error = null;
|
|
ipv6controller.text = '';
|
|
ipv6error = null;
|
|
}
|
|
setState(() => blockingMode = mode);
|
|
validateData();
|
|
}
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text(AppLocalizations.of(context)!.dnsServerSettings),
|
|
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
|
|
actions: [
|
|
IconButton(
|
|
onPressed: isDataValid == true
|
|
? () => saveData()
|
|
: null,
|
|
icon: const Icon(Icons.save_rounded),
|
|
tooltip: AppLocalizations.of(context)!.save,
|
|
),
|
|
const SizedBox(width: 10)
|
|
],
|
|
),
|
|
body: ListView(
|
|
padding: const EdgeInsets.only(top: 10),
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: TextFormField(
|
|
controller: limitRequestsController,
|
|
onChanged: (value) {
|
|
if (int.tryParse(value) != null) {
|
|
setState(() => limitRequestsError = null);
|
|
}
|
|
else {
|
|
setState(() => limitRequestsError = AppLocalizations.of(context)!.valueNotNumber);
|
|
}
|
|
validateData();
|
|
},
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.looks_one_rounded),
|
|
border: const OutlineInputBorder(
|
|
borderRadius: BorderRadius.all(
|
|
Radius.circular(10)
|
|
)
|
|
),
|
|
labelText: AppLocalizations.of(context)!.limitRequestsSecond,
|
|
errorText: limitRequestsError
|
|
),
|
|
keyboardType: TextInputType.number,
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
CustomSwitchListTile(
|
|
value: enableEdns,
|
|
onChanged: (value) => setState(() => enableEdns = value),
|
|
title: AppLocalizations.of(context)!.enableEdns,
|
|
subtitle: AppLocalizations.of(context)!.enableEdnsDescription,
|
|
),
|
|
CustomSwitchListTile(
|
|
value: enableDnssec,
|
|
onChanged: (value) => setState(() => enableDnssec = value),
|
|
title: AppLocalizations.of(context)!.enableDnssec,
|
|
subtitle: AppLocalizations.of(context)!.enableDnssecDescription,
|
|
),
|
|
CustomSwitchListTile(
|
|
value: disableIpv6Resolving,
|
|
onChanged: (value) => setState(() => disableIpv6Resolving = value),
|
|
title: AppLocalizations.of(context)!.disableResolvingIpv6,
|
|
subtitle: AppLocalizations.of(context)!.disableResolvingIpv6Description,
|
|
),
|
|
SectionLabel(label: AppLocalizations.of(context)!.blockingMode),
|
|
CustomRadioListTile(
|
|
groupValue: blockingMode,
|
|
value: "default",
|
|
radioBackgroundColor: Theme.of(context).dialogBackgroundColor,
|
|
title: AppLocalizations.of(context)!.defaultMode,
|
|
subtitle: AppLocalizations.of(context)!.defaultDescription,
|
|
onChanged: updateBlockingMode,
|
|
),
|
|
CustomRadioListTile(
|
|
groupValue: blockingMode,
|
|
value: "refused",
|
|
radioBackgroundColor: Theme.of(context).dialogBackgroundColor,
|
|
title: "REFUSED",
|
|
subtitle: AppLocalizations.of(context)!.refusedDescription,
|
|
onChanged: updateBlockingMode,
|
|
),
|
|
CustomRadioListTile(
|
|
groupValue: blockingMode,
|
|
value: "nxdomain",
|
|
radioBackgroundColor: Theme.of(context).dialogBackgroundColor,
|
|
title: "NXDOMAIN",
|
|
subtitle: AppLocalizations.of(context)!.nxdomainDescription,
|
|
onChanged: updateBlockingMode,
|
|
),
|
|
CustomRadioListTile(
|
|
groupValue: blockingMode,
|
|
value: "null_ip",
|
|
radioBackgroundColor: Theme.of(context).dialogBackgroundColor,
|
|
title: AppLocalizations.of(context)!.nullIp,
|
|
subtitle: AppLocalizations.of(context)!.nullIpDescription,
|
|
onChanged: updateBlockingMode,
|
|
),
|
|
CustomRadioListTile(
|
|
groupValue: blockingMode,
|
|
value: "custom_ip",
|
|
radioBackgroundColor: Theme.of(context).dialogBackgroundColor,
|
|
title: AppLocalizations.of(context)!.customIp,
|
|
subtitle: AppLocalizations.of(context)!.customIpDescription,
|
|
onChanged: updateBlockingMode,
|
|
),
|
|
const SizedBox(height: 10),
|
|
if (blockingMode == 'custom_ip') ...[
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
child: TextFormField(
|
|
controller: ipv4controller,
|
|
onChanged: validateIpv4,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.link_rounded),
|
|
border: const OutlineInputBorder(
|
|
borderRadius: BorderRadius.all(
|
|
Radius.circular(10)
|
|
)
|
|
),
|
|
errorText: ipv4error,
|
|
helperText: AppLocalizations.of(context)!.blockingIpv4Description,
|
|
helperMaxLines: 10,
|
|
labelText: AppLocalizations.of(context)!.blockingIpv4,
|
|
),
|
|
keyboardType: TextInputType.number,
|
|
),
|
|
),
|
|
const SizedBox(height: 30),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
child: TextFormField(
|
|
controller: ipv6controller,
|
|
onChanged: validateIpv6,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.link_rounded),
|
|
border: const OutlineInputBorder(
|
|
borderRadius: BorderRadius.all(
|
|
Radius.circular(10)
|
|
)
|
|
),
|
|
errorText: ipv6error,
|
|
helperText: AppLocalizations.of(context)!.blockingIpv6Description,
|
|
helperMaxLines: 10,
|
|
labelText: AppLocalizations.of(context)!.blockingIpv6,
|
|
),
|
|
keyboardType: TextInputType.number,
|
|
),
|
|
),
|
|
const SizedBox(height: 30)
|
|
]
|
|
],
|
|
),
|
|
);
|
|
}
|
|
} |