Created block time schedule settings

This commit is contained in:
Juan Gilsanz Polo 2024-01-25 22:34:30 +01:00
parent 5b2523158b
commit d73ad93180
10 changed files with 560 additions and 8 deletions

View file

@ -130,6 +130,7 @@ On [this repository](https://github.com/JuanRodenas/Pihole_list) you can find a
- [flutter reorderable list](https://pub.dev/packages/flutter_reorderable_list) - [flutter reorderable list](https://pub.dev/packages/flutter_reorderable_list)
- [pie chart](https://pub.dev/packages/pie_chart) - [pie chart](https://pub.dev/packages/pie_chart)
- [segmented button slide](https://pub.dev/packages/segmented_button_slide) - [segmented button slide](https://pub.dev/packages/segmented_button_slide)
- [timezone](https://pub.dev/packages/timezone)
<br> <br>

View file

@ -719,7 +719,7 @@
"unblockClient": "Unblock client", "unblockClient": "Unblock client",
"blockingClient": "Blocking client...", "blockingClient": "Blocking client...",
"unblockingClient": "Unblocking client...", "unblockingClient": "Unblocking client...",
"upstreamDnsCacheConfiguration": "Configuración de la caché DNS upstream", "upstreamDnsCacheConfiguration": "DNS upstream cache configuration",
"enableDnsCachingClient": "Enable DNS caching for this client", "enableDnsCachingClient": "Enable DNS caching for this client",
"dnsCacheSize": "DNS cache size", "dnsCacheSize": "DNS cache size",
"nameInvalid": "Name is required", "nameInvalid": "Name is required",
@ -729,5 +729,21 @@
"redirectHttpsWarning": "If you have enabled \"Redirect to HTTPS automatically\" on your AdGuard Home server, you must select an HTTPS connection and use the HTTPS port of your server.", "redirectHttpsWarning": "If you have enabled \"Redirect to HTTPS automatically\" on your AdGuard Home server, you must select an HTTPS connection and use the HTTPS port of your server.",
"logsSettingsDescription": "Configure query logs", "logsSettingsDescription": "Configure query logs",
"ignoredDomains": "Ignored domains", "ignoredDomains": "Ignored domains",
"noIgnoredDomainsAdded": "No domains to ignore added" "noIgnoredDomainsAdded": "No domains to ignore added",
"pauseServiceBlocking": "Pause service blocking",
"newSchedule": "New schedule",
"editSchedule": "Edit schedule",
"timezone": "Timezone",
"monday": "Monday",
"tuesday": "Tuesday",
"wednesday": "Wednesday",
"thursday": "Thursday",
"friday": "Friday",
"saturday": "Saturday",
"sunday": "Sunday",
"from": "From: {from}",
"to": "To: {to}",
"selectStartTime": "Select start time",
"selectEndTime": "Select end time",
"startTimeBeforeEndTime": "Start time must be before end time."
} }

View file

@ -729,5 +729,21 @@
"redirectHttpsWarning": "Si tienes activado \"Redireccionar a HTTPS automáticamente\" en tu servidor AdGuard Home, debes seleccionar una conexión HTTPS y utilizar el puerto de HTTPS de tu servidor.", "redirectHttpsWarning": "Si tienes activado \"Redireccionar a HTTPS automáticamente\" en tu servidor AdGuard Home, debes seleccionar una conexión HTTPS y utilizar el puerto de HTTPS de tu servidor.",
"logsSettingsDescription": "Configura los registros de peticiones", "logsSettingsDescription": "Configura los registros de peticiones",
"ignoredDomains": "Dominios ignorados", "ignoredDomains": "Dominios ignorados",
"noIgnoredDomainsAdded": "No hay añadidos dominios para ignorar" "noIgnoredDomainsAdded": "No hay añadidos dominios para ignorar",
"pauseServiceBlocking": "Pausa del servicio de bloqueo",
"newSchedule": "Nueva programación",
"editSchedule": "Editar programación",
"timezone": "Zona horaria",
"monday": "Lunes",
"tuesday": "Martes",
"wednesday": "Miércoles",
"thursday": "Jueves",
"friday": "Viernes",
"saturday": "Sábado",
"sunday": "Domingo",
"from": "Desde: {from}",
"to": "Hasta: {to}",
"selectStartTime": "Seleccionar hora de inicio",
"selectEndTime": "Seleccionar hora de fin",
"startTimeBeforeEndTime": "La hora de inicio debe ser anterior a la hora de fin."
} }

View file

@ -91,6 +91,7 @@ class Client {
final bool? ignoreStatistics; final bool? ignoreStatistics;
final bool? upstreamsCacheEnabled; final bool? upstreamsCacheEnabled;
final int? upstreamsCacheSize; final int? upstreamsCacheSize;
final BlockedServicesSchedule? blockedServicesSchedule;
Client({ Client({
required this.name, required this.name,
@ -108,6 +109,7 @@ class Client {
required this.ignoreStatistics, required this.ignoreStatistics,
required this.upstreamsCacheEnabled, required this.upstreamsCacheEnabled,
required this.upstreamsCacheSize, required this.upstreamsCacheSize,
required this.blockedServicesSchedule,
}); });
factory Client.fromJson(Map<String, dynamic> json) => Client( factory Client.fromJson(Map<String, dynamic> json) => Client(
@ -127,7 +129,8 @@ class Client {
ignoreQuerylog: json["ignore_querylog"], ignoreQuerylog: json["ignore_querylog"],
ignoreStatistics: json["ignore_statistics"], ignoreStatistics: json["ignore_statistics"],
upstreamsCacheEnabled: json["upstreams_cache_enabled"], upstreamsCacheEnabled: json["upstreams_cache_enabled"],
upstreamsCacheSize: json["upstreams_cache_size"] upstreamsCacheSize: json["upstreams_cache_size"],
blockedServicesSchedule: BlockedServicesSchedule.fromJson(json["blocked_services_schedule"])
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -145,6 +148,67 @@ class Client {
"ignore_querylog": ignoreQuerylog, "ignore_querylog": ignoreQuerylog,
"ignore_statistics": ignoreStatistics, "ignore_statistics": ignoreStatistics,
"upstreams_cache_enabled": upstreamsCacheEnabled, "upstreams_cache_enabled": upstreamsCacheEnabled,
"upstreams_cache_size": upstreamsCacheSize "upstreams_cache_size": upstreamsCacheSize,
"blocked_services_schedule":blockedServicesSchedule?.toJson()
};
}
class BlockedServicesSchedule {
final String? timeZone;
final BlockedServicesScheduleDay? mon;
final BlockedServicesScheduleDay? tue;
final BlockedServicesScheduleDay? wed;
final BlockedServicesScheduleDay? thu;
final BlockedServicesScheduleDay? fri;
final BlockedServicesScheduleDay? sat;
final BlockedServicesScheduleDay? sun;
BlockedServicesSchedule({
this.timeZone,
this.mon,
this.tue,
this.wed,
this.thu,
this.fri,
this.sat,
this.sun
});
factory BlockedServicesSchedule.fromJson(Map<String, dynamic> json) => BlockedServicesSchedule(
timeZone: json["time_zone"],
mon: json["mon"] == null ? null : BlockedServicesScheduleDay.fromJson(json["mon"]),
tue: json["tue"] == null ? null : BlockedServicesScheduleDay.fromJson(json["tue"]),
wed: json["wed"] == null ? null : BlockedServicesScheduleDay.fromJson(json["wed"]),
thu: json["thu"] == null ? null : BlockedServicesScheduleDay.fromJson(json["thu"]),
fri: json["fri"] == null ? null : BlockedServicesScheduleDay.fromJson(json["fri"]),
sat: json["sat"] == null ? null : BlockedServicesScheduleDay.fromJson(json["sat"]),
sun: json["sun"] == null ? null : BlockedServicesScheduleDay.fromJson(json["sun"]),
);
Map<String, dynamic> toJson() => {
"time_zone": timeZone,
"tue": tue?.toJson(),
"wed": wed?.toJson(),
"thu": thu?.toJson(),
};
}
class BlockedServicesScheduleDay {
final int? start;
final int? end;
BlockedServicesScheduleDay({
this.start,
this.end,
});
factory BlockedServicesScheduleDay.fromJson(Map<String, dynamic> json) => BlockedServicesScheduleDay(
start: json["start"],
end: json["end"],
);
Map<String, dynamic> toJson() => {
"start": start,
"end": end,
}; };
} }

View file

@ -0,0 +1,143 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/clients/client/blocking_schedule_modal.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/models/clients.dart';
class BlockingSchedule extends StatelessWidget {
final BlockedServicesSchedule blockedServicesSchedule;
final void Function(BlockedServicesSchedule) setBlockedServicesSchedule;
const BlockingSchedule({
super.key,
required this.blockedServicesSchedule,
required this.setBlockedServicesSchedule,
});
@override
Widget build(BuildContext context) {
void openAddScheduleModal() {
showDialog(
context: context,
builder: (context) => BlockingScheduleModal(
onConfirm: (v) => {},
),
);
}
String formatTime(int time) {
final formatted = Duration(milliseconds: time);
final hours = formatted.inHours;
final minutes = formatted.inMinutes - hours*60;
return "${hours.toString().padLeft(2 , '0')}:${minutes.toString().padLeft(2, '0')}";
}
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SectionLabel(label: AppLocalizations.of(context)!.pauseServiceBlocking),
Padding(
padding: const EdgeInsets.only(right: 12),
child: IconButton(
onPressed: openAddScheduleModal,
icon: const Icon(Icons.add)
),
)
],
),
const SizedBox(height: 2),
if (blockedServicesSchedule.mon != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.monday,
schedule: "${formatTime(blockedServicesSchedule.mon!.start!)} - ${formatTime(blockedServicesSchedule.mon!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
if (blockedServicesSchedule.tue != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.tuesday,
schedule: "${formatTime(blockedServicesSchedule.tue!.start!)} - ${formatTime(blockedServicesSchedule.tue!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
if (blockedServicesSchedule.wed != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.wednesday,
schedule: "${formatTime(blockedServicesSchedule.wed!.start!)} - ${formatTime(blockedServicesSchedule.wed!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
if (blockedServicesSchedule.thu != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.thursday,
schedule: "${formatTime(blockedServicesSchedule.thu!.start!)} - ${formatTime(blockedServicesSchedule.thu!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
if (blockedServicesSchedule.fri != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.friday,
schedule: "${formatTime(blockedServicesSchedule.fri!.start!)} - ${formatTime(blockedServicesSchedule.fri!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
if (blockedServicesSchedule.sat != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.saturday,
schedule: "${formatTime(blockedServicesSchedule.sat!.start!)} - ${formatTime(blockedServicesSchedule.sat!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
if (blockedServicesSchedule.sun != null) _ScheduleTile(
weekday: AppLocalizations.of(context)!.sunday,
schedule: "${formatTime(blockedServicesSchedule.sun!.start!)} - ${formatTime(blockedServicesSchedule.sun!.end!)}",
onEdit: () => {},
onDelete: () => {}
),
],
);
}
}
class _ScheduleTile extends StatelessWidget {
final String weekday;
final String schedule;
final void Function() onEdit;
final void Function() onDelete;
const _ScheduleTile({
required this.weekday,
required this.schedule,
required this.onEdit,
required this.onDelete,
});
@override
Widget build(BuildContext context) {
return CustomListTile(
title: weekday,
subtitle: schedule,
trailing: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: onEdit,
icon: const Icon(Icons.edit_rounded),
tooltip: AppLocalizations.of(context)!.edit,
),
const SizedBox(width: 4),
IconButton(
onPressed: onDelete,
icon: const Icon(Icons.delete_rounded),
tooltip: AppLocalizations.of(context)!.delete,
),
],
),
padding: const EdgeInsets.only(
left: 16,
top: 6,
right: 12,
bottom: 6
)
);
}
}

View file

@ -0,0 +1,283 @@
import 'package:flutter/material.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/models/clients.dart';
class BlockingScheduleModal extends StatefulWidget {
final void Function(BlockedServicesSchedule) onConfirm;
const BlockingScheduleModal({
super.key,
required this.onConfirm,
});
@override
State<BlockingScheduleModal> createState() => _BlockingScheduleModalState();
}
class _BlockingScheduleModalState extends State<BlockingScheduleModal> {
String? _timezone;
List<String> _weekdays = [];
TimeOfDay? _from;
TimeOfDay? _to;
bool _compareTimes(TimeOfDay startTime, TimeOfDay endTime) {
bool result = false;
int startTimeInt = (startTime.hour * 60 + startTime.minute) * 60;
int endTimeInt = (endTime.hour * 60 + endTime.minute) * 60;
if (endTimeInt > startTimeInt) {
result = true;
} else {
result = false;
}
return result;
}
bool _validate() {
return _timezone != null &&
_weekdays.isNotEmpty &&
_from != null &&
_to != null &&
_compareTimes(_from!, _to!);
}
int _timeOfDayToInt(TimeOfDay timeOfDay) {
return Duration(
days: 0,
hours: timeOfDay.hour,
minutes: timeOfDay.minute,
seconds: 0
).inMinutes;
}
@override
void initState() {
tz.initializeTimeZones();
_timezone = tz.local.name;
super.initState();
}
@override
Widget build(BuildContext context) {
void onSelectWeekday(bool newStatus, String day) {
if (newStatus == true && !_weekdays.contains(day)) {
setState(() => _weekdays.add(day));
}
else if (newStatus == false) {
setState(() => _weekdays = _weekdays.where((e) => e != day).toList());
}
}
void onConfirm() {
widget.onConfirm(
BlockedServicesSchedule(
timeZone: _timezone,
mon: _weekdays.contains("mon") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
tue: _weekdays.contains("tue") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
wed: _weekdays.contains("wed") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
thu: _weekdays.contains("thu") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
fri: _weekdays.contains("fri") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
sat: _weekdays.contains("sat") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
sun: _weekdays.contains("sun") ? BlockedServicesScheduleDay(start: _timeOfDayToInt(_from!), end: _timeOfDayToInt(_to!)) : null,
)
);
}
final valid = _validate();
final validTimes = _from != null && _to != null
? _compareTimes(_from!, _to!)
: null;
return Dialog(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.schedule_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
const SizedBox(height: 16),
Text(
AppLocalizations.of(context)!.newSchedule,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 24,
),
),
const SizedBox(height: 30),
LayoutBuilder(
builder: (context, constraints) => DropdownButtonFormField(
items: tz.timeZoneDatabase.locations.keys.map((item) => DropdownMenuItem(
value: item,
child: SizedBox(
width: constraints.maxWidth-48,
child: Text(
item,
overflow: TextOverflow.ellipsis,
),
),
)).toList(),
value: _timezone,
onChanged: (v) => setState(() => _timezone = v),
decoration: InputDecoration(
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
label: Text(AppLocalizations.of(context)!.timezone)
),
borderRadius: BorderRadius.circular(20),
),
),
const SizedBox(height: 16),
SizedBox(
height: 50,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
FilterChip(
label: Text(AppLocalizations.of(context)!.monday),
selected: _weekdays.contains("mon"),
onSelected: (value) => onSelectWeekday(value, "mon")
),
const SizedBox(width: 8),
FilterChip(
label: Text(AppLocalizations.of(context)!.tuesday),
selected: _weekdays.contains("tue"),
onSelected: (value) => onSelectWeekday(value, "tue")
),
const SizedBox(width: 8),
FilterChip(
label: Text(AppLocalizations.of(context)!.wednesday),
selected: _weekdays.contains("wed"),
onSelected: (value) => onSelectWeekday(value, "wed")
),
const SizedBox(width: 8),
FilterChip(
label: Text(AppLocalizations.of(context)!.thursday),
selected: _weekdays.contains("thu"),
onSelected: (value) => onSelectWeekday(value, "thu")
),
const SizedBox(width: 8),
FilterChip(
label: Text(AppLocalizations.of(context)!.friday),
selected: _weekdays.contains("fri"),
onSelected: (value) => onSelectWeekday(value, "fri")
),
const SizedBox(width: 8),
FilterChip(
label: Text(AppLocalizations.of(context)!.saturday),
selected: _weekdays.contains("sat"),
onSelected: (value) => onSelectWeekday(value, "sat")
),
const SizedBox(width: 8),
FilterChip(
label: Text(AppLocalizations.of(context)!.sunday),
selected: _weekdays.contains("sun"),
onSelected: (value) => onSelectWeekday(value, "sun")
),
],
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () async {
final selected = await showTimePicker(
context: context,
initialTime: _from ?? const TimeOfDay(hour: 0, minute: 0),
helpText: AppLocalizations.of(context)!.selectStartTime,
confirmText: AppLocalizations.of(context)!.confirm,
);
setState(() => _from = selected);
},
child: Text(
AppLocalizations.of(context)!.from(
_from != null ? "${_from!.hour.toString().padLeft(2, '0')}:${_from!.minute.toString().padLeft(2, '0')}" : "--:--"
)
)
),
ElevatedButton(
onPressed: () async {
final selected = await showTimePicker(
context: context,
initialTime: _to ?? const TimeOfDay(hour: 23, minute: 59),
helpText: AppLocalizations.of(context)!.selectEndTime,
confirmText: AppLocalizations.of(context)!.confirm
);
setState(() => _to = selected);
},
child: Text(
AppLocalizations.of(context)!.to(
_to != null ? "${_to!.hour.toString().padLeft(2, '0')}:${_to!.minute.toString().padLeft(2, '0')}" : "--:--"
)
)
),
],
),
if (validTimes == false) Padding(
padding: const EdgeInsets.only(top: 16),
child: Card(
color: const Color.fromARGB(255, 255, 182, 175),
elevation: 0,
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(
Icons.error_rounded,
color: Theme.of(context).colorScheme.onSurfaceVariant
),
const SizedBox(width: 16),
Expanded(
child: Text(
AppLocalizations.of(context)!.startTimeBeforeEndTime,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface
),
),
),
],
),
),
)
)
],
),
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)!.close)
),
const SizedBox(width: 8),
TextButton(
onPressed: valid ? () => onConfirm() : null,
child: Text(AppLocalizations.of(context)!.confirm)
),
],
)
],
),
),
);
}
}

View file

@ -8,6 +8,7 @@ import 'package:adguard_home_manager/screens/clients/client/identifiers_section.
import 'package:adguard_home_manager/screens/clients/client/settings_tile.dart'; import 'package:adguard_home_manager/screens/clients/client/settings_tile.dart';
import 'package:adguard_home_manager/screens/clients/client/tags_section.dart'; import 'package:adguard_home_manager/screens/clients/client/tags_section.dart';
import 'package:adguard_home_manager/screens/clients/client/upstream_servers_section.dart'; import 'package:adguard_home_manager/screens/clients/client/upstream_servers_section.dart';
import 'package:adguard_home_manager/screens/clients/client/blocking_schedule.dart';
import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
import 'package:adguard_home_manager/widgets/custom_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
@ -52,6 +53,8 @@ class ClientForm extends StatelessWidget {
final TextEditingController dnsCacheField; final TextEditingController dnsCacheField;
final String? dnsCacheError; final String? dnsCacheError;
final void Function(String?) updateDnsCacheError; final void Function(String?) updateDnsCacheError;
final BlockedServicesSchedule blockedServicesSchedule;
final void Function(BlockedServicesSchedule) setBlockedServicesSchedule;
const ClientForm({ const ClientForm({
super.key, super.key,
@ -90,6 +93,8 @@ class ClientForm extends StatelessWidget {
required this.dnsCacheField, required this.dnsCacheField,
required this.dnsCacheError, required this.dnsCacheError,
required this.updateDnsCacheError, required this.updateDnsCacheError,
required this.blockedServicesSchedule,
required this.setBlockedServicesSchedule,
}); });
@override @override
@ -282,6 +287,11 @@ class ClientForm extends StatelessWidget {
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
), ),
), ),
BlockingSchedule(
blockedServicesSchedule: blockedServicesSchedule,
setBlockedServicesSchedule: setBlockedServicesSchedule,
),
const SizedBox(height: 16),
], ],
); );
} }

View file

@ -81,6 +81,8 @@ class _ClientScreenState extends State<ClientScreen> {
bool _enableDnsCache = false; bool _enableDnsCache = false;
final _dnsCacheField = TextEditingController(); final _dnsCacheField = TextEditingController();
String? _dnsCacheError; String? _dnsCacheError;
BlockedServicesSchedule _blockedServicesSchedule = BlockedServicesSchedule();
// VALIDATIONS // VALIDATIONS
bool _nameValid = true; bool _nameValid = true;
@ -140,6 +142,9 @@ class _ClientScreenState extends State<ClientScreen> {
_dnsCacheField.text = widget.client!.upstreamsCacheSize != null _dnsCacheField.text = widget.client!.upstreamsCacheSize != null
? widget.client!.upstreamsCacheSize.toString() ? widget.client!.upstreamsCacheSize.toString()
: ""; : "";
if (widget.client!.blockedServicesSchedule != null) {
_blockedServicesSchedule = widget.client!.blockedServicesSchedule!;
}
} }
super.initState(); super.initState();
} }
@ -166,7 +171,8 @@ class _ClientScreenState extends State<ClientScreen> {
upstreamsCacheEnabled: _enableDnsCache, upstreamsCacheEnabled: _enableDnsCache,
upstreamsCacheSize: _dnsCacheField.text != "" upstreamsCacheSize: _dnsCacheField.text != ""
? int.parse(_dnsCacheField.text) ? int.parse(_dnsCacheField.text)
: null : null,
blockedServicesSchedule: _blockedServicesSchedule
); );
widget.onConfirm(client); widget.onConfirm(client);
} }
@ -268,7 +274,9 @@ class _ClientScreenState extends State<ClientScreen> {
updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v), updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v),
dnsCacheField: _dnsCacheField, dnsCacheField: _dnsCacheField,
dnsCacheError: _dnsCacheError, dnsCacheError: _dnsCacheError,
updateDnsCacheError: (v) => setState(() => _dnsCacheError = v) updateDnsCacheError: (v) => setState(() => _dnsCacheError = v),
blockedServicesSchedule: _blockedServicesSchedule,
setBlockedServicesSchedule: (v) => setState(() => _blockedServicesSchedule = v),
), ),
], ],
), ),
@ -353,7 +361,9 @@ class _ClientScreenState extends State<ClientScreen> {
updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v), updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v),
dnsCacheField: _dnsCacheField, dnsCacheField: _dnsCacheField,
dnsCacheError: _dnsCacheError, dnsCacheError: _dnsCacheError,
updateDnsCacheError: (v) => setState(() => _dnsCacheError = v) updateDnsCacheError: (v) => setState(() => _dnsCacheError = v),
blockedServicesSchedule: _blockedServicesSchedule,
setBlockedServicesSchedule: (v) => setState(() => _blockedServicesSchedule = v),
), ),
], ],
), ),

View file

@ -659,6 +659,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.6.1"
timezone:
dependency: "direct main"
description:
name: timezone
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"
url: "https://pub.dev"
source: hosted
version: "0.9.2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View file

@ -76,6 +76,7 @@ dependencies:
pie_chart: ^5.4.0 pie_chart: ^5.4.0
segmented_button_slide: ^1.0.4 segmented_button_slide: ^1.0.4
http: ^1.1.2 http: ^1.1.2
timezone: ^0.9.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: