mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-20 13:59:12 +00:00
Support AGH without DHCP server
This commit is contained in:
parent
2511ac2c24
commit
83ea589187
9 changed files with 291 additions and 274 deletions
|
@ -688,5 +688,7 @@
|
||||||
"yourVersion": "Your version: {version}",
|
"yourVersion": "Your version: {version}",
|
||||||
"minimumRequiredVersion": "Minimum required version: {version}",
|
"minimumRequiredVersion": "Minimum required version: {version}",
|
||||||
"topUpstreams": "Top upstreams",
|
"topUpstreams": "Top upstreams",
|
||||||
"averageUpstreamResponseTime": "Average upstream response time"
|
"averageUpstreamResponseTime": "Average upstream response time",
|
||||||
|
"dhcpNotAvailable": "The DHCP server is not available.",
|
||||||
|
"osServerInstalledIncompatible": "The OS where the server is installed is not compatible with this feature."
|
||||||
}
|
}
|
|
@ -688,5 +688,7 @@
|
||||||
"yourVersion": "Tu versión: {version}",
|
"yourVersion": "Tu versión: {version}",
|
||||||
"minimumRequiredVersion": "Versión mínima requerida: {version}",
|
"minimumRequiredVersion": "Versión mínima requerida: {version}",
|
||||||
"topUpstreams": "DNS de subida más frecuentes",
|
"topUpstreams": "DNS de subida más frecuentes",
|
||||||
"averageUpstreamResponseTime": "Tiempo promedio de respuesta upstream"
|
"averageUpstreamResponseTime": "Tiempo promedio de respuesta upstream",
|
||||||
|
"dhcpNotAvailable": "El servidor DHCP no está disponible.",
|
||||||
|
"osServerInstalledIncompatible": "El SO donde el servidor está instalado no es compatible con esta característica."
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
class DhcpModel {
|
class DhcpModel {
|
||||||
|
bool dhcpAvailable;
|
||||||
List<NetworkInterface> networkInterfaces;
|
List<NetworkInterface> networkInterfaces;
|
||||||
DhcpStatus dhcpStatus;
|
DhcpStatus? dhcpStatus;
|
||||||
|
|
||||||
DhcpModel({
|
DhcpModel({
|
||||||
|
required this.dhcpAvailable,
|
||||||
required this.networkInterfaces,
|
required this.networkInterfaces,
|
||||||
required this.dhcpStatus,
|
required this.dhcpStatus,
|
||||||
});
|
});
|
||||||
|
|
|
@ -69,7 +69,7 @@ class DhcpProvider with ChangeNotifier {
|
||||||
|
|
||||||
if (result.successful == true) {
|
if (result.successful == true) {
|
||||||
DhcpModel data = dhcp!;
|
DhcpModel data = dhcp!;
|
||||||
data.dhcpStatus.staticLeases = data.dhcpStatus.staticLeases.where((l) => l.mac != lease.mac).toList();
|
data.dhcpStatus!.staticLeases = data.dhcpStatus!.staticLeases.where((l) => l.mac != lease.mac).toList();
|
||||||
setDhcpData(data);
|
setDhcpData(data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ class DhcpProvider with ChangeNotifier {
|
||||||
|
|
||||||
if (result.successful == true) {
|
if (result.successful == true) {
|
||||||
DhcpModel data = dhcp!;
|
DhcpModel data = dhcp!;
|
||||||
data.dhcpStatus.staticLeases.add(lease);
|
data.dhcpStatus!.staticLeases.add(lease);
|
||||||
setDhcpData(data);
|
setDhcpData(data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ import 'package:flutter_split_view/flutter_split_view.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/section_label.dart';
|
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp_not_available.dart';
|
||||||
import 'package:adguard_home_manager/widgets/confirm_action_modal.dart';
|
import 'package:adguard_home_manager/widgets/confirm_action_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp_main_button.dart';
|
||||||
|
import 'package:adguard_home_manager/widgets/section_label.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp_leases.dart';
|
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp_leases.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/dhcp/select_interface_modal.dart';
|
import 'package:adguard_home_manager/screens/settings/dhcp/select_interface_modal.dart';
|
||||||
|
|
||||||
|
@ -22,7 +24,7 @@ import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
|
||||||
class DhcpScreen extends StatefulWidget {
|
class DhcpScreen extends StatefulWidget {
|
||||||
const DhcpScreen({Key? key}) : super(key: key);
|
const DhcpScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DhcpScreen> createState() => _DhcpScreenState();
|
State<DhcpScreen> createState() => _DhcpScreenState();
|
||||||
|
@ -55,24 +57,25 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
|
|
||||||
void loadDhcpStatus() async {
|
void loadDhcpStatus() async {
|
||||||
final result = await Provider.of<DhcpProvider>(context, listen: false).loadDhcpStatus();
|
final result = await Provider.of<DhcpProvider>(context, listen: false).loadDhcpStatus();
|
||||||
if (mounted && result == true) {
|
if (!mounted || result == false) return;
|
||||||
|
|
||||||
final dhcpProvider = Provider.of<DhcpProvider>(context, listen: false);
|
final dhcpProvider = Provider.of<DhcpProvider>(context, listen: false);
|
||||||
if (dhcpProvider.dhcp != null) {
|
if (dhcpProvider.dhcp == null) return;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if (dhcpProvider.dhcp!.dhcpStatus.interfaceName != null && dhcpProvider.dhcp!.dhcpStatus.interfaceName != '') {
|
if (dhcpProvider.dhcp!.dhcpStatus!.interfaceName != null && dhcpProvider.dhcp!.dhcpStatus!.interfaceName != '') {
|
||||||
try {selectedInterface = dhcpProvider.dhcp!.networkInterfaces.firstWhere((iface) => iface.name == dhcpProvider.dhcp!.dhcpStatus.interfaceName);} catch (_) {}
|
try {selectedInterface = dhcpProvider.dhcp!.networkInterfaces.firstWhere((iface) => iface.name == dhcpProvider.dhcp!.dhcpStatus!.interfaceName);} catch (_) {}
|
||||||
enabled = dhcpProvider.dhcp!.dhcpStatus.enabled;
|
enabled = dhcpProvider.dhcp!.dhcpStatus!.enabled;
|
||||||
if (dhcpProvider.dhcp!.dhcpStatus.v4 != null) {
|
if (dhcpProvider.dhcp!.dhcpStatus!.v4 != null) {
|
||||||
ipv4StartRangeController.text = dhcpProvider.dhcp!.dhcpStatus.v4!.rangeStart;
|
ipv4StartRangeController.text = dhcpProvider.dhcp!.dhcpStatus!.v4!.rangeStart;
|
||||||
ipv4EndRangeController.text = dhcpProvider.dhcp!.dhcpStatus.v4!.rangeEnd ?? '';
|
ipv4EndRangeController.text = dhcpProvider.dhcp!.dhcpStatus!.v4!.rangeEnd ?? '';
|
||||||
ipv4SubnetMaskController.text = dhcpProvider.dhcp!.dhcpStatus.v4!.subnetMask ?? '';
|
ipv4SubnetMaskController.text = dhcpProvider.dhcp!.dhcpStatus!.v4!.subnetMask ?? '';
|
||||||
ipv4GatewayController.text = dhcpProvider.dhcp!.dhcpStatus.v4!.gatewayIp ?? '';
|
ipv4GatewayController.text = dhcpProvider.dhcp!.dhcpStatus!.v4!.gatewayIp ?? '';
|
||||||
ipv4LeaseTimeController.text = dhcpProvider.dhcp!.dhcpStatus.v4!.leaseDuration.toString();
|
ipv4LeaseTimeController.text = dhcpProvider.dhcp!.dhcpStatus!.v4!.leaseDuration.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
checkDataValid();
|
checkDataValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +269,8 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
|
|
||||||
if (result.successful == true) {
|
if (result.successful == true) {
|
||||||
DhcpModel data = dhcpProvider.dhcp!;
|
DhcpModel data = dhcpProvider.dhcp!;
|
||||||
data.dhcpStatus.staticLeases = [];
|
data.dhcpStatus!.staticLeases = [];
|
||||||
data.dhcpStatus.leases = [];
|
data.dhcpStatus!.leases = [];
|
||||||
dhcpProvider.setDhcpData(data);
|
dhcpProvider.setDhcpData(data);
|
||||||
|
|
||||||
showSnacbkar(
|
showSnacbkar(
|
||||||
|
@ -350,6 +353,14 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
dhcpProvider.loadStatus == LoadStatus.loaded &&
|
||||||
|
dhcpProvider.dhcp != null &&
|
||||||
|
dhcpProvider.dhcp!.dhcpAvailable == false
|
||||||
|
) {
|
||||||
|
return const DhcpNotAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.dhcpSettings),
|
title: Text(AppLocalizations.of(context)!.dhcpSettings),
|
||||||
|
@ -429,60 +440,10 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
DhcpMainButton(
|
||||||
padding: const EdgeInsets.only(
|
selectedInterface: selectedInterface,
|
||||||
top: 10,
|
enabled: enabled,
|
||||||
left: 16,
|
setEnabled: (v) => setState(() => enabled = v)
|
||||||
right: 16
|
|
||||||
),
|
|
||||||
child: Material(
|
|
||||||
color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: selectedInterface != null
|
|
||||||
? () => setState(() => enabled = !enabled)
|
|
||||||
: null,
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 20,
|
|
||||||
vertical: 12
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.enableDhcpServer,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (selectedInterface != null) ...[
|
|
||||||
Text(
|
|
||||||
selectedInterface!.name,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).listTileTheme.textColor
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Switch(
|
|
||||||
value: enabled,
|
|
||||||
onChanged: selectedInterface != null
|
|
||||||
? (value) => setState(() => enabled = value)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (selectedInterface!.ipv4Addresses.isNotEmpty) ...[
|
if (selectedInterface!.ipv4Addresses.isNotEmpty) ...[
|
||||||
SectionLabel(
|
SectionLabel(
|
||||||
|
@ -491,103 +452,37 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
top: 24, left: 16, right: 16, bottom: 8
|
top: 24, left: 16, right: 16, bottom: 8
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
FractionallySizedBox(
|
_DhcpField(
|
||||||
widthFactor: width > 900 ? 0.5 : 1,
|
icon: Icons.skip_previous_rounded,
|
||||||
child: Padding(
|
label: AppLocalizations.of(context)!.startOfRange,
|
||||||
padding: width > 900
|
|
||||||
? const EdgeInsets.only(top: 12, bottom: 12, left: 16, right: 8)
|
|
||||||
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv4StartRangeController,
|
controller: ipv4StartRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
decoration: InputDecoration(
|
error: ipv4StartRangeError
|
||||||
prefixIcon: const Icon(Icons.skip_previous_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
errorText: ipv4StartRangeError,
|
_DhcpField(
|
||||||
labelText: AppLocalizations.of(context)!.startOfRange,
|
icon: Icons.skip_next_rounded,
|
||||||
),
|
label: AppLocalizations.of(context)!.endOfRange,
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: width > 900 ? 0.5 : 1,
|
|
||||||
child: Padding(
|
|
||||||
padding: width > 900
|
|
||||||
? const EdgeInsets.only(top: 12, bottom: 12, left: 8, right: 16)
|
|
||||||
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv4EndRangeController,
|
controller: ipv4EndRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
decoration: InputDecoration(
|
error: ipv4EndRangeError
|
||||||
prefixIcon: const Icon(Icons.skip_next_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
errorText: ipv4EndRangeError,
|
_DhcpField(
|
||||||
labelText: AppLocalizations.of(context)!.endOfRange,
|
icon: Icons.hub_rounded,
|
||||||
),
|
label: AppLocalizations.of(context)!.subnetMask,
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: width > 900 ? 0.5 : 1,
|
|
||||||
child: Padding(
|
|
||||||
padding: width > 900
|
|
||||||
? const EdgeInsets.only(top: 12, bottom: 12, left: 16, right: 8)
|
|
||||||
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv4SubnetMaskController,
|
controller: ipv4SubnetMaskController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4SubnetMaskError', AppLocalizations.of(context)!.subnetMaskNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4SubnetMaskError', AppLocalizations.of(context)!.subnetMaskNotValid),
|
||||||
decoration: InputDecoration(
|
error: ipv4SubnetMaskError
|
||||||
prefixIcon: const Icon(Icons.hub_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
errorText: ipv4SubnetMaskError,
|
_DhcpField(
|
||||||
labelText: AppLocalizations.of(context)!.subnetMask,
|
icon: Icons.router_rounded,
|
||||||
),
|
label: AppLocalizations.of(context)!.gateway,
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: width > 900 ? 0.5 : 1,
|
|
||||||
child: Padding(
|
|
||||||
padding: width > 900
|
|
||||||
? const EdgeInsets.only(top: 12, bottom: 12, left: 8, right: 16)
|
|
||||||
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv4GatewayController,
|
controller: ipv4GatewayController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4GatewayError', AppLocalizations.of(context)!.gatewayNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4GatewayError', AppLocalizations.of(context)!.gatewayNotValid),
|
||||||
decoration: InputDecoration(
|
error: ipv4GatewayError
|
||||||
prefixIcon: const Icon(Icons.router_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
errorText: ipv4GatewayError,
|
_DhcpField(
|
||||||
labelText: AppLocalizations.of(context)!.gateway,
|
icon: Icons.timer,
|
||||||
),
|
label: AppLocalizations.of(context)!.leaseTime,
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: 1,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv4LeaseTimeController,
|
controller: ipv4LeaseTimeController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (int.tryParse(value).runtimeType == int) {
|
if (int.tryParse(value).runtimeType == int) {
|
||||||
|
@ -597,19 +492,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
setState(() => ipv4LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
|
setState(() => ipv4LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
error: ipv4LeaseTimeError
|
||||||
prefixIcon: const Icon(Icons.timer),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
errorText: ipv4LeaseTimeError,
|
|
||||||
labelText: AppLocalizations.of(context)!.leaseTime,
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (selectedInterface!.ipv6Addresses.isNotEmpty) ...[
|
if (selectedInterface!.ipv6Addresses.isNotEmpty) ...[
|
||||||
|
@ -617,57 +500,23 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
label: AppLocalizations.of(context)!.ipv6settings,
|
label: AppLocalizations.of(context)!.ipv6settings,
|
||||||
padding: const EdgeInsets.all(16)
|
padding: const EdgeInsets.all(16)
|
||||||
),
|
),
|
||||||
FractionallySizedBox(
|
_DhcpField(
|
||||||
widthFactor: width > 900 ? 0.5 : 1,
|
icon: Icons.skip_next_rounded,
|
||||||
child: Padding(
|
label: AppLocalizations.of(context)!.startOfRange,
|
||||||
padding: width > 900
|
|
||||||
? const EdgeInsets.only(top: 8, bottom: 12, left: 16, right: 8)
|
|
||||||
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv6StartRangeController,
|
controller: ipv6StartRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv6StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV6(value, 'ipv6StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
decoration: InputDecoration(
|
error: ipv6StartRangeError
|
||||||
prefixIcon: const Icon(Icons.skip_next_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
errorText: ipv6StartRangeError,
|
_DhcpField(
|
||||||
labelText: AppLocalizations.of(context)!.startOfRange,
|
icon: Icons.skip_previous_rounded,
|
||||||
),
|
label: AppLocalizations.of(context)!.endOfRange,
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: width > 900 ? 0.5 : 1,
|
|
||||||
child: Padding(
|
|
||||||
padding: width > 900
|
|
||||||
? const EdgeInsets.only(top: 8, bottom: 12, left: 8, right: 16)
|
|
||||||
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv6EndRangeController,
|
controller: ipv6EndRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv6EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV6(value, 'ipv6EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
decoration: InputDecoration(
|
error: ipv6EndRangeError
|
||||||
prefixIcon: const Icon(Icons.skip_previous_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
errorText: ipv6EndRangeError,
|
_DhcpField(
|
||||||
labelText: AppLocalizations.of(context)!.endOfRange,
|
icon: Icons.timer,
|
||||||
),
|
label: AppLocalizations.of(context)!.leaseTime,
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: 1,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: ipv6LeaseTimeController,
|
controller: ipv6LeaseTimeController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (int.tryParse(value).runtimeType == int) {
|
if (int.tryParse(value).runtimeType == int) {
|
||||||
|
@ -677,20 +526,8 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
setState(() => ipv6LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
|
setState(() => ipv6LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
error: ipv6LeaseTimeError
|
||||||
prefixIcon: const Icon(Icons.timer),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
)
|
||||||
),
|
|
||||||
errorText: ipv6LeaseTimeError,
|
|
||||||
labelText: AppLocalizations.of(context)!.leaseTime,
|
|
||||||
),
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
SectionLabel(
|
SectionLabel(
|
||||||
|
@ -704,7 +541,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DhcpLeases(
|
builder: (context) => DhcpLeases(
|
||||||
items: dhcpProvider.dhcp!.dhcpStatus.leases,
|
items: dhcpProvider.dhcp!.dhcpStatus!.leases,
|
||||||
staticLeases: false,
|
staticLeases: false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -739,7 +576,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DhcpLeases(
|
builder: (context) => DhcpLeases(
|
||||||
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
|
items: dhcpProvider.dhcp!.dhcpStatus!.staticLeases,
|
||||||
staticLeases: true,
|
staticLeases: true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -775,7 +612,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
if (!(Platform.isAndroid || Platform.isIOS)) {
|
if (!(Platform.isAndroid || Platform.isIOS)) {
|
||||||
SplitView.of(context).push(
|
SplitView.of(context).push(
|
||||||
DhcpLeases(
|
DhcpLeases(
|
||||||
items: dhcpProvider.dhcp!.dhcpStatus.leases,
|
items: dhcpProvider.dhcp!.dhcpStatus!.leases,
|
||||||
staticLeases: false,
|
staticLeases: false,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -784,7 +621,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DhcpLeases(
|
builder: (context) => DhcpLeases(
|
||||||
items: dhcpProvider.dhcp!.dhcpStatus.leases,
|
items: dhcpProvider.dhcp!.dhcpStatus!.leases,
|
||||||
staticLeases: false,
|
staticLeases: false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -804,7 +641,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
if (!(Platform.isAndroid || Platform.isIOS)) {
|
if (!(Platform.isAndroid || Platform.isIOS)) {
|
||||||
SplitView.of(context).push(
|
SplitView.of(context).push(
|
||||||
DhcpLeases(
|
DhcpLeases(
|
||||||
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
|
items: dhcpProvider.dhcp!.dhcpStatus!.staticLeases,
|
||||||
staticLeases: true,
|
staticLeases: true,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -813,7 +650,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DhcpLeases(
|
builder: (context) => DhcpLeases(
|
||||||
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
|
items: dhcpProvider.dhcp!.dhcpStatus!.staticLeases,
|
||||||
staticLeases: true,
|
staticLeases: true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -900,3 +737,48 @@ class _DhcpScreenState extends State<DhcpScreen> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DhcpField extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final String label;
|
||||||
|
final TextEditingController controller;
|
||||||
|
final void Function(String) onChanged;
|
||||||
|
final String? error;
|
||||||
|
|
||||||
|
const _DhcpField({
|
||||||
|
required this.icon,
|
||||||
|
required this.label,
|
||||||
|
required this.controller,
|
||||||
|
required this.onChanged,
|
||||||
|
required this.error,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
return FractionallySizedBox(
|
||||||
|
widthFactor: width > 900 ? 0.5 : 1,
|
||||||
|
child: Padding(
|
||||||
|
padding: width > 900
|
||||||
|
? const EdgeInsets.only(top: 12, bottom: 12, left: 16, right: 8)
|
||||||
|
: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
onChanged: onChanged,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: Icon(icon),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: error,
|
||||||
|
labelText: label,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
76
lib/screens/settings/dhcp/dhcp_main_button.dart
Normal file
76
lib/screens/settings/dhcp/dhcp_main_button.dart
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/models/dhcp.dart';
|
||||||
|
|
||||||
|
class DhcpMainButton extends StatelessWidget {
|
||||||
|
final NetworkInterface? selectedInterface;
|
||||||
|
final bool enabled;
|
||||||
|
final void Function(bool) setEnabled;
|
||||||
|
|
||||||
|
const DhcpMainButton({
|
||||||
|
super.key,
|
||||||
|
required this.selectedInterface,
|
||||||
|
required this.enabled,
|
||||||
|
required this.setEnabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 10,
|
||||||
|
left: 16,
|
||||||
|
right: 16
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: selectedInterface != null
|
||||||
|
? () => setEnabled(!enabled)
|
||||||
|
: null,
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 12
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.enableDhcpServer,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (selectedInterface != null) ...[
|
||||||
|
Text(
|
||||||
|
selectedInterface!.name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: enabled,
|
||||||
|
onChanged: selectedInterface != null
|
||||||
|
? (value) => setEnabled(value)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
47
lib/screens/settings/dhcp/dhcp_not_available.dart
Normal file
47
lib/screens/settings/dhcp/dhcp_not_available.dart
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/functions/desktop_mode.dart';
|
||||||
|
|
||||||
|
class DhcpNotAvailable extends StatelessWidget {
|
||||||
|
const DhcpNotAvailable({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context)!.dhcpSettings),
|
||||||
|
centerTitle: false,
|
||||||
|
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.dhcpNotAvailable,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 24
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.osServerInstalledIncompatible,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -482,8 +482,13 @@ class ApiClientV2 {
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
successful: true,
|
successful: true,
|
||||||
content: DhcpModel(
|
content: DhcpModel(
|
||||||
|
dhcpAvailable: jsonDecode(results[1].body!)['message'] != null
|
||||||
|
? false
|
||||||
|
: true,
|
||||||
networkInterfaces: interfaces,
|
networkInterfaces: interfaces,
|
||||||
dhcpStatus: DhcpStatus.fromJson(jsonDecode(results[1].body!))
|
dhcpStatus: jsonDecode(results[1].body!)['message'] != null
|
||||||
|
? null
|
||||||
|
: DhcpStatus.fromJson(jsonDecode(results[1].body!))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
|
|
|
@ -1352,6 +1352,7 @@ class ApiClient {
|
||||||
return {
|
return {
|
||||||
'result': 'success',
|
'result': 'success',
|
||||||
'data': DhcpModel(
|
'data': DhcpModel(
|
||||||
|
dhcpAvailable: true,
|
||||||
networkInterfaces: interfaces,
|
networkInterfaces: interfaces,
|
||||||
dhcpStatus: DhcpStatus.fromJson(jsonDecode(result[1]['body']))
|
dhcpStatus: DhcpStatus.fromJson(jsonDecode(result[1]['body']))
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue