diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fca314e..ee587fc 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -111,5 +111,21 @@ "logsNotLoaded": "Logs list could not be loaded", "processed": "Processed (no list)", "blockedBlacklist": "Blocked (blacklist)", - "processedWhitelist": "Processed (whitelist)" + "processedWhitelist": "Processed (whitelist)", + "status": "Status", + "result": "Result", + "time": "Time", + "blocklist": "Blocklist", + "request": "Request", + "domain": "Domain", + "type": "Type", + "clas": "Class", + "response": "Response", + "dnsServer": "DNS server", + "elapsedTime": "Elapsed time", + "responseCode": "Response code", + "client": "Client", + "device": "Device", + "logDetails": "Log details", + "blockingRule": "Blocking rule" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 902bdcf..826c227 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -111,5 +111,21 @@ "logsNotLoaded": "No se pudieron cargar los registros", "processed": "Procesada (sin lista)", "blockedBlacklist": "Bloqueada (lista negra)", - "processedWhitelist": "Procesada (lista blanca)" + "processedWhitelist": "Procesada (lista blanca)", + "status": "Estado", + "result": "Resultado", + "time": "Hora", + "blocklist": "Lista de bloqueo", + "request": "Petición", + "domain": "Dominio", + "type": "Tipo", + "clas": "Clase", + "response": "Respuesta", + "dnsServer": "Servidor DNS", + "elapsedTime": "Tiempo transcurrido", + "responseCode": "Código de respuesta", + "client": "Cliente", + "device": "Dispositivo", + "logDetails": "Detalles del registro", + "blockingRule": "Regla de bloqueo" } \ No newline at end of file diff --git a/lib/screens/logs/log_details_modal.dart b/lib/screens/logs/log_details_modal.dart new file mode 100644 index 0000000..6c3abed --- /dev/null +++ b/lib/screens/logs/log_details_modal.dart @@ -0,0 +1,219 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:adguard_home_manager/screens/logs/log_list_tile.dart'; + +import 'package:adguard_home_manager/functions/format_time.dart'; +import 'package:adguard_home_manager/models/logs.dart'; + +class LogDetailsModal extends StatelessWidget { + final Log log; + + const LogDetailsModal({ + Key? key, + required this.log + }) : super(key: key); + + @override + Widget build(BuildContext context) { + + Widget getResult() { + switch (log.reason) { + case 'NotFilteredNotFound': + return Text( + AppLocalizations.of(context)!.processed, + style: const TextStyle( + color: Colors.green, + fontWeight: FontWeight.w500 + ), + ); + + case 'NotFilteredWhiteList': + return Text( + AppLocalizations.of(context)!.processedWhitelist, + style: const TextStyle( + color: Colors.green, + fontWeight: FontWeight.w500 + ), + ); + + case 'FilteredBlackList': + return Text( + AppLocalizations.of(context)!.blockedBlacklist, + style: const TextStyle( + color: Colors.red, + fontWeight: FontWeight.w500 + ), + ); + + default: + return const Text(""); + } + } + + return DraggableScrollableSheet( + initialChildSize: 0.6, + minChildSize: 0.4, + maxChildSize: 0.95, + builder: (context, controller) => Container( + decoration: BoxDecoration( + color: Theme.of(context).dialogBackgroundColor, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(28), + topRight: Radius.circular(28), + ) + ), + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only( + top: 24, + bottom: 20, + ), + child: Icon( + Icons.list_rounded, + size: 26, + ), + ), + Text( + AppLocalizations.of(context)!.logDetails, + style: const TextStyle( + fontSize: 24 + ), + ), + Expanded( + child: ListView( + controller: controller, + children: [ + Padding( + padding: const EdgeInsets.all(20), + child: Text( + AppLocalizations.of(context)!.status, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).primaryColor + ), + ), + ), + LogListTile( + icon: Icons.shield_rounded, + title: AppLocalizations.of(context)!.result, + subtitleWidget: getResult(), + trailing: log.cached == true + ? Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.circular(10) + ), + child: const Text( + "CACHE", + style: TextStyle( + fontSize: 12, + color: Colors.white, + fontWeight: FontWeight.w500 + ), + ), + ) + : null, + ), + if (log.rule != null) LogListTile( + icon: Icons.block, + title: AppLocalizations.of(context)!.blockingRule, + subtitle: log.rule + ), + LogListTile( + icon: Icons.schedule, + title: AppLocalizations.of(context)!.time, + subtitle: formatTimestamp(log.time, 'HH:mm:ss') + ), + Padding( + padding: const EdgeInsets.all(20), + child: Text( + AppLocalizations.of(context)!.request, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).primaryColor + ), + ), + ), + LogListTile( + icon: Icons.domain_rounded, + title: AppLocalizations.of(context)!.domain, + subtitle: log.question.name + ), + LogListTile( + icon: Icons.category_rounded, + title: AppLocalizations.of(context)!.type, + subtitle: log.question.type + ), + LogListTile( + icon: Icons.class_rounded, + title: AppLocalizations.of(context)!.clas, + subtitle: log.question.questionClass + ), + Padding( + padding: const EdgeInsets.all(20), + child: Text( + AppLocalizations.of(context)!.response, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).primaryColor + ), + ), + ), + if (log.upstream != '') LogListTile( + icon: Icons.dns_rounded, + title: AppLocalizations.of(context)!.dnsServer, + subtitle: log.upstream + ), + LogListTile( + icon: Icons.timer_rounded, + title: AppLocalizations.of(context)!.elapsedTime, + subtitle: "${double.parse(log.elapsedMs).toStringAsFixed(2)} ms" + ), + LogListTile( + icon: Icons.system_update_alt_rounded, + title: AppLocalizations.of(context)!.responseCode, + subtitle: log.status + ), + Padding( + padding: const EdgeInsets.all(20), + child: Text( + AppLocalizations.of(context)!.client, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).primaryColor + ), + ), + ), + LogListTile( + icon: Icons.smartphone_rounded, + title: AppLocalizations.of(context)!.device, + subtitle: log.client + ), + ], + ) + ), + Padding( + padding: const EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(AppLocalizations.of(context)!.close) + ) + ], + ), + ) + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/logs/log_list_tile.dart b/lib/screens/logs/log_list_tile.dart new file mode 100644 index 0000000..ca48922 --- /dev/null +++ b/lib/screens/logs/log_list_tile.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +class LogListTile extends StatelessWidget { + final IconData icon; + final String title; + final String? subtitle; + final Widget? subtitleWidget; + final Widget? trailing; + + const LogListTile({ + Key? key, + required this.icon, + required this.title, + this.subtitle, + this.subtitleWidget, + this.trailing, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final width = MediaQuery.of(context).size.width; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon( + icon, + size: 24, + 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), + subtitleWidget ?? SizedBox( + width: width-100, + child: Text( + subtitle!, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 14, + color: Colors.grey + ), + ), + ) + ], + ), + ], + ), + if (trailing != null) trailing! + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/logs/log_tile.dart b/lib/screens/logs/log_tile.dart index f073a78..94b9044 100644 --- a/lib/screens/logs/log_tile.dart +++ b/lib/screens/logs/log_tile.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:adguard_home_manager/screens/logs/log_details_modal.dart'; + import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/functions/format_time.dart'; @@ -58,7 +60,7 @@ class LogTile extends StatelessWidget { return logStatusWidget( icon: Icons.verified_user_rounded, color: Colors.red, - text:AppLocalizations.of(context)!.blockedBlacklist, + text: AppLocalizations.of(context)!.blockedBlacklist, ); case "NotFilteredWhiteList": @@ -77,11 +79,21 @@ class LogTile extends StatelessWidget { } } + void openLogDetailsModal() { + showModalBottomSheet( + context: context, + builder: (context) => LogDetailsModal( + log: log + ), + backgroundColor: Colors.transparent, + isScrollControlled: true + ); + } return Material( color: Colors.transparent, child: InkWell( - onTap: () => {}, + onTap: openLogDetailsModal, child: Container( width: double.maxFinite, padding: const EdgeInsets.all(10),