Added add and remove custom rules

This commit is contained in:
Juan Gilsanz Polo 2022-10-07 21:49:50 +02:00
parent 6800c6f20f
commit d12a1134f0
8 changed files with 359 additions and 14 deletions

View file

@ -207,5 +207,14 @@
"customRules": "Custom rules", "customRules": "Custom rules",
"enabledRules": "Enabled rules", "enabledRules": "Enabled rules",
"enabled": "Enabled", "enabled": "Enabled",
"disabled": "Disabled" "disabled": "Disabled",
"rule": "Rule",
"addCustomRule": "Add custom rule",
"removeCustomRule": "Remove custom rule",
"removeCustomRuleMessage": "Are you sure you want to remove this custom rule?",
"updatingRules": "Updating custom rules...",
"ruleRemovedSuccessfully": "Rule removed successfully",
"ruleNotRemoved": "Couldn't remove the rule",
"ruleAddedSuccessfully": "Rule added successfully",
"ruleNotAdded": "Couldn't add the rule,"
} }

View file

@ -207,5 +207,14 @@
"customRules": "Reglas personalizadas", "customRules": "Reglas personalizadas",
"enabledRules": "Reglas activas", "enabledRules": "Reglas activas",
"enabled": "Activada", "enabled": "Activada",
"disabled": "Desactivada" "disabled": "Desactivada",
"rule": "Regla",
"addCustomRule": "Añadir regla personalizada",
"removeCustomRule": "Eliminar regla personalizada",
"removeCustomRuleMessage": "¿Estás seguro que deseas eliminar esta regla personalizada?",
"updatingRules": "Updating custom rules...",
"ruleRemovedSuccessfully": "Regla eliminada correctamente",
"ruleNotRemoved": "No se ha podido eliminar la regla",
"ruleAddedSuccessfully": "Regla añadida correctamente",
"ruleNotAdded": "No se ha podido añadir la regla"
} }

View file

@ -17,7 +17,7 @@ class Filtering {
class FilteringData { class FilteringData {
final List<Filter> filters; final List<Filter> filters;
final List<Filter> whitelistFilters; final List<Filter> whitelistFilters;
final List<String> userRules; List<String> userRules;
final int interval; final int interval;
final bool enabled; final bool enabled;

View file

@ -0,0 +1,112 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class AddCustomRule extends StatefulWidget {
final void Function(String) onConfirm;
const AddCustomRule({
Key? key,
required this.onConfirm
}) : super(key: key);
@override
State<AddCustomRule> createState() => _AddCustomRuleState();
}
class _AddCustomRuleState extends State<AddCustomRule> {
TextEditingController ruleController = TextEditingController();
bool validValues = false;
void checkValidValues() {
if (ruleController.text != '') {
setState(() => validValues = true);
}
else {
setState(() => validValues = false);
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
height: 300,
padding: const EdgeInsets.all(28),
decoration: BoxDecoration(
color: Theme.of(context).dialogBackgroundColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(28),
topRight: Radius.circular(28)
)
),
child: Column(
children: [
const Icon(
Icons.shield_rounded,
size: 26,
),
const SizedBox(height: 20),
Text(
AppLocalizations.of(context)!.addCustomRule,
style: const TextStyle(
fontSize: 24
),
),
const SizedBox(height: 30),
TextFormField(
controller: ruleController,
onChanged: (_) => checkValidValues(),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.rule),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
labelText: AppLocalizations.of(context)!.rule,
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)!.cancel)
),
const SizedBox(width: 20),
TextButton(
onPressed: validValues == true
? () {
Navigator.pop(context);
widget.onConfirm(ruleController.text);
}
: null,
child: Text(
AppLocalizations.of(context)!.confirm,
style: TextStyle(
color: validValues == true
? Theme.of(context).primaryColor
: Colors.grey
),
)
),
],
),
),
],
),
)
],
),
),
);
}
}

View file

@ -1,4 +1,17 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/fab.dart';
import 'package:adguard_home_manager/screens/filters/remove_custom_rule_modal.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
class CustomRulesList extends StatelessWidget { class CustomRulesList extends StatelessWidget {
final List<String> data; final List<String> data;
@ -10,17 +23,69 @@ class CustomRulesList extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView.builder( final serversProvider = Provider.of<ServersProvider>(context);
padding: const EdgeInsets.only(top: 0), final appConfigProvider = Provider.of<AppConfigProvider>(context);
itemCount: data.length,
itemBuilder: (context, index) => ListTile( void removeCustomRule(String rule) async {
onLongPress: () => {}, ProcessModal processModal = ProcessModal(context: context);
title: Text(data[index]), processModal.open(AppLocalizations.of(context)!.updatingRules);
trailing: IconButton(
onPressed: () => {}, final List<String> newRules = serversProvider.filtering.data!.userRules.where((r) => r != rule).toList();
icon: const Icon(Icons.delete)
final result = await setCustomRules(server: serversProvider.selectedServer!, rules: newRules);
processModal.close();
if (result['result'] == 'success') {
FilteringData filteringData = serversProvider.filtering.data!;
filteringData.userRules = newRules;
serversProvider.setFilteringData(filteringData);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.ruleRemovedSuccessfully),
backgroundColor: Colors.green,
)
);
}
else {
appConfigProvider.addLog(result['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.ruleNotRemoved),
backgroundColor: Colors.red,
)
);
}
}
void openRemoveCustomRuleModal(String rule) {
showDialog(
context: context,
builder: (context) => RemoveCustomRule(
onConfirm: () => removeCustomRule(rule),
)
);
}
return Stack(
children: [
ListView.builder(
padding: const EdgeInsets.only(top: 0),
itemCount: data.length,
itemBuilder: (context, index) => ListTile(
title: Text(data[index]),
trailing: IconButton(
onPressed: () => openRemoveCustomRuleModal(data[index]),
icon: const Icon(Icons.delete)
),
)
), ),
) const Positioned(
bottom: 20,
right: 20,
child: FiltersFab()
)
],
); );
} }
} }

View file

@ -0,0 +1,72 @@
// ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/filters/add_custom_rule.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/models/filtering.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class FiltersFab extends StatelessWidget {
const FiltersFab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
void confirmAddRule(String rule) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingRules);
final List<String> newRules = serversProvider.filtering.data!.userRules;
newRules.add(rule);
final result = await setCustomRules(server: serversProvider.selectedServer!, rules: newRules);
processModal.close();
if (result['result'] == 'success') {
FilteringData filteringData = serversProvider.filtering.data!;
filteringData.userRules = newRules;
serversProvider.setFilteringData(filteringData);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.ruleAddedSuccessfully),
backgroundColor: Colors.green,
)
);
}
else {
appConfigProvider.addLog(result['log']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.ruleNotAdded),
backgroundColor: Colors.red,
)
);
}
}
void openAddClient() {
showModalBottomSheet(
context: context,
builder: (ctx) => AddCustomRule(
onConfirm: confirmAddRule
),
isScrollControlled: true,
backgroundColor: Colors.transparent
);
}
return FloatingActionButton(
onPressed: openAddClient,
child: const Icon(Icons.add),
);
}
}

View file

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class RemoveCustomRule extends StatelessWidget {
final void Function() onConfirm;
const RemoveCustomRule({
Key? key,
required this.onConfirm
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Column(
children: [
const Icon(
Icons.shield_rounded,
size: 26,
),
const SizedBox(height: 20),
Text(
AppLocalizations.of(context)!.removeCustomRule,
textAlign: TextAlign.center,
)
],
),
content: Text(AppLocalizations.of(context)!.removeCustomRuleMessage),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)!.cancel)
),
TextButton(
onPressed: () {
onConfirm();
Navigator.pop(context);
},
child: Text(AppLocalizations.of(context)!.confirm)
),
],
);
}
}

View file

@ -676,7 +676,7 @@ Future postDeleteClient({
required Server server, required Server server,
required String name, required String name,
}) async { }) async {
final result = await apiRequest( final result = await apiRequest(
urlPath: '/clients/delete', urlPath: '/clients/delete',
method: 'post', method: 'post',
server: server, server: server,
@ -740,3 +740,37 @@ Future getFiltering({
return result; return result;
} }
} }
Future setCustomRules({
required Server server,
required List<String> rules,
}) async {
final result = await apiRequest(
urlPath: '/filtering/set_rules',
method: 'post',
server: server,
body: {'rules': rules},
type: 'set_custom_rules'
);
if (result['hasResponse'] == true) {
if (result['statusCode'] == 200) {
return {'result': 'success'};
}
else {
return {
'result': 'error',
'log': AppLog(
type: 'set_custom_rules',
dateTime: DateTime.now(),
message: 'error_code_not_expected',
statusCode: result['statusCode'].toString(),
resBody: result['body']
)
};
}
}
else {
return result;
}
}