mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-19 13:29:12 +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
|
@ -127,3 +127,42 @@ Map<String, dynamic> getFilteredStatus(BuildContext context, AppConfigProvider a
|
|||
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",
|
||||
"disableList": "Disable 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",
|
||||
"disableList": "Deshabilitar 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) {
|
||||
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!,
|
||||
);
|
||||
},
|
||||
|
|
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: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/functions/copy_clipboard.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
|
||||
class ActiveClientTile extends StatelessWidget {
|
||||
|
@ -23,6 +26,23 @@ class ActiveClientTile extends StatelessWidget {
|
|||
if (splitView == true) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: ContextMenuArea(
|
||||
builder: (context) => [
|
||||
CustomListTile(
|
||||
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),
|
||||
|
@ -77,10 +97,28 @@ class ActiveClientTile extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
return CustomListTile(
|
||||
return ContextMenuArea(
|
||||
builder: (context) => [
|
||||
CustomListTile(
|
||||
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: CustomListTile(
|
||||
title: client.name != ''
|
||||
? client.name!
|
||||
: client.ip,
|
||||
|
@ -94,6 +132,7 @@ class ActiveClientTile extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
onTap: () => onTap(client),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:contextmenu/contextmenu.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/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/providers/servers_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
|
||||
class AddedClientTile extends StatefulWidget {
|
||||
class AddedClientTile extends StatelessWidget {
|
||||
final Client client;
|
||||
final void Function(Client) onTap;
|
||||
final void Function(Client) onLongPress;
|
||||
|
@ -26,41 +29,57 @@ class AddedClientTile extends StatefulWidget {
|
|||
required this.splitView
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AddedClientTile> createState() => _AddedClientTileState();
|
||||
}
|
||||
|
||||
class _AddedClientTileState extends State<AddedClientTile> {
|
||||
bool hover = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||
|
||||
if (widget.splitView == true) {
|
||||
if (splitView == true) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
child: ContextMenuArea(
|
||||
builder: (context) => [
|
||||
CustomListTile(
|
||||
title: AppLocalizations.of(context)!.seeDetails,
|
||||
icon: Icons.file_open_rounded,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
onEdit(client);
|
||||
}
|
||||
),
|
||||
CustomListTile(
|
||||
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: InkWell(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
onTap: () => widget.onTap(widget.client),
|
||||
onHover: (v) => setState(() => hover = v),
|
||||
onTap: () => onTap(client),
|
||||
onLongPress: () => onLongPress(client),
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
color: widget.client == widget.selectedClient
|
||||
color: client == selectedClient
|
||||
? Theme.of(context).colorScheme.primaryContainer
|
||||
: null
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
@ -69,7 +88,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||
client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
|
@ -82,7 +101,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
Icon(
|
||||
Icons.filter_list_rounded,
|
||||
size: 19,
|
||||
color: widget.client.filteringEnabled == true
|
||||
color: client.filteringEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -94,7 +113,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
Icon(
|
||||
Icons.vpn_lock_rounded,
|
||||
size: 18,
|
||||
color: widget.client.safebrowsingEnabled == true
|
||||
color: client.safebrowsingEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -106,7 +125,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
Icon(
|
||||
Icons.block,
|
||||
size: 18,
|
||||
color: widget.client.parentalEnabled == true
|
||||
color: client.parentalEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -123,14 +142,14 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
referenceVersion: 'v0.107.28',
|
||||
referenceVersionBeta: 'v0.108.0-b.33'
|
||||
) == true
|
||||
? widget.client.safeSearch != null && widget.client.safeSearch!.enabled == 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
|
||||
: widget.client.safesearchEnabled == true
|
||||
: client.safesearchEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -146,28 +165,47 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (hover == true) IconButton(
|
||||
onPressed: () => widget.onEdit(widget.client),
|
||||
icon: const Icon(Icons.edit_rounded)
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
return CustomListTile(
|
||||
onLongPress: () => widget.onLongPress(widget.client),
|
||||
onTap: () => widget.onTap(widget.client),
|
||||
onHover: (v) => setState(() => hover = v),
|
||||
title: widget.client.name,
|
||||
return ContextMenuArea(
|
||||
builder: (context) => [
|
||||
CustomListTile(
|
||||
title: AppLocalizations.of(context)!.seeDetails,
|
||||
icon: Icons.file_open_rounded,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
onEdit(client);
|
||||
}
|
||||
),
|
||||
CustomListTile(
|
||||
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(
|
||||
widget.client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||
client.ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).listTileTheme.textColor
|
||||
),
|
||||
|
@ -178,7 +216,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
Icon(
|
||||
Icons.filter_list_rounded,
|
||||
size: 19,
|
||||
color: widget.client.filteringEnabled == true
|
||||
color: client.filteringEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -190,7 +228,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
Icon(
|
||||
Icons.vpn_lock_rounded,
|
||||
size: 18,
|
||||
color: widget.client.safebrowsingEnabled == true
|
||||
color: client.safebrowsingEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -202,7 +240,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
Icon(
|
||||
Icons.block,
|
||||
size: 18,
|
||||
color: widget.client.parentalEnabled == true
|
||||
color: client.parentalEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -219,14 +257,14 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
referenceVersion: 'v0.107.28',
|
||||
referenceVersionBeta: 'v0.108.0-b.33'
|
||||
) == true
|
||||
? widget.client.safeSearch != null && widget.client.safeSearch!.enabled == 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
|
||||
: widget.client.safesearchEnabled == true
|
||||
: client.safesearchEnabled == true
|
||||
? appConfigProvider.useThemeColorForStatus == true
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Colors.green
|
||||
|
@ -238,12 +276,7 @@ class _AddedClientTileState extends State<AddedClientTile> {
|
|||
)
|
||||
],
|
||||
),
|
||||
trailing: hover == true
|
||||
? IconButton(
|
||||
onPressed: () => widget.onEdit(widget.client),
|
||||
icon: const Icon(Icons.edit_rounded)
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
);
|
||||
|
||||
case 1:
|
||||
if (logsData!.data.isNotEmpty) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: fetchLogs,
|
||||
child: ListView.builder(
|
||||
|
@ -191,6 +192,19 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
return Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.noLogsDisplay,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
case 2:
|
||||
return SizedBox(
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:adguard_home_manager/screens/filters/add_button.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: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/options_modal.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/functions/number_format.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
|
@ -235,23 +239,47 @@ class FiltersTripleColumn extends StatelessWidget {
|
|||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: serversProvider.filtering.data!.userRules.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
title: Text(
|
||||
serversProvider.filtering.data!.userRules[index],
|
||||
style: TextStyle(
|
||||
color: checkIfComment(serversProvider.filtering.data!.userRules[index]) == true
|
||||
? Theme.of(context).colorScheme.onSurface.withOpacity(0.6)
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.normal,
|
||||
itemBuilder: (context, index) => ContextMenuArea(
|
||||
builder: (context) => [
|
||||
CustomListTile(
|
||||
title: AppLocalizations.of(context)!.copyClipboard,
|
||||
icon: Icons.copy_rounded,
|
||||
onTap: () {
|
||||
copyToClipboard(
|
||||
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,
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
subtitle: generateSubtitle(serversProvider.filtering.data!.userRules[index]),
|
||||
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)
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -216,9 +216,9 @@ class _HomeState extends State<Home> {
|
|||
maxWidth: 500
|
||||
),
|
||||
child: TopItems(
|
||||
label: AppLocalizations.of(context)!.topBlockedDomains,
|
||||
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
|
||||
type: 'topBlockedDomains',
|
||||
label: AppLocalizations.of(context)!.topClients,
|
||||
data: serversProvider.serverStatus.data!.stats.topClients,
|
||||
type: 'topClients',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
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/services.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/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/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/classes/process_modal.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) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => TopItemsOptionsModal(
|
||||
isBlocked: getIsBlocked(),
|
||||
changeStatus: (String status) => blockUnblock(domain, status),
|
||||
copyToClipboard: () => copyDomainClipboard(domain),
|
||||
type: type,
|
||||
builder: (context) => OptionsModal(
|
||||
options: generateOptions(domain),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -143,7 +162,10 @@ class TopItems extends StatelessWidget {
|
|||
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
child: DomainOptions(
|
||||
item: item.keys.toList()[0],
|
||||
isClient: type == 'topClients',
|
||||
isBlocked: type == 'topBlockedDomains',
|
||||
onTap: () {
|
||||
if (type == 'topQueriedDomains' || type == 'topBlockedDomains') {
|
||||
logsProvider.setSearchText(item.keys.toList()[0]);
|
||||
|
@ -167,10 +189,8 @@ class TopItems extends StatelessWidget {
|
|||
clients: [item.keys.toList()[0]]
|
||||
)
|
||||
);
|
||||
appConfigProvider.setSelectedScreen(2);
|
||||
}
|
||||
},
|
||||
onLongPress: () => openOptionsModal(item.keys.toList()[0], type),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
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: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/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/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)) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
child: DomainOptions(
|
||||
onTap: () => onLogTap(log),
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
item: log.question.name,
|
||||
isBlocked: isDomainBlocked(log.reason),
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
|
@ -291,9 +261,10 @@ class LogTile extends StatelessWidget {
|
|||
else {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
child: DomainOptions(
|
||||
onTap: () => onLogTap(log),
|
||||
onLongPress: () => openOptionsModal(log),
|
||||
item: log.question.name,
|
||||
isBlocked: isDomainBlocked(log.reason),
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
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: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/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/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||
|
@ -68,44 +67,6 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
|||
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(
|
||||
appBar: AppBar(
|
||||
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: () {
|
||||
if (widget.type == 'topQueriedDomains' || widget.type == 'topBlockedDomains') {
|
||||
logsProvider.setSearchText(screenData[index].keys.toList()[0]);
|
||||
|
@ -226,10 +190,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
|||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
onLongPress: () => openOptionsModal(
|
||||
screenData[index].keys.toList()[0],
|
||||
widget.type
|
||||
),
|
||||
child: CustomListTile(
|
||||
title: screenData[index].keys.toList()[0],
|
||||
trailing: Text(
|
||||
screenData[index].values.toList()[0].toString(),
|
||||
|
@ -279,6 +240,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
|||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
)
|
||||
|
|
|
@ -7,11 +7,10 @@ import 'package:percent_indicator/percent_indicator.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/widgets/custom_list_tile.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/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||
|
@ -67,44 +66,6 @@ class _TopItemsModalState extends State<TopItemsModal> {
|
|||
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(
|
||||
child: ConstrainedBox(
|
||||
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: () {
|
||||
if (widget.type == 'topQueriedDomains' || widget.type == 'topBlockedDomains') {
|
||||
logsProvider.setSearchText(screenData[index].keys.toList()[0]);
|
||||
|
@ -198,10 +162,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
|
|||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
onLongPress: () => openOptionsModal(
|
||||
screenData[index].keys.toList()[0],
|
||||
widget.type
|
||||
),
|
||||
child: CustomListTile(
|
||||
title: screenData[index].keys.toList()[0],
|
||||
trailing: Text(
|
||||
screenData[index].values.toList()[0].toString(),
|
||||
|
@ -251,6 +212,7 @@ class _TopItemsModalState extends State<TopItemsModal> {
|
|||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
|
|
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
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
after_layout:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: after_layout
|
||||
sha256: "95a1cb2ca1464f44f14769329fbf15987d20ab6c88f8fc5d359bd362be625f29"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
animations:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -81,6 +89,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.0"
|
||||
contextmenu:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: contextmenu
|
||||
sha256: e0c7d60e2fc9f316f5b03f5fe2c0f977d65125345d1a1f77eea02be612e32d0c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -68,6 +68,7 @@ dependencies:
|
|||
url: https://github.com/JGeek00/flutter_split_view
|
||||
ref: master-alt
|
||||
url_launcher: ^6.1.10
|
||||
contextmenu: ^3.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Add table
Reference in a new issue