mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-06-06 14:50:17 +00:00
Added some context menus on desktop
This commit is contained in:
parent
d628e56248
commit
27ffa75d63
19 changed files with 864 additions and 623 deletions
|
@ -126,4 +126,43 @@ Map<String, dynamic> getFilteredStatus(BuildContext context, AppConfigProvider a
|
||||||
default:
|
default:
|
||||||
return {'filtered': null, 'label': 'Unknown'};
|
return {'filtered': null, 'label': 'Unknown'};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDomainBlocked(String filterKey) {
|
||||||
|
switch (filterKey) {
|
||||||
|
case 'NotFilteredNotFound':
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 'NotFilteredWhiteList':
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 'NotFilteredError':
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 'FilteredBlackList':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'FilteredSafeBrowsing':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'FilteredParental':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'FilteredInvalid':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'FilteredSafeSearch':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'FilteredBlockedService':
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'Rewrite':
|
||||||
|
case 'RewriteEtcHosts':
|
||||||
|
case 'RewriteRule':
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -612,5 +612,7 @@
|
||||||
"selectClientLeftColumn": "Select a client of the left column",
|
"selectClientLeftColumn": "Select a client of the left column",
|
||||||
"disableList": "Disable list",
|
"disableList": "Disable list",
|
||||||
"enableList": "Enable list",
|
"enableList": "Enable list",
|
||||||
"screens": "Screens"
|
"screens": "Screens",
|
||||||
|
"copiedClipboard": "Copied to clipboard",
|
||||||
|
"seeDetails": "See details"
|
||||||
}
|
}
|
|
@ -612,5 +612,7 @@
|
||||||
"selectClientLeftColumn": "Selecciona un cliente de la columna de la izquierda",
|
"selectClientLeftColumn": "Selecciona un cliente de la columna de la izquierda",
|
||||||
"disableList": "Deshabilitar lista",
|
"disableList": "Deshabilitar lista",
|
||||||
"enableList": "Habilitar lista",
|
"enableList": "Habilitar lista",
|
||||||
"screens": "Pantallas"
|
"screens": "Pantallas",
|
||||||
|
"copiedClipboard": "Copiado al portapapeles",
|
||||||
|
"seeDetails": "Ver los detalles"
|
||||||
}
|
}
|
|
@ -140,7 +140,11 @@ class _MainState extends State<Main> {
|
||||||
],
|
],
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
|
data: MediaQuery.of(context).copyWith(
|
||||||
|
textScaleFactor: !(Platform.isAndroid || Platform.isIOS)
|
||||||
|
? 0.9
|
||||||
|
: 1.0
|
||||||
|
),
|
||||||
child: child!,
|
child: child!,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
15
lib/models/menu_option.dart
Normal file
15
lib/models/menu_option.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MenuOption {
|
||||||
|
final IconData? icon;
|
||||||
|
final String title;
|
||||||
|
final void Function() action;
|
||||||
|
final bool? disabled;
|
||||||
|
|
||||||
|
const MenuOption({
|
||||||
|
required this.title,
|
||||||
|
required this.action,
|
||||||
|
this.icon,
|
||||||
|
this.disabled
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:contextmenu/contextmenu.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
|
|
||||||
class ActiveClientTile extends StatelessWidget {
|
class ActiveClientTile extends StatelessWidget {
|
||||||
|
@ -23,77 +26,113 @@ class ActiveClientTile extends StatelessWidget {
|
||||||
if (splitView == true) {
|
if (splitView == true) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: Material(
|
child: ContextMenuArea(
|
||||||
color: Colors.transparent,
|
builder: (context) => [
|
||||||
borderRadius: BorderRadius.circular(28),
|
CustomListTile(
|
||||||
child: InkWell(
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
|
icon: Icons.copy_rounded,
|
||||||
|
onTap: () {
|
||||||
|
copyToClipboard(
|
||||||
|
context: context,
|
||||||
|
value: client.name != ''
|
||||||
|
? client.name!
|
||||||
|
: client.ip,
|
||||||
|
successMessage: AppLocalizations.of(context)!.copiedClipboard,
|
||||||
|
);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(28),
|
borderRadius: BorderRadius.circular(28),
|
||||||
onTap: () => onTap(client),
|
child: InkWell(
|
||||||
child: Container(
|
borderRadius: BorderRadius.circular(28),
|
||||||
width: double.maxFinite,
|
onTap: () => onTap(client),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
width: double.maxFinite,
|
||||||
borderRadius: BorderRadius.circular(28),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
color: client == selectedClient
|
decoration: BoxDecoration(
|
||||||
? Theme.of(context).colorScheme.primaryContainer
|
borderRadius: BorderRadius.circular(28),
|
||||||
: null
|
color: client == selectedClient
|
||||||
),
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
child: Row(
|
: null
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
),
|
||||||
children: [
|
child: Row(
|
||||||
Flexible(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: Row(
|
children: [
|
||||||
mainAxisSize: MainAxisSize.min,
|
Flexible(
|
||||||
children: [
|
child: Row(
|
||||||
Flexible(
|
mainAxisSize: MainAxisSize.min,
|
||||||
child: Column(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Flexible(
|
||||||
children: [
|
child: Column(
|
||||||
Text(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
client.name != ''
|
children: [
|
||||||
? client.name!
|
Text(
|
||||||
: client.ip,
|
client.name != ''
|
||||||
style: TextStyle(
|
? client.name!
|
||||||
fontSize: 16,
|
: client.ip,
|
||||||
fontWeight: FontWeight.w400,
|
style: TextStyle(
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (client.name != '') Text(client.ip)
|
||||||
if (client.name != '') Text(client.ip)
|
],
|
||||||
],
|
),
|
||||||
),
|
)
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
Text(
|
||||||
Text(
|
client.source,
|
||||||
client.source,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
)
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return CustomListTile(
|
return ContextMenuArea(
|
||||||
title: client.name != ''
|
builder: (context) => [
|
||||||
? client.name!
|
CustomListTile(
|
||||||
: client.ip,
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
subtitle: client.name != ''
|
icon: Icons.copy_rounded,
|
||||||
? client.ip
|
onTap: () {
|
||||||
: null,
|
copyToClipboard(
|
||||||
trailing: Text(
|
context: context,
|
||||||
client.source,
|
value: client.name != ''
|
||||||
style: TextStyle(
|
? client.name!
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
: client.ip,
|
||||||
|
successMessage: AppLocalizations.of(context)!.copiedClipboard,
|
||||||
|
);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
child: CustomListTile(
|
||||||
|
title: client.name != ''
|
||||||
|
? client.name!
|
||||||
|
: client.ip,
|
||||||
|
subtitle: client.name != ''
|
||||||
|
? client.ip
|
||||||
|
: null,
|
||||||
|
trailing: Text(
|
||||||
|
client.source,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
onTap: () => onTap(client),
|
||||||
),
|
),
|
||||||
onTap: () => onTap(client),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:contextmenu/contextmenu.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/functions/compare_versions.dart';
|
import 'package:adguard_home_manager/functions/compare_versions.dart';
|
||||||
|
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.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/providers/app_config_provider.dart';
|
||||||
|
|
||||||
class AddedClientTile extends StatefulWidget {
|
class AddedClientTile extends StatelessWidget {
|
||||||
final Client client;
|
final Client client;
|
||||||
final void Function(Client) onTap;
|
final void Function(Client) onTap;
|
||||||
final void Function(Client) onLongPress;
|
final void Function(Client) onLongPress;
|
||||||
|
@ -26,224 +29,254 @@ class AddedClientTile extends StatefulWidget {
|
||||||
required this.splitView
|
required this.splitView
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
|
||||||
State<AddedClientTile> createState() => _AddedClientTileState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AddedClientTileState extends State<AddedClientTile> {
|
|
||||||
bool hover = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final serversProvider = Provider.of<ServersProvider>(context);
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
if (widget.splitView == true) {
|
if (splitView == true) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(28),
|
borderRadius: BorderRadius.circular(28),
|
||||||
child: InkWell(
|
child: ContextMenuArea(
|
||||||
borderRadius: BorderRadius.circular(28),
|
builder: (context) => [
|
||||||
onTap: () => widget.onTap(widget.client),
|
CustomListTile(
|
||||||
onHover: (v) => setState(() => hover = v),
|
title: AppLocalizations.of(context)!.seeDetails,
|
||||||
child: Container(
|
icon: Icons.file_open_rounded,
|
||||||
width: double.maxFinite,
|
onTap: () {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
Navigator.pop(context);
|
||||||
decoration: BoxDecoration(
|
onEdit(client);
|
||||||
borderRadius: BorderRadius.circular(28),
|
}
|
||||||
color: widget.client == widget.selectedClient
|
|
||||||
? Theme.of(context).colorScheme.primaryContainer
|
|
||||||
: null
|
|
||||||
),
|
),
|
||||||
child: Row(
|
CustomListTile(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
children: [
|
icon: Icons.copy_rounded,
|
||||||
Flexible(
|
onTap: () {
|
||||||
child: Row(
|
copyToClipboard(
|
||||||
mainAxisSize: MainAxisSize.min,
|
context: context,
|
||||||
children: [
|
value: client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||||
Flexible(
|
successMessage: AppLocalizations.of(context)!.copiedClipboard,
|
||||||
child: Column(
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Navigator.pop(context);
|
||||||
children: [
|
}
|
||||||
Text(
|
),
|
||||||
widget.client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
],
|
||||||
style: TextStyle(
|
child: InkWell(
|
||||||
fontSize: 16,
|
borderRadius: BorderRadius.circular(28),
|
||||||
fontWeight: FontWeight.w400,
|
onTap: () => onTap(client),
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
onLongPress: () => onLongPress(client),
|
||||||
|
child: Container(
|
||||||
|
width: double.maxFinite,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
color: client == selectedClient
|
||||||
|
? Theme.of(context).colorScheme.primaryContainer
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 8),
|
||||||
const SizedBox(height: 8),
|
Row(
|
||||||
Row(
|
children: [
|
||||||
children: [
|
Icon(
|
||||||
Icon(
|
Icons.filter_list_rounded,
|
||||||
Icons.filter_list_rounded,
|
size: 19,
|
||||||
size: 19,
|
color: client.filteringEnabled == true
|
||||||
color: widget.client.filteringEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Icon(
|
|
||||||
Icons.vpn_lock_rounded,
|
|
||||||
size: 18,
|
|
||||||
color: widget.client.safebrowsingEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Icon(
|
|
||||||
Icons.block,
|
|
||||||
size: 18,
|
|
||||||
color: widget.client.parentalEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Icon(
|
|
||||||
Icons.search_rounded,
|
|
||||||
size: 19,
|
|
||||||
color: serverVersionIsAhead(
|
|
||||||
currentVersion: serversProvider.serverStatus.data!.serverVersion,
|
|
||||||
referenceVersion: 'v0.107.28',
|
|
||||||
referenceVersionBeta: 'v0.108.0-b.33'
|
|
||||||
) == true
|
|
||||||
? widget.client.safeSearch != null && widget.client.safeSearch!.enabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red
|
|
||||||
: widget.client.safesearchEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
? Theme.of(context).colorScheme.primary
|
? Theme.of(context).colorScheme.primary
|
||||||
: Colors.green
|
: Colors.green
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
? Colors.grey
|
? Colors.grey
|
||||||
: Colors.red,
|
: Colors.red,
|
||||||
)
|
),
|
||||||
],
|
const SizedBox(width: 10),
|
||||||
)
|
Icon(
|
||||||
],
|
Icons.vpn_lock_rounded,
|
||||||
),
|
size: 18,
|
||||||
)
|
color: client.safebrowsingEnabled == true
|
||||||
],
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Icon(
|
||||||
|
Icons.block,
|
||||||
|
size: 18,
|
||||||
|
color: client.parentalEnabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Icon(
|
||||||
|
Icons.search_rounded,
|
||||||
|
size: 19,
|
||||||
|
color: serverVersionIsAhead(
|
||||||
|
currentVersion: serversProvider.serverStatus.data!.serverVersion,
|
||||||
|
referenceVersion: 'v0.107.28',
|
||||||
|
referenceVersionBeta: 'v0.108.0-b.33'
|
||||||
|
) == true
|
||||||
|
? client.safeSearch != null && client.safeSearch!.enabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red
|
||||||
|
: client.safesearchEnabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
if (hover == true) IconButton(
|
)
|
||||||
onPressed: () => widget.onEdit(widget.client),
|
),
|
||||||
icon: const Icon(Icons.edit_rounded)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return CustomListTile(
|
return ContextMenuArea(
|
||||||
onLongPress: () => widget.onLongPress(widget.client),
|
builder: (context) => [
|
||||||
onTap: () => widget.onTap(widget.client),
|
CustomListTile(
|
||||||
onHover: (v) => setState(() => hover = v),
|
title: AppLocalizations.of(context)!.seeDetails,
|
||||||
title: widget.client.name,
|
icon: Icons.file_open_rounded,
|
||||||
subtitleWidget: Column(
|
onTap: () {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Navigator.pop(context);
|
||||||
children: [
|
onEdit(client);
|
||||||
Text(
|
}
|
||||||
widget.client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
),
|
||||||
style: TextStyle(
|
CustomListTile(
|
||||||
color: Theme.of(context).listTileTheme.textColor
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
|
icon: Icons.copy_rounded,
|
||||||
|
onTap: () {
|
||||||
|
copyToClipboard(
|
||||||
|
context: context,
|
||||||
|
value: client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||||
|
successMessage: AppLocalizations.of(context)!.copiedClipboard,
|
||||||
|
);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: CustomListTile(
|
||||||
|
onLongPress: () => onLongPress(client),
|
||||||
|
onTap: () => onTap(client),
|
||||||
|
title: client.name,
|
||||||
|
subtitleWidget: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 8),
|
||||||
const SizedBox(height: 8),
|
Row(
|
||||||
Row(
|
children: [
|
||||||
children: [
|
Icon(
|
||||||
Icon(
|
Icons.filter_list_rounded,
|
||||||
Icons.filter_list_rounded,
|
size: 19,
|
||||||
size: 19,
|
color: client.filteringEnabled == true
|
||||||
color: widget.client.filteringEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Icon(
|
|
||||||
Icons.vpn_lock_rounded,
|
|
||||||
size: 18,
|
|
||||||
color: widget.client.safebrowsingEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Icon(
|
|
||||||
Icons.block,
|
|
||||||
size: 18,
|
|
||||||
color: widget.client.parentalEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Icon(
|
|
||||||
Icons.search_rounded,
|
|
||||||
size: 19,
|
|
||||||
color: serverVersionIsAhead(
|
|
||||||
currentVersion: serversProvider.serverStatus.data!.serverVersion,
|
|
||||||
referenceVersion: 'v0.107.28',
|
|
||||||
referenceVersionBeta: 'v0.108.0-b.33'
|
|
||||||
) == true
|
|
||||||
? widget.client.safeSearch != null && widget.client.safeSearch!.enabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red
|
|
||||||
: widget.client.safesearchEnabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
? Theme.of(context).colorScheme.primary
|
? Theme.of(context).colorScheme.primary
|
||||||
: Colors.green
|
: Colors.green
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
? Colors.grey
|
? Colors.grey
|
||||||
: Colors.red,
|
: Colors.red,
|
||||||
)
|
),
|
||||||
],
|
const SizedBox(width: 10),
|
||||||
)
|
Icon(
|
||||||
],
|
Icons.vpn_lock_rounded,
|
||||||
|
size: 18,
|
||||||
|
color: client.safebrowsingEnabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Icon(
|
||||||
|
Icons.block,
|
||||||
|
size: 18,
|
||||||
|
color: client.parentalEnabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Icon(
|
||||||
|
Icons.search_rounded,
|
||||||
|
size: 19,
|
||||||
|
color: serverVersionIsAhead(
|
||||||
|
currentVersion: serversProvider.serverStatus.data!.serverVersion,
|
||||||
|
referenceVersion: 'v0.107.28',
|
||||||
|
referenceVersionBeta: 'v0.108.0-b.33'
|
||||||
|
) == true
|
||||||
|
? client.safeSearch != null && client.safeSearch!.enabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red
|
||||||
|
: client.safesearchEnabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
trailing: hover == true
|
|
||||||
? IconButton(
|
|
||||||
onPressed: () => widget.onEdit(widget.client),
|
|
||||||
icon: const Icon(Icons.edit_rounded)
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,53 +144,67 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
);
|
);
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
return RefreshIndicator(
|
if (logsData!.data.isNotEmpty) {
|
||||||
onRefresh: fetchLogs,
|
return RefreshIndicator(
|
||||||
child: ListView.builder(
|
onRefresh: fetchLogs,
|
||||||
controller: scrollController,
|
child: ListView.builder(
|
||||||
padding: const EdgeInsets.only(top: 0),
|
controller: scrollController,
|
||||||
itemCount: isLoadingMore == true
|
padding: const EdgeInsets.only(top: 0),
|
||||||
? logsData!.data.length+1
|
itemCount: isLoadingMore == true
|
||||||
: logsData!.data.length,
|
? logsData!.data.length+1
|
||||||
itemBuilder: (context, index) {
|
: logsData!.data.length,
|
||||||
if (isLoadingMore == true && index == logsData!.data.length) {
|
itemBuilder: (context, index) {
|
||||||
return const Padding(
|
if (isLoadingMore == true && index == logsData!.data.length) {
|
||||||
padding: EdgeInsets.symmetric(vertical: 20),
|
return const Padding(
|
||||||
child: Center(
|
padding: EdgeInsets.symmetric(vertical: 20),
|
||||||
child: CircularProgressIndicator(),
|
child: Center(
|
||||||
),
|
child: CircularProgressIndicator(),
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
else {
|
}
|
||||||
return LogTile(
|
else {
|
||||||
log: logsData!.data[index],
|
return LogTile(
|
||||||
index: index,
|
log: logsData!.data[index],
|
||||||
length: logsData!.data.length,
|
index: index,
|
||||||
useAlwaysNormalTile: true,
|
length: logsData!.data.length,
|
||||||
onLogTap: (log) => {
|
useAlwaysNormalTile: true,
|
||||||
if (width > 700) {
|
onLogTap: (log) => {
|
||||||
showDialog(
|
if (width > 700) {
|
||||||
context: context,
|
showDialog(
|
||||||
builder: (context) => LogDetailsScreen(
|
context: context,
|
||||||
log: log,
|
builder: (context) => LogDetailsScreen(
|
||||||
dialog: true
|
log: log,
|
||||||
|
dialog: true
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
else {
|
||||||
|
Navigator.push(context, MaterialPageRoute(
|
||||||
|
builder: (context) => LogDetailsScreen(
|
||||||
|
log: log,
|
||||||
|
dialog: false
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
);
|
||||||
Navigator.push(context, MaterialPageRoute(
|
}
|
||||||
builder: (context) => LogDetailsScreen(
|
|
||||||
log: log,
|
|
||||||
dialog: false
|
|
||||||
)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
|
else {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.noLogsDisplay,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/filters/add_button.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:contextmenu/contextmenu.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/screens/filters/add_button.dart';
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
import 'package:adguard_home_manager/widgets/options_modal.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/constants/enums.dart';
|
import 'package:adguard_home_manager/constants/enums.dart';
|
||||||
|
import 'package:adguard_home_manager/models/menu_option.dart';
|
||||||
|
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
||||||
import 'package:adguard_home_manager/models/filtering.dart';
|
import 'package:adguard_home_manager/models/filtering.dart';
|
||||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
@ -235,20 +239,44 @@ class FiltersTripleColumn extends StatelessWidget {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: serversProvider.filtering.data!.userRules.length,
|
itemCount: serversProvider.filtering.data!.userRules.length,
|
||||||
itemBuilder: (context, index) => ListTile(
|
itemBuilder: (context, index) => ContextMenuArea(
|
||||||
title: Text(
|
builder: (context) => [
|
||||||
serversProvider.filtering.data!.userRules[index],
|
CustomListTile(
|
||||||
style: TextStyle(
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
color: checkIfComment(serversProvider.filtering.data!.userRules[index]) == true
|
icon: Icons.copy_rounded,
|
||||||
? Theme.of(context).colorScheme.onSurface.withOpacity(0.6)
|
onTap: () {
|
||||||
: Theme.of(context).colorScheme.onSurface,
|
copyToClipboard(
|
||||||
fontWeight: FontWeight.normal,
|
context: context,
|
||||||
|
value: serversProvider.filtering.data!.userRules[index],
|
||||||
|
successMessage: AppLocalizations.of(context)!.copiedClipboard,
|
||||||
|
);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: CustomListTile(
|
||||||
|
onLongPress: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => OptionsModal(
|
||||||
|
options: [
|
||||||
|
MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
|
icon: Icons.copy_rounded,
|
||||||
|
action: () => copyToClipboard(
|
||||||
|
context: context,
|
||||||
|
value: serversProvider.filtering.data!.userRules[index],
|
||||||
|
successMessage: AppLocalizations.of(context)!.copiedClipboard,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
title: serversProvider.filtering.data!.userRules[index],
|
||||||
|
subtitleWidget: generateSubtitle(serversProvider.filtering.data!.userRules[index]),
|
||||||
|
trailing: IconButton(
|
||||||
|
onPressed: () => onRemoveCustomRule(serversProvider.filtering.data!.userRules[index]),
|
||||||
|
icon: const Icon(Icons.delete)
|
||||||
),
|
),
|
||||||
),
|
|
||||||
subtitle: generateSubtitle(serversProvider.filtering.data!.userRules[index]),
|
|
||||||
trailing: IconButton(
|
|
||||||
onPressed: () => onRemoveCustomRule(serversProvider.filtering.data!.userRules[index]),
|
|
||||||
icon: const Icon(Icons.delete)
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -216,9 +216,9 @@ class _HomeState extends State<Home> {
|
||||||
maxWidth: 500
|
maxWidth: 500
|
||||||
),
|
),
|
||||||
child: TopItems(
|
child: TopItems(
|
||||||
label: AppLocalizations.of(context)!.topBlockedDomains,
|
label: AppLocalizations.of(context)!.topClients,
|
||||||
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
|
data: serversProvider.serverStatus.data!.stats.topClients,
|
||||||
type: 'topBlockedDomains',
|
type: 'topClients',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,17 +2,18 @@
|
||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/top_items/top_items_modal.dart';
|
|
||||||
import 'package:animations/animations.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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/home/top_items_options_modal.dart';
|
import 'package:adguard_home_manager/widgets/domain_options.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/top_items/top_items_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/widgets/options_modal.dart';
|
||||||
import 'package:adguard_home_manager/screens/top_items/top_items.dart';
|
import 'package:adguard_home_manager/screens/top_items/top_items.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/models/applied_filters.dart';
|
import 'package:adguard_home_manager/models/applied_filters.dart';
|
||||||
|
import 'package:adguard_home_manager/models/menu_option.dart';
|
||||||
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
||||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||||
import 'package:adguard_home_manager/models/filtering_status.dart';
|
import 'package:adguard_home_manager/models/filtering_status.dart';
|
||||||
|
@ -119,14 +120,32 @@ class TopItems extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<MenuOption> generateOptions(String domain) {
|
||||||
|
final isBlocked = getIsBlocked();
|
||||||
|
return [
|
||||||
|
if (isBlocked == true) MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.unblock,
|
||||||
|
icon: Icons.check,
|
||||||
|
action: () => blockUnblock(domain, 'unblock')
|
||||||
|
),
|
||||||
|
if (isBlocked == false) MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.block,
|
||||||
|
icon: Icons.check,
|
||||||
|
action: () => blockUnblock(domain, 'block')
|
||||||
|
),
|
||||||
|
MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
|
icon: Icons.check,
|
||||||
|
action: () => copyDomainClipboard(domain)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
void openOptionsModal(String domain, String type) {
|
void openOptionsModal(String domain, String type) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => TopItemsOptionsModal(
|
builder: (context) => OptionsModal(
|
||||||
isBlocked: getIsBlocked(),
|
options: generateOptions(domain),
|
||||||
changeStatus: (String status) => blockUnblock(domain, status),
|
|
||||||
copyToClipboard: () => copyDomainClipboard(domain),
|
|
||||||
type: type,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -143,7 +162,10 @@ class TopItems extends StatelessWidget {
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: DomainOptions(
|
||||||
|
item: item.keys.toList()[0],
|
||||||
|
isClient: type == 'topClients',
|
||||||
|
isBlocked: type == 'topBlockedDomains',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (type == 'topQueriedDomains' || type == 'topBlockedDomains') {
|
if (type == 'topQueriedDomains' || type == 'topBlockedDomains') {
|
||||||
logsProvider.setSearchText(item.keys.toList()[0]);
|
logsProvider.setSearchText(item.keys.toList()[0]);
|
||||||
|
@ -167,10 +189,8 @@ class TopItems extends StatelessWidget {
|
||||||
clients: [item.keys.toList()[0]]
|
clients: [item.keys.toList()[0]]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
appConfigProvider.setSelectedScreen(2);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () => openOptionsModal(item.keys.toList()[0], type),
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 20,
|
horizontal: 20,
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile_dialog.dart';
|
|
||||||
|
|
||||||
class TopItemsOptionsModal extends StatelessWidget {
|
|
||||||
final bool? isBlocked;
|
|
||||||
final void Function(String status)? changeStatus;
|
|
||||||
final void Function() copyToClipboard;
|
|
||||||
final String type;
|
|
||||||
|
|
||||||
const TopItemsOptionsModal({
|
|
||||||
Key? key,
|
|
||||||
this.isBlocked,
|
|
||||||
this.changeStatus,
|
|
||||||
required this.copyToClipboard,
|
|
||||||
required this.type
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
title: Column(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.more_horiz,
|
|
||||||
size: 24,
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.options,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (type == 'topQueriedDomains' || type == 'topBlockedDomains') ...[
|
|
||||||
if (isBlocked == true && changeStatus != null) CustomListTileDialog(
|
|
||||||
title: AppLocalizations.of(context)!.unblock,
|
|
||||||
icon: Icons.check,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
changeStatus!('unblock');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (isBlocked == false && changeStatus != null) CustomListTileDialog(
|
|
||||||
title: AppLocalizations.of(context)!.block,
|
|
||||||
icon: Icons.block,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
changeStatus!('block');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
CustomListTileDialog(
|
|
||||||
title: AppLocalizations.of(context)!.copyClipboard,
|
|
||||||
icon: Icons.copy,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
copyToClipboard();
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text(AppLocalizations.of(context)!.cancel)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,15 +2,11 @@
|
||||||
|
|
||||||
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:adguard_home_manager/screens/home/top_items_options_modal.dart';
|
import 'package:adguard_home_manager/widgets/domain_options.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
|
||||||
import 'package:adguard_home_manager/functions/block_unblock_domain.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/functions/get_filtered_status.dart';
|
import 'package:adguard_home_manager/functions/get_filtered_status.dart';
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
|
||||||
import 'package:adguard_home_manager/models/logs.dart';
|
import 'package:adguard_home_manager/models/logs.dart';
|
||||||
import 'package:adguard_home_manager/functions/format_time.dart';
|
import 'package:adguard_home_manager/functions/format_time.dart';
|
||||||
|
|
||||||
|
@ -75,42 +71,16 @@ class LogTile extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeBlockStatus(String status) async {
|
|
||||||
final result = await blockUnblock(context, log.question.name, status);
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: result['message'],
|
|
||||||
color: result['success'] == true ? Colors.green : Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void openOptionsModal(Log log) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => TopItemsOptionsModal(
|
|
||||||
isBlocked: getFilteredStatus(context, appConfigProvider, log.reason, false)['color'] == Colors.red
|
|
||||||
? true : false,
|
|
||||||
changeStatus: changeBlockStatus,
|
|
||||||
copyToClipboard: () => copyToClipboard(
|
|
||||||
context: context,
|
|
||||||
value: log.question.name,
|
|
||||||
successMessage: AppLocalizations.of(context)!.domainCopiedClipboard
|
|
||||||
),
|
|
||||||
type: 'topQueriedDomains', // topQueriedDomains can also be used here. It's the same
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width > 1100 && !(useAlwaysNormalTile == true)) {
|
if (width > 1100 && !(useAlwaysNormalTile == true)) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: Material(
|
child: InkWell(
|
||||||
color: Colors.transparent,
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
borderRadius: BorderRadius.circular(28),
|
||||||
child: InkWell(
|
child: DomainOptions(
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
onTap: () => onLogTap(log),
|
onTap: () => onLogTap(log),
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
item: log.question.name,
|
||||||
|
isBlocked: isDomainBlocked(log.reason),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
@ -291,9 +261,10 @@ class LogTile extends StatelessWidget {
|
||||||
else {
|
else {
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: DomainOptions(
|
||||||
onTap: () => onLogTap(log),
|
onTap: () => onLogTap(log),
|
||||||
onLongPress: () => openOptionsModal(log),
|
item: log.question.name,
|
||||||
|
isBlocked: isDomainBlocked(log.reason),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
|
|
@ -7,11 +7,10 @@ import 'package:percent_indicator/percent_indicator.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/home/top_items_options_modal.dart';
|
import 'package:adguard_home_manager/widgets/domain_options.dart';
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/models/applied_filters.dart';
|
import 'package:adguard_home_manager/models/applied_filters.dart';
|
||||||
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
|
||||||
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||||
|
@ -67,45 +66,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
for (var element in data) {
|
for (var element in data) {
|
||||||
total = total + int.parse(element.values.toList()[0].toString());
|
total = total + int.parse(element.values.toList()[0].toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool? getIsBlocked() {
|
|
||||||
if (widget.type == 'topBlockedDomains') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (widget.type == 'topQueriedDomains') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeBlockStatus(String status, String domain) async {
|
|
||||||
final result = await blockUnblock(context, domain, status);
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: result['message'],
|
|
||||||
color: result['success'] == true ? Colors.green : Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void openOptionsModal(String domain, String type) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => TopItemsOptionsModal(
|
|
||||||
isBlocked: getIsBlocked(),
|
|
||||||
changeStatus: (String status) => changeBlockStatus(status, domain),
|
|
||||||
copyToClipboard: () => copyToClipboard(
|
|
||||||
context: context,
|
|
||||||
value: domain,
|
|
||||||
successMessage: AppLocalizations.of(context)!.domainCopiedClipboard
|
|
||||||
),
|
|
||||||
type: type,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: searchActive == true
|
title: searchActive == true
|
||||||
|
@ -197,7 +158,10 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CustomListTile(
|
return DomainOptions(
|
||||||
|
item: screenData[index].keys.toList()[0],
|
||||||
|
isBlocked: widget.type == 'topBlockedDomains',
|
||||||
|
isClient: widget.type == 'topClients',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.type == 'topQueriedDomains' || widget.type == 'topBlockedDomains') {
|
if (widget.type == 'topQueriedDomains' || widget.type == 'topBlockedDomains') {
|
||||||
logsProvider.setSearchText(screenData[index].keys.toList()[0]);
|
logsProvider.setSearchText(screenData[index].keys.toList()[0]);
|
||||||
|
@ -226,59 +190,57 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () => openOptionsModal(
|
child: CustomListTile(
|
||||||
screenData[index].keys.toList()[0],
|
title: screenData[index].keys.toList()[0],
|
||||||
widget.type
|
trailing: Text(
|
||||||
),
|
screenData[index].values.toList()[0].toString(),
|
||||||
title: screenData[index].keys.toList()[0],
|
style: TextStyle(
|
||||||
trailing: Text(
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
screenData[index].values.toList()[0].toString(),
|
),
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant
|
|
||||||
),
|
),
|
||||||
),
|
subtitleWidget: Column(
|
||||||
subtitleWidget: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
if (name != null) ...[
|
||||||
if (name != null) ...[
|
Text(
|
||||||
Text(
|
name,
|
||||||
name,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
fontSize: 14,
|
||||||
fontSize: 14,
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 5),
|
||||||
const SizedBox(height: 5),
|
],
|
||||||
],
|
Row(
|
||||||
Row(
|
children: [
|
||||||
children: [
|
SizedBox(
|
||||||
SizedBox(
|
width: 50,
|
||||||
width: 50,
|
child: Text(
|
||||||
child: Text(
|
"${doubleFormat((screenData[index].values.toList()[0]/total*100), Platform.localeName)}%",
|
||||||
"${doubleFormat((screenData[index].values.toList()[0]/total*100), Platform.localeName)}%",
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
color: Theme.of(context).listTileTheme.textColor
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 10),
|
||||||
const SizedBox(width: 10),
|
Flexible(
|
||||||
Flexible(
|
child: LinearPercentIndicator(
|
||||||
child: LinearPercentIndicator(
|
animation: true,
|
||||||
animation: true,
|
lineHeight: 4,
|
||||||
lineHeight: 4,
|
animationDuration: 500,
|
||||||
animationDuration: 500,
|
curve: Curves.easeOut,
|
||||||
curve: Curves.easeOut,
|
percent: screenData[index].values.toList()[0]/total,
|
||||||
percent: screenData[index].values.toList()[0]/total,
|
barRadius: const Radius.circular(5),
|
||||||
barRadius: const Radius.circular(5),
|
progressColor: Theme.of(context).colorScheme.primary,
|
||||||
progressColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 10),
|
||||||
const SizedBox(width: 10),
|
],
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
],
|
)
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,11 +7,10 @@ import 'package:percent_indicator/percent_indicator.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/home/top_items_options_modal.dart';
|
import 'package:adguard_home_manager/widgets/domain_options.dart';
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/models/applied_filters.dart';
|
import 'package:adguard_home_manager/models/applied_filters.dart';
|
||||||
import 'package:adguard_home_manager/functions/copy_clipboard.dart';
|
|
||||||
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||||
|
@ -66,45 +65,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
|
||||||
for (var element in data) {
|
for (var element in data) {
|
||||||
total = total + int.parse(element.values.toList()[0].toString());
|
total = total + int.parse(element.values.toList()[0].toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool? getIsBlocked() {
|
|
||||||
if (widget.type == 'topBlockedDomains') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (widget.type == 'topQueriedDomains') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeBlockStatus(String status, String domain) async {
|
|
||||||
final result = await blockUnblock(context, domain, status);
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: result['message'],
|
|
||||||
color: result['success'] == true ? Colors.green : Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void openOptionsModal(String domain, String type) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => TopItemsOptionsModal(
|
|
||||||
isBlocked: getIsBlocked(),
|
|
||||||
changeStatus: (String status) => changeBlockStatus(status, domain),
|
|
||||||
copyToClipboard: () => copyToClipboard(
|
|
||||||
context: context,
|
|
||||||
value: domain,
|
|
||||||
successMessage: AppLocalizations.of(context)!.domainCopiedClipboard
|
|
||||||
),
|
|
||||||
type: type,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Dialog(
|
return Dialog(
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
|
@ -169,7 +130,10 @@ class _TopItemsModalState extends State<TopItemsModal> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CustomListTile(
|
return DomainOptions(
|
||||||
|
isBlocked: widget.type == 'topBlockedDomains',
|
||||||
|
isClient: widget.type == 'topClients',
|
||||||
|
item: screenData[index].keys.toList()[0],
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.type == 'topQueriedDomains' || widget.type == 'topBlockedDomains') {
|
if (widget.type == 'topQueriedDomains' || widget.type == 'topBlockedDomains') {
|
||||||
logsProvider.setSearchText(screenData[index].keys.toList()[0]);
|
logsProvider.setSearchText(screenData[index].keys.toList()[0]);
|
||||||
|
@ -198,59 +162,57 @@ class _TopItemsModalState extends State<TopItemsModal> {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () => openOptionsModal(
|
child: CustomListTile(
|
||||||
screenData[index].keys.toList()[0],
|
title: screenData[index].keys.toList()[0],
|
||||||
widget.type
|
trailing: Text(
|
||||||
),
|
screenData[index].values.toList()[0].toString(),
|
||||||
title: screenData[index].keys.toList()[0],
|
style: TextStyle(
|
||||||
trailing: Text(
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
screenData[index].values.toList()[0].toString(),
|
),
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant
|
|
||||||
),
|
),
|
||||||
),
|
subtitleWidget: Column(
|
||||||
subtitleWidget: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
if (name != null) ...[
|
||||||
if (name != null) ...[
|
Text(
|
||||||
Text(
|
name,
|
||||||
name,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
fontSize: 14,
|
||||||
fontSize: 14,
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
color: Theme.of(context).colorScheme.onSurface
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 5),
|
||||||
const SizedBox(height: 5),
|
],
|
||||||
],
|
Row(
|
||||||
Row(
|
children: [
|
||||||
children: [
|
SizedBox(
|
||||||
SizedBox(
|
width: 50,
|
||||||
width: 50,
|
child: Text(
|
||||||
child: Text(
|
"${doubleFormat((screenData[index].values.toList()[0]/total*100), Platform.localeName)}%",
|
||||||
"${doubleFormat((screenData[index].values.toList()[0]/total*100), Platform.localeName)}%",
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
color: Theme.of(context).listTileTheme.textColor
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 10),
|
||||||
const SizedBox(width: 10),
|
Flexible(
|
||||||
Flexible(
|
child: LinearPercentIndicator(
|
||||||
child: LinearPercentIndicator(
|
animation: true,
|
||||||
animation: true,
|
lineHeight: 4,
|
||||||
lineHeight: 4,
|
animationDuration: 500,
|
||||||
animationDuration: 500,
|
curve: Curves.easeOut,
|
||||||
curve: Curves.easeOut,
|
percent: screenData[index].values.toList()[0]/total,
|
||||||
percent: screenData[index].values.toList()[0]/total,
|
barRadius: const Radius.circular(5),
|
||||||
barRadius: const Radius.circular(5),
|
progressColor: Theme.of(context).colorScheme.primary,
|
||||||
progressColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 10),
|
||||||
const SizedBox(width: 10),
|
],
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
],
|
)
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
158
lib/widgets/domain_options.dart
Normal file
158
lib/widgets/domain_options.dart
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:contextmenu/contextmenu.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/widgets/options_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/models/filtering_status.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/services/http_requests.dart';
|
||||||
|
import 'package:adguard_home_manager/models/menu_option.dart';
|
||||||
|
|
||||||
|
class DomainOptions extends StatelessWidget {
|
||||||
|
final bool isBlocked;
|
||||||
|
final bool? isClient;
|
||||||
|
final String item;
|
||||||
|
final Widget child;
|
||||||
|
final void Function() onTap;
|
||||||
|
final BorderRadius? borderRadius;
|
||||||
|
|
||||||
|
const DomainOptions({
|
||||||
|
Key? key,
|
||||||
|
required this.isBlocked,
|
||||||
|
this.isClient,
|
||||||
|
required this.item,
|
||||||
|
required this.child,
|
||||||
|
required this.onTap,
|
||||||
|
this.borderRadius
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
void blockUnblock(String domain, String newStatus) async {
|
||||||
|
final ProcessModal processModal = ProcessModal(context: context);
|
||||||
|
processModal.open(AppLocalizations.of(context)!.savingUserFilters);
|
||||||
|
|
||||||
|
final rules = await getFilteringRules(server: serversProvider.selectedServer!);
|
||||||
|
|
||||||
|
if (rules['result'] == 'success') {
|
||||||
|
FilteringStatus oldStatus = serversProvider.serverStatus.data!.filteringStatus;
|
||||||
|
|
||||||
|
List<String> newRules = rules['data'].userRules.where((d) => !d.contains(domain)).toList();
|
||||||
|
if (newStatus == 'block') {
|
||||||
|
newRules.add("||$domain^");
|
||||||
|
}
|
||||||
|
else if (newStatus == 'unblock') {
|
||||||
|
newRules.add("@@||$domain^");
|
||||||
|
}
|
||||||
|
FilteringStatus newObj = serversProvider.serverStatus.data!.filteringStatus;
|
||||||
|
newObj.userRules = newRules;
|
||||||
|
serversProvider.setFilteringStatus(newObj);
|
||||||
|
|
||||||
|
final result = await postFilteringRules(server: serversProvider.selectedServer!, data: {'rules': newRules});
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
if (result['result'] == 'success') {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.userFilteringRulesUpdated),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appConfigProvider.addLog(result['log']);
|
||||||
|
serversProvider.setFilteringStatus(oldStatus);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appConfigProvider.addLog(rules['log']);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.userFilteringRulesNotUpdated),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyDomainClipboard(String domain) async {
|
||||||
|
await Clipboard.setData(
|
||||||
|
ClipboardData(text: domain)
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.domainCopiedClipboard),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MenuOption> generateOptions() {
|
||||||
|
return [
|
||||||
|
if (isClient != true && isBlocked == true) MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.unblock,
|
||||||
|
icon: Icons.check,
|
||||||
|
action: () => blockUnblock(item, 'unblock')
|
||||||
|
),
|
||||||
|
if (isClient != true && isBlocked == false) MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.block,
|
||||||
|
icon: Icons.block,
|
||||||
|
action: () => blockUnblock(item, 'block')
|
||||||
|
),
|
||||||
|
MenuOption(
|
||||||
|
title: AppLocalizations.of(context)!.copyClipboard,
|
||||||
|
icon: Icons.copy,
|
||||||
|
action: () => copyDomainClipboard(item)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
void openOptionsModal() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => OptionsModal(
|
||||||
|
options: generateOptions(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
child: ContextMenuArea(
|
||||||
|
builder: (context) => generateOptions().map((opt) => CustomListTile(
|
||||||
|
title: opt.title,
|
||||||
|
icon: opt.icon,
|
||||||
|
onTap: () {
|
||||||
|
opt.action();
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
)).toList(),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
onLongPress: () => openOptionsModal(),
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
59
lib/widgets/options_modal.dart
Normal file
59
lib/widgets/options_modal.dart
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:adguard_home_manager/models/menu_option.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/widgets/custom_list_tile_dialog.dart';
|
||||||
|
|
||||||
|
class OptionsModal extends StatelessWidget {
|
||||||
|
final List<MenuOption> options;
|
||||||
|
|
||||||
|
const OptionsModal({
|
||||||
|
Key? key,
|
||||||
|
required this.options,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
title: Column(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.more_horiz,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.options,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: options.map((opt) => CustomListTileDialog(
|
||||||
|
title: opt.title,
|
||||||
|
icon: opt.icon,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
opt.action();
|
||||||
|
},
|
||||||
|
)).toList()
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text(AppLocalizations.of(context)!.cancel)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
16
pubspec.lock
16
pubspec.lock
|
@ -1,6 +1,14 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
after_layout:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: after_layout
|
||||||
|
sha256: "95a1cb2ca1464f44f14769329fbf15987d20ab6c88f8fc5d359bd362be625f29"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
animations:
|
animations:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -81,6 +89,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.17.0"
|
||||||
|
contextmenu:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: contextmenu
|
||||||
|
sha256: e0c7d60e2fc9f316f5b03f5fe2c0f977d65125345d1a1f77eea02be612e32d0c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -68,6 +68,7 @@ dependencies:
|
||||||
url: https://github.com/JGeek00/flutter_split_view
|
url: https://github.com/JGeek00/flutter_split_view
|
||||||
ref: master-alt
|
ref: master-alt
|
||||||
url_launcher: ^6.1.10
|
url_launcher: ^6.1.10
|
||||||
|
contextmenu: ^3.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue