Support AGH without DHCP server

This commit is contained in:
Juan Gilsanz Polo 2023-12-08 20:43:45 +01:00
parent 2511ac2c24
commit 83ea589187
9 changed files with 291 additions and 274 deletions

View file

@ -688,5 +688,7 @@
"yourVersion": "Your version: {version}",
"minimumRequiredVersion": "Minimum required version: {version}",
"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."
}

View file

@ -688,5 +688,7 @@
"yourVersion": "Tu versión: {version}",
"minimumRequiredVersion": "Versión mínima requerida: {version}",
"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."
}

View file

@ -1,9 +1,11 @@
import 'dart:convert';
class DhcpModel {
bool dhcpAvailable;
List<NetworkInterface> networkInterfaces;
DhcpStatus dhcpStatus;
DhcpStatus? dhcpStatus;
DhcpModel({
required this.dhcpAvailable,
required this.networkInterfaces,
required this.dhcpStatus,
});

View file

@ -69,7 +69,7 @@ class DhcpProvider with ChangeNotifier {
if (result.successful == true) {
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);
return true;
}
@ -90,7 +90,7 @@ class DhcpProvider with ChangeNotifier {
if (result.successful == true) {
DhcpModel data = dhcp!;
data.dhcpStatus.staticLeases.add(lease);
data.dhcpStatus!.staticLeases.add(lease);
setDhcpData(data);
return result;
}

View file

@ -7,8 +7,10 @@ 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/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/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/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';
class DhcpScreen extends StatefulWidget {
const DhcpScreen({Key? key}) : super(key: key);
const DhcpScreen({super.key});
@override
State<DhcpScreen> createState() => _DhcpScreenState();
@ -55,24 +57,25 @@ class _DhcpScreenState extends State<DhcpScreen> {
void loadDhcpStatus() async {
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 (dhcpProvider.dhcp!.dhcpStatus.interfaceName != null && dhcpProvider.dhcp!.dhcpStatus.interfaceName != '') {
try {selectedInterface = dhcpProvider.dhcp!.networkInterfaces.firstWhere((iface) => iface.name == dhcpProvider.dhcp!.dhcpStatus.interfaceName);} catch (_) {}
enabled = dhcpProvider.dhcp!.dhcpStatus.enabled;
if (dhcpProvider.dhcp!.dhcpStatus.v4 != null) {
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();
}
}
});
if (!mounted || result == false) return;
final dhcpProvider = Provider.of<DhcpProvider>(context, listen: false);
if (dhcpProvider.dhcp == null) return;
setState(() {
if (dhcpProvider.dhcp!.dhcpStatus!.interfaceName != null && dhcpProvider.dhcp!.dhcpStatus!.interfaceName != '') {
try {selectedInterface = dhcpProvider.dhcp!.networkInterfaces.firstWhere((iface) => iface.name == dhcpProvider.dhcp!.dhcpStatus!.interfaceName);} catch (_) {}
enabled = dhcpProvider.dhcp!.dhcpStatus!.enabled;
if (dhcpProvider.dhcp!.dhcpStatus!.v4 != null) {
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();
}
}
}
});
checkDataValid();
}
@ -266,8 +269,8 @@ class _DhcpScreenState extends State<DhcpScreen> {
if (result.successful == true) {
DhcpModel data = dhcpProvider.dhcp!;
data.dhcpStatus.staticLeases = [];
data.dhcpStatus.leases = [];
data.dhcpStatus!.staticLeases = [];
data.dhcpStatus!.leases = [];
dhcpProvider.setDhcpData(data);
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(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.dhcpSettings),
@ -429,60 +440,10 @@ class _DhcpScreenState extends State<DhcpScreen> {
return SingleChildScrollView(
child: Wrap(
children: [
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
? () => 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,
),
],
),
),
),
),
DhcpMainButton(
selectedInterface: selectedInterface,
enabled: enabled,
setEnabled: (v) => setState(() => enabled = v)
),
if (selectedInterface!.ipv4Addresses.isNotEmpty) ...[
SectionLabel(
@ -491,125 +452,47 @@ class _DhcpScreenState extends State<DhcpScreen> {
top: 24, left: 16, right: 16, bottom: 8
)
),
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: ipv4StartRangeController,
onChanged: (value) => validateIpV4(value, 'ipv4StartRangeError', AppLocalizations.of(context)!.ipNotValid),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.skip_previous_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv4StartRangeError,
labelText: AppLocalizations.of(context)!.startOfRange,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.skip_previous_rounded,
label: AppLocalizations.of(context)!.startOfRange,
controller: ipv4StartRangeController,
onChanged: (value) => validateIpV4(value, 'ipv4StartRangeError', AppLocalizations.of(context)!.ipNotValid),
error: ipv4StartRangeError
),
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,
onChanged: (value) => validateIpV4(value, 'ipv4EndRangeError', AppLocalizations.of(context)!.ipNotValid),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.skip_next_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv4EndRangeError,
labelText: AppLocalizations.of(context)!.endOfRange,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.skip_next_rounded,
label: AppLocalizations.of(context)!.endOfRange,
controller: ipv4EndRangeController,
onChanged: (value) => validateIpV4(value, 'ipv4EndRangeError', AppLocalizations.of(context)!.ipNotValid),
error: ipv4EndRangeError
),
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,
onChanged: (value) => validateIpV4(value, 'ipv4SubnetMaskError', AppLocalizations.of(context)!.subnetMaskNotValid),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.hub_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv4SubnetMaskError,
labelText: AppLocalizations.of(context)!.subnetMask,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.hub_rounded,
label: AppLocalizations.of(context)!.subnetMask,
controller: ipv4SubnetMaskController,
onChanged: (value) => validateIpV4(value, 'ipv4SubnetMaskError', AppLocalizations.of(context)!.subnetMaskNotValid),
error: ipv4SubnetMaskError
),
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,
onChanged: (value) => validateIpV4(value, 'ipv4GatewayError', AppLocalizations.of(context)!.gatewayNotValid),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.router_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv4GatewayError,
labelText: AppLocalizations.of(context)!.gateway,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.router_rounded,
label: AppLocalizations.of(context)!.gateway,
controller: ipv4GatewayController,
onChanged: (value) => validateIpV4(value, 'ipv4GatewayError', AppLocalizations.of(context)!.gatewayNotValid),
error: ipv4GatewayError
),
FractionallySizedBox(
widthFactor: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: TextFormField(
controller: ipv4LeaseTimeController,
onChanged: (value) {
if (int.tryParse(value).runtimeType == int) {
setState(() => ipv4LeaseTimeError = null);
}
else {
setState(() => ipv4LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
}
},
decoration: InputDecoration(
prefixIcon: const Icon(Icons.timer),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv4LeaseTimeError,
labelText: AppLocalizations.of(context)!.leaseTime,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.timer,
label: AppLocalizations.of(context)!.leaseTime,
controller: ipv4LeaseTimeController,
onChanged: (value) {
if (int.tryParse(value).runtimeType == int) {
setState(() => ipv4LeaseTimeError = null);
}
else {
setState(() => ipv4LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
}
},
error: ipv4LeaseTimeError
),
],
if (selectedInterface!.ipv6Addresses.isNotEmpty) ...[
@ -617,80 +500,34 @@ class _DhcpScreenState extends State<DhcpScreen> {
label: AppLocalizations.of(context)!.ipv6settings,
padding: const EdgeInsets.all(16)
),
FractionallySizedBox(
widthFactor: width > 900 ? 0.5 : 1,
child: Padding(
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,
onChanged: (value) => validateIpV4(value, 'ipv6StartRangeError', AppLocalizations.of(context)!.ipNotValid),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.skip_next_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv6StartRangeError,
labelText: AppLocalizations.of(context)!.startOfRange,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.skip_next_rounded,
label: AppLocalizations.of(context)!.startOfRange,
controller: ipv6StartRangeController,
onChanged: (value) => validateIpV6(value, 'ipv6StartRangeError', AppLocalizations.of(context)!.ipNotValid),
error: ipv6StartRangeError
),
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,
onChanged: (value) => validateIpV4(value, 'ipv6EndRangeError', AppLocalizations.of(context)!.ipNotValid),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.skip_previous_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv6EndRangeError,
labelText: AppLocalizations.of(context)!.endOfRange,
),
keyboardType: TextInputType.number,
),
),
),
FractionallySizedBox(
widthFactor: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: TextFormField(
controller: ipv6LeaseTimeController,
onChanged: (value) {
if (int.tryParse(value).runtimeType == int) {
setState(() => ipv6LeaseTimeError = null);
}
else {
setState(() => ipv6LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
}
},
decoration: InputDecoration(
prefixIcon: const Icon(Icons.timer),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: ipv6LeaseTimeError,
labelText: AppLocalizations.of(context)!.leaseTime,
),
keyboardType: TextInputType.number,
),
),
_DhcpField(
icon: Icons.skip_previous_rounded,
label: AppLocalizations.of(context)!.endOfRange,
controller: ipv6EndRangeController,
onChanged: (value) => validateIpV6(value, 'ipv6EndRangeError', AppLocalizations.of(context)!.ipNotValid),
error: ipv6EndRangeError
),
_DhcpField(
icon: Icons.timer,
label: AppLocalizations.of(context)!.leaseTime,
controller: ipv6LeaseTimeController,
onChanged: (value) {
if (int.tryParse(value).runtimeType == int) {
setState(() => ipv6LeaseTimeError = null);
}
else {
setState(() => ipv6LeaseTimeError = AppLocalizations.of(context)!.leaseTimeNotValid);
}
},
error: ipv6LeaseTimeError
)
],
const SizedBox(height: 20),
SectionLabel(
@ -704,7 +541,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DhcpLeases(
items: dhcpProvider.dhcp!.dhcpStatus.leases,
items: dhcpProvider.dhcp!.dhcpStatus!.leases,
staticLeases: false,
)
)
@ -739,7 +576,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DhcpLeases(
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
items: dhcpProvider.dhcp!.dhcpStatus!.staticLeases,
staticLeases: true,
)
)
@ -775,7 +612,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
if (!(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push(
DhcpLeases(
items: dhcpProvider.dhcp!.dhcpStatus.leases,
items: dhcpProvider.dhcp!.dhcpStatus!.leases,
staticLeases: false,
)
);
@ -784,7 +621,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DhcpLeases(
items: dhcpProvider.dhcp!.dhcpStatus.leases,
items: dhcpProvider.dhcp!.dhcpStatus!.leases,
staticLeases: false,
)
)
@ -804,7 +641,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
if (!(Platform.isAndroid || Platform.isIOS)) {
SplitView.of(context).push(
DhcpLeases(
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
items: dhcpProvider.dhcp!.dhcpStatus!.staticLeases,
staticLeases: true,
)
);
@ -813,7 +650,7 @@ class _DhcpScreenState extends State<DhcpScreen> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DhcpLeases(
items: dhcpProvider.dhcp!.dhcpStatus.staticLeases,
items: dhcpProvider.dhcp!.dhcpStatus!.staticLeases,
staticLeases: true,
)
)
@ -899,4 +736,49 @@ 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,
),
),
);
}
}

View 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,
),
],
),
),
),
),
);
}
}

View 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
),
),
],
),
),
);
}
}

View file

@ -482,8 +482,13 @@ class ApiClientV2 {
return ApiResponse(
successful: true,
content: DhcpModel(
dhcpAvailable: jsonDecode(results[1].body!)['message'] != null
? false
: true,
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) {

View file

@ -1352,6 +1352,7 @@ class ApiClient {
return {
'result': 'success',
'data': DhcpModel(
dhcpAvailable: true,
networkInterfaces: interfaces,
dhcpStatus: DhcpStatus.fromJson(jsonDecode(result[1]['body']))
)