diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 076bebe..6e73c2d 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -228,5 +228,16 @@ "listAdded": "List added successfully. Items added:", "listAlreadyAdded": "List already added", "listUrlInvalid": "List URL invalid", - "listNotAdded": "List couldn't be added" + "listNotAdded": "List couldn't be added", + "listDetails": "List details", + "listType": "List type", + "whitelist": "White list", + "blacklist": "Black list", + "latestUpdate": "Latest update", + "disable": "Disable", + "enable": "Enable", + "currentStatus": "Current status", + "listDataUpdated": "List data updated successfull", + "listDataNotUpdated": "Couldn't update list data", + "updatingListData": "Updating list data..." } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 119465a..c83db03 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -228,5 +228,16 @@ "listAdded": "Lista añadida correctamente. Items añadidos:", "listAlreadyAdded": "La lista ya estaba añadida", "listUrlInvalid": "URL de la lista no válida", - "listNotAdded": "La lista no se pudo añadir" + "listNotAdded": "La lista no se pudo añadir", + "listDetails": "Detalles de la lista", + "listType": "Tipo de lista", + "whitelist": "Lista blanca", + "blacklist": "Lista negra", + "latestUpdate": "Última actualización", + "disable": "Deshabilitar", + "enable": "Habilitar", + "currentStatus": "Estado actual", + "listDataUpdated": "Datos de lista actualizados correctamente", + "listDataNotUpdated": "No se han podido actualizar los datos de la lista", + "updatingListData": "Actualizando datos de lista..." } \ No newline at end of file diff --git a/lib/screens/filters/filter_list_tile.dart b/lib/screens/filters/filter_list_tile.dart new file mode 100644 index 0000000..76ab8f1 --- /dev/null +++ b/lib/screens/filters/filter_list_tile.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; + +class FilterListTile extends StatelessWidget { + final IconData icon; + final String title; + final String subtitle; + final Color? color; + final bool? bold; + + const FilterListTile({ + Key? key, + required this.icon, + required this.title, + required this.subtitle, + this.color, + this.bold, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Icon( + icon, + size: 26, + color: Colors.grey, + ), + const SizedBox(width: 20), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500 + ), + ), + const SizedBox(height: 5), + SizedBox( + width: MediaQuery.of(context).size.width-86, + child: Text( + subtitle, + style: TextStyle( + fontSize: 14, + color: color ?? Colors.grey, + fontWeight: bold == true ? FontWeight.bold : null + ), + ), + ), + ], + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/filters/filters_list.dart b/lib/screens/filters/filters_list.dart index 43a4b2e..cb77d64 100644 --- a/lib/screens/filters/filters_list.dart +++ b/lib/screens/filters/filters_list.dart @@ -1,11 +1,19 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:flutter/rendering.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/list_details_modal.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/servers_provider.dart'; +import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/models/filtering.dart'; @@ -53,6 +61,72 @@ class _FiltersListState extends State { @override Widget build(BuildContext context) { + final serversProvider = Provider.of(context); + final appConfigProvider = Provider.of(context); + + void enableDisableList(Filter list, bool enabled) async { + ProcessModal processModal = ProcessModal(context: context); + processModal.open(AppLocalizations.of(context)!.updatingListData); + + final result = await updateFilterList(server: serversProvider.selectedServer!, data: { + "data": { + "enabled": enabled, + "name": list.name, + "url": list.url + }, + "url": list.url, + "whitelist": widget.type == 'whitelist' ? true : false + }); + + processModal.close(); + + if (result['result'] == 'success') { + final result2 = await getFiltering(server: serversProvider.selectedServer!); + + if (result2['result'] == 'success') { + serversProvider.setFilteringData(result2['data']); + serversProvider.setFilteringLoadStatus(1, true); + } + else { + appConfigProvider.addLog(result2['log']); + serversProvider.setFilteringLoadStatus(2, true); + } + + processModal.close(); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.listDataUpdated), + backgroundColor: Colors.green, + ) + ); + } + else { + appConfigProvider.addLog(result['log']); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.listDataNotUpdated), + backgroundColor: Colors.red, + ) + ); + } + } + + void openDetailsModal(Filter filter) { + showModalBottomSheet( + context: context, + builder: (ctx) => ListDetailsModal( + list: filter, + type: widget.type, + onDelete: () => {}, + edit: () => {}, + onEnableDisable: enableDisableList, + ), + backgroundColor: Colors.transparent, + isScrollControlled: true + ); + } + return Stack( children: [ if (widget.data.isNotEmpty) ListView.builder( @@ -61,7 +135,7 @@ class _FiltersListState extends State { itemBuilder: (context, index) => Material( color: Colors.transparent, child: InkWell( - onTap: () => {}, + onTap: () => openDetailsModal(widget.data[index]), child: Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), child: Row( diff --git a/lib/screens/filters/list_details_modal.dart b/lib/screens/filters/list_details_modal.dart new file mode 100644 index 0000000..370226b --- /dev/null +++ b/lib/screens/filters/list_details_modal.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:adguard_home_manager/screens/filters/filter_list_tile.dart'; + +import 'package:adguard_home_manager/functions/format_time.dart'; +import 'package:adguard_home_manager/models/filtering.dart'; + +class ListDetailsModal extends StatelessWidget { + final Filter list; + final String type; + final void Function() onDelete; + final void Function() edit; + final void Function(Filter, bool) onEnableDisable; + + const ListDetailsModal({ + Key? key, + required this.list, + required this.type, + required this.onDelete, + required this.edit, + required this.onEnableDisable, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return DraggableScrollableSheet( + initialChildSize: 0.6, + minChildSize: 0.6, + maxChildSize: list.lastUpdated != null + ? 740/MediaQuery.of(context).size.height + : 670/MediaQuery.of(context).size.height, + builder: (context, scrollController) => Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(28), + topRight: Radius.circular(28) + ), + color: Theme.of(context).dialogBackgroundColor + ), + child: Column( + children: [ + Expanded( + child: ListView( + controller: scrollController, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Padding( + padding: const EdgeInsets.only(top: 24), + child: Icon( + type == 'whitelist' + ? Icons.verified_user_rounded + : Icons.gpp_bad_rounded, + size: 26, + ), + ), + ), + const SizedBox(height: 20), + Text( + AppLocalizations.of(context)!.listDetails, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24, + ), + ), + const SizedBox(height: 30), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton.icon( + onPressed: () { + onEnableDisable(list, !list.enabled); + }, + label: Text( + list.enabled == true + ? AppLocalizations.of(context)!.disable + : AppLocalizations.of(context)!.enable + ), + icon: Icon( + list.enabled == true + ? Icons.gpp_bad_rounded + : Icons.verified_user_rounded + ), + ), + ], + ), + const SizedBox(height: 30), + FilterListTile( + icon: Icons.shield_rounded, + title: AppLocalizations.of(context)!.currentStatus, + subtitle: list.enabled == true + ? AppLocalizations.of(context)!.enabled + : AppLocalizations.of(context)!.disabled, + color: list.enabled == true + ? Colors.green + : Colors.red, + bold: true, + ), + FilterListTile( + icon: Icons.badge_rounded, + title: AppLocalizations.of(context)!.name, + subtitle: list.name + ), + FilterListTile( + icon: Icons.link_rounded, + title: "URL", + subtitle: list.url + ), + FilterListTile( + icon: Icons.list_rounded, + title: AppLocalizations.of(context)!.rules, + subtitle: list.rulesCount.toString() + ), + FilterListTile( + icon: Icons.shield_rounded, + title: AppLocalizations.of(context)!.listType, + subtitle: type == 'whitelist' + ? AppLocalizations.of(context)!.whitelist + : AppLocalizations.of(context)!.blacklist, + ), + if (list.lastUpdated != null) FilterListTile( + icon: Icons.schedule_rounded, + title: AppLocalizations.of(context)!.latestUpdate, + subtitle: formatTimestampUTC(list.lastUpdated!, 'dd-MM-yyyy HH:mm'), + ), + ], + ) + ), + Padding( + padding: const EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: edit, + icon: const Icon(Icons.edit) + ), + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(AppLocalizations.of(context)!.close) + ) + ], + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/services/http_requests.dart b/lib/services/http_requests.dart index 6373205..0b98d18 100644 --- a/lib/services/http_requests.dart +++ b/lib/services/http_requests.dart @@ -775,6 +775,7 @@ Future setCustomRules({ } } + Future addFilteringList({ required Server server, required Map data, @@ -810,4 +811,38 @@ Future addFilteringList({ else { return result; } +} + +Future updateFilterList({ + required Server server, + required Map data, +}) async { + final result = await apiRequest( + urlPath: '/filtering/set_url', + method: 'post', + server: server, + body: data, + type: 'update_filter_list' + ); + + if (result['hasResponse'] == true) { + if (result['statusCode'] == 200) { + return {'result': 'success'}; + } + else { + return { + 'result': 'error', + 'log': AppLog( + type: 'update_filter_list', + dateTime: DateTime.now(), + message: 'error_code_not_expected', + statusCode: result['statusCode'].toString(), + resBody: result['body'] + ) + }; + } + } + else { + return result; + } } \ No newline at end of file