Refactor code

This commit is contained in:
Juan Gilsanz Polo 2023-11-01 18:52:30 +01:00
parent 9bca87a4f2
commit 61b402a0bd
5 changed files with 693 additions and 637 deletions

View file

@ -32,156 +32,18 @@ class _ClientsModalState extends State<ClientsModal> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
final clientsProvider = Provider.of<ClientsProvider>(context);
final height = MediaQuery.of(context).size.height; final height = MediaQuery.of(context).size.height;
void apply() async {
logsProvider.setSelectedClients(
selectedClients.isNotEmpty ? selectedClients : null
);
Navigator.pop(context);
}
Widget listItem({
required String label,
required void Function() onChanged
}) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => onChanged(),
child: Padding(
padding: const EdgeInsets.only(
left: 24,
top: 8,
right: 12,
bottom: 8
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
label,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface
),
),
),
Checkbox(
value: selectedClients.contains(label),
onChanged: (_) => onChanged(),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)
),
)
],
),
),
),
);
}
void selectAll() {
setState(() {
selectedClients = clientsProvider.clients!.autoClients.map((item) => item.ip).toList();
});
}
void unselectAll() {
setState(() {
selectedClients = [];
});
}
Widget content() {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.only(
top: 24,
bottom: 16,
),
child: Icon(
Icons.smartphone_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
),
Text(
AppLocalizations.of(context)!.clients,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 16),
],
),
Flexible(
child: ListView.builder(
itemCount: clientsProvider.clients!.autoClients.length,
itemBuilder: (context, index) => listItem(
label: clientsProvider.clients!.autoClients[index].ip,
onChanged: () {
if (selectedClients.contains(clientsProvider.clients!.autoClients[index].ip)) {
setState(() {
selectedClients = selectedClients.where(
(item) => item != clientsProvider.clients!.autoClients[index].ip
).toList();
});
}
else {
setState(() {
selectedClients.add(clientsProvider.clients!.autoClients[index].ip);
});
}
}
)
)
),
Padding(
padding: const EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: selectedClients.length == clientsProvider.clients!.autoClients.length
? () => unselectAll()
: () => selectAll(),
child: Text(
selectedClients.length == clientsProvider.clients!.autoClients.length
? AppLocalizations.of(context)!.unselectAll
: AppLocalizations.of(context)!.selectAll
)
),
TextButton(
onPressed: apply,
child: Text(AppLocalizations.of(context)!.apply)
)
],
),
),
if (Platform.isIOS) const SizedBox(height: 16)
],
);
}
if (widget.dialog == true) { if (widget.dialog == true) {
return Dialog( return Dialog(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxWidth: 500 maxWidth: 500
), ),
child: content() child: _ModalContent(
selectedClients: selectedClients,
onClientsSelected: (v) => setState(() => selectedClients = v),
)
), ),
); );
} }
@ -198,9 +60,176 @@ class _ClientsModalState extends State<ClientsModal> {
), ),
color: Theme.of(context).dialogBackgroundColor color: Theme.of(context).dialogBackgroundColor
), ),
child: content() child: _ModalContent(
selectedClients: selectedClients,
onClientsSelected: (v) => setState(() => selectedClients = v),
)
), ),
); );
} }
} }
}
class _ModalContent extends StatelessWidget {
final List<String> selectedClients;
final void Function(List<String>) onClientsSelected;
const _ModalContent({
Key? key,
required this.selectedClients,
required this.onClientsSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final clientsProvider = Provider.of<ClientsProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
void apply() async {
logsProvider.setSelectedClients(
selectedClients.isNotEmpty ? selectedClients : null
);
Navigator.pop(context);
}
void selectAll() {
onClientsSelected(
clientsProvider.clients!.autoClients.map((item) => item.ip).toList()
);
}
void unselectAll() {
onClientsSelected([]);
}
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.only(
top: 24,
bottom: 16,
),
child: Icon(
Icons.smartphone_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
),
Text(
AppLocalizations.of(context)!.clients,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w400,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 16),
],
),
Flexible(
child: ListView.builder(
itemCount: clientsProvider.clients!.autoClients.length,
itemBuilder: (context, index) => _ListItem(
label: clientsProvider.clients!.autoClients[index].ip,
checkboxActive: selectedClients.contains(clientsProvider.clients!.autoClients[index].ip),
onChanged: (isSelected) {
if (isSelected == true) {
onClientsSelected([
...selectedClients,
clientsProvider.clients!.autoClients[index].ip
]);
}
else {
onClientsSelected(
selectedClients.where(
(item) => item != clientsProvider.clients!.autoClients[index].ip
).toList()
);
}
}
)
)
),
Padding(
padding: const EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: selectedClients.length == clientsProvider.clients!.autoClients.length
? () => unselectAll()
: () => selectAll(),
child: Text(
selectedClients.length == clientsProvider.clients!.autoClients.length
? AppLocalizations.of(context)!.unselectAll
: AppLocalizations.of(context)!.selectAll
)
),
TextButton(
onPressed: apply,
child: Text(AppLocalizations.of(context)!.apply)
)
],
),
),
if (Platform.isIOS) const SizedBox(height: 16)
],
);
}
}
class _ListItem extends StatelessWidget {
final String label;
final bool checkboxActive;
final void Function(bool) onChanged;
const _ListItem({
Key? key,
required this.label,
required this.checkboxActive,
required this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => onChanged(!checkboxActive),
child: Padding(
padding: const EdgeInsets.only(
left: 24,
top: 8,
right: 12,
bottom: 8
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
label,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface
),
),
),
Checkbox(
value: checkboxActive,
onChanged: (v) => onChanged(!checkboxActive),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)
),
)
],
),
),
),
);
}
} }

View file

@ -18,8 +18,6 @@ class _LogsState extends State<Logs> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
if (constraints.maxWidth > 1000) { if (constraints.maxWidth > 1000) {

View file

@ -15,7 +15,7 @@ import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
class LogsFiltersModal extends StatelessWidget { class LogsFiltersModal extends StatefulWidget {
final bool dialog; final bool dialog;
const LogsFiltersModal({ const LogsFiltersModal({
@ -24,39 +24,67 @@ class LogsFiltersModal extends StatelessWidget {
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { State<LogsFiltersModal> createState() => _LogsFiltersModalState();
final logsProvider = Provider.of<LogsProvider>(context);
return LogsFiltersModalWidget(
logsProvider: logsProvider,
dialog: dialog,
);
}
} }
class LogsFiltersModalWidget extends StatefulWidget { class _LogsFiltersModalState extends State<LogsFiltersModal> {
final LogsProvider logsProvider;
final bool dialog;
const LogsFiltersModalWidget({
Key? key,
required this.logsProvider,
required this.dialog
}) : super(key: key);
@override
State<LogsFiltersModalWidget> createState() => _LogsFiltersModalWidgetState();
}
class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
TextEditingController searchController = TextEditingController(); TextEditingController searchController = TextEditingController();
@override @override
void initState() { void initState() {
searchController.text = widget.logsProvider.searchText ?? ''; searchController.text = Provider.of<LogsProvider>(context, listen: false).searchText ?? '';
super.initState(); super.initState();
} }
@override
Widget build(BuildContext context) {
if (widget.dialog == true) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: _FiltersList(
searchController: searchController,
onClearSearch: () => setState(() => searchController.text = "")
)
)
),
);
}
else {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).dialogBackgroundColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(28),
topRight: Radius.circular(28)
)
),
child: _FiltersList(
searchController: searchController,
onClearSearch: () => setState(() => searchController.text = "")
)
),
);
}
}
}
class _FiltersList extends StatelessWidget {
final TextEditingController searchController;
final void Function() onClearSearch;
const _FiltersList({
Key? key,
required this.searchController,
required this.onClearSearch,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
@ -125,200 +153,167 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
} }
} }
Widget content() { return Column(
return Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, children: [
children: [ Flexible(
Flexible( child: SingleChildScrollView(
child: SingleChildScrollView( child: Wrap(
child: Wrap( children: [
children: [ Row(
Row( mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [
children: [ Column(
Column(
children: [
Padding(
padding: const EdgeInsets.only(
top: 24,
bottom: 16,
),
child: Icon(
Icons.filter_list_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
),
Text(
AppLocalizations.of(context)!.filters,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w400,
height: 1.3,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 16),
],
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Row(
children: [ children: [
Expanded( Padding(
child: TextFormField( padding: const EdgeInsets.only(
controller: searchController, top: 24,
onChanged: logsProvider.setSearchText, bottom: 16,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search_rounded),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
labelText: AppLocalizations.of(context)!.search,
suffixIcon: IconButton(
onPressed: () {
setState(() {
searchController.text = '';
});
logsProvider.setSearchText(null);
},
icon: const Icon(Icons.clear)
),
),
), ),
) child: Icon(
Icons.filter_list_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
),
Text(
AppLocalizations.of(context)!.filters,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w400,
height: 1.3,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 16),
], ],
), ),
), ],
Container(height: 16), ),
CustomListTile( Padding(
title: AppLocalizations.of(context)!.client, padding: const EdgeInsets.symmetric(horizontal: 24),
subtitle: logsProvider.selectedClients != null child: Row(
? "${logsProvider.selectedClients!.length} ${AppLocalizations.of(context)!.clientsSelected}" children: [
: AppLocalizations.of(context)!.all, Expanded(
onTap: clientsProvider.loadStatus == LoadStatus.loaded child: TextFormField(
? openSelectClients controller: searchController,
: null, onChanged: logsProvider.setSearchText,
disabled: clientsProvider.loadStatus != LoadStatus.loaded, decoration: InputDecoration(
icon: Icons.smartphone_rounded, prefixIcon: const Icon(Icons.search_rounded),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), border: const OutlineInputBorder(
trailing: clientsProvider.loadStatus == LoadStatus.loading borderRadius: BorderRadius.all(
? const SizedBox( Radius.circular(10)
width: 20, )
height: 20, ),
child: CircularProgressIndicator( labelText: AppLocalizations.of(context)!.search,
strokeWidth: 2, suffixIcon: IconButton(
onPressed: () {
onClearSearch();
logsProvider.setSearchText(null);
},
icon: const Icon(Icons.clear)
),
),
), ),
) )
: clientsProvider.loadStatus == LoadStatus.error
? const Icon(
Icons.error_rounded,
color: Colors.red,
)
: null,
),
SectionLabel(
label: AppLocalizations.of(context)!.quickFilters,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 16
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FilterChip(
selected: logsProvider.selectedResultStatus == "all",
label: Text(AppLocalizations.of(context)!.all),
onSelected: (_) => logsProvider.setSelectedResultStatus("all")
),
FilterChip(
selected: logsProvider.selectedResultStatus == "processed" ||
logsProvider.selectedResultStatus == "whitelisted",
label: Text(AppLocalizations.of(context)!.allowed),
onSelected: (_) => logsProvider.setSelectedResultStatus("processed")
),
FilterChip(
selected: logsProvider.selectedResultStatus == "blocked" ||
logsProvider.selectedResultStatus == "blocked_safebrowsing" ||
logsProvider.selectedResultStatus == "blocked_parental" ||
logsProvider.selectedResultStatus == "safe_search",
label: Text(AppLocalizations.of(context)!.blocked),
onSelected: (_) => logsProvider.setSelectedResultStatus("blocked")
),
], ],
), ),
const Padding(padding: EdgeInsets.all(8)),
CustomListTile(
title: AppLocalizations.of(context)!.responseStatus,
subtitle: "${translatedString[logsProvider.selectedResultStatus]}",
onTap: openSelectFilterStatus,
icon: Icons.shield_rounded,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
],
),
),
),
Padding(
padding: const EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
searchController.text = "";
logsProvider.requestResetFilters();
},
child: Text(AppLocalizations.of(context)!.resetFilters)
), ),
TextButton( Container(height: 16),
onPressed: () { CustomListTile(
Navigator.pop(context); title: AppLocalizations.of(context)!.client,
logsProvider.filterLogs(); subtitle: logsProvider.selectedClients != null
}, ? "${logsProvider.selectedClients!.length} ${AppLocalizations.of(context)!.clientsSelected}"
child: Text(AppLocalizations.of(context)!.apply) : AppLocalizations.of(context)!.all,
onTap: clientsProvider.loadStatus == LoadStatus.loaded
? openSelectClients
: null,
disabled: clientsProvider.loadStatus != LoadStatus.loaded,
icon: Icons.smartphone_rounded,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
trailing: clientsProvider.loadStatus == LoadStatus.loading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
: clientsProvider.loadStatus == LoadStatus.error
? const Icon(
Icons.error_rounded,
color: Colors.red,
)
: null,
),
SectionLabel(
label: AppLocalizations.of(context)!.quickFilters,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 16
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FilterChip(
selected: logsProvider.selectedResultStatus == "all",
label: Text(AppLocalizations.of(context)!.all),
onSelected: (_) => logsProvider.setSelectedResultStatus("all")
),
FilterChip(
selected: logsProvider.selectedResultStatus == "processed" ||
logsProvider.selectedResultStatus == "whitelisted",
label: Text(AppLocalizations.of(context)!.allowed),
onSelected: (_) => logsProvider.setSelectedResultStatus("processed")
),
FilterChip(
selected: logsProvider.selectedResultStatus == "blocked" ||
logsProvider.selectedResultStatus == "blocked_safebrowsing" ||
logsProvider.selectedResultStatus == "blocked_parental" ||
logsProvider.selectedResultStatus == "safe_search",
label: Text(AppLocalizations.of(context)!.blocked),
onSelected: (_) => logsProvider.setSelectedResultStatus("blocked")
),
],
),
const Padding(padding: EdgeInsets.all(8)),
CustomListTile(
title: AppLocalizations.of(context)!.responseStatus,
subtitle: "${translatedString[logsProvider.selectedResultStatus]}",
onTap: openSelectFilterStatus,
icon: Icons.shield_rounded,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
), ),
], ],
), ),
), ),
if (Platform.isIOS) const SizedBox(height: 16)
],
);
}
if (widget.dialog == true) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: content()
)
), ),
); Padding(
} padding: const EdgeInsets.all(24),
else { child: Row(
return Padding( mainAxisAlignment: MainAxisAlignment.spaceBetween,
padding: MediaQuery.of(context).viewInsets, children: [
child: Container( TextButton(
decoration: BoxDecoration( onPressed: () {
color: Theme.of(context).dialogBackgroundColor, searchController.text = "";
borderRadius: const BorderRadius.only( logsProvider.requestResetFilters();
topLeft: Radius.circular(28), },
topRight: Radius.circular(28) child: Text(AppLocalizations.of(context)!.resetFilters)
) ),
TextButton(
onPressed: () {
Navigator.pop(context);
logsProvider.filterLogs();
},
child: Text(AppLocalizations.of(context)!.apply)
),
],
), ),
child: content()
), ),
); if (Platform.isIOS) const SizedBox(height: 16)
} ],
);
} }
} }

View file

@ -1,27 +1,19 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/logs/log_details_screen.dart'; import 'package:adguard_home_manager/screens/logs/log_details_screen.dart';
import 'package:adguard_home_manager/screens/logs/log_tile.dart'; import 'package:adguard_home_manager/screens/logs/log_tile.dart';
import 'package:adguard_home_manager/screens/logs/logs_config_modal.dart'; import 'package:adguard_home_manager/screens/logs/logs_list_appbar.dart';
import 'package:adguard_home_manager/screens/logs/logs_filters_modal.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/constants/enums.dart'; import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/functions/snackbar.dart'; import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/models/logs.dart'; import 'package:adguard_home_manager/models/logs.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/clients_provider.dart'; import 'package:adguard_home_manager/providers/clients_provider.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart'; import 'package:adguard_home_manager/providers/status_provider.dart';
class LogsListWidget extends StatefulWidget { class LogsListWidget extends StatefulWidget {
@ -99,292 +91,17 @@ class _LogsListWidgetState extends State<LogsListWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context); final logsProvider = Provider.of<LogsProvider>(context);
final width = MediaQuery.of(context).size.width;
void updateConfig(Map<String, dynamic> data) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = serverVersionIsAhead(
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
? await serversProvider.apiClient!.updateQueryLogParameters(data: data)
: await serversProvider.apiClient!.updateQueryLogParametersLegacy(data: data);
processModal.close();
if (result['result'] == 'success') {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsConfigUpdated,
color: Colors.green
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsConfigNotUpdated,
color: Colors.red
);
}
}
void clearQueries() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = await serversProvider.apiClient!.clearLogs();
processModal.close();
if (result['result'] == 'success') {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsCleared,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsNotCleared,
color: Colors.red
);
}
}
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
);
}
}
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,
};
return Scaffold( return Scaffold(
body: NestedScrollView( body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [ headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber( SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar.large( sliver: LogsListAppBar(
pinned: true, innerBoxIsScrolled: innerBoxIsScrolled,
floating: true, showDivider: showDivider,
centerTitle: false, )
forceElevated: innerBoxIsScrolled,
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
title: Text(AppLocalizations.of(context)!.logs),
expandedHeight: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? 170 : null,
actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh,
),
logsProvider.loadStatus == LoadStatus.loaded
? IconButton(
onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded),
tooltip: AppLocalizations.of(context)!.filters,
)
: const SizedBox(),
if (statusProvider.serverStatus != null) IconButton(
tooltip: AppLocalizations.of(context)!.settings,
onPressed: () => {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog(
context: context,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: true,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
barrierDismissible: false
)
}
else {
showModalBottomSheet(
context: context,
useRootNavigator: true,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: false,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
backgroundColor: Colors.transparent,
isScrollControlled: true
)
}
},
icon: const Icon(Icons.settings)
),
const SizedBox(width: 5),
],
bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? 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
)
);
logsProvider.setSelectedResultStatus('all');
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: 'all'
);
},
),
],
if (logsProvider.appliedFilters.clients != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.smartphone_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.clients!.length == 1
? logsProvider.appliedFilters.clients![0]
: "${logsProvider.appliedFilters.clients!.length} ${AppLocalizations.of(context)!.clients}",
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: logsProvider.appliedFilters.searchText,
clients: null
)
);
logsProvider.setSelectedClients(null);
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus
);
},
),
],
const SizedBox(width: 15),
],
),
)
)
: null,
),
) )
], ],
body: Builder( body: Builder(

View file

@ -0,0 +1,317 @@
// 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';
import 'package:adguard_home_manager/screens/logs/logs_config_modal.dart';
import 'package:adguard_home_manager/screens/logs/logs_filters_modal.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/constants/enums.dart';
import 'package:adguard_home_manager/functions/compare_versions.dart';
import 'package:adguard_home_manager/functions/desktop_mode.dart';
import 'package:adguard_home_manager/functions/snackbar.dart';
import 'package:adguard_home_manager/models/applied_filters.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/status_provider.dart';
import 'package:adguard_home_manager/providers/logs_provider.dart';
class LogsListAppBar extends StatelessWidget {
final bool innerBoxIsScrolled;
final bool showDivider;
const LogsListAppBar({
Key? key,
required this.innerBoxIsScrolled,
required this.showDivider,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final logsProvider = Provider.of<LogsProvider>(context);
final statusProvider = Provider.of<StatusProvider>(context);
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
void updateConfig(Map<String, dynamic> data) async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = serverVersionIsAhead(
currentVersion: statusProvider.serverStatus!.serverVersion,
referenceVersion: 'v0.107.28',
referenceVersionBeta: 'v0.108.0-b.33'
) == true
? await serversProvider.apiClient!.updateQueryLogParameters(data: data)
: await serversProvider.apiClient!.updateQueryLogParametersLegacy(data: data);
processModal.close();
if (result['result'] == 'success') {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsConfigUpdated,
color: Colors.green
);
}
else {
appConfigProvider.addLog(result['log']);
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsConfigNotUpdated,
color: Colors.red
);
}
}
void clearQueries() async {
ProcessModal processModal = ProcessModal(context: context);
processModal.open(AppLocalizations.of(context)!.updatingSettings);
final result = await serversProvider.apiClient!.clearLogs();
processModal.close();
if (result['result'] == 'success') {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsCleared,
color: Colors.green
);
}
else {
showSnacbkar(
appConfigProvider: appConfigProvider,
label: AppLocalizations.of(context)!.logsNotCleared,
color: Colors.red
);
}
}
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
);
}
}
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,
};
return SliverAppBar.large(
pinned: true,
floating: true,
centerTitle: false,
forceElevated: innerBoxIsScrolled,
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
title: Text(AppLocalizations.of(context)!.logs),
expandedHeight: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? 170 : null,
actions: [
if (!(Platform.isAndroid || Platform.isIOS)) IconButton(
onPressed: () => logsProvider.fetchLogs(inOffset: 0),
icon: const Icon(Icons.refresh_rounded),
tooltip: AppLocalizations.of(context)!.refresh,
),
logsProvider.loadStatus == LoadStatus.loaded
? IconButton(
onPressed: openFilersModal,
icon: const Icon(Icons.filter_list_rounded),
tooltip: AppLocalizations.of(context)!.filters,
)
: const SizedBox(),
if (statusProvider.serverStatus != null) IconButton(
tooltip: AppLocalizations.of(context)!.settings,
onPressed: () => {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog(
context: context,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: true,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
barrierDismissible: false
)
}
else {
showModalBottomSheet(
context: context,
useRootNavigator: true,
builder: (context) => LogsConfigModal(
onConfirm: updateConfig,
onClear: clearQueries,
dialog: false,
serverVersion: statusProvider.serverStatus!.serverVersion,
),
backgroundColor: Colors.transparent,
isScrollControlled: true
)
}
},
icon: const Icon(Icons.settings)
),
const SizedBox(width: 5),
],
bottom: logsProvider.appliedFilters.searchText != null || logsProvider.appliedFilters.selectedResultStatus != 'all' || logsProvider.appliedFilters.clients != null
? 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
)
);
logsProvider.setSelectedResultStatus('all');
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: 'all'
);
},
),
],
if (logsProvider.appliedFilters.clients != null) ...[
const SizedBox(width: 15),
Chip(
avatar: const Icon(
Icons.smartphone_rounded,
),
label: Row(
children: [
Text(
logsProvider.appliedFilters.clients!.length == 1
? logsProvider.appliedFilters.clients![0]
: "${logsProvider.appliedFilters.clients!.length} ${AppLocalizations.of(context)!.clients}",
),
],
),
deleteIcon: const Icon(
Icons.clear,
size: 18,
),
onDeleted: () {
logsProvider.setAppliedFilters(
AppliedFiters(
selectedResultStatus: logsProvider.appliedFilters.selectedResultStatus,
searchText: logsProvider.appliedFilters.searchText,
clients: null
)
);
logsProvider.setSelectedClients(null);
logsProvider.fetchLogs(
inOffset: 0,
responseStatus: logsProvider.appliedFilters.selectedResultStatus
);
},
),
],
const SizedBox(width: 15),
],
),
)
)
: null,
);
}
}