adguard-home-manager/lib/screens/logs/details/log_details_screen.dart

374 lines
14 KiB
Dart
Raw Normal View History

2022-11-03 14:51:32 +01:00
// 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';
2022-11-30 23:35:31 +01:00
import 'package:adguard_home_manager/widgets/section_label.dart';
2023-11-01 20:46:03 +01:00
import 'package:adguard_home_manager/screens/logs/details/log_list_tile.dart';
2022-11-03 14:51:32 +01:00
2023-10-29 02:19:00 +01:00
import 'package:adguard_home_manager/functions/desktop_mode.dart';
2023-07-14 19:51:18 +02:00
import 'package:adguard_home_manager/functions/open_url.dart';
2024-09-08 19:03:57 +02:00
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
2023-07-14 19:51:18 +02:00
import 'package:adguard_home_manager/constants/urls.dart';
2022-11-03 14:51:32 +01:00
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/functions/get_filtered_status.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
2022-11-03 14:51:32 +01:00
import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/functions/format_time.dart';
import 'package:adguard_home_manager/models/filtering_status.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
class LogDetailsScreen extends StatelessWidget {
final Log log;
2023-05-02 14:01:49 +02:00
final bool dialog;
2024-09-08 19:03:57 +02:00
final bool twoColumns;
2022-11-03 14:51:32 +01:00
const LogDetailsScreen({
2023-12-09 04:04:14 +01:00
super.key,
2023-05-02 14:01:49 +02:00
required this.log,
2024-09-08 19:03:57 +02:00
required this.dialog,
required this.twoColumns,
2023-12-09 04:04:14 +01:00
});
2022-11-03 14:51:32 +01:00
@override
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
2022-11-03 14:51:32 +01:00
2023-10-29 02:19:00 +01:00
final width = MediaQuery.of(context).size.width;
void blockUnblock(String domain, String newStatus) async {
2023-11-20 15:16:20 +01:00
final ProcessModal processModal = ProcessModal();
2022-11-03 14:51:32 +01:00
processModal.open(AppLocalizations.of(context)!.savingUserFilters);
final rules = await statusProvider.blockUnblockDomain(
domain: domain,
newStatus: newStatus
);
2022-11-03 14:51:32 +01:00
processModal.close();
2022-11-03 14:51:32 +01:00
if (rules == true) {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesUpdated,
color: Colors.green
);
2022-11-03 14:51:32 +01:00
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.userFilteringRulesNotUpdated,
color: Colors.red
2022-11-03 14:51:32 +01:00
);
}
}
2023-05-02 14:01:49 +02:00
if (dialog) {
return Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
2023-07-14 19:51:18 +02:00
IconButton(
2023-05-02 14:01:49 +02:00
onPressed: () => Navigator.pop(context),
icon: const Icon(Icons.clear_rounded)
),
const SizedBox(width: 16),
Text(
AppLocalizations.of(context)!.logDetails,
style: const TextStyle(
fontSize: 22
),
),
],
),
Row(
children: [
2023-07-14 19:51:18 +02:00
IconButton(
onPressed: () => openUrl("${Urls.googleSearchUrl}?q=${log.question.name}"),
icon: const Icon(Icons.travel_explore_rounded),
tooltip: AppLocalizations.of(context)!.searchDomainInternet
),
2023-05-02 14:01:49 +02:00
IconButton(
onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
2023-05-02 14:01:49 +02:00
icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded
: Icons.block
),
tooltip: getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? AppLocalizations.of(context)!.unblockDomain
: AppLocalizations.of(context)!.blockDomain,
),
],
)
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
2023-09-04 23:32:55 +02:00
child: ListView(
2024-02-18 21:37:06 +01:00
children: [
_Content(log: log)
]
2023-09-04 23:32:55 +02:00
)
2023-05-02 14:01:49 +02:00
),
)
],
),
),
);
}
else {
2024-09-08 19:03:57 +02:00
print(twoColumns);
2023-05-02 14:01:49 +02:00
return Scaffold(
2023-09-04 23:32:55 +02:00
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar.large(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
2023-10-29 02:19:00 +01:00
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
2024-09-08 19:03:57 +02:00
automaticallyImplyLeading: twoColumns != true,
2023-09-04 23:32:55 +02:00
title: Text(AppLocalizations.of(context)!.logDetails),
actions: [
IconButton(
onPressed: () => openUrl("${Urls.googleSearchUrl}?q=${log.question.name}"),
icon: const Icon(Icons.travel_explore_rounded),
tooltip: AppLocalizations.of(context)!.searchDomainInternet
),
if (statusProvider.filteringStatus != null) IconButton(
onPressed: log.question.name != null
? () => blockUnblock(
log.question.name!,
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'
)
: null,
icon: Icon(
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? Icons.check_circle_rounded
: Icons.block
),
tooltip: getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
? AppLocalizations.of(context)!.unblockDomain
: AppLocalizations.of(context)!.blockDomain,
),
const SizedBox(width: 10)
],
2023-05-02 14:01:49 +02:00
),
2023-09-04 23:32:55 +02:00
)
2023-05-02 14:01:49 +02:00
],
2023-09-04 23:32:55 +02:00
body: SafeArea(
top: false,
child: Builder(
builder: (context) => CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SliverList.list(
2024-02-18 21:37:06 +01:00
children: [
_Content(log: log)
]
2023-09-04 23:32:55 +02:00
)
],
),
)
)
2023-05-02 14:01:49 +02:00
),
);
}
2022-11-03 14:51:32 +01:00
}
2024-02-18 21:37:06 +01:00
}
class _Content extends StatelessWidget {
final Log log;
const _Content({
required this.log,
});
@override
Widget build(BuildContext context) {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
Widget getResult() {
final filter = getFilteredStatus(context, appConfigProvider, log.reason, true);
return Text(
filter['label'],
style: TextStyle(
color: filter['color'],
fontWeight: FontWeight.w500
),
);
}
Filter? getList(int id) {
try {
return statusProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () {
return statusProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id);
});
} catch (_) {
return null;
}
}
return Column(
children: [
SectionLabel(label: AppLocalizations.of(context)!.status),
LogListTile(
icon: Icons.shield_rounded,
title: AppLocalizations.of(context)!.result,
subtitleWidget: getResult(),
trailing: log.cached == true
? Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5
),
decoration: BoxDecoration(
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
borderRadius: BorderRadius.circular(30)
),
child: Text(
"CACHE",
style: TextStyle(
fontSize: 12,
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
fontWeight: FontWeight.w500
),
),
)
: null,
),
if (log.rule != null) LogListTile(
icon: Icons.block,
title: AppLocalizations.of(context)!.blockingRule,
subtitle: log.rule
),
LogListTile(
icon: Icons.calendar_month_rounded,
title: AppLocalizations.of(context)!.date,
subtitle: convertTimestampLocalTimezone(log.time, 'dd-MM-yyyy')
),
LogListTile(
icon: Icons.schedule,
title: AppLocalizations.of(context)!.time,
subtitle: convertTimestampLocalTimezone(log.time, 'HH:mm:ss')
),
SectionLabel(label: AppLocalizations.of(context)!.request),
if (log.question.name != null) LogListTile(
2024-02-18 21:37:06 +01:00
icon: Icons.domain_rounded,
title: AppLocalizations.of(context)!.domain,
subtitle: log.question.name,
onTap: () => copyToClipboard(value: log.question.name!, successMessage: AppLocalizations.of(context)!.domainCopiedClipboard),
2024-02-18 21:37:06 +01:00
),
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
),
SectionLabel(label: AppLocalizations.of(context)!.response),
if (log.upstream != null && log.upstream != '') LogListTile(
icon: Icons.dns_rounded,
title: AppLocalizations.of(context)!.dnsServer,
subtitle: log.upstream,
onTap: () => copyToClipboard(value: log.upstream!, successMessage: AppLocalizations.of(context)!.dnsServerAddressCopied)
2024-02-18 21:37:06 +01:00
),
LogListTile(
icon: Icons.timer_rounded,
title: AppLocalizations.of(context)!.elapsedTime,
subtitle: "${double.parse(log.elapsedMs).toStringAsFixed(2)} ms"
),
if (log.status != null) LogListTile(
icon: Icons.system_update_alt_rounded,
title: AppLocalizations.of(context)!.responseCode,
subtitle: log.status
),
SectionLabel(label: AppLocalizations.of(context)!.client),
LogListTile(
icon: Icons.smartphone_rounded,
title: AppLocalizations.of(context)!.deviceIp,
subtitle: log.client,
onTap: () => copyToClipboard(value: log.client, successMessage: AppLocalizations.of(context)!.clientIpCopied),
2024-02-18 21:37:06 +01:00
),
if (log.clientInfo != null && log.clientInfo!.name != '') LogListTile(
icon: Icons.abc_rounded,
title: AppLocalizations.of(context)!.deviceName,
subtitle: log.clientInfo!.name,
onTap: () => copyToClipboard(value: log.clientInfo!.name, successMessage: AppLocalizations.of(context)!.clientNameCopied),
2024-02-18 21:37:06 +01:00
),
if (log.rules.isNotEmpty) ...[
SectionLabel(label: AppLocalizations.of(context)!.rules),
...log.rules.map((rule) {
final Filter? list = getList(rule.filterListId);
if (list != null) {
return LogListTile(
icon: Icons.rule_rounded,
title: rule.text,
subtitle: list.name
);
}
else {
return const SizedBox();
}
})
],
if (log.answer.isNotEmpty) ...[
SectionLabel(label: AppLocalizations.of(context)!.answers),
...log.answer.map((a) => LogListTile(
icon: Icons.download_rounded,
title: a.value,
subtitle: "TTL: ${a.ttl.toString()}",
trailing: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5
),
decoration: BoxDecoration(
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
borderRadius: BorderRadius.circular(30)
),
child: Text(
a.type,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
fontWeight: FontWeight.w500
),
),
)
))
]
],
);
}
}