diff --git a/README.md b/README.md
index 930d090..fb9505d 100644
--- a/README.md
+++ b/README.md
@@ -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)
- [pie chart](https://pub.dev/packages/pie_chart)
- [segmented button slide](https://pub.dev/packages/segmented_button_slide)
+- [timezone](https://pub.dev/packages/timezone)
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index b7e9999..6e281d4 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -719,7 +719,7 @@
"unblockClient": "Unblock client",
"blockingClient": "Blocking client...",
"unblockingClient": "Unblocking client...",
- "upstreamDnsCacheConfiguration": "Configuración de la caché DNS upstream",
+ "upstreamDnsCacheConfiguration": "DNS upstream cache configuration",
"enableDnsCachingClient": "Enable DNS caching for this client",
"dnsCacheSize": "DNS cache size",
"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.",
"logsSettingsDescription": "Configure query logs",
"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."
}
\ No newline at end of file
diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb
index 0ea54a0..55f8237 100644
--- a/lib/l10n/app_es.arb
+++ b/lib/l10n/app_es.arb
@@ -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.",
"logsSettingsDescription": "Configura los registros de peticiones",
"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."
}
\ No newline at end of file
diff --git a/lib/models/clients.dart b/lib/models/clients.dart
index 67740bd..56a967e 100644
--- a/lib/models/clients.dart
+++ b/lib/models/clients.dart
@@ -91,6 +91,7 @@ class Client {
final bool? ignoreStatistics;
final bool? upstreamsCacheEnabled;
final int? upstreamsCacheSize;
+ final BlockedServicesSchedule? blockedServicesSchedule;
Client({
required this.name,
@@ -108,6 +109,7 @@ class Client {
required this.ignoreStatistics,
required this.upstreamsCacheEnabled,
required this.upstreamsCacheSize,
+ required this.blockedServicesSchedule,
});
factory Client.fromJson(Map json) => Client(
@@ -127,7 +129,8 @@ class Client {
ignoreQuerylog: json["ignore_querylog"],
ignoreStatistics: json["ignore_statistics"],
upstreamsCacheEnabled: json["upstreams_cache_enabled"],
- upstreamsCacheSize: json["upstreams_cache_size"]
+ upstreamsCacheSize: json["upstreams_cache_size"],
+ blockedServicesSchedule: BlockedServicesSchedule.fromJson(json["blocked_services_schedule"])
);
Map toJson() => {
@@ -145,6 +148,67 @@ class Client {
"ignore_querylog": ignoreQuerylog,
"ignore_statistics": ignoreStatistics,
"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 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 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 json) => BlockedServicesScheduleDay(
+ start: json["start"],
+ end: json["end"],
+ );
+
+ Map toJson() => {
+ "start": start,
+ "end": end,
};
}
\ No newline at end of file
diff --git a/lib/screens/clients/client/blocking_schedule.dart b/lib/screens/clients/client/blocking_schedule.dart
new file mode 100644
index 0000000..0ae7abb
--- /dev/null
+++ b/lib/screens/clients/client/blocking_schedule.dart
@@ -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
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/screens/clients/client/blocking_schedule_modal.dart b/lib/screens/clients/client/blocking_schedule_modal.dart
new file mode 100644
index 0000000..f4e18ef
--- /dev/null
+++ b/lib/screens/clients/client/blocking_schedule_modal.dart
@@ -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 createState() => _BlockingScheduleModalState();
+}
+
+class _BlockingScheduleModalState extends State {
+ String? _timezone;
+ List _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)
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/screens/clients/client/client_form.dart b/lib/screens/clients/client/client_form.dart
index e127466..2d22dd7 100644
--- a/lib/screens/clients/client/client_form.dart
+++ b/lib/screens/clients/client/client_form.dart
@@ -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/tags_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_list_tile.dart';
@@ -52,6 +53,8 @@ class ClientForm extends StatelessWidget {
final TextEditingController dnsCacheField;
final String? dnsCacheError;
final void Function(String?) updateDnsCacheError;
+ final BlockedServicesSchedule blockedServicesSchedule;
+ final void Function(BlockedServicesSchedule) setBlockedServicesSchedule;
const ClientForm({
super.key,
@@ -90,6 +93,8 @@ class ClientForm extends StatelessWidget {
required this.dnsCacheField,
required this.dnsCacheError,
required this.updateDnsCacheError,
+ required this.blockedServicesSchedule,
+ required this.setBlockedServicesSchedule,
});
@override
@@ -282,6 +287,11 @@ class ClientForm extends StatelessWidget {
keyboardType: TextInputType.number,
),
),
+ BlockingSchedule(
+ blockedServicesSchedule: blockedServicesSchedule,
+ setBlockedServicesSchedule: setBlockedServicesSchedule,
+ ),
+ const SizedBox(height: 16),
],
);
}
diff --git a/lib/screens/clients/client/client_screen.dart b/lib/screens/clients/client/client_screen.dart
index f41de69..225b5eb 100644
--- a/lib/screens/clients/client/client_screen.dart
+++ b/lib/screens/clients/client/client_screen.dart
@@ -81,6 +81,8 @@ class _ClientScreenState extends State {
bool _enableDnsCache = false;
final _dnsCacheField = TextEditingController();
String? _dnsCacheError;
+
+ BlockedServicesSchedule _blockedServicesSchedule = BlockedServicesSchedule();
// VALIDATIONS
bool _nameValid = true;
@@ -140,6 +142,9 @@ class _ClientScreenState extends State {
_dnsCacheField.text = widget.client!.upstreamsCacheSize != null
? widget.client!.upstreamsCacheSize.toString()
: "";
+ if (widget.client!.blockedServicesSchedule != null) {
+ _blockedServicesSchedule = widget.client!.blockedServicesSchedule!;
+ }
}
super.initState();
}
@@ -166,7 +171,8 @@ class _ClientScreenState extends State {
upstreamsCacheEnabled: _enableDnsCache,
upstreamsCacheSize: _dnsCacheField.text != ""
? int.parse(_dnsCacheField.text)
- : null
+ : null,
+ blockedServicesSchedule: _blockedServicesSchedule
);
widget.onConfirm(client);
}
@@ -268,7 +274,9 @@ class _ClientScreenState extends State {
updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v),
dnsCacheField: _dnsCacheField,
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 {
updateEnableDnsCache: (v) => setState(() => _enableDnsCache = v),
dnsCacheField: _dnsCacheField,
dnsCacheError: _dnsCacheError,
- updateDnsCacheError: (v) => setState(() => _dnsCacheError = v)
+ updateDnsCacheError: (v) => setState(() => _dnsCacheError = v),
+ blockedServicesSchedule: _blockedServicesSchedule,
+ setBlockedServicesSchedule: (v) => setState(() => _blockedServicesSchedule = v),
),
],
),
diff --git a/pubspec.lock b/pubspec.lock
index cf61106..1cb21ba 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -659,6 +659,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index e4dbaa8..a488bef 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -76,6 +76,7 @@ dependencies:
pie_chart: ^5.4.0
segmented_button_slide: ^1.0.4
http: ^1.1.2
+ timezone: ^0.9.2
dev_dependencies:
flutter_test: