adguard-home-manager/lib/screens/logs/logs_list_appbar.dart

345 lines
13 KiB
Dart
Raw Normal View History

2023-11-01 18:52:30 +01:00
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
2023-11-01 20:46:03 +01:00
import 'package:adguard_home_manager/screens/logs/filters/logs_filters_modal.dart';
2023-11-01 18:52:30 +01:00
2024-03-09 14:40:02 +01:00
import 'package:adguard_home_manager/config/globals.dart';
2023-11-01 18:52:30 +01:00
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart';
2024-03-09 14:40:02 +01:00
final GlobalKey _searchButtonKey = GlobalKey();
2023-11-01 18:52:30 +01:00
class LogsListAppBar extends StatelessWidget {
final bool innerBoxIsScrolled;
final bool showDivider;
const LogsListAppBar({
2023-11-19 22:52:40 +01:00
super.key,
2023-11-01 18:52:30 +01:00
required this.innerBoxIsScrolled,
required this.showDivider,
2023-11-19 22:52:40 +01:00
});
2023-11-01 18:52:30 +01:00
@override
Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
final width = MediaQuery.of(context).size.width;
void openFilersModal() {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog(
context: context,
builder: (context) => const LogsFiltersModal(
dialog: true,
),
barrierDismissible: false
);
}
else {
showModalBottomSheet(
context: context,
useRootNavigator: true,
builder: (context) => const LogsFiltersModal(
dialog: false,
),
backgroundColor: Colors.transparent,
isScrollControlled: true
);
}
}
2024-03-09 14:40:02 +01:00
void showSearchDialog() {
showDialog(
context: context,
builder: (context) => _Search(
2024-03-10 20:30:25 +01:00
searchButtonRenderBox: _searchButtonKey.currentContext?.findRenderObject() as RenderBox?,
2024-03-09 14:40:02 +01:00
onSearch: (v) {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: v != "" ? v : null,
clients: logsProvider.appliedFilters.clients
)
);
logsProvider.filterLogs();
},
),
);
}
2023-11-01 18:52:30 +01:00
final Map<String, String> translatedString = {
"all": AppLocalizations.of(context)!.all,
"filtered": AppLocalizations.of(context)!.filtered,
"processed": AppLocalizations.of(context)!.processedRow,
"whitelisted": AppLocalizations.of(context)!.processedWhitelistRow,
"blocked": AppLocalizations.of(context)!.blocked,
"blocked_safebrowsing": AppLocalizations.of(context)!.blockedSafeBrowsingRow,
"blocked_parental": AppLocalizations.of(context)!.blockedParentalRow,
"safe_search": AppLocalizations.of(context)!.safeSearch,
};
2024-02-18 21:37:06 +01:00
2023-11-01 18:52:30 +01:00
return SliverAppBar.large(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
title: Text(AppLocalizations.of(context)!.logs),
actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh,
),
2024-02-08 00:25:58 +01:00
if (logsProvider.loadStatus == LoadStatus.loaded) IconButton(
2024-03-09 14:40:02 +01:00
key: _searchButtonKey,
onPressed: showSearchDialog,
2024-02-08 00:25:58 +01:00
icon: const Icon(Icons.search_rounded),
tooltip: AppLocalizations.of(context)!.search,
),
if (logsProvider.loadStatus == LoadStatus.loaded) IconButton(
onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded),
tooltip: AppLocalizations.of(context)!.filters,
),
const SizedBox(width: 8),
2023-11-01 18:52:30 +01:00
],
2024-01-30 00:43:57 +01:00
bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients.isNotEmpty
2023-11-01 18:52:30 +01:00
? PreferredSize(
preferredSize: const Size(double.maxFinite, 70),
child: Container(
height: 50,
width: double.maxFinite,
padding: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: showDivider == true
? Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
: Colors.transparent,
)
)
),
child: ListView(
scrollDirection: Axis.horizontal,
children: [
if (logsProvider.appliedFilters.searchText != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.search_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.searchText!,
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: null,
clients: logsProvider.appliedFilters.clients
)
);
logsProvider.setSearchText(null);
logsProvider.fetchLogs(
inOffset: 0,
searchText: ''
);
},
),
],
if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.shield_rounded,
),
label: Row(
children: [
Text(
translatedString[logsProvider.appliedFilters.selectedResultStatus]!,
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: 'all',
searchText: logsProvider.appliedFilters.searchText,
clients: logsProvider.appliedFilters.clients
)
);
2023-12-17 14:14:31 +01:00
logsProvider.setSelectedResultStatus(value: 'all');
2023-11-01 18:52:30 +01:00
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: 'all'
);
},
),
],
2024-01-30 00:43:57 +01:00
if (logsProvider.appliedFilters.clients.isNotEmpty) ...[
2023-11-01 18:52:30 +01:00
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.smartphone_rounded,
),
label: Row(
children: [
Text(
2024-01-30 00:43:57 +01:00
logsProvider.appliedFilters.clients.length == 1
? logsProvider.appliedFilters.clients[0]
: "${logsProvider.appliedFilters.clients.length} ${AppLocalizations.of(context)!.clients}",
2023-11-01 18:52:30 +01:00
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: logsProvider.appliedFilters.searchText,
2024-01-30 00:43:57 +01:00
clients: []
2023-11-01 18:52:30 +01:00
)
);
logsProvider.setSelectedClients(null);
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus
);
},
),
],
const SizedBox(width: 15),
],
),
)
)
: null,
);
}
2024-02-08 00:25:58 +01:00
}
class _Search extends StatefulWidget {
final void Function(String) onSearch;
2024-03-10 20:30:25 +01:00
final RenderBox? searchButtonRenderBox;
2024-02-08 00:25:58 +01:00
const _Search({
2024-02-09 01:44:31 +01:00
required this.onSearch,
2024-03-09 14:40:02 +01:00
required this.searchButtonRenderBox,
2024-02-08 00:25:58 +01:00
});
@override
State<_Search> createState() => _SearchState();
}
class _SearchState extends State<_Search> {
final _searchController = TextEditingController();
@override
void initState() {
final logsProvider = Provider.of<LogsProvider>(context, listen: false);
_searchController.text = logsProvider.appliedFilters.searchText ?? "";
super.initState();
}
@override
Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
2024-03-10 20:30:25 +01:00
final position = widget.searchButtonRenderBox?.localToGlobal(Offset.zero);
final topPadding = MediaQuery.of(globalNavigatorKey.currentContext!).viewPadding.top;
2024-03-09 14:40:02 +01:00
2024-02-08 00:25:58 +01:00
return GestureDetector(
onTap: () => Navigator.pop(context),
child: Material(
color: Colors.transparent,
2024-03-09 14:40:02 +01:00
child: LayoutBuilder(
builder: (context, constraints) {
final double width = constraints.maxWidth - 32 > 500 ? 500 : constraints.maxWidth - 32;
return Stack(
alignment: Alignment.topCenter,
children: [
Positioned(
2024-03-10 20:30:25 +01:00
top: position != null ? position.dy - topPadding : topPadding,
2024-03-09 14:40:02 +01:00
child: SizedBox(
width: width,
child: GestureDetector(
onTap: () => {},
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16)
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: TextFormField(
controller: _searchController,
onChanged: (v) {
if (v == "") {
2024-02-08 00:25:58 +01:00
logsProvider.setSearchText(null);
2024-03-09 14:40:02 +01:00
return;
}
logsProvider.setSearchText(v);
},
onFieldSubmitted: (v) {
widget.onSearch(v);
Navigator.pop(context);
},
autofocus: true,
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.search,
prefixIcon: const Icon(Icons.search_rounded),
border: InputBorder.none,
filled: true,
fillColor: Colors.grey.withOpacity(0.2),
suffixIcon: _searchController.text != ""
? IconButton(
onPressed: () {
_searchController.text = "";
logsProvider.setSearchText(null);
},
icon: const Icon(
Icons.close_rounded,
size: 20,
),
tooltip: AppLocalizations.of(context)!.clearSearch,
)
: null
),
),
),
2024-02-08 00:25:58 +01:00
),
),
),
2024-03-09 14:40:02 +01:00
)
],
);
}
2024-02-08 00:25:58 +01:00
),
),
);
}
2023-11-01 18:52:30 +01:00
}