mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-06-03 13:20:34 +00:00
Merge branch 'ui-changes'
This commit is contained in:
commit
05815af868
80 changed files with 2854 additions and 2661 deletions
|
@ -25,11 +25,16 @@ ThemeData lightTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
indicatorColor: dynamicColorScheme != null ? dynamicColorScheme.primaryContainer : adguardGreenColor,
|
indicatorColor: dynamicColorScheme != null ? dynamicColorScheme.secondaryContainer : adguardGreenColor,
|
||||||
|
iconTheme: MaterialStateProperty.all(
|
||||||
|
IconThemeData(
|
||||||
|
color: dynamicColorScheme != null ? dynamicColorScheme.onSecondaryContainer : adguardGreenColor,
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: dynamicColorScheme != null ? dynamicColorScheme.onPrimaryContainer : Colors.white,
|
||||||
backgroundColor: dynamicColorScheme != null ? dynamicColorScheme.primary : adguardGreenColor
|
backgroundColor: dynamicColorScheme != null ? dynamicColorScheme.primaryContainer : adguardGreenColor
|
||||||
),
|
),
|
||||||
textButtonTheme: TextButtonThemeData(
|
textButtonTheme: TextButtonThemeData(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
|
@ -42,9 +47,10 @@ ThemeData lightTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dividerColor: Colors.black12,
|
dividerColor: Colors.black12,
|
||||||
listTileTheme: const ListTileThemeData(
|
listTileTheme: ListTileThemeData(
|
||||||
tileColor: Colors.transparent,
|
tileColor: Colors.transparent,
|
||||||
iconColor: Color.fromRGBO(138, 138, 138, 1),
|
textColor: dynamicColorScheme != null ? dynamicColorScheme.onSurfaceVariant : const Color.fromRGBO(117, 117, 117, 1),
|
||||||
|
iconColor: dynamicColorScheme != null ? dynamicColorScheme.onSurfaceVariant : const Color.fromRGBO(117, 117, 117, 1),
|
||||||
),
|
),
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
checkColor: MaterialStateProperty.all(Colors.white),
|
checkColor: MaterialStateProperty.all(Colors.white),
|
||||||
|
@ -79,7 +85,12 @@ ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
||||||
scaffoldBackgroundColor: dynamicColorScheme != null ? dynamicColorScheme.background :const Color.fromRGBO(18, 18, 18, 1),
|
scaffoldBackgroundColor: dynamicColorScheme != null ? dynamicColorScheme.background :const Color.fromRGBO(18, 18, 18, 1),
|
||||||
dialogBackgroundColor: dynamicColorScheme != null ? dynamicColorScheme.background : const Color.fromRGBO(44, 44, 44, 1),
|
dialogBackgroundColor: dynamicColorScheme != null ? dynamicColorScheme.background : const Color.fromRGBO(44, 44, 44, 1),
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
indicatorColor: dynamicColorScheme != null ? dynamicColorScheme.primaryContainer : adguardGreenColor,
|
indicatorColor: dynamicColorScheme != null ? dynamicColorScheme.secondaryContainer : adguardGreenColor,
|
||||||
|
iconTheme: MaterialStateProperty.all(
|
||||||
|
IconThemeData(
|
||||||
|
color: dynamicColorScheme != null ? dynamicColorScheme.onSecondaryContainer : adguardGreenColor,
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
snackBarTheme: SnackBarThemeData(
|
snackBarTheme: SnackBarThemeData(
|
||||||
contentTextStyle: const TextStyle(
|
contentTextStyle: const TextStyle(
|
||||||
|
@ -92,8 +103,8 @@ ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
),
|
),
|
||||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: dynamicColorScheme != null ? dynamicColorScheme.onPrimaryContainer : Colors.white,
|
||||||
backgroundColor: dynamicColorScheme != null ? dynamicColorScheme.primary : adguardGreenColor
|
backgroundColor: dynamicColorScheme != null ? dynamicColorScheme.primaryContainer : adguardGreenColor
|
||||||
),
|
),
|
||||||
textButtonTheme: TextButtonThemeData(
|
textButtonTheme: TextButtonThemeData(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
|
@ -115,14 +126,17 @@ ThemeData darkTheme(ColorScheme? dynamicColorScheme) => ThemeData(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dividerColor: Colors.white12,
|
dividerColor: Colors.white12,
|
||||||
listTileTheme: const ListTileThemeData(
|
listTileTheme: ListTileThemeData(
|
||||||
tileColor: Colors.transparent,
|
tileColor: Colors.transparent,
|
||||||
iconColor: Color.fromRGBO(187, 187, 187, 1),
|
textColor: dynamicColorScheme != null ? dynamicColorScheme.onSurfaceVariant : const Color.fromRGBO(187, 187, 187, 1),
|
||||||
|
iconColor: dynamicColorScheme != null ? dynamicColorScheme.onSurfaceVariant : const Color.fromRGBO(187, 187, 187, 1),
|
||||||
),
|
),
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
checkColor: MaterialStateProperty.all(Colors.white),
|
checkColor: MaterialStateProperty.all(
|
||||||
|
dynamicColorScheme != null ? dynamicColorScheme.onPrimary : Colors.white
|
||||||
|
),
|
||||||
fillColor: MaterialStateProperty.all(
|
fillColor: MaterialStateProperty.all(
|
||||||
dynamicColorScheme != null ? dynamicColorScheme.primary : adguardGreenColor
|
dynamicColorScheme != null ? dynamicColorScheme.onSurface : adguardGreenColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
tabBarTheme: TabBarTheme(
|
tabBarTheme: TabBarTheme(
|
||||||
|
@ -187,6 +201,9 @@ ThemeData lightThemeOldVersions(MaterialColor primaryColor) => ThemeData(
|
||||||
overlayColor: MaterialStateProperty.all(primaryColor.shade50),
|
overlayColor: MaterialStateProperty.all(primaryColor.shade50),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
cardTheme: CardTheme(
|
||||||
|
surfaceTintColor: primaryColor
|
||||||
|
),
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
surfaceTintColor: primaryColor,
|
surfaceTintColor: primaryColor,
|
||||||
indicatorColor: primaryColor
|
indicatorColor: primaryColor
|
||||||
|
@ -210,11 +227,12 @@ ThemeData lightThemeOldVersions(MaterialColor primaryColor) => ThemeData(
|
||||||
dividerColor: Colors.black12,
|
dividerColor: Colors.black12,
|
||||||
listTileTheme: const ListTileThemeData(
|
listTileTheme: const ListTileThemeData(
|
||||||
tileColor: Colors.transparent,
|
tileColor: Colors.transparent,
|
||||||
iconColor: Color.fromRGBO(138, 138, 138, 1),
|
textColor: Color.fromRGBO(117, 117, 117, 1),
|
||||||
|
iconColor: Color.fromRGBO(117, 117, 117, 1),
|
||||||
),
|
),
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
checkColor: MaterialStateProperty.all(Colors.white),
|
checkColor: MaterialStateProperty.all(Colors.white),
|
||||||
fillColor: MaterialStateProperty.all(primaryColor),
|
fillColor: MaterialStateProperty.all(primaryColor),
|
||||||
),
|
),
|
||||||
tabBarTheme: TabBarTheme(
|
tabBarTheme: TabBarTheme(
|
||||||
unselectedLabelColor: Colors.black,
|
unselectedLabelColor: Colors.black,
|
||||||
|
@ -250,7 +268,7 @@ ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData(
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
color: Color.fromRGBO(18, 18, 18, 1),
|
color: const Color.fromRGBO(18, 18, 18, 1),
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
surfaceTintColor: primaryColor
|
surfaceTintColor: primaryColor
|
||||||
|
@ -283,6 +301,9 @@ ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData(
|
||||||
overlayColor: MaterialStateProperty.all(primaryColor.shade50),
|
overlayColor: MaterialStateProperty.all(primaryColor.shade50),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
cardTheme: CardTheme(
|
||||||
|
surfaceTintColor: primaryColor
|
||||||
|
),
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
floatingLabelStyle: TextStyle(
|
floatingLabelStyle: TextStyle(
|
||||||
color: primaryColor
|
color: primaryColor
|
||||||
|
@ -295,6 +316,15 @@ ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
checkboxTheme: CheckboxThemeData(
|
||||||
|
checkColor: MaterialStateProperty.all(Colors.white),
|
||||||
|
fillColor: MaterialStateProperty.all(primaryColor),
|
||||||
|
),
|
||||||
|
listTileTheme: const ListTileThemeData(
|
||||||
|
tileColor: Colors.transparent,
|
||||||
|
textColor: Color.fromRGBO(187, 187, 187, 1),
|
||||||
|
iconColor: Color.fromRGBO(187, 187, 187, 1),
|
||||||
|
),
|
||||||
textSelectionTheme: TextSelectionThemeData(
|
textSelectionTheme: TextSelectionThemeData(
|
||||||
cursorColor: primaryColor
|
cursorColor: primaryColor
|
||||||
),
|
),
|
||||||
|
@ -308,14 +338,6 @@ ThemeData darkThemeOldVersions(MaterialColor primaryColor) => ThemeData(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dividerColor: Colors.white12,
|
dividerColor: Colors.white12,
|
||||||
listTileTheme: const ListTileThemeData(
|
|
||||||
tileColor: Colors.transparent,
|
|
||||||
iconColor: Color.fromRGBO(187, 187, 187, 1),
|
|
||||||
),
|
|
||||||
checkboxTheme: CheckboxThemeData(
|
|
||||||
checkColor: MaterialStateProperty.all(Colors.white),
|
|
||||||
fillColor: MaterialStateProperty.all(Colors.blue),
|
|
||||||
),
|
|
||||||
tabBarTheme: TabBarTheme(
|
tabBarTheme: TabBarTheme(
|
||||||
unselectedLabelColor: Colors.white,
|
unselectedLabelColor: Colors.white,
|
||||||
labelColor: primaryColor,
|
labelColor: primaryColor,
|
||||||
|
|
|
@ -569,5 +569,6 @@
|
||||||
"doNotRememberAgainUpdate": "Do not remember again for this version",
|
"doNotRememberAgainUpdate": "Do not remember again for this version",
|
||||||
"downloadingUpdate": "Downloading",
|
"downloadingUpdate": "Downloading",
|
||||||
"completed": "completed",
|
"completed": "completed",
|
||||||
"permissionNotGranted": "Permission not granted"
|
"permissionNotGranted": "Permission not granted",
|
||||||
|
"inputSearchTerm": "Input a search term."
|
||||||
}
|
}
|
|
@ -569,5 +569,6 @@
|
||||||
"doNotRememberAgainUpdate": "No recordar de nuevo para esta actualización",
|
"doNotRememberAgainUpdate": "No recordar de nuevo para esta actualización",
|
||||||
"downloadingUpdate": "Descargando",
|
"downloadingUpdate": "Descargando",
|
||||||
"completed": "completado",
|
"completed": "completado",
|
||||||
"permissionNotGranted": "Permiso no concedido"
|
"permissionNotGranted": "Permiso no concedido",
|
||||||
|
"inputSearchTerm": "Introduce un término de búsqueda."
|
||||||
}
|
}
|
|
@ -43,16 +43,18 @@ class _AppLogDetailsModalState extends State<AppLogDetailsModal> {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.description_rounded,
|
Icons.description_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.logDetails,
|
AppLocalizations.of(context)!.logDetails,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -50,8 +50,22 @@ class AppLogs extends StatelessWidget {
|
||||||
padding: const EdgeInsets.only(top: 0),
|
padding: const EdgeInsets.only(top: 0),
|
||||||
itemCount: appConfigProvider.logs.length,
|
itemCount: appConfigProvider.logs.length,
|
||||||
itemBuilder: (context, index) => ListTile(
|
itemBuilder: (context, index) => ListTile(
|
||||||
title: Text(appConfigProvider.logs[index].message),
|
title: Text(
|
||||||
subtitle: Text(appConfigProvider.logs[index].dateTime.toString()),
|
appConfigProvider.logs[index].message,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
appConfigProvider.logs[index].dateTime.toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
|
),
|
||||||
|
),
|
||||||
trailing: Text(appConfigProvider.logs[index].type),
|
trailing: Text(appConfigProvider.logs[index].type),
|
||||||
onTap: () => {
|
onTap: () => {
|
||||||
showDialog(
|
showDialog(
|
||||||
|
|
|
@ -2,15 +2,14 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:bottom_sheet/bottom_sheet.dart';
|
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.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/clients/client_screen.dart';
|
||||||
import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
|
import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
|
||||||
import 'package:adguard_home_manager/screens/clients/fab.dart';
|
import 'package:adguard_home_manager/screens/clients/fab.dart';
|
||||||
import 'package:adguard_home_manager/screens/clients/options_modal.dart';
|
import 'package:adguard_home_manager/screens/clients/options_modal.dart';
|
||||||
import 'package:adguard_home_manager/screens/clients/client_modal.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||||
|
@ -141,23 +140,14 @@ class _AddedListState extends State<AddedList> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void openClientModal(Client client) {
|
void openClientModal(Client client) {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
Navigator.push(context, MaterialPageRoute(
|
||||||
showFlexibleBottomSheet(
|
fullscreenDialog: true,
|
||||||
minHeight: 0.6,
|
builder: (BuildContext context) => ClientScreen(
|
||||||
initHeight: 0.6,
|
|
||||||
maxHeight: 0.95,
|
|
||||||
isCollapsible: true,
|
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
anchors: [0.95],
|
|
||||||
context: context,
|
|
||||||
builder: (ctx, controller, offset) => ClientModal(
|
|
||||||
scrollController: controller,
|
|
||||||
client: client,
|
|
||||||
onConfirm: confirmEditClient,
|
onConfirm: confirmEditClient,
|
||||||
onDelete: deleteClient,
|
onDelete: deleteClient,
|
||||||
),
|
client: client,
|
||||||
bottomSheetColor: Colors.transparent
|
)
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void openDeleteModal(Client client) {
|
void openDeleteModal(Client client) {
|
||||||
|
@ -209,7 +199,7 @@ class _AddedListState extends State<AddedList> {
|
||||||
padding: const EdgeInsets.only(top: 0),
|
padding: const EdgeInsets.only(top: 0),
|
||||||
itemCount: widget.data.length,
|
itemCount: widget.data.length,
|
||||||
itemBuilder: (context, index) => ListTile(
|
itemBuilder: (context, index) => ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
isThreeLine: true,
|
isThreeLine: true,
|
||||||
onLongPress: () => openOptionsModal(widget.data[index]),
|
onLongPress: () => openOptionsModal(widget.data[index]),
|
||||||
onTap: () => openClientModal(widget.data[index]),
|
onTap: () => openClientModal(widget.data[index]),
|
||||||
|
@ -217,16 +207,22 @@ class _AddedListState extends State<AddedList> {
|
||||||
padding: const EdgeInsets.only(bottom: 5),
|
padding: const EdgeInsets.only(bottom: 5),
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.data[index].name,
|
widget.data[index].name,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(widget.data[index].ids.toString().replaceAll(RegExp(r'^\[|\]$'), '')),
|
Text(
|
||||||
|
widget.data[index].ids.toString().replaceAll(RegExp(r'^\[|\]$'), ''),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 7),
|
const SizedBox(height: 7),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -1,706 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/clients/services_modal.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/clients/tags_modal.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
|
||||||
|
|
||||||
class ClientModal extends StatefulWidget {
|
|
||||||
final ScrollController scrollController;
|
|
||||||
final Client? client;
|
|
||||||
final void Function(Client) onConfirm;
|
|
||||||
final void Function(Client)? onDelete;
|
|
||||||
|
|
||||||
const ClientModal({
|
|
||||||
Key? key,
|
|
||||||
required this.scrollController,
|
|
||||||
this.client,
|
|
||||||
required this.onConfirm,
|
|
||||||
this.onDelete,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ClientModal> createState() => _ClientModalState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ClientModalState extends State<ClientModal> {
|
|
||||||
final Uuid uuid = const Uuid();
|
|
||||||
bool editMode = true;
|
|
||||||
|
|
||||||
TextEditingController nameController = TextEditingController();
|
|
||||||
|
|
||||||
List<String> selectedTags = [];
|
|
||||||
|
|
||||||
List<Map<dynamic, dynamic>> identifiersControllers = [
|
|
||||||
{
|
|
||||||
'id': 0,
|
|
||||||
'controller': TextEditingController()
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
bool useGlobalSettingsFiltering = true;
|
|
||||||
bool? enableFiltering;
|
|
||||||
bool? enableSafeBrowsing;
|
|
||||||
bool? enableParentalControl;
|
|
||||||
bool? enableSafeSearch;
|
|
||||||
|
|
||||||
bool useGlobalSettingsServices = true;
|
|
||||||
List<String> blockedServices = [];
|
|
||||||
|
|
||||||
List<Map<dynamic, dynamic>> upstreamServers = [];
|
|
||||||
|
|
||||||
|
|
||||||
bool checkValidValues() {
|
|
||||||
if (
|
|
||||||
nameController.text != '' &&
|
|
||||||
identifiersControllers.isNotEmpty &&
|
|
||||||
identifiersControllers[0]['controller'].text != ''
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
if (widget.client != null) {
|
|
||||||
editMode = false;
|
|
||||||
|
|
||||||
nameController.text = widget.client!.name;
|
|
||||||
selectedTags = widget.client!.tags;
|
|
||||||
identifiersControllers = widget.client!.ids.map((e) => {
|
|
||||||
'id': uuid.v4(),
|
|
||||||
'controller': TextEditingController(text: e)
|
|
||||||
}).toList();
|
|
||||||
useGlobalSettingsFiltering = widget.client!.useGlobalSettings;
|
|
||||||
enableFiltering = widget.client!.filteringEnabled;
|
|
||||||
enableParentalControl = widget.client!.parentalEnabled;
|
|
||||||
enableSafeBrowsing = widget.client!.safebrowsingEnabled;
|
|
||||||
enableSafeSearch = widget.client!.safesearchEnabled;
|
|
||||||
useGlobalSettingsServices = widget.client!.useGlobalBlockedServices;
|
|
||||||
blockedServices = widget.client!.blockedServices;
|
|
||||||
upstreamServers = widget.client!.upstreams.map((e) => {
|
|
||||||
'id': uuid.v4(),
|
|
||||||
'controller': TextEditingController(text: e)
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final serversProvider = Provider.of<ServersProvider>(context);
|
|
||||||
|
|
||||||
void createClient() {
|
|
||||||
final Client client = Client(
|
|
||||||
name: nameController.text,
|
|
||||||
ids: List<String>.from(identifiersControllers.map((e) => e['controller'].text)),
|
|
||||||
useGlobalSettings: useGlobalSettingsFiltering,
|
|
||||||
filteringEnabled: enableFiltering ?? false,
|
|
||||||
parentalEnabled: enableParentalControl ?? false,
|
|
||||||
safebrowsingEnabled: enableSafeBrowsing ?? false,
|
|
||||||
safesearchEnabled: enableSafeSearch ?? false,
|
|
||||||
useGlobalBlockedServices: useGlobalSettingsServices,
|
|
||||||
blockedServices: blockedServices,
|
|
||||||
upstreams: List<String>.from(upstreamServers.map((e) => e['controller'].text)),
|
|
||||||
tags: selectedTags
|
|
||||||
);
|
|
||||||
widget.onConfirm(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget sectionLabel(String label) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 30,
|
|
||||||
horizontal: 20
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
label,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
fontSize: 16,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enableDisableGlobalSettingsFiltering() {
|
|
||||||
if (useGlobalSettingsFiltering == true) {
|
|
||||||
setState(() {
|
|
||||||
useGlobalSettingsFiltering = false;
|
|
||||||
|
|
||||||
enableFiltering = false;
|
|
||||||
enableSafeBrowsing = false;
|
|
||||||
enableParentalControl = false;
|
|
||||||
enableSafeSearch = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (useGlobalSettingsFiltering == false) {
|
|
||||||
setState(() {
|
|
||||||
useGlobalSettingsFiltering = true;
|
|
||||||
|
|
||||||
enableFiltering = null;
|
|
||||||
enableSafeBrowsing = null;
|
|
||||||
enableParentalControl = null;
|
|
||||||
enableSafeSearch = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void openTagsModal() {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => TagsModal(
|
|
||||||
selectedTags: selectedTags,
|
|
||||||
tags: serversProvider.clients.data!.supportedTags,
|
|
||||||
onConfirm: (selected) => setState(() => selectedTags = selected),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void openServicesModal() {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => ServicesModal(
|
|
||||||
blockedServices: blockedServices,
|
|
||||||
onConfirm: (values) => setState(() => blockedServices = values),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateServicesGlobalSettings(bool value) {
|
|
||||||
if (value == true) {
|
|
||||||
setState(() {
|
|
||||||
blockedServices = [];
|
|
||||||
useGlobalSettingsServices = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (value == false) {
|
|
||||||
setState(() {
|
|
||||||
useGlobalSettingsServices = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void openDeleteClientModal() {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (ctx) => RemoveClientModal(
|
|
||||||
onConfirm: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
widget.onDelete!(widget.client!);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget settignsTile({
|
|
||||||
required String label,
|
|
||||||
required bool? value,
|
|
||||||
void Function(bool)? onChange
|
|
||||||
}) {
|
|
||||||
return Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: onChange != null
|
|
||||||
? value != null ? () => onChange(!value) : null
|
|
||||||
: null,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 30,
|
|
||||||
vertical: 5
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 15
|
|
||||||
),
|
|
||||||
),
|
|
||||||
useGlobalSettingsFiltering == false
|
|
||||||
? Switch(
|
|
||||||
value: value!,
|
|
||||||
onChanged: onChange,
|
|
||||||
activeColor: Theme.of(context).primaryColor,
|
|
||||||
)
|
|
||||||
: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
|
||||||
child: Text(
|
|
||||||
"Global",
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(28),
|
|
||||||
topRight: Radius.circular(28)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
controller: widget.scrollController,
|
|
||||||
children: [
|
|
||||||
const SizedBox(height: 28),
|
|
||||||
const Icon(
|
|
||||||
Icons.add,
|
|
||||||
size: 26,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.addClient,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 24
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
child: TextFormField(
|
|
||||||
enabled: widget.client != null ? false : true,
|
|
||||||
controller: nameController,
|
|
||||||
onChanged: (_) => checkValidValues(),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.badge_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
labelText: AppLocalizations.of(context)!.name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
sectionLabel(AppLocalizations.of(context)!.tags),
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: editMode == true ? () => openTagsModal() : null,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 10, horizontal: 20
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.label_rounded,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.selectTags,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
selectedTags.isNotEmpty
|
|
||||||
? "${selectedTags.length} ${AppLocalizations.of(context)!.tagsSelected}"
|
|
||||||
: AppLocalizations.of(context)!.noTagsSelected,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
sectionLabel(AppLocalizations.of(context)!.identifiers),
|
|
||||||
if (editMode == true) Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 20),
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () => setState(() => identifiersControllers.add({
|
|
||||||
'id': uuid.v4(),
|
|
||||||
'controller': TextEditingController()
|
|
||||||
})),
|
|
||||||
icon: const Icon(Icons.add)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (identifiersControllers.isNotEmpty) ...identifiersControllers.map((controller) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 20),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: editMode == true
|
|
||||||
? MediaQuery.of(context).size.width - 108
|
|
||||||
: MediaQuery.of(context).size.width - 40,
|
|
||||||
child: TextFormField(
|
|
||||||
enabled: editMode,
|
|
||||||
controller: controller['controller'],
|
|
||||||
onChanged: (_) => checkValidValues(),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.tag),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
helperText: AppLocalizations.of(context)!.identifierHelper,
|
|
||||||
labelText: AppLocalizations.of(context)!.identifier,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (editMode == true) ...[
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 25),
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () => setState(
|
|
||||||
() => identifiersControllers = identifiersControllers.where((e) => e['id'] != controller['id']).toList()
|
|
||||||
),
|
|
||||||
icon: const Icon(Icons.remove_circle_outline_outlined)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)).toList(),
|
|
||||||
if (identifiersControllers.isEmpty) Container(
|
|
||||||
padding: const EdgeInsets.only(top: 10),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.noIdentifiers,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
color: Colors.grey
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
sectionLabel(AppLocalizations.of(context)!.settings),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
||||||
child: Material(
|
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: editMode
|
|
||||||
? () => enableDisableGlobalSettingsFiltering()
|
|
||||||
: null,
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 20,
|
|
||||||
vertical: 5
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.useGlobalSettings,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Switch(
|
|
||||||
value: useGlobalSettingsFiltering,
|
|
||||||
onChanged: editMode == true
|
|
||||||
? (value) => enableDisableGlobalSettingsFiltering()
|
|
||||||
: null,
|
|
||||||
activeColor: Theme.of(context).primaryColor,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
settignsTile(
|
|
||||||
label: AppLocalizations.of(context)!.enableFiltering,
|
|
||||||
value: enableFiltering,
|
|
||||||
onChange: editMode == true
|
|
||||||
? (value) => setState(() => enableFiltering = value)
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
settignsTile(
|
|
||||||
label: AppLocalizations.of(context)!.enableSafeBrowsing,
|
|
||||||
value: enableSafeBrowsing,
|
|
||||||
onChange: editMode == true
|
|
||||||
? (value) => setState(() => enableSafeBrowsing = value)
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
settignsTile(
|
|
||||||
label: AppLocalizations.of(context)!.enableParentalControl,
|
|
||||||
value: enableParentalControl,
|
|
||||||
onChange: editMode == true
|
|
||||||
? (value) => setState(() => enableParentalControl = value)
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
settignsTile(
|
|
||||||
label: AppLocalizations.of(context)!.enableSafeSearch,
|
|
||||||
value: enableSafeSearch,
|
|
||||||
onChange: editMode == true
|
|
||||||
? (value) => setState(() => enableSafeSearch = value)
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
sectionLabel(AppLocalizations.of(context)!.blockedServices),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
||||||
child: Material(
|
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
child: InkWell(
|
|
||||||
onTap: editMode == true
|
|
||||||
? () => updateServicesGlobalSettings(!useGlobalSettingsServices)
|
|
||||||
: null,
|
|
||||||
borderRadius: BorderRadius.circular(28),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 20,
|
|
||||||
vertical: 5
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.useGlobalSettings,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Switch(
|
|
||||||
value: useGlobalSettingsServices,
|
|
||||||
onChanged: editMode == true
|
|
||||||
? (value) => updateServicesGlobalSettings(value)
|
|
||||||
: null,
|
|
||||||
activeColor: Theme.of(context).primaryColor,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: editMode == true
|
|
||||||
? useGlobalSettingsServices == false
|
|
||||||
? openServicesModal
|
|
||||||
: null
|
|
||||||
: null,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 10, horizontal: 20
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.public,
|
|
||||||
color: useGlobalSettingsServices == false
|
|
||||||
? null
|
|
||||||
: Colors.grey,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.selectBlockedServices,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: useGlobalSettingsServices == false
|
|
||||||
? null
|
|
||||||
: Theme.of(context).listTileTheme.iconColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (useGlobalSettingsServices == false) ...[
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
blockedServices.isNotEmpty
|
|
||||||
? "${blockedServices.length} ${AppLocalizations.of(context)!.servicesBlocked}"
|
|
||||||
: AppLocalizations.of(context)!.noBlockedServicesSelected,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
sectionLabel(AppLocalizations.of(context)!.upstreamServers),
|
|
||||||
if (editMode == true) Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 20),
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () => setState(() => upstreamServers.add({
|
|
||||||
'id': uuid.v4(),
|
|
||||||
'controller': TextEditingController()
|
|
||||||
})),
|
|
||||||
icon: const Icon(Icons.add)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (upstreamServers.isNotEmpty) ...upstreamServers.map((controller) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 20),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: editMode == true
|
|
||||||
? MediaQuery.of(context).size.width - 108
|
|
||||||
: MediaQuery.of(context).size.width - 40,
|
|
||||||
child: TextFormField(
|
|
||||||
enabled: editMode,
|
|
||||||
controller: controller['controller'],
|
|
||||||
onChanged: (_) => checkValidValues(),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.dns_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
labelText: AppLocalizations.of(context)!.serverAddress,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (editMode == true) ...[
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () => setState(
|
|
||||||
() => upstreamServers = upstreamServers.where((e) => e['id'] != controller['id']).toList()
|
|
||||||
),
|
|
||||||
icon: const Icon(Icons.remove_circle_outline_outlined)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)).toList(),
|
|
||||||
if (upstreamServers.isEmpty) Container(
|
|
||||||
padding: const EdgeInsets.only(top: 10),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.noUpstreamServers,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
color: Colors.grey
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.willBeUsedGeneralServers,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
color: Colors.grey
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (widget.client != null && editMode == false) ...[
|
|
||||||
IconButton(
|
|
||||||
onPressed: () => setState(() => editMode = true),
|
|
||||||
icon: const Icon(Icons.edit)
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
],
|
|
||||||
if (widget.client != null && widget.onDelete != null) IconButton(
|
|
||||||
onPressed: openDeleteClientModal,
|
|
||||||
icon: const Icon(Icons.delete)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text(AppLocalizations.of(context)!.cancel)
|
|
||||||
),
|
|
||||||
if (widget.client == null || (widget.client != null && editMode == true)) ...[
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
TextButton(
|
|
||||||
onPressed: checkValidValues() == true
|
|
||||||
? () {
|
|
||||||
createClient();
|
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: Text(
|
|
||||||
widget.client != null && editMode == true
|
|
||||||
? AppLocalizations.of(context)!.save
|
|
||||||
: AppLocalizations.of(context)!.confirm,
|
|
||||||
style: TextStyle(
|
|
||||||
color: checkValidValues() == true
|
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: Colors.grey
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
661
lib/screens/clients/client_screen.dart
Normal file
661
lib/screens/clients/client_screen.dart
Normal file
|
@ -0,0 +1,661 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/clients/services_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/clients/tags_modal.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
|
|
||||||
|
class ClientScreen extends StatefulWidget {
|
||||||
|
final Client? client;
|
||||||
|
final void Function(Client) onConfirm;
|
||||||
|
final void Function(Client)? onDelete;
|
||||||
|
|
||||||
|
const ClientScreen({
|
||||||
|
Key? key,
|
||||||
|
this.client,
|
||||||
|
required this.onConfirm,
|
||||||
|
this.onDelete,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ClientScreen> createState() => _ClientScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ClientScreenState extends State<ClientScreen> {
|
||||||
|
final Uuid uuid = const Uuid();
|
||||||
|
bool editMode = true;
|
||||||
|
|
||||||
|
TextEditingController nameController = TextEditingController();
|
||||||
|
|
||||||
|
List<String> selectedTags = [];
|
||||||
|
|
||||||
|
List<Map<dynamic, dynamic>> identifiersControllers = [
|
||||||
|
{
|
||||||
|
'id': 0,
|
||||||
|
'controller': TextEditingController()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
bool useGlobalSettingsFiltering = true;
|
||||||
|
bool? enableFiltering;
|
||||||
|
bool? enableSafeBrowsing;
|
||||||
|
bool? enableParentalControl;
|
||||||
|
bool? enableSafeSearch;
|
||||||
|
|
||||||
|
bool useGlobalSettingsServices = true;
|
||||||
|
List<String> blockedServices = [];
|
||||||
|
|
||||||
|
List<Map<dynamic, dynamic>> upstreamServers = [];
|
||||||
|
|
||||||
|
|
||||||
|
bool checkValidValues() {
|
||||||
|
if (
|
||||||
|
nameController.text != '' &&
|
||||||
|
identifiersControllers.isNotEmpty &&
|
||||||
|
identifiersControllers[0]['controller'].text != ''
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
if (widget.client != null) {
|
||||||
|
editMode = false;
|
||||||
|
|
||||||
|
nameController.text = widget.client!.name;
|
||||||
|
selectedTags = widget.client!.tags;
|
||||||
|
identifiersControllers = widget.client!.ids.map((e) => {
|
||||||
|
'id': uuid.v4(),
|
||||||
|
'controller': TextEditingController(text: e)
|
||||||
|
}).toList();
|
||||||
|
useGlobalSettingsFiltering = widget.client!.useGlobalSettings;
|
||||||
|
enableFiltering = widget.client!.filteringEnabled;
|
||||||
|
enableParentalControl = widget.client!.parentalEnabled;
|
||||||
|
enableSafeBrowsing = widget.client!.safebrowsingEnabled;
|
||||||
|
enableSafeSearch = widget.client!.safesearchEnabled;
|
||||||
|
useGlobalSettingsServices = widget.client!.useGlobalBlockedServices;
|
||||||
|
blockedServices = widget.client!.blockedServices;
|
||||||
|
upstreamServers = widget.client!.upstreams.map((e) => {
|
||||||
|
'id': uuid.v4(),
|
||||||
|
'controller': TextEditingController(text: e)
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
|
||||||
|
void createClient() {
|
||||||
|
final Client client = Client(
|
||||||
|
name: nameController.text,
|
||||||
|
ids: List<String>.from(identifiersControllers.map((e) => e['controller'].text)),
|
||||||
|
useGlobalSettings: useGlobalSettingsFiltering,
|
||||||
|
filteringEnabled: enableFiltering ?? false,
|
||||||
|
parentalEnabled: enableParentalControl ?? false,
|
||||||
|
safebrowsingEnabled: enableSafeBrowsing ?? false,
|
||||||
|
safesearchEnabled: enableSafeSearch ?? false,
|
||||||
|
useGlobalBlockedServices: useGlobalSettingsServices,
|
||||||
|
blockedServices: blockedServices,
|
||||||
|
upstreams: List<String>.from(upstreamServers.map((e) => e['controller'].text)),
|
||||||
|
tags: selectedTags
|
||||||
|
);
|
||||||
|
widget.onConfirm(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget sectionLabel(String label) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 24,
|
||||||
|
horizontal: 24
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableDisableGlobalSettingsFiltering() {
|
||||||
|
if (useGlobalSettingsFiltering == true) {
|
||||||
|
setState(() {
|
||||||
|
useGlobalSettingsFiltering = false;
|
||||||
|
|
||||||
|
enableFiltering = false;
|
||||||
|
enableSafeBrowsing = false;
|
||||||
|
enableParentalControl = false;
|
||||||
|
enableSafeSearch = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (useGlobalSettingsFiltering == false) {
|
||||||
|
setState(() {
|
||||||
|
useGlobalSettingsFiltering = true;
|
||||||
|
|
||||||
|
enableFiltering = null;
|
||||||
|
enableSafeBrowsing = null;
|
||||||
|
enableParentalControl = null;
|
||||||
|
enableSafeSearch = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void openTagsModal() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => TagsModal(
|
||||||
|
selectedTags: selectedTags,
|
||||||
|
tags: serversProvider.clients.data!.supportedTags,
|
||||||
|
onConfirm: (selected) => setState(() => selectedTags = selected),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openServicesModal() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => ServicesModal(
|
||||||
|
blockedServices: blockedServices,
|
||||||
|
onConfirm: (values) => setState(() => blockedServices = values),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateServicesGlobalSettings(bool value) {
|
||||||
|
if (value == true) {
|
||||||
|
setState(() {
|
||||||
|
blockedServices = [];
|
||||||
|
useGlobalSettingsServices = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (value == false) {
|
||||||
|
setState(() {
|
||||||
|
useGlobalSettingsServices = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void openDeleteClientScreen() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => RemoveClientModal(
|
||||||
|
onConfirm: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
widget.onDelete!(widget.client!);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget settignsTile({
|
||||||
|
required String label,
|
||||||
|
required bool? value,
|
||||||
|
void Function(bool)? onChange
|
||||||
|
}) {
|
||||||
|
return Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onChange != null
|
||||||
|
? value != null ? () => onChange(!value) : null
|
||||||
|
: null,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 42,
|
||||||
|
vertical: 5
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
useGlobalSettingsFiltering == false
|
||||||
|
? Switch(
|
||||||
|
value: value!,
|
||||||
|
onChanged: onChange,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
child: Text(
|
||||||
|
"Global",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
icon: const Icon(Icons.close)
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
widget.client != null
|
||||||
|
? AppLocalizations.of(context)!.client
|
||||||
|
: AppLocalizations.of(context)!.addClient
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
if (widget.client == null || (widget.client != null && editMode == true)) IconButton(
|
||||||
|
onPressed: checkValidValues() == true
|
||||||
|
? () {
|
||||||
|
createClient();
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
icon: Icon(
|
||||||
|
widget.client != null && editMode == true
|
||||||
|
? Icons.save_rounded
|
||||||
|
: Icons.check_rounded
|
||||||
|
),
|
||||||
|
tooltip: widget.client != null && editMode == true
|
||||||
|
? AppLocalizations.of(context)!.save
|
||||||
|
: AppLocalizations.of(context)!.confirm,
|
||||||
|
),
|
||||||
|
if (widget.client != null && editMode == false) IconButton(
|
||||||
|
onPressed: () => setState(() => editMode = true),
|
||||||
|
icon: const Icon(Icons.edit_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.edit,
|
||||||
|
),
|
||||||
|
if (widget.client != null) IconButton(
|
||||||
|
onPressed: openDeleteClientScreen,
|
||||||
|
icon: const Icon(Icons.delete_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.delete,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: ListView(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: TextFormField(
|
||||||
|
enabled: widget.client != null ? false : true,
|
||||||
|
controller: nameController,
|
||||||
|
onChanged: (_) => checkValidValues(),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.badge_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
labelText: AppLocalizations.of(context)!.name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
sectionLabel(AppLocalizations.of(context)!.tags),
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: editMode == true ? () => openTagsModal() : null,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 0, horizontal: 24
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.label_rounded,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.selectTags,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 3),
|
||||||
|
Text(
|
||||||
|
selectedTags.isNotEmpty
|
||||||
|
? "${selectedTags.length} ${AppLocalizations.of(context)!.tagsSelected}"
|
||||||
|
: AppLocalizations.of(context)!.noTagsSelected,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
sectionLabel(AppLocalizations.of(context)!.identifiers),
|
||||||
|
if (editMode == true) Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 20),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () => setState(() => identifiersControllers.add({
|
||||||
|
'id': uuid.v4(),
|
||||||
|
'controller': TextEditingController()
|
||||||
|
})),
|
||||||
|
icon: const Icon(Icons.add)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (identifiersControllers.isNotEmpty) ...identifiersControllers.map((controller) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
enabled: editMode,
|
||||||
|
controller: controller['controller'],
|
||||||
|
onChanged: (_) => checkValidValues(),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.tag),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
helperText: AppLocalizations.of(context)!.identifierHelper,
|
||||||
|
labelText: AppLocalizations.of(context)!.identifier,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (editMode == true) ...[
|
||||||
|
const SizedBox(width: 20),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 25),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () => setState(
|
||||||
|
() => identifiersControllers = identifiersControllers.where((e) => e['id'] != controller['id']).toList()
|
||||||
|
),
|
||||||
|
icon: const Icon(Icons.remove_circle_outline_outlined)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
if (identifiersControllers.isEmpty) Container(
|
||||||
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.noIdentifiers,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
color: Colors.grey
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
sectionLabel(AppLocalizations.of(context)!.settings),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Material(
|
||||||
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: editMode
|
||||||
|
? () => enableDisableGlobalSettingsFiltering()
|
||||||
|
: null,
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 5
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.useGlobalSettings,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: useGlobalSettingsFiltering,
|
||||||
|
onChanged: editMode == true
|
||||||
|
? (value) => enableDisableGlobalSettingsFiltering()
|
||||||
|
: null,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
settignsTile(
|
||||||
|
label: AppLocalizations.of(context)!.enableFiltering,
|
||||||
|
value: enableFiltering,
|
||||||
|
onChange: editMode == true
|
||||||
|
? (value) => setState(() => enableFiltering = value)
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
settignsTile(
|
||||||
|
label: AppLocalizations.of(context)!.enableSafeBrowsing,
|
||||||
|
value: enableSafeBrowsing,
|
||||||
|
onChange: editMode == true
|
||||||
|
? (value) => setState(() => enableSafeBrowsing = value)
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
settignsTile(
|
||||||
|
label: AppLocalizations.of(context)!.enableParentalControl,
|
||||||
|
value: enableParentalControl,
|
||||||
|
onChange: editMode == true
|
||||||
|
? (value) => setState(() => enableParentalControl = value)
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
settignsTile(
|
||||||
|
label: AppLocalizations.of(context)!.enableSafeSearch,
|
||||||
|
value: enableSafeSearch,
|
||||||
|
onChange: editMode == true
|
||||||
|
? (value) => setState(() => enableSafeSearch = value)
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
sectionLabel(AppLocalizations.of(context)!.blockedServices),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
child: Material(
|
||||||
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: editMode == true
|
||||||
|
? () => updateServicesGlobalSettings(!useGlobalSettingsServices)
|
||||||
|
: null,
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 5
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.useGlobalSettings,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: useGlobalSettingsServices,
|
||||||
|
onChanged: editMode == true
|
||||||
|
? (value) => updateServicesGlobalSettings(value)
|
||||||
|
: null,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: editMode == true
|
||||||
|
? useGlobalSettingsServices == false
|
||||||
|
? openServicesModal
|
||||||
|
: null
|
||||||
|
: null,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8, horizontal: 24
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.public,
|
||||||
|
color: useGlobalSettingsServices == false
|
||||||
|
? Theme.of(context).listTileTheme.iconColor
|
||||||
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.selectBlockedServices,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: useGlobalSettingsServices == false
|
||||||
|
? Theme.of(context).colorScheme.onSurface
|
||||||
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (useGlobalSettingsServices == false) ...[
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
blockedServices.isNotEmpty
|
||||||
|
? "${blockedServices.length} ${AppLocalizations.of(context)!.servicesBlocked}"
|
||||||
|
: AppLocalizations.of(context)!.noBlockedServicesSelected,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
sectionLabel(AppLocalizations.of(context)!.upstreamServers),
|
||||||
|
if (editMode == true) Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 20),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () => setState(() => upstreamServers.add({
|
||||||
|
'id': uuid.v4(),
|
||||||
|
'controller': TextEditingController()
|
||||||
|
})),
|
||||||
|
icon: const Icon(Icons.add)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (upstreamServers.isNotEmpty) ...upstreamServers.map((controller) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 20),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: editMode == true
|
||||||
|
? MediaQuery.of(context).size.width - 108
|
||||||
|
: MediaQuery.of(context).size.width - 40,
|
||||||
|
child: TextFormField(
|
||||||
|
enabled: editMode,
|
||||||
|
controller: controller['controller'],
|
||||||
|
onChanged: (_) => checkValidValues(),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.dns_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
labelText: AppLocalizations.of(context)!.serverAddress,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (editMode == true) ...[
|
||||||
|
const SizedBox(width: 20),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => setState(
|
||||||
|
() => upstreamServers = upstreamServers.where((e) => e['id'] != controller['id']).toList()
|
||||||
|
),
|
||||||
|
icon: const Icon(Icons.remove_circle_outline_outlined)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
if (upstreamServers.isEmpty) Container(
|
||||||
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.noUpstreamServers,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
color: Colors.grey
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.willBeUsedGeneralServers,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.grey
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,26 +121,15 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
|
||||||
],
|
],
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
|
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.devices),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.activeClients,
|
||||||
children: [
|
|
||||||
const Icon(Icons.devices),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.activeClients)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.add_rounded),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.added,
|
||||||
children: [
|
|
||||||
const Icon(Icons.add),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.added)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -154,9 +143,7 @@ class _ClientsWidgetState extends State<ClientsWidget> with TickerProviderStateM
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
top: BorderSide(
|
||||||
color: Theme.of(context).brightness == Brightness.light
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
|
||||||
? const Color.fromRGBO(220, 220, 220, 1)
|
|
||||||
: const Color.fromRGBO(50, 50, 50, 1)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -56,7 +56,12 @@ class ClientsList extends StatelessWidget {
|
||||||
subtitle: data[index].name != ''
|
subtitle: data[index].name != ''
|
||||||
? data[index].ip
|
? data[index].ip
|
||||||
: null,
|
: null,
|
||||||
trailing: Text(data[index].source),
|
trailing: Text(
|
||||||
|
data[index].source,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,13 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:bottom_sheet/bottom_sheet.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/clients/client_modal.dart';
|
import 'package:adguard_home_manager/screens/clients/client_screen.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||||
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
|
|
||||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
import 'package:adguard_home_manager/classes/process_modal.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';
|
||||||
|
@ -61,28 +59,20 @@ class ClientsFab extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void openAddClient() {
|
void openAddClient() {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
Navigator.push(context, MaterialPageRoute(
|
||||||
showFlexibleBottomSheet(
|
fullscreenDialog: true,
|
||||||
minHeight: 0.6,
|
builder: (BuildContext context) => ClientScreen(
|
||||||
initHeight: 0.6,
|
onConfirm: confirmAddClient,
|
||||||
maxHeight: 0.95,
|
)
|
||||||
isCollapsible: true,
|
));
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
anchors: [0.95],
|
|
||||||
context: context,
|
|
||||||
builder: (ctx, controller, offset) => ClientModal(
|
|
||||||
scrollController: controller,
|
|
||||||
onConfirm: confirmAddClient
|
|
||||||
),
|
|
||||||
bottomSheetColor: Colors.transparent
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
onPressed: () => openAddClient(),
|
onPressed: () => openAddClient(),
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,51 +14,64 @@ class OptionsModal extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
contentPadding: const EdgeInsets.all(0),
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 0,
|
||||||
|
vertical: 16
|
||||||
|
),
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.more_horiz),
|
Icon(
|
||||||
const SizedBox(height: 20),
|
Icons.more_horiz,
|
||||||
Text(AppLocalizations.of(context)!.options)
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.options,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: SizedBox(
|
content: Column(
|
||||||
height: 150,
|
mainAxisSize: MainAxisSize.min,
|
||||||
width: double.minPositive,
|
children: [
|
||||||
child: ListView(
|
const SizedBox(height: 24),
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
ListTile(
|
||||||
children: [
|
onTap: () {
|
||||||
const SizedBox(height: 25),
|
Navigator.pop(context);
|
||||||
ListTile(
|
onEdit();
|
||||||
onTap: () {
|
},
|
||||||
Navigator.pop(context);
|
title: Text(
|
||||||
onEdit();
|
AppLocalizations.of(context)!.edit,
|
||||||
},
|
style: TextStyle(
|
||||||
title: Padding(
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
padding: const EdgeInsets.all(10.0),
|
fontWeight: FontWeight.normal
|
||||||
child: Text(AppLocalizations.of(context)!.edit),
|
|
||||||
),
|
|
||||||
leading: const Padding(
|
|
||||||
padding: EdgeInsets.only(left: 10),
|
|
||||||
child: Icon(Icons.edit),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
leading: Icon(
|
||||||
onTap: () {
|
Icons.edit,
|
||||||
Navigator.pop(context);
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
onDelete();
|
),
|
||||||
},
|
),
|
||||||
title: Padding(
|
ListTile(
|
||||||
padding: const EdgeInsets.all(10.0),
|
onTap: () {
|
||||||
child: Text(AppLocalizations.of(context)!.delete),
|
Navigator.pop(context);
|
||||||
),
|
onDelete();
|
||||||
leading: const Padding(
|
},
|
||||||
padding: EdgeInsets.only(left: 10),
|
title: Text(
|
||||||
child: Icon(Icons.delete),
|
AppLocalizations.of(context)!.delete,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
fontWeight: FontWeight.normal
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
leading: Icon(
|
||||||
),
|
Icons.delete,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|
|
@ -14,15 +14,26 @@ class RemoveClientModal extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.delete_rounded,
|
Icons.delete_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(AppLocalizations.of(context)!.removeClient)
|
Text(
|
||||||
|
AppLocalizations.of(context)!.removeClient,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Text(AppLocalizations.of(context)!.removeClientMessage),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.removeClientMessage,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:bottom_sheet/bottom_sheet.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/clients/client_modal.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
|
import 'package:adguard_home_manager/screens/clients/remove_client_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/clients/client_screen.dart';
|
||||||
import 'package:adguard_home_manager/screens/clients/options_modal.dart';
|
import 'package:adguard_home_manager/screens/clients/options_modal.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
@ -59,10 +58,18 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
|
||||||
bool showDivider = true;
|
bool showDivider = true;
|
||||||
|
|
||||||
void search(String value) {
|
void search(String value) {
|
||||||
setState(() {
|
if (value == '') {
|
||||||
clientsScreen = clients.where((client) => client.name.contains(value) || client.ids.where((e) => e.contains(value)).isNotEmpty).toList();
|
setState(() {
|
||||||
autoClientsScreen = autoClients.where((client) => (client.name != null ? client.name!.contains(value) : true) || client.ip.contains(value)).toList();
|
clientsScreen = [];
|
||||||
});
|
autoClientsScreen = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
clientsScreen = clients.where((client) => client.name.contains(value) || client.ids.where((e) => e.contains(value)).isNotEmpty).toList();
|
||||||
|
autoClientsScreen = autoClients.where((client) => (client.name != null ? client.name!.contains(value) : true) || client.ip.contains(value)).toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollListener() {
|
void scrollListener() {
|
||||||
|
@ -81,9 +88,6 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
|
||||||
setState(() {
|
setState(() {
|
||||||
clients = widget.serversProvider.clients.data!.clients;
|
clients = widget.serversProvider.clients.data!.clients;
|
||||||
autoClients = widget.serversProvider.clients.data!.autoClientsData;
|
autoClients = widget.serversProvider.clients.data!.autoClientsData;
|
||||||
|
|
||||||
clientsScreen = widget.serversProvider.clients.data!.clients;
|
|
||||||
autoClientsScreen = widget.serversProvider.clients.data!.autoClientsData;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -178,23 +182,14 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void openClientModal(Client client) {
|
void openClientModal(Client client) {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
Navigator.push(context, MaterialPageRoute(
|
||||||
showFlexibleBottomSheet(
|
fullscreenDialog: true,
|
||||||
minHeight: 0.6,
|
builder: (BuildContext context) => ClientScreen(
|
||||||
initHeight: 0.6,
|
|
||||||
maxHeight: 0.95,
|
|
||||||
isCollapsible: true,
|
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
anchors: [0.95],
|
|
||||||
context: context,
|
|
||||||
builder: (ctx, controller, offset) => ClientModal(
|
|
||||||
scrollController: controller,
|
|
||||||
client: client,
|
|
||||||
onConfirm: confirmEditClient,
|
onConfirm: confirmEditClient,
|
||||||
onDelete: deleteClient,
|
onDelete: deleteClient,
|
||||||
),
|
client: client,
|
||||||
bottomSheetColor: Colors.transparent
|
)
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void openDeleteModal(Client client) {
|
void openDeleteModal(Client client) {
|
||||||
|
@ -387,7 +382,9 @@ class _SearchClientsWidgetState extends State<SearchClientsWidget> {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(context)!.noClientsSearch,
|
searchController.text == ''
|
||||||
|
? AppLocalizations.of(context)!.inputSearchTerm
|
||||||
|
: AppLocalizations.of(context)!.noClientsSearch,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
|
|
|
@ -45,13 +45,21 @@ class _ServicesModalState extends State<ServicesModal> {
|
||||||
scrollable: true,
|
scrollable: true,
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
horizontal: 0,
|
horizontal: 0,
|
||||||
vertical: 20
|
vertical: 16
|
||||||
),
|
),
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.public),
|
Icon(
|
||||||
const SizedBox(height: 20),
|
Icons.public,
|
||||||
Text(AppLocalizations.of(context)!.services)
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.services,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
|
@ -65,8 +73,9 @@ class _ServicesModalState extends State<ServicesModal> {
|
||||||
padding: const EdgeInsets.only(left: 10),
|
padding: const EdgeInsets.only(left: 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
services[index]['label']!,
|
services[index]['label']!,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -95,7 +104,7 @@ class _ServicesModalState extends State<ServicesModal> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: blockedServices.isNotEmpty
|
color: blockedServices.isNotEmpty
|
||||||
? Theme.of(context).primaryColor
|
? Theme.of(context).primaryColor
|
||||||
: Colors.grey
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -45,13 +45,21 @@ class _TagsModalState extends State<TagsModal> {
|
||||||
scrollable: true,
|
scrollable: true,
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
horizontal: 0,
|
horizontal: 0,
|
||||||
vertical: 20
|
vertical: 16
|
||||||
),
|
),
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.label_rounded),
|
Icon(
|
||||||
const SizedBox(height: 20),
|
Icons.label_rounded,
|
||||||
Text(AppLocalizations.of(context)!.tags)
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.tags,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
|
@ -63,8 +71,9 @@ class _TagsModalState extends State<TagsModal> {
|
||||||
itemBuilder: (context, index) => CheckboxListTile(
|
itemBuilder: (context, index) => CheckboxListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
widget.tags[index],
|
widget.tags[index],
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
value: selectedTags.contains(widget.tags[index]),
|
value: selectedTags.contains(widget.tags[index]),
|
||||||
|
@ -92,7 +101,7 @@ class _TagsModalState extends State<TagsModal> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: selectedTags.isNotEmpty
|
color: selectedTags.isNotEmpty
|
||||||
? Theme.of(context).primaryColor
|
? Theme.of(context).primaryColor
|
||||||
: Colors.grey
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -17,9 +17,10 @@ class FabConnect extends StatelessWidget {
|
||||||
|
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
onPressed: openAddServerModal,
|
onPressed: openAddServerModal,
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add_rounded,
|
Icons.add_rounded,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:material_segmented_control/material_segmented_control.dart';
|
||||||
import 'package:flutter_web_browser/flutter_web_browser.dart';
|
import 'package:flutter_web_browser/flutter_web_browser.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_radio_toggle.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/constants/urls.dart';
|
import 'package:adguard_home_manager/constants/urls.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
|
||||||
class AddCustomRule extends StatefulWidget {
|
class AddCustomRule extends StatefulWidget {
|
||||||
final ScrollController scrollController;
|
|
||||||
final void Function(String) onConfirm;
|
final void Function(String) onConfirm;
|
||||||
|
|
||||||
const AddCustomRule({
|
const AddCustomRule({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.scrollController,
|
|
||||||
required this.onConfirm
|
required this.onConfirm
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@ -24,19 +23,14 @@ class _AddCustomRuleState extends State<AddCustomRule> {
|
||||||
final TextEditingController domainController = TextEditingController();
|
final TextEditingController domainController = TextEditingController();
|
||||||
String? domainError;
|
String? domainError;
|
||||||
|
|
||||||
String preset = "block";
|
int preset = 0;
|
||||||
|
|
||||||
bool addImportant = false;
|
bool addImportant = false;
|
||||||
|
|
||||||
bool checkValidValues() {
|
bool checkValidValues() {
|
||||||
if (
|
if (
|
||||||
domainController.text != '' &&
|
domainController.text != '' &&
|
||||||
domainError == null &&
|
domainError == null
|
||||||
(
|
|
||||||
preset == 'block' ||
|
|
||||||
preset == 'unblock' ||
|
|
||||||
preset == 'custom'
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -61,10 +55,10 @@ class _AddCustomRuleState extends State<AddCustomRule> {
|
||||||
|
|
||||||
String fieldValue = value ?? domainController.text;
|
String fieldValue = value ?? domainController.text;
|
||||||
|
|
||||||
if (preset == 'block') {
|
if (preset == 0) {
|
||||||
rule = "||${fieldValue.trim()}^";
|
rule = "||${fieldValue.trim()}^";
|
||||||
}
|
}
|
||||||
else if (preset == 'unblock') {
|
else if (preset == 1) {
|
||||||
rule = "@@||${fieldValue.trim()}^";
|
rule = "@@||${fieldValue.trim()}^";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -96,318 +90,325 @@ class _AddCustomRuleState extends State<AddCustomRule> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
|
||||||
child: Container(
|
Map<int, Widget> presets = {
|
||||||
decoration: BoxDecoration(
|
0: Text(
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
AppLocalizations.of(context)!.block,
|
||||||
borderRadius: const BorderRadius.only(
|
style: TextStyle(
|
||||||
topLeft: Radius.circular(28),
|
color: appConfigProvider.useDynamicColor == true
|
||||||
topRight: Radius.circular(28)
|
? Theme.of(context).floatingActionButtonTheme.foregroundColor!
|
||||||
)
|
: preset == 0
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
),
|
),
|
||||||
child: Column(
|
),
|
||||||
children: [
|
1: Text(
|
||||||
Expanded(
|
AppLocalizations.of(context)!.unblock,
|
||||||
child: ListView(
|
style: TextStyle(
|
||||||
controller: widget.scrollController,
|
color: appConfigProvider.useDynamicColor == true
|
||||||
children: [
|
? Theme.of(context).floatingActionButtonTheme.foregroundColor!
|
||||||
const Padding(
|
: preset == 1
|
||||||
padding: EdgeInsets.only(top: 28),
|
? Colors.white
|
||||||
child: Icon(
|
: Theme.of(context).primaryColor,
|
||||||
Icons.shield_rounded,
|
fontSize: 14,
|
||||||
size: 26,
|
fontWeight: FontWeight.w500
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
2: Text(
|
||||||
|
AppLocalizations.of(context)!.custom,
|
||||||
|
style: TextStyle(
|
||||||
|
color: appConfigProvider.useDynamicColor == true
|
||||||
|
? Theme.of(context).floatingActionButtonTheme.foregroundColor!
|
||||||
|
: preset == 2
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context)!.addCustomRule),
|
||||||
|
),
|
||||||
|
body: ListView(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 5
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
)
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
buildRule(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
)
|
||||||
Text(
|
),
|
||||||
AppLocalizations.of(context)!.addCustomRule,
|
],
|
||||||
textAlign: TextAlign.center,
|
),
|
||||||
style: const TextStyle(
|
const SizedBox(height: 30),
|
||||||
fontSize: 24
|
Padding(
|
||||||
),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
),
|
child: TextFormField(
|
||||||
const SizedBox(height: 30),
|
controller: domainController,
|
||||||
Row(
|
onChanged: (value) => setState(() => {}),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
decoration: InputDecoration(
|
||||||
mainAxisSize: MainAxisSize.min,
|
prefixIcon: const Icon(Icons.link_rounded),
|
||||||
children: [
|
border: const OutlineInputBorder(
|
||||||
Container(
|
borderRadius: BorderRadius.all(
|
||||||
padding: const EdgeInsets.symmetric(
|
Radius.circular(10)
|
||||||
horizontal: 10,
|
)
|
||||||
vertical: 5
|
),
|
||||||
),
|
errorText: domainError,
|
||||||
decoration: BoxDecoration(
|
labelText: AppLocalizations.of(context)!.domain,
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
border: Border.all(
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
)
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
buildRule(),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
fontWeight: FontWeight.w500
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
|
||||||
child: TextFormField(
|
|
||||||
controller: domainController,
|
|
||||||
onChanged: (value) => setState(() => {}),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
prefixIcon: const Icon(Icons.link_rounded),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
errorText: domainError,
|
|
||||||
labelText: AppLocalizations.of(context)!.domain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
CustomRadioToggle(
|
|
||||||
groupSelected: preset,
|
|
||||||
value: 'block',
|
|
||||||
label: AppLocalizations.of(context)!.block,
|
|
||||||
onTap: (value) => setState(() => preset = value)
|
|
||||||
),
|
|
||||||
CustomRadioToggle(
|
|
||||||
groupSelected: preset,
|
|
||||||
value: 'unblock',
|
|
||||||
label: AppLocalizations.of(context)!.unblock,
|
|
||||||
onTap: (value) => setState(() => preset = value)
|
|
||||||
),
|
|
||||||
CustomRadioToggle(
|
|
||||||
groupSelected: preset,
|
|
||||||
value: 'custom',
|
|
||||||
label: AppLocalizations.of(context)!.custom,
|
|
||||||
onTap: (value) => setState(() => preset = value)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () => setState(() => addImportant = !addImportant),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.addImportant,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Switch(
|
|
||||||
value: addImportant,
|
|
||||||
onChanged: (value) => setState(() => addImportant = value),
|
|
||||||
activeColor: Theme.of(context).primaryColor,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
child: Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.info),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.examples,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 18
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
SizedBox(
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"||example.org^",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.example1,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
"@@||example.org^",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.example2,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
"! Here goes a comment",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"# Also a comment",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.example3,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
"/REGEX/",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.example4,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: openDocsPage,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 10),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.moreInformation,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(right: 15),
|
|
||||||
child: Icon(Icons.open_in_new),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.only(
|
const SizedBox(height: 30),
|
||||||
left: 28,
|
MaterialSegmentedControl(
|
||||||
right: 28,
|
children: presets,
|
||||||
top: 20,
|
selectionIndex: preset,
|
||||||
bottom: 28
|
onSegmentChosen: (value) => setState(() => preset = value),
|
||||||
|
selectedColor: Theme.of(context).floatingActionButtonTheme.backgroundColor!,
|
||||||
|
unselectedColor: Colors.transparent,
|
||||||
|
borderColor: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => setState(() => addImportant = !addImportant),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 28),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.addImportant,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: addImportant,
|
||||||
|
onChanged: (value) => setState(() => addImportant = value),
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
),
|
||||||
children: [
|
const SizedBox(height: 20),
|
||||||
TextButton(
|
Padding(
|
||||||
onPressed: () => Navigator.pop(context),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Text(AppLocalizations.of(context)!.cancel)
|
child: Card(
|
||||||
),
|
child: Padding(
|
||||||
const SizedBox(width: 20),
|
padding: const EdgeInsets.all(20),
|
||||||
TextButton(
|
child: Column(
|
||||||
onPressed: checkValidValues() == true
|
children: [
|
||||||
? () {
|
Row(
|
||||||
Navigator.pop(context);
|
children: [
|
||||||
widget.onConfirm(buildRule());
|
Icon(
|
||||||
}
|
Icons.info,
|
||||||
: null,
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
child: Text(
|
),
|
||||||
AppLocalizations.of(context)!.confirm,
|
const SizedBox(width: 20),
|
||||||
style: TextStyle(
|
Text(
|
||||||
color: checkValidValues() == true
|
AppLocalizations.of(context)!.examples,
|
||||||
? Theme.of(context).primaryColor
|
style: TextStyle(
|
||||||
: Colors.grey
|
fontSize: 18,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
SizedBox(
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"||example.org^",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.example1,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"@@||example.org^",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.example2,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"! Here goes a comment",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"# Also a comment",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.example3,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"/REGEX/",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.example4,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
),
|
||||||
),
|
const SizedBox(height: 20),
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: openDocsPage,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.moreInformation,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 15),
|
||||||
|
child: Icon(
|
||||||
|
Icons.open_in_new,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.only(
|
||||||
|
// left: 28,
|
||||||
|
// right: 28,
|
||||||
|
// top: 20,
|
||||||
|
// bottom: 28
|
||||||
|
// ),
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
// children: [
|
||||||
|
// TextButton(
|
||||||
|
// onPressed: () => Navigator.pop(context),
|
||||||
|
// child: Text(AppLocalizations.of(context)!.cancel)
|
||||||
|
// ),
|
||||||
|
// const SizedBox(width: 20),
|
||||||
|
// TextButton(
|
||||||
|
// onPressed: checkValidValues() == true
|
||||||
|
// ? () {
|
||||||
|
// Navigator.pop(context);
|
||||||
|
// widget.onConfirm(buildRule());
|
||||||
|
// }
|
||||||
|
// : null,
|
||||||
|
// child: Text(
|
||||||
|
// AppLocalizations.of(context)!.confirm,
|
||||||
|
// style: TextStyle(
|
||||||
|
// color: checkValidValues() == true
|
||||||
|
// ? Theme.of(context).primaryColor
|
||||||
|
// : Colors.grey
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// )
|
|
@ -69,7 +69,7 @@ class _AddListModalState extends State<AddListModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 410,
|
height: 370,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(28),
|
topLeft: Radius.circular(28),
|
||||||
|
@ -86,15 +86,16 @@ class _AddListModalState extends State<AddListModal> {
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
widget.type == 'whitelist'
|
widget.type == 'whitelist'
|
||||||
? Icons.verified_user_rounded
|
? Icons.verified_user_rounded
|
||||||
: Icons.gpp_bad_rounded,
|
: Icons.gpp_bad_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
widget.list != null
|
widget.list != null
|
||||||
? widget.type == 'whitelist'
|
? widget.type == 'whitelist'
|
||||||
|
@ -104,13 +105,14 @@ class _AddListModalState extends State<AddListModal> {
|
||||||
? AppLocalizations.of(context)!.addWhitelist
|
? AppLocalizations.of(context)!.addWhitelist
|
||||||
: AppLocalizations.of(context)!.addBlacklist,
|
: AppLocalizations.of(context)!.addBlacklist,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
onChanged: (_) => checkValidValues(),
|
onChanged: (_) => checkValidValues(),
|
||||||
|
@ -127,7 +129,7 @@ class _AddListModalState extends State<AddListModal> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: urlController,
|
controller: urlController,
|
||||||
onChanged: validateUrl,
|
onChanged: validateUrl,
|
||||||
|
@ -148,7 +150,7 @@ class _AddListModalState extends State<AddListModal> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -71,19 +71,21 @@ class _BlockedServicesModalState extends State<BlockedServicesModal> {
|
||||||
child: ListView(
|
child: ListView(
|
||||||
controller: widget.scrollController,
|
controller: widget.scrollController,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.block,
|
Icons.block,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.blockedServices,
|
AppLocalizations.of(context)!.blockedServices,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
@ -102,8 +104,9 @@ class _BlockedServicesModalState extends State<BlockedServicesModal> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
services[index]['label']!,
|
services[index]['label']!,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Checkbox(
|
Checkbox(
|
||||||
|
|
|
@ -120,7 +120,7 @@ class _CheckHostModalState extends State<CheckHostModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 350,
|
height: 330,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
|
@ -138,24 +138,26 @@ class _CheckHostModalState extends State<CheckHostModal> {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.shield_rounded,
|
Icons.shield_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.checkHostFiltered,
|
AppLocalizations.of(context)!.checkHostFiltered,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: domainController,
|
controller: domainController,
|
||||||
onChanged: validateDomain,
|
onChanged: validateDomain,
|
||||||
|
@ -202,8 +204,8 @@ class _CheckHostModalState extends State<CheckHostModal> {
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
bottom: 20,
|
bottom: 24,
|
||||||
right: 20
|
right: 24
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
|
|
@ -148,10 +148,8 @@ class _CustomRulesListState extends State<CustomRulesList> {
|
||||||
widget.data[index],
|
widget.data[index],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: checkIfComment(widget.data[index]) == true
|
color: checkIfComment(widget.data[index]) == true
|
||||||
? Theme.of(context).brightness == Brightness.light
|
? Theme.of(context).colorScheme.onSurface.withOpacity(0.6)
|
||||||
? const Color.fromRGBO(100, 100, 100, 1)
|
: Theme.of(context).colorScheme.onSurface,
|
||||||
: const Color.fromRGBO(200, 200, 200, 1)
|
|
||||||
: null,
|
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,15 +14,27 @@ class DeleteListModal extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.delete_rounded,
|
Icons.delete_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(AppLocalizations.of(context)!.deleteList)
|
Text(
|
||||||
|
AppLocalizations.of(context)!.deleteList,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Text(AppLocalizations.of(context)!.deleteListMessage),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.deleteListMessage,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
|
|
|
@ -64,20 +64,12 @@ class FiltersFab extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void openAddCustomRule() {
|
void openAddCustomRule() {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
Navigator.of(context).push(
|
||||||
showFlexibleBottomSheet(
|
MaterialPageRoute(
|
||||||
minHeight: 0.7,
|
builder: (context) => AddCustomRule(
|
||||||
initHeight: 0.7,
|
onConfirm: confirmAddRule
|
||||||
maxHeight: 0.95,
|
),
|
||||||
isCollapsible: true,
|
)
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
anchors: [0.7, 0.95],
|
|
||||||
context: context,
|
|
||||||
builder: (ctx, controller, offset) => AddCustomRule(
|
|
||||||
scrollController: controller,
|
|
||||||
onConfirm: confirmAddRule
|
|
||||||
),
|
|
||||||
bottomSheetColor: Colors.transparent
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,9 +168,10 @@ class FiltersFab extends StatelessWidget {
|
||||||
onPressed: type == 'blacklist' || type == 'whitelist'
|
onPressed: type == 'blacklist' || type == 'whitelist'
|
||||||
? () => openAddWhitelistBlacklist()
|
? () => openAddWhitelistBlacklist()
|
||||||
: () => openAddCustomRule(),
|
: () => openAddCustomRule(),
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,31 +19,35 @@ class FilterListTile extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 16),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 3),
|
||||||
Text(
|
Text(
|
||||||
subtitle,
|
subtitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: color ?? Theme.of(context).listTileTheme.iconColor,
|
color: color ?? Theme.of(context).listTileTheme.textColor,
|
||||||
fontWeight: bold == true ? FontWeight.bold : null
|
fontWeight: bold == true ? FontWeight.bold : FontWeight.w400
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -367,36 +367,19 @@ class _FiltersWidgetState extends State<FiltersWidget> with TickerProviderStateM
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
isScrollable: true,
|
isScrollable: true,
|
||||||
|
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.verified_user_rounded),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.whitelists,
|
||||||
children: [
|
|
||||||
const Icon(Icons.verified_user_rounded),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.whitelists),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.gpp_bad_rounded),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.blacklist,
|
||||||
children: [
|
|
||||||
const Icon(Icons.gpp_bad_rounded),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.blacklist),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.shield_rounded),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.customRules,
|
||||||
children: [
|
|
||||||
const Icon(Icons.shield_rounded),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.customRules),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -410,9 +393,7 @@ class _FiltersWidgetState extends State<FiltersWidget> with TickerProviderStateM
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
top: BorderSide(
|
||||||
color: Theme.of(context).brightness == Brightness.light
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
|
||||||
? const Color.fromRGBO(220, 220, 220, 1)
|
|
||||||
: const Color.fromRGBO(50, 50, 50, 1)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,21 +3,14 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:bottom_sheet/bottom_sheet.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.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/filters/fab.dart';
|
import 'package:adguard_home_manager/screens/filters/fab.dart';
|
||||||
import 'package:adguard_home_manager/screens/filters/list_details_modal.dart';
|
import 'package:adguard_home_manager/screens/filters/list_details_screen.dart';
|
||||||
import 'package:adguard_home_manager/screens/filters/add_list_modal.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/filters/delete_list_modal.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/services/http_requests.dart';
|
|
||||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
|
||||||
import 'package:adguard_home_manager/classes/process_modal.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';
|
||||||
import 'package:adguard_home_manager/functions/number_format.dart';
|
import 'package:adguard_home_manager/functions/number_format.dart';
|
||||||
import 'package:adguard_home_manager/models/filtering.dart';
|
import 'package:adguard_home_manager/models/filtering.dart';
|
||||||
|
@ -68,196 +61,16 @@ class _FiltersListState extends State<FiltersList> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final serversProvider = Provider.of<ServersProvider>(context);
|
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
void enableDisableList(Filter list, bool enabled) async {
|
|
||||||
ProcessModal processModal = ProcessModal(context: context);
|
|
||||||
processModal.open(
|
|
||||||
enabled == true
|
|
||||||
? AppLocalizations.of(context)!.enablingList
|
|
||||||
: AppLocalizations.of(context)!.disablingList,
|
|
||||||
);
|
|
||||||
|
|
||||||
final result = await updateFilterList(server: serversProvider.selectedServer!, data: {
|
|
||||||
"data": {
|
|
||||||
"enabled": enabled,
|
|
||||||
"name": list.name,
|
|
||||||
"url": list.url
|
|
||||||
},
|
|
||||||
"url": list.url,
|
|
||||||
"whitelist": widget.type == 'whitelist' ? true : false
|
|
||||||
});
|
|
||||||
|
|
||||||
processModal.close();
|
|
||||||
|
|
||||||
if (result['result'] == 'success') {
|
|
||||||
final result2 = await getFiltering(server: serversProvider.selectedServer!);
|
|
||||||
|
|
||||||
if (result2['result'] == 'success') {
|
|
||||||
serversProvider.setFilteringData(result2['data']);
|
|
||||||
serversProvider.setFilteringLoadStatus(1, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appConfigProvider.addLog(result2['log']);
|
|
||||||
serversProvider.setFilteringLoadStatus(2, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: AppLocalizations.of(context)!.listDataUpdated,
|
|
||||||
color: Colors.green
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appConfigProvider.addLog(result['log']);
|
|
||||||
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: AppLocalizations.of(context)!.listDataNotUpdated,
|
|
||||||
color: Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void confirmEditList({required Filter list, required String type}) async {
|
|
||||||
ProcessModal processModal = ProcessModal(context: context);
|
|
||||||
processModal.open(AppLocalizations.of(context)!.updatingListData);
|
|
||||||
|
|
||||||
final result1 = await updateFilterList(server: serversProvider.selectedServer!, data: {
|
|
||||||
"data": {
|
|
||||||
"enabled": list.enabled,
|
|
||||||
"name": list.name,
|
|
||||||
"url": list.url
|
|
||||||
},
|
|
||||||
"url": list.url,
|
|
||||||
"whitelist": type == 'whitelist' ? true : false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result1['result'] == 'success') {
|
|
||||||
final result2 = await getFiltering(server: serversProvider.selectedServer!);
|
|
||||||
|
|
||||||
if (result2['result'] == 'success') {
|
|
||||||
serversProvider.setFilteringData(result2['data']);
|
|
||||||
serversProvider.setFilteringLoadStatus(1, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appConfigProvider.addLog(result2['log']);
|
|
||||||
serversProvider.setFilteringLoadStatus(2, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
processModal.close();
|
|
||||||
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: AppLocalizations.of(context)!.listDataUpdated,
|
|
||||||
color: Colors.green
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
processModal.close();
|
|
||||||
appConfigProvider.addLog(result1['log']);
|
|
||||||
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: AppLocalizations.of(context)!.listDataNotUpdated,
|
|
||||||
color: Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteList(Filter list, String type) async {
|
|
||||||
ProcessModal processModal = ProcessModal(context: context);
|
|
||||||
processModal.open(AppLocalizations.of(context)!.deletingList);
|
|
||||||
|
|
||||||
final result1 = await deleteFilterList(server: serversProvider.selectedServer!, data: {
|
|
||||||
"url": list.url,
|
|
||||||
"whitelist": type == 'whitelist' ? true : false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result1['result'] == 'success') {
|
|
||||||
final result2 = await getFiltering(server: serversProvider.selectedServer!);
|
|
||||||
|
|
||||||
if (result2['result'] == 'success') {
|
|
||||||
serversProvider.setFilteringData(result2['data']);
|
|
||||||
serversProvider.setFilteringLoadStatus(1, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appConfigProvider.addLog(result2['log']);
|
|
||||||
serversProvider.setFilteringLoadStatus(2, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
processModal.close();
|
|
||||||
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: AppLocalizations.of(context)!.listDeleted,
|
|
||||||
color: Colors.green
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
processModal.close();
|
|
||||||
appConfigProvider.addLog(result1['log']);
|
|
||||||
|
|
||||||
showSnacbkar(
|
|
||||||
context: context,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
label: AppLocalizations.of(context)!.listNotDeleted,
|
|
||||||
color: Colors.red
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void openDetailsModal(Filter filter) {
|
void openDetailsModal(Filter filter) {
|
||||||
final height = (filter.enabled == true ? 774 : 755)/MediaQuery.of(context).size.height < 1
|
Navigator.of(context).push(
|
||||||
? (filter.enabled == true ? 774 : 755)/MediaQuery.of(context).size.height
|
MaterialPageRoute(
|
||||||
: 0.95;
|
builder: (context) => ListDetailsScreen(
|
||||||
|
list: filter,
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
type: widget.type,
|
||||||
|
)
|
||||||
showFlexibleBottomSheet(
|
)
|
||||||
minHeight: 0.6,
|
|
||||||
initHeight: 0.6,
|
|
||||||
maxHeight: height,
|
|
||||||
isCollapsible: true,
|
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
anchors: [height],
|
|
||||||
context: context,
|
|
||||||
builder: (ctx, controller, offset) => ListDetailsModal(
|
|
||||||
scrollController: controller,
|
|
||||||
list: filter,
|
|
||||||
type: widget.type,
|
|
||||||
onDelete: (Filter list, String type) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => DeleteListModal(
|
|
||||||
onConfirm: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
deleteList(list, type);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
edit: (type) => {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
builder: (ctx) => AddListModal(
|
|
||||||
list: filter,
|
|
||||||
type: type,
|
|
||||||
onEdit: confirmEditList
|
|
||||||
),
|
|
||||||
isScrollControlled: true,
|
|
||||||
backgroundColor: Colors.transparent
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onEnableDisable: enableDisableList,
|
|
||||||
),
|
|
||||||
bottomSheetColor: Colors.transparent
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
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/filters/filter_list_tile.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/functions/format_time.dart';
|
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
|
||||||
import 'package:adguard_home_manager/models/filtering.dart';
|
|
||||||
|
|
||||||
class ListDetailsModal extends StatelessWidget {
|
|
||||||
final ScrollController scrollController;
|
|
||||||
final Filter list;
|
|
||||||
final String type;
|
|
||||||
final void Function(Filter, String) onDelete;
|
|
||||||
final void Function(String) edit;
|
|
||||||
final void Function(Filter, bool) onEnableDisable;
|
|
||||||
|
|
||||||
const ListDetailsModal({
|
|
||||||
Key? key,
|
|
||||||
required this.scrollController,
|
|
||||||
required this.list,
|
|
||||||
required this.type,
|
|
||||||
required this.onDelete,
|
|
||||||
required this.edit,
|
|
||||||
required this.onEnableDisable,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(28),
|
|
||||||
topRight: Radius.circular(28)
|
|
||||||
),
|
|
||||||
color: Theme.of(context).dialogBackgroundColor
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: NotificationListener<OverscrollIndicatorNotification>(
|
|
||||||
onNotification: (overscroll) {
|
|
||||||
overscroll.disallowIndicator();
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
child: ListView(
|
|
||||||
controller: scrollController,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 24),
|
|
||||||
child: Icon(
|
|
||||||
type == 'whitelist'
|
|
||||||
? Icons.verified_user_rounded
|
|
||||||
: Icons.gpp_bad_rounded,
|
|
||||||
size: 26,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.listDetails,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ElevatedButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
onEnableDisable(list, !list.enabled);
|
|
||||||
},
|
|
||||||
label: Text(
|
|
||||||
list.enabled == true
|
|
||||||
? AppLocalizations.of(context)!.disable
|
|
||||||
: AppLocalizations.of(context)!.enable
|
|
||||||
),
|
|
||||||
icon: Icon(
|
|
||||||
list.enabled == true
|
|
||||||
? Icons.gpp_bad_rounded
|
|
||||||
: Icons.verified_user_rounded
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 30),
|
|
||||||
FilterListTile(
|
|
||||||
icon: Icons.shield_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.currentStatus,
|
|
||||||
subtitle: list.enabled == true
|
|
||||||
? AppLocalizations.of(context)!.enabled
|
|
||||||
: AppLocalizations.of(context)!.disabled,
|
|
||||||
color: list.enabled == true
|
|
||||||
? appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: Colors.green
|
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
|
||||||
? Colors.grey
|
|
||||||
: Colors.red,
|
|
||||||
bold: true,
|
|
||||||
),
|
|
||||||
FilterListTile(
|
|
||||||
icon: Icons.badge_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.name,
|
|
||||||
subtitle: list.name
|
|
||||||
),
|
|
||||||
FilterListTile(
|
|
||||||
icon: Icons.link_rounded,
|
|
||||||
title: "URL",
|
|
||||||
subtitle: list.url
|
|
||||||
),
|
|
||||||
FilterListTile(
|
|
||||||
icon: Icons.list_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.rules,
|
|
||||||
subtitle: list.rulesCount.toString()
|
|
||||||
),
|
|
||||||
FilterListTile(
|
|
||||||
icon: Icons.shield_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.listType,
|
|
||||||
subtitle: type == 'whitelist'
|
|
||||||
? AppLocalizations.of(context)!.whitelist
|
|
||||||
: AppLocalizations.of(context)!.blacklist,
|
|
||||||
),
|
|
||||||
if (list.lastUpdated != null) FilterListTile(
|
|
||||||
icon: Icons.schedule_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.latestUpdate,
|
|
||||||
subtitle: formatTimestampUTC(list.lastUpdated!, 'dd-MM-yyyy HH:mm'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
edit(type);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.edit)
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
onDelete(list, type);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.delete)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text(AppLocalizations.of(context)!.close)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
322
lib/screens/filters/list_details_screen.dart
Normal file
322
lib/screens/filters/list_details_screen.dart
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/screens/filters/filter_list_tile.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/filters/add_list_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/filters/delete_list_modal.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/functions/format_time.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||||
|
import 'package:adguard_home_manager/classes/process_modal.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/filtering.dart';
|
||||||
|
|
||||||
|
class ListDetailsScreen extends StatefulWidget {
|
||||||
|
final Filter list;
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
const ListDetailsScreen({
|
||||||
|
Key? key,
|
||||||
|
required this.list,
|
||||||
|
required this.type,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ListDetailsScreen> createState() => _ListDetailsScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ListDetailsScreenState extends State<ListDetailsScreen> {
|
||||||
|
final ScrollController scrollController = ScrollController();
|
||||||
|
String name = "";
|
||||||
|
bool enabled = true;
|
||||||
|
bool fabVisible = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
name = widget.list.name;
|
||||||
|
enabled = widget.list.enabled;
|
||||||
|
|
||||||
|
scrollController.addListener(() {
|
||||||
|
if (scrollController.position.userScrollDirection == ScrollDirection.reverse) {
|
||||||
|
if (mounted && fabVisible == true) {
|
||||||
|
setState(() => fabVisible = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (scrollController.position.userScrollDirection == ScrollDirection.forward) {
|
||||||
|
if (mounted && fabVisible == false) {
|
||||||
|
setState(() => fabVisible = true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
void enableDisableList(Filter list, bool newStatus) async {
|
||||||
|
ProcessModal processModal = ProcessModal(context: context);
|
||||||
|
processModal.open(
|
||||||
|
enabled == true
|
||||||
|
? AppLocalizations.of(context)!.disablingList
|
||||||
|
: AppLocalizations.of(context)!.enablingList,
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await updateFilterList(server: serversProvider.selectedServer!, data: {
|
||||||
|
"data": {
|
||||||
|
"enabled": newStatus,
|
||||||
|
"name": list.name,
|
||||||
|
"url": list.url
|
||||||
|
},
|
||||||
|
"url": list.url,
|
||||||
|
"whitelist": widget.type == 'whitelist' ? true : false
|
||||||
|
});
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
if (result['result'] == 'success') {
|
||||||
|
final result2 = await getFiltering(server: serversProvider.selectedServer!);
|
||||||
|
|
||||||
|
if (result2['result'] == 'success') {
|
||||||
|
serversProvider.setFilteringData(result2['data']);
|
||||||
|
serversProvider.setFilteringLoadStatus(1, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appConfigProvider.addLog(result2['log']);
|
||||||
|
serversProvider.setFilteringLoadStatus(2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => enabled = newStatus);
|
||||||
|
|
||||||
|
showSnacbkar(
|
||||||
|
context: context,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.listDataUpdated,
|
||||||
|
color: Colors.green
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appConfigProvider.addLog(result['log']);
|
||||||
|
|
||||||
|
showSnacbkar(
|
||||||
|
context: context,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.listDataNotUpdated,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void confirmEditList({required Filter list, required String type}) async {
|
||||||
|
ProcessModal processModal = ProcessModal(context: context);
|
||||||
|
processModal.open(AppLocalizations.of(context)!.updatingListData);
|
||||||
|
|
||||||
|
final result1 = await updateFilterList(server: serversProvider.selectedServer!, data: {
|
||||||
|
"data": {
|
||||||
|
"enabled": list.enabled,
|
||||||
|
"name": list.name,
|
||||||
|
"url": list.url
|
||||||
|
},
|
||||||
|
"url": list.url,
|
||||||
|
"whitelist": type == 'whitelist' ? true : false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result1['result'] == 'success') {
|
||||||
|
final result2 = await getFiltering(server: serversProvider.selectedServer!);
|
||||||
|
|
||||||
|
if (result2['result'] == 'success') {
|
||||||
|
serversProvider.setFilteringData(result2['data']);
|
||||||
|
serversProvider.setFilteringLoadStatus(1, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appConfigProvider.addLog(result2['log']);
|
||||||
|
serversProvider.setFilteringLoadStatus(2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
setState(() => name = list.name);
|
||||||
|
|
||||||
|
showSnacbkar(
|
||||||
|
context: context,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.listDataUpdated,
|
||||||
|
color: Colors.green
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processModal.close();
|
||||||
|
appConfigProvider.addLog(result1['log']);
|
||||||
|
|
||||||
|
showSnacbkar(
|
||||||
|
context: context,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.listDataNotUpdated,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteList(Filter list, String type) async {
|
||||||
|
ProcessModal processModal = ProcessModal(context: context);
|
||||||
|
processModal.open(AppLocalizations.of(context)!.deletingList);
|
||||||
|
|
||||||
|
final result1 = await deleteFilterList(server: serversProvider.selectedServer!, data: {
|
||||||
|
"url": list.url,
|
||||||
|
"whitelist": type == 'whitelist' ? true : false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result1['result'] == 'success') {
|
||||||
|
final result2 = await getFiltering(server: serversProvider.selectedServer!);
|
||||||
|
|
||||||
|
if (result2['result'] == 'success') {
|
||||||
|
serversProvider.setFilteringData(result2['data']);
|
||||||
|
serversProvider.setFilteringLoadStatus(1, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
appConfigProvider.addLog(result2['log']);
|
||||||
|
serversProvider.setFilteringLoadStatus(2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
processModal.close();
|
||||||
|
|
||||||
|
Navigator.pop(context); // Closes the screen
|
||||||
|
|
||||||
|
showSnacbkar(
|
||||||
|
context: context,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.listDeleted,
|
||||||
|
color: Colors.green
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processModal.close();
|
||||||
|
appConfigProvider.addLog(result1['log']);
|
||||||
|
|
||||||
|
showSnacbkar(
|
||||||
|
context: context,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
label: AppLocalizations.of(context)!.listNotDeleted,
|
||||||
|
color: Colors.red
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context)!.listDetails),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => AddListModal(
|
||||||
|
list: widget.list,
|
||||||
|
type: widget.type,
|
||||||
|
onEdit: confirmEditList
|
||||||
|
),
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent
|
||||||
|
)
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.edit),
|
||||||
|
tooltip: AppLocalizations.of(context)!.edit,
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => DeleteListModal(
|
||||||
|
onConfirm: () => deleteList(widget.list, widget.type),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
tooltip: AppLocalizations.of(context)!.delete,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
FilterListTile(
|
||||||
|
icon: Icons.shield_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.currentStatus,
|
||||||
|
subtitle: enabled == true
|
||||||
|
? AppLocalizations.of(context)!.enabled
|
||||||
|
: AppLocalizations.of(context)!.disabled,
|
||||||
|
color: enabled == true
|
||||||
|
? appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: Colors.green
|
||||||
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
|
? Colors.grey
|
||||||
|
: Colors.red,
|
||||||
|
bold: true,
|
||||||
|
),
|
||||||
|
FilterListTile(
|
||||||
|
icon: Icons.badge_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.name,
|
||||||
|
subtitle: name
|
||||||
|
),
|
||||||
|
FilterListTile(
|
||||||
|
icon: Icons.link_rounded,
|
||||||
|
title: "URL",
|
||||||
|
subtitle: widget.list.url
|
||||||
|
),
|
||||||
|
FilterListTile(
|
||||||
|
icon: Icons.list_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.rules,
|
||||||
|
subtitle: widget.list.rulesCount.toString()
|
||||||
|
),
|
||||||
|
FilterListTile(
|
||||||
|
icon: Icons.shield_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.listType,
|
||||||
|
subtitle: widget.type == 'whitelist'
|
||||||
|
? AppLocalizations.of(context)!.whitelist
|
||||||
|
: AppLocalizations.of(context)!.blacklist,
|
||||||
|
),
|
||||||
|
if (widget.list.lastUpdated != null) FilterListTile(
|
||||||
|
icon: Icons.schedule_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.latestUpdate,
|
||||||
|
subtitle: formatTimestampUTC(widget.list.lastUpdated!, 'dd-MM-yyyy HH:mm'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
AnimatedPositioned(
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
bottom: fabVisible ?
|
||||||
|
appConfigProvider.showingSnackbar
|
||||||
|
? 70 : 20
|
||||||
|
: -70,
|
||||||
|
right: 20,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
onPressed: () => enableDisableList(widget.list, !enabled),
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
|
child: Icon(
|
||||||
|
enabled == true
|
||||||
|
? Icons.gpp_bad_rounded
|
||||||
|
: Icons.verified_user_rounded,
|
||||||
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,18 +14,27 @@ class RemoveCustomRule extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.shield_rounded,
|
Icons.shield_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.removeCustomRule,
|
AppLocalizations.of(context)!.removeCustomRule,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Text(AppLocalizations.of(context)!.removeCustomRuleMessage),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.removeCustomRuleMessage,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
|
|
|
@ -42,7 +42,7 @@ class _UpdateIntervalListsModalState extends State<UpdateIntervalListsModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: mediaQueryData.viewInsets,
|
padding: mediaQueryData.viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 410,
|
height: 390,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
color: Theme.of(context).dialogBackgroundColor,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
|
@ -59,211 +59,216 @@ class _UpdateIntervalListsModalState extends State<UpdateIntervalListsModal> {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.update_rounded,
|
Icons.update_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
),
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(24),
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.updateFrequency,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 24,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Container(
|
||||||
SizedBox(
|
padding: const EdgeInsets.symmetric(
|
||||||
width: double.maxFinite,
|
horizontal: 24,
|
||||||
child: Padding(
|
vertical: 16
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
),
|
||||||
child: Column(
|
width: double.maxFinite,
|
||||||
children: [
|
child: Text(
|
||||||
Row(
|
AppLocalizations.of(context)!.updateFrequency,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
textAlign: TextAlign.center,
|
||||||
children: [
|
overflow: TextOverflow.ellipsis,
|
||||||
Container(
|
style: TextStyle(
|
||||||
width: (mediaQueryData.size.width-70)/2,
|
fontSize: 24,
|
||||||
margin: const EdgeInsets.only(
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
top: 10,
|
),
|
||||||
right: 5,
|
),
|
||||||
bottom: 5
|
),
|
||||||
),
|
SizedBox(
|
||||||
child: OptionBox(
|
width: double.maxFinite,
|
||||||
optionsValue: selectedOption,
|
child: Padding(
|
||||||
itemValue: 0,
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
onTap: _updateRadioValue,
|
child: Column(
|
||||||
child: Center(
|
children: [
|
||||||
child: AnimatedDefaultTextStyle(
|
Row(
|
||||||
duration: const Duration(milliseconds: 250),
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
style: TextStyle(
|
children: [
|
||||||
fontWeight: FontWeight.bold,
|
Container(
|
||||||
fontSize: 14,
|
width: (mediaQueryData.size.width-70)/2,
|
||||||
color: selectedOption == 0
|
margin: const EdgeInsets.only(
|
||||||
? Theme.of(context).primaryColor
|
top: 10,
|
||||||
: Theme.of(context).textTheme.bodyText1!.color
|
right: 5,
|
||||||
),
|
bottom: 5
|
||||||
child: Text(AppLocalizations.of(context)!.never),
|
),
|
||||||
),
|
child: OptionBox(
|
||||||
),
|
optionsValue: selectedOption,
|
||||||
),
|
itemValue: 0,
|
||||||
),
|
onTap: _updateRadioValue,
|
||||||
Container(
|
child: Center(
|
||||||
width: (mediaQueryData.size.width-70)/2,
|
child: AnimatedDefaultTextStyle(
|
||||||
margin: const EdgeInsets.only(
|
duration: const Duration(milliseconds: 250),
|
||||||
top: 10,
|
style: TextStyle(
|
||||||
left: 5,
|
fontWeight: FontWeight.bold,
|
||||||
bottom: 5
|
fontSize: 14,
|
||||||
),
|
color: selectedOption == 0
|
||||||
child: OptionBox(
|
? Theme.of(context).primaryColor
|
||||||
optionsValue: selectedOption,
|
: Theme.of(context).textTheme.bodyText1!.color
|
||||||
itemValue: 1,
|
),
|
||||||
onTap: _updateRadioValue,
|
child: Text(AppLocalizations.of(context)!.never),
|
||||||
child: Center(
|
),
|
||||||
child: AnimatedDefaultTextStyle(
|
),
|
||||||
duration: const Duration(milliseconds: 250),
|
),
|
||||||
style: TextStyle(
|
),
|
||||||
fontWeight: FontWeight.bold,
|
Container(
|
||||||
fontSize: 14,
|
width: (mediaQueryData.size.width-70)/2,
|
||||||
color: selectedOption == 1
|
margin: const EdgeInsets.only(
|
||||||
? Theme.of(context).primaryColor
|
top: 10,
|
||||||
: Theme.of(context).textTheme.bodyText1!.color
|
left: 5,
|
||||||
),
|
bottom: 5
|
||||||
child: Text(AppLocalizations.of(context)!.hour1),
|
),
|
||||||
),
|
child: OptionBox(
|
||||||
),
|
optionsValue: selectedOption,
|
||||||
),
|
itemValue: 1,
|
||||||
),
|
onTap: _updateRadioValue,
|
||||||
],
|
child: Center(
|
||||||
),
|
child: AnimatedDefaultTextStyle(
|
||||||
Row(
|
duration: const Duration(milliseconds: 250),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
style: TextStyle(
|
||||||
children: [
|
fontWeight: FontWeight.bold,
|
||||||
Container(
|
fontSize: 14,
|
||||||
width: (mediaQueryData.size.width-70)/2,
|
color: selectedOption == 1
|
||||||
margin: const EdgeInsets.only(
|
? Theme.of(context).primaryColor
|
||||||
top: 5,
|
: Theme.of(context).textTheme.bodyText1!.color
|
||||||
right: 5,
|
),
|
||||||
bottom: 5
|
child: Text(AppLocalizations.of(context)!.hour1),
|
||||||
),
|
),
|
||||||
child: OptionBox(
|
),
|
||||||
optionsValue: selectedOption,
|
),
|
||||||
itemValue: 12,
|
),
|
||||||
onTap: _updateRadioValue,
|
],
|
||||||
child: Center(
|
),
|
||||||
child: AnimatedDefaultTextStyle(
|
Row(
|
||||||
duration: const Duration(milliseconds: 250),
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
style: TextStyle(
|
children: [
|
||||||
fontWeight: FontWeight.bold,
|
Container(
|
||||||
fontSize: 14,
|
width: (mediaQueryData.size.width-70)/2,
|
||||||
color: selectedOption == 12
|
margin: const EdgeInsets.only(
|
||||||
? Theme.of(context).primaryColor
|
top: 5,
|
||||||
: Theme.of(context).textTheme.bodyText1!.color
|
right: 5,
|
||||||
),
|
bottom: 5
|
||||||
child: Text(AppLocalizations.of(context)!.hours12),
|
),
|
||||||
),
|
child: OptionBox(
|
||||||
),
|
optionsValue: selectedOption,
|
||||||
),
|
itemValue: 12,
|
||||||
),
|
onTap: _updateRadioValue,
|
||||||
Container(
|
child: Center(
|
||||||
width: (mediaQueryData.size.width-70)/2,
|
child: AnimatedDefaultTextStyle(
|
||||||
margin: const EdgeInsets.only(
|
duration: const Duration(milliseconds: 250),
|
||||||
top: 5,
|
style: TextStyle(
|
||||||
left: 5,
|
fontWeight: FontWeight.bold,
|
||||||
bottom: 5
|
fontSize: 14,
|
||||||
),
|
color: selectedOption == 12
|
||||||
child: OptionBox(
|
? Theme.of(context).primaryColor
|
||||||
optionsValue: selectedOption,
|
: Theme.of(context).textTheme.bodyText1!.color
|
||||||
itemValue: 24,
|
),
|
||||||
onTap: _updateRadioValue,
|
child: Text(AppLocalizations.of(context)!.hours12),
|
||||||
child: Center(
|
),
|
||||||
child: AnimatedDefaultTextStyle(
|
),
|
||||||
duration: const Duration(milliseconds: 250),
|
),
|
||||||
style: TextStyle(
|
),
|
||||||
fontWeight: FontWeight.bold,
|
Container(
|
||||||
fontSize: 14,
|
width: (mediaQueryData.size.width-70)/2,
|
||||||
color: selectedOption == 24
|
margin: const EdgeInsets.only(
|
||||||
? Theme.of(context).primaryColor
|
top: 5,
|
||||||
: Theme.of(context).textTheme.bodyText1!.color
|
left: 5,
|
||||||
),
|
bottom: 5
|
||||||
child: Text(AppLocalizations.of(context)!.hours24),
|
),
|
||||||
),
|
child: OptionBox(
|
||||||
),
|
optionsValue: selectedOption,
|
||||||
),
|
itemValue: 24,
|
||||||
),
|
onTap: _updateRadioValue,
|
||||||
],
|
child: Center(
|
||||||
),
|
child: AnimatedDefaultTextStyle(
|
||||||
Row(
|
duration: const Duration(milliseconds: 250),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
style: TextStyle(
|
||||||
children: [
|
fontWeight: FontWeight.bold,
|
||||||
Container(
|
fontSize: 14,
|
||||||
width: (mediaQueryData.size.width-70)/2,
|
color: selectedOption == 24
|
||||||
margin: const EdgeInsets.only(
|
? Theme.of(context).primaryColor
|
||||||
top: 5,
|
: Theme.of(context).textTheme.bodyText1!.color
|
||||||
right: 5,
|
),
|
||||||
bottom: 10
|
child: Text(AppLocalizations.of(context)!.hours24),
|
||||||
),
|
),
|
||||||
child: OptionBox(
|
),
|
||||||
optionsValue: selectedOption,
|
),
|
||||||
itemValue: 72,
|
),
|
||||||
onTap: _updateRadioValue,
|
],
|
||||||
child: Center(
|
),
|
||||||
child: AnimatedDefaultTextStyle(
|
Row(
|
||||||
duration: const Duration(milliseconds: 250),
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
style: TextStyle(
|
children: [
|
||||||
fontWeight: FontWeight.bold,
|
Container(
|
||||||
fontSize: 14,
|
width: (mediaQueryData.size.width-70)/2,
|
||||||
color: selectedOption == 72
|
margin: const EdgeInsets.only(
|
||||||
? Theme.of(context).primaryColor
|
top: 5,
|
||||||
: Theme.of(context).textTheme.bodyText1!.color
|
right: 5,
|
||||||
),
|
bottom: 10
|
||||||
child: Text(AppLocalizations.of(context)!.days3),
|
),
|
||||||
),
|
child: OptionBox(
|
||||||
),
|
optionsValue: selectedOption,
|
||||||
),
|
itemValue: 72,
|
||||||
),
|
onTap: _updateRadioValue,
|
||||||
Container(
|
child: Center(
|
||||||
width: (mediaQueryData.size.width-70)/2,
|
child: AnimatedDefaultTextStyle(
|
||||||
margin: const EdgeInsets.only(
|
duration: const Duration(milliseconds: 250),
|
||||||
top: 5,
|
style: TextStyle(
|
||||||
left: 5,
|
fontWeight: FontWeight.bold,
|
||||||
bottom: 10
|
fontSize: 14,
|
||||||
),
|
color: selectedOption == 72
|
||||||
child: OptionBox(
|
? Theme.of(context).primaryColor
|
||||||
optionsValue: selectedOption,
|
: Theme.of(context).textTheme.bodyText1!.color
|
||||||
itemValue: 168,
|
),
|
||||||
onTap: _updateRadioValue,
|
child: Text(AppLocalizations.of(context)!.days3),
|
||||||
child: Center(
|
),
|
||||||
child: AnimatedDefaultTextStyle(
|
),
|
||||||
duration: const Duration(milliseconds: 250),
|
),
|
||||||
style: TextStyle(
|
),
|
||||||
fontWeight: FontWeight.bold,
|
Container(
|
||||||
fontSize: 14,
|
width: (mediaQueryData.size.width-70)/2,
|
||||||
color: selectedOption == 168
|
margin: const EdgeInsets.only(
|
||||||
? Theme.of(context).primaryColor
|
top: 5,
|
||||||
: Theme.of(context).textTheme.bodyText1!.color
|
left: 5,
|
||||||
),
|
bottom: 10
|
||||||
child: Text(AppLocalizations.of(context)!.days7),
|
),
|
||||||
),
|
child: OptionBox(
|
||||||
),
|
optionsValue: selectedOption,
|
||||||
),
|
itemValue: 168,
|
||||||
),
|
onTap: _updateRadioValue,
|
||||||
],
|
child: Center(
|
||||||
),
|
child: AnimatedDefaultTextStyle(
|
||||||
],
|
duration: const Duration(milliseconds: 250),
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
color: selectedOption == 168
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: Theme.of(context).textTheme.bodyText1!.color
|
||||||
|
),
|
||||||
|
child: Text(AppLocalizations.of(context)!.days7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -66,9 +66,9 @@ class HomeAppBar extends StatelessWidget with PreferredSizeWidget {
|
||||||
? Theme.of(context).primaryColor
|
? Theme.of(context).primaryColor
|
||||||
: Colors.green
|
: Colors.green
|
||||||
: appConfigProvider.useThemeColorForStatus == true
|
: appConfigProvider.useThemeColorForStatus == true
|
||||||
? Colors.grey
|
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
: Colors.red
|
: Colors.red
|
||||||
: Colors.grey,
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
Column(
|
Column(
|
||||||
|
@ -84,9 +84,9 @@ class HomeAppBar extends StatelessWidget with PreferredSizeWidget {
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
Text(
|
Text(
|
||||||
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
|
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Color.fromRGBO(140, 140, 140, 1)
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -50,9 +50,10 @@ class HomeChart extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.w500
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
!isEmpty
|
!isEmpty
|
||||||
|
@ -110,10 +111,11 @@ class HomeChart extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: Divider(
|
child: Divider(
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
|
@ -24,9 +24,10 @@ class HomeFab extends StatelessWidget {
|
||||||
return serversProvider.serverStatus.loadStatus == 1
|
return serversProvider.serverStatus.loadStatus == 1
|
||||||
? FloatingActionButton(
|
? FloatingActionButton(
|
||||||
onPressed: openManagementBottomSheet,
|
onPressed: openManagementBottomSheet,
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.shield_rounded,
|
Icons.shield_rounded,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const SizedBox();
|
: const SizedBox();
|
||||||
|
|
|
@ -83,10 +83,11 @@ class _HomeState extends State<Home> {
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
children: [
|
children: [
|
||||||
ServerStatus(serverStatus: serversProvider.serverStatus.data!),
|
ServerStatus(serverStatus: serversProvider.serverStatus.data!),
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: Divider(
|
child: Divider(
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
@ -128,10 +129,11 @@ class _HomeState extends State<Home> {
|
||||||
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
|
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
|
||||||
type: 'topQueriedDomains',
|
type: 'topQueriedDomains',
|
||||||
),
|
),
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: Divider(
|
child: Divider(
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
@ -141,10 +143,11 @@ class _HomeState extends State<Home> {
|
||||||
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
|
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
|
||||||
type: 'topBlockedDomains',
|
type: 'topBlockedDomains',
|
||||||
),
|
),
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: Divider(
|
child: Divider(
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ManagementModal extends StatelessWidget {
|
||||||
|
|
||||||
Widget mainSwitch() {
|
Widget mainSwitch() {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
borderRadius: BorderRadius.circular(28),
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
@ -84,7 +84,7 @@ class ManagementModal extends StatelessWidget {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 35,
|
horizontal: 35,
|
||||||
vertical: 5
|
vertical: 8
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -94,12 +94,15 @@ class ManagementModal extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -136,53 +139,55 @@ class ManagementModal extends StatelessWidget {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.shield_rounded,
|
Icons.shield_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
),
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.manageServer,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 22
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
mainSwitch(),
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
const SizedBox(height: 10),
|
child: Text(
|
||||||
smallSwitch(
|
AppLocalizations.of(context)!.manageServer,
|
||||||
AppLocalizations.of(context)!.ruleFiltering,
|
textAlign: TextAlign.center,
|
||||||
Icons.filter_list_rounded,
|
style: TextStyle(
|
||||||
serversProvider.serverStatus.data!.filteringEnabled,
|
fontSize: 24,
|
||||||
(value) => updateBlocking(value, 'filtering'),
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
serversProvider.protectionsManagementProcess.contains('filtering')
|
),
|
||||||
),
|
),
|
||||||
smallSwitch(
|
),
|
||||||
AppLocalizations.of(context)!.safeBrowsing,
|
mainSwitch(),
|
||||||
Icons.vpn_lock_rounded,
|
const SizedBox(height: 10),
|
||||||
serversProvider.serverStatus.data!.safeBrowsingEnabled,
|
smallSwitch(
|
||||||
(value) => updateBlocking(value, 'safeBrowsing'),
|
AppLocalizations.of(context)!.ruleFiltering,
|
||||||
serversProvider.protectionsManagementProcess.contains('safeBrowsing')
|
Icons.filter_list_rounded,
|
||||||
),
|
serversProvider.serverStatus.data!.filteringEnabled,
|
||||||
smallSwitch(
|
(value) => updateBlocking(value, 'filtering'),
|
||||||
AppLocalizations.of(context)!.parentalFiltering,
|
serversProvider.protectionsManagementProcess.contains('filtering')
|
||||||
Icons.block,
|
),
|
||||||
serversProvider.serverStatus.data!.parentalControlEnabled,
|
smallSwitch(
|
||||||
(value) => updateBlocking(value, 'parentalControl'),
|
AppLocalizations.of(context)!.safeBrowsing,
|
||||||
serversProvider.protectionsManagementProcess.contains('parentalControl')
|
Icons.vpn_lock_rounded,
|
||||||
),
|
serversProvider.serverStatus.data!.safeBrowsingEnabled,
|
||||||
smallSwitch(
|
(value) => updateBlocking(value, 'safeBrowsing'),
|
||||||
AppLocalizations.of(context)!.safeSearch,
|
serversProvider.protectionsManagementProcess.contains('safeBrowsing')
|
||||||
Icons.search_rounded,
|
),
|
||||||
serversProvider.serverStatus.data!.safeSearchEnabled,
|
smallSwitch(
|
||||||
(value) => updateBlocking(value, 'safeSearch'),
|
AppLocalizations.of(context)!.parentalFiltering,
|
||||||
serversProvider.protectionsManagementProcess.contains('safeSearch')
|
Icons.block,
|
||||||
),
|
serversProvider.serverStatus.data!.parentalControlEnabled,
|
||||||
|
(value) => updateBlocking(value, 'parentalControl'),
|
||||||
|
serversProvider.protectionsManagementProcess.contains('parentalControl')
|
||||||
|
),
|
||||||
|
smallSwitch(
|
||||||
|
AppLocalizations.of(context)!.safeSearch,
|
||||||
|
Icons.search_rounded,
|
||||||
|
serversProvider.serverStatus.data!.safeSearchEnabled,
|
||||||
|
(value) => updateBlocking(value, 'safeSearch'),
|
||||||
|
serversProvider.protectionsManagementProcess.contains('safeSearch')
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -21,9 +21,10 @@ class ServerStatus extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.serverStatus,
|
AppLocalizations.of(context)!.serverStatus,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.w500
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
|
@ -48,8 +48,9 @@ class TopItems extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
item.keys.toList()[0],
|
item.keys.toList()[0],
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (name != null) ...[
|
if (name != null) ...[
|
||||||
|
@ -59,14 +60,19 @@ class TopItems extends StatelessWidget {
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).listTileTheme.iconColor
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(item.values.toList()[0].toString())
|
Text(
|
||||||
|
item.values.toList()[0].toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -93,9 +99,10 @@ class TopItems extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.w500
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
|
@ -48,7 +48,7 @@ class _FilterStatusModalState extends State<FilterStatusModal> {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onChanged(id),
|
onTap: () => onChanged(id),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -57,12 +57,14 @@ class _FilterStatusModalState extends State<FilterStatusModal> {
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -80,8 +82,8 @@ class _FilterStatusModalState extends State<FilterStatusModal> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: height >= 680 == true
|
height: height >= 720 == true
|
||||||
? 680
|
? 720
|
||||||
: height-25,
|
: height-25,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
|
@ -92,26 +94,29 @@ class _FilterStatusModalState extends State<FilterStatusModal> {
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 24,
|
top: 24,
|
||||||
bottom: 20,
|
bottom: 16,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.shield_rounded,
|
Icons.shield_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.responseStatus,
|
AppLocalizations.of(context)!.responseStatus,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
physics: height >= 680 == true
|
physics: height >= 720 == true
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
|
@ -168,7 +173,7 @@ class _FilterStatusModalState extends State<FilterStatusModal> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -1,276 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/logs/log_list_tile.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/functions/get_filtered_status.dart';
|
|
||||||
import 'package:adguard_home_manager/functions/format_time.dart';
|
|
||||||
import 'package:adguard_home_manager/models/filtering_status.dart';
|
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
|
||||||
import 'package:adguard_home_manager/models/logs.dart';
|
|
||||||
|
|
||||||
class LogDetailsModal extends StatelessWidget {
|
|
||||||
final ScrollController scrollController;
|
|
||||||
final Log log;
|
|
||||||
final void Function(Log, String) blockUnblock;
|
|
||||||
|
|
||||||
const LogDetailsModal({
|
|
||||||
Key? key,
|
|
||||||
required this.scrollController,
|
|
||||||
required this.log,
|
|
||||||
required this.blockUnblock
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final serversProvider = Provider.of<ServersProvider>(context);
|
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
|
||||||
|
|
||||||
Filter getList(int id) {
|
|
||||||
return serversProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () {
|
|
||||||
return serversProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget getResult() {
|
|
||||||
final filter = getFilteredStatus(context, appConfigProvider, log.reason, true);
|
|
||||||
return Text(
|
|
||||||
filter['label'],
|
|
||||||
style: TextStyle(
|
|
||||||
color: filter['color'],
|
|
||||||
fontWeight: FontWeight.w500
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(28),
|
|
||||||
topRight: Radius.circular(28),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
controller: scrollController,
|
|
||||||
children: [
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
top: 28,
|
|
||||||
bottom: 20,
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.list_rounded,
|
|
||||||
size: 26,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context)!.logDetails,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 24
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.status,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.shield_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.result,
|
|
||||||
subtitleWidget: getResult(),
|
|
||||||
trailing: log.cached == true
|
|
||||||
? Container(
|
|
||||||
padding: const EdgeInsets.all(5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
|
||||||
borderRadius: BorderRadius.circular(10)
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
"CACHE",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.w500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
if (log.rule != null) LogListTile(
|
|
||||||
icon: Icons.block,
|
|
||||||
title: AppLocalizations.of(context)!.blockingRule,
|
|
||||||
subtitle: log.rule
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.schedule,
|
|
||||||
title: AppLocalizations.of(context)!.time,
|
|
||||||
subtitle: formatTimestampUTCFromAPI(log.time, 'HH:mm:ss')
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.request,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.domain_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.domain,
|
|
||||||
subtitle: log.question.name
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.category_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.type,
|
|
||||||
subtitle: log.question.type
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.class_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.clas,
|
|
||||||
subtitle: log.question.questionClass
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.response,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (log.upstream != '') LogListTile(
|
|
||||||
icon: Icons.dns_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.dnsServer,
|
|
||||||
subtitle: log.upstream
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.timer_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.elapsedTime,
|
|
||||||
subtitle: "${double.parse(log.elapsedMs).toStringAsFixed(2)} ms"
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.system_update_alt_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.responseCode,
|
|
||||||
subtitle: log.status
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.client,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
LogListTile(
|
|
||||||
icon: Icons.smartphone_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.deviceIp,
|
|
||||||
subtitle: log.client
|
|
||||||
),
|
|
||||||
if (log.clientInfo != null && log.clientInfo!.name != '') LogListTile(
|
|
||||||
icon: Icons.abc_rounded,
|
|
||||||
title: AppLocalizations.of(context)!.deviceName,
|
|
||||||
subtitle: log.clientInfo!.name
|
|
||||||
),
|
|
||||||
if (log.rules.isNotEmpty) ...[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.rules,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
...log.rules.map((rule) => LogListTile(
|
|
||||||
icon: Icons.rule_rounded,
|
|
||||||
title: rule.text,
|
|
||||||
subtitle: getList(rule.filterListId).name,
|
|
||||||
)).toList()
|
|
||||||
],
|
|
||||||
if (log.answer.isNotEmpty) ...[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Text(
|
|
||||||
AppLocalizations.of(context)!.answer,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).primaryColor
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
...log.answer.map((a) => LogListTile(
|
|
||||||
icon: Icons.download_rounded,
|
|
||||||
title: a.value,
|
|
||||||
subtitle: "TTL: ${a.ttl.toString()}",
|
|
||||||
trailing: Container(
|
|
||||||
padding: const EdgeInsets.all(5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
|
||||||
borderRadius: BorderRadius.circular(10)
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
a.type,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.w500
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)).toList()
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
blockUnblock(log, getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block');
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
|
|
||||||
? AppLocalizations.of(context)!.unblockDomain
|
|
||||||
: AppLocalizations.of(context)!.blockDomain
|
|
||||||
)
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text(AppLocalizations.of(context)!.close)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
299
lib/screens/logs/log_details_screen.dart
Normal file
299
lib/screens/logs/log_details_screen.dart
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/screens/logs/log_list_tile.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||||
|
import 'package:adguard_home_manager/functions/get_filtered_status.dart';
|
||||||
|
import 'package:adguard_home_manager/models/logs.dart';
|
||||||
|
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||||
|
import 'package:adguard_home_manager/functions/format_time.dart';
|
||||||
|
import 'package:adguard_home_manager/models/filtering_status.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
|
||||||
|
class LogDetailsScreen extends StatelessWidget {
|
||||||
|
final Log log;
|
||||||
|
|
||||||
|
const LogDetailsScreen({
|
||||||
|
Key? key,
|
||||||
|
required this.log
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
Filter getList(int id) {
|
||||||
|
return serversProvider.filteringStatus!.filters.firstWhere((filter) => filter.id == id, orElse: () {
|
||||||
|
return serversProvider.filteringStatus!.whitelistFilters.firstWhere((filter) => filter.id == id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getResult() {
|
||||||
|
final filter = getFilteredStatus(context, appConfigProvider, log.reason, true);
|
||||||
|
return Text(
|
||||||
|
filter['label'],
|
||||||
|
style: TextStyle(
|
||||||
|
color: filter['color'],
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blockUnblock(Log log, 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.filteringStatus!;
|
||||||
|
|
||||||
|
List<String> newRules = rules['data'].userRules.where((domain) => !domain.contains(log.question.name)).toList();
|
||||||
|
if (newStatus == 'block') {
|
||||||
|
newRules.add("||${log.question.name}^");
|
||||||
|
}
|
||||||
|
else if (newStatus == 'unblock') {
|
||||||
|
newRules.add("@@||${log.question.name}^");
|
||||||
|
}
|
||||||
|
FilteringStatus newObj = serversProvider.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,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context)!.logDetails),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => blockUnblock(log, getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true ? 'unblock' : 'block'),
|
||||||
|
icon: Icon(
|
||||||
|
getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
|
||||||
|
? Icons.check_circle_rounded
|
||||||
|
: Icons.block
|
||||||
|
),
|
||||||
|
tooltip: getFilteredStatus(context, appConfigProvider, log.reason, true)['filtered'] == true
|
||||||
|
? AppLocalizations.of(context)!.unblockDomain
|
||||||
|
: AppLocalizations.of(context)!.blockDomain,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: ListView(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.status,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.shield_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.result,
|
||||||
|
subtitleWidget: getResult(),
|
||||||
|
trailing: log.cached == true
|
||||||
|
? Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 5
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular(30)
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"CACHE",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
if (log.rule != null) LogListTile(
|
||||||
|
icon: Icons.block,
|
||||||
|
title: AppLocalizations.of(context)!.blockingRule,
|
||||||
|
subtitle: log.rule
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.schedule,
|
||||||
|
title: AppLocalizations.of(context)!.time,
|
||||||
|
subtitle: formatTimestampUTCFromAPI(log.time, 'HH:mm:ss')
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.request,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.domain_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.domain,
|
||||||
|
subtitle: log.question.name
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.category_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.type,
|
||||||
|
subtitle: log.question.type
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.class_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.clas,
|
||||||
|
subtitle: log.question.questionClass
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.response,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (log.upstream != '') LogListTile(
|
||||||
|
icon: Icons.dns_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.dnsServer,
|
||||||
|
subtitle: log.upstream
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.timer_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.elapsedTime,
|
||||||
|
subtitle: "${double.parse(log.elapsedMs).toStringAsFixed(2)} ms"
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.system_update_alt_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.responseCode,
|
||||||
|
subtitle: log.status
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.client,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
LogListTile(
|
||||||
|
icon: Icons.smartphone_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.deviceIp,
|
||||||
|
subtitle: log.client
|
||||||
|
),
|
||||||
|
if (log.clientInfo != null && log.clientInfo!.name != '') LogListTile(
|
||||||
|
icon: Icons.abc_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.deviceName,
|
||||||
|
subtitle: log.clientInfo!.name
|
||||||
|
),
|
||||||
|
if (log.rules.isNotEmpty) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.rules,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...log.rules.map((rule) => LogListTile(
|
||||||
|
icon: Icons.rule_rounded,
|
||||||
|
title: rule.text,
|
||||||
|
subtitle: getList(rule.filterListId).name,
|
||||||
|
)).toList()
|
||||||
|
],
|
||||||
|
if (log.answer.isNotEmpty) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.answer,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).primaryColor
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...log.answer.map((a) => LogListTile(
|
||||||
|
icon: Icons.download_rounded,
|
||||||
|
title: a.value,
|
||||||
|
subtitle: "TTL: ${a.ttl.toString()}",
|
||||||
|
trailing: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 5
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
|
borderRadius: BorderRadius.circular(30)
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
a.type,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)).toList()
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ class LogListTile extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -29,8 +29,9 @@ class LogListTile extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 16),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -38,15 +39,16 @@ class LogListTile extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 3),
|
||||||
subtitleWidget ?? Text(
|
subtitleWidget ?? Text(
|
||||||
subtitle!,
|
subtitle!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -56,7 +58,7 @@ class LogListTile extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (trailing != null) ...[
|
if (trailing != null) ...[
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 16),
|
||||||
trailing!
|
trailing!
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,17 +2,11 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:bottom_sheet/bottom_sheet.dart';
|
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/logs/log_details_modal.dart';
|
import 'package:adguard_home_manager/screens/logs/log_details_screen.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/models/filtering_status.dart';
|
|
||||||
import 'package:adguard_home_manager/classes/process_modal.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/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';
|
||||||
|
|
||||||
|
@ -30,7 +24,6 @@ class LogTile extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final serversProvider = Provider.of<ServersProvider>(context);
|
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
final width = MediaQuery.of(context).size.width;
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
@ -71,86 +64,15 @@ class LogTile extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockUnblock(Log log, 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.filteringStatus!;
|
|
||||||
|
|
||||||
List<String> newRules = rules['data'].userRules.where((domain) => !domain.contains(log.question.name)).toList();
|
|
||||||
if (newStatus == 'block') {
|
|
||||||
newRules.add("||${log.question.name}^");
|
|
||||||
}
|
|
||||||
else if (newStatus == 'unblock') {
|
|
||||||
newRules.add("@@||${log.question.name}^");
|
|
||||||
}
|
|
||||||
FilteringStatus newObj = serversProvider.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 openLogDetailsModal() {
|
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
|
||||||
showFlexibleBottomSheet(
|
|
||||||
minHeight: 0.6,
|
|
||||||
initHeight: 0.6,
|
|
||||||
maxHeight: 0.95,
|
|
||||||
isCollapsible: true,
|
|
||||||
duration: const Duration(milliseconds: 250),
|
|
||||||
anchors: [0.95],
|
|
||||||
context: context,
|
|
||||||
builder: (ctx, controller, offset) => LogDetailsModal(
|
|
||||||
scrollController: controller,
|
|
||||||
log: log,
|
|
||||||
blockUnblock: blockUnblock,
|
|
||||||
),
|
|
||||||
bottomSheetColor: Colors.transparent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: openLogDetailsModal,
|
onTap: () => Navigator.push(context, MaterialPageRoute(
|
||||||
|
builder: (context) => LogDetailsScreen(log: log)
|
||||||
|
)),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -161,19 +83,21 @@ class LogTile extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
log.question.name,
|
log.question.name,
|
||||||
overflow: TextOverflow.ellipsis,
|
style: TextStyle(
|
||||||
style: const TextStyle(
|
fontSize: 16,
|
||||||
fontSize: 18
|
height: 1.5,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 5),
|
||||||
if (log.client.length <= 15 && appConfigProvider.showNameTimeLogs == false) Row(
|
if (log.client.length <= 15 && appConfigProvider.showNameTimeLogs == false) Row(
|
||||||
children: [
|
children: [
|
||||||
...[
|
...[
|
||||||
Icon(
|
Icon(
|
||||||
Icons.smartphone_rounded,
|
Icons.smartphone_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -181,8 +105,10 @@ class LogTile extends StatelessWidget {
|
||||||
log.client,
|
log.client,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 13
|
fontSize: 14,
|
||||||
|
height: 1.4,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -192,7 +118,7 @@ class LogTile extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.schedule_rounded,
|
Icons.schedule_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -200,7 +126,7 @@ class LogTile extends StatelessWidget {
|
||||||
formatTimestampUTCFromAPI(log.time, 'HH:mm:ss'),
|
formatTimestampUTCFromAPI(log.time, 'HH:mm:ss'),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -215,7 +141,7 @@ class LogTile extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.smartphone_rounded,
|
Icons.smartphone_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -223,7 +149,7 @@ class LogTile extends StatelessWidget {
|
||||||
log.client,
|
log.client,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -237,7 +163,7 @@ class LogTile extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.badge_rounded,
|
Icons.badge_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -245,7 +171,7 @@ class LogTile extends StatelessWidget {
|
||||||
log.clientInfo!.name,
|
log.clientInfo!.name,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -259,7 +185,7 @@ class LogTile extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.schedule_rounded,
|
Icons.schedule_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -267,7 +193,7 @@ class LogTile extends StatelessWidget {
|
||||||
formatTimestampUTCFromAPI(log.time, 'HH:mm:ss'),
|
formatTimestampUTCFromAPI(log.time, 'HH:mm:ss'),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -281,7 +207,7 @@ class LogTile extends StatelessWidget {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.timer,
|
Icons.timer,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
@ -289,7 +215,7 @@ class LogTile extends StatelessWidget {
|
||||||
"${double.parse(log.elapsedMs).toStringAsFixed(2)} ms",
|
"${double.parse(log.elapsedMs).toStringAsFixed(2)} ms",
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 13
|
fontSize: 13
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -224,11 +224,11 @@ class _LogsWidgetState extends State<LogsWidget> {
|
||||||
final Map<String, String> translatedString = {
|
final Map<String, String> translatedString = {
|
||||||
"all": AppLocalizations.of(context)!.all,
|
"all": AppLocalizations.of(context)!.all,
|
||||||
"filtered": AppLocalizations.of(context)!.filtered,
|
"filtered": AppLocalizations.of(context)!.filtered,
|
||||||
"processed": AppLocalizations.of(context)!.processed,
|
"processed": AppLocalizations.of(context)!.processedRow,
|
||||||
"whitelisted": AppLocalizations.of(context)!.processedWhitelist,
|
"whitelisted": AppLocalizations.of(context)!.processedWhitelistRow,
|
||||||
"blocked": AppLocalizations.of(context)!.blocked,
|
"blocked": AppLocalizations.of(context)!.blocked,
|
||||||
"blocked_safebrowsing": AppLocalizations.of(context)!.blockedSafeBrowsing,
|
"blocked_safebrowsing": AppLocalizations.of(context)!.blockedSafeBrowsingRow,
|
||||||
"blocked_parental": AppLocalizations.of(context)!.blockedParental,
|
"blocked_parental": AppLocalizations.of(context)!.blockedParentalRow,
|
||||||
"safe_search": AppLocalizations.of(context)!.safeSearch,
|
"safe_search": AppLocalizations.of(context)!.safeSearch,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -392,17 +392,26 @@ class _LogsWidgetState extends State<LogsWidget> {
|
||||||
if (logsProvider.appliedFilters.searchText != null) ...[
|
if (logsProvider.appliedFilters.searchText != null) ...[
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
Chip(
|
Chip(
|
||||||
|
avatar: Icon(
|
||||||
|
Icons.search,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
label: Row(
|
label: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.search),
|
Text(
|
||||||
const SizedBox(width: 10),
|
logsProvider.appliedFilters.searchText!,
|
||||||
Text(logsProvider.appliedFilters.searchText!),
|
style: const TextStyle(
|
||||||
const SizedBox(width: 10),
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
deleteIcon: const Icon(
|
deleteIcon: Icon(
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
size: 20,
|
size: 18,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
logsProvider.setAppliedFilters(
|
logsProvider.setAppliedFilters(
|
||||||
|
@ -417,22 +426,38 @@ class _LogsWidgetState extends State<LogsWidget> {
|
||||||
searchText: ''
|
searchText: ''
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
),
|
||||||
|
backgroundColor: Theme.of(context).dialogBackgroundColor,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
|
if (logsProvider.appliedFilters.selectedResultStatus != 'all') ...[
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
Chip(
|
Chip(
|
||||||
|
avatar: Icon(
|
||||||
|
Icons.shield_rounded,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
label: Row(
|
label: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.shield_rounded),
|
Text(
|
||||||
const SizedBox(width: 10),
|
translatedString[logsProvider.appliedFilters.selectedResultStatus]!,
|
||||||
Text(translatedString[logsProvider.appliedFilters.selectedResultStatus]!),
|
style: const TextStyle(
|
||||||
const SizedBox(width: 10),
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
deleteIcon: const Icon(
|
deleteIcon: Icon(
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
size: 20,
|
size: 18,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
logsProvider.setAppliedFilters(
|
logsProvider.setAppliedFilters(
|
||||||
|
@ -447,6 +472,13 @@ class _LogsWidgetState extends State<LogsWidget> {
|
||||||
responseStatus: 'all'
|
responseStatus: 'all'
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
),
|
||||||
|
backgroundColor: Theme.of(context).dialogBackgroundColor,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
|
|
|
@ -122,28 +122,30 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
physics: 450 < MediaQuery.of(context).size.height
|
physics: 420 < MediaQuery.of(context).size.height
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.settings,
|
Icons.settings,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.logsSettings,
|
AppLocalizations.of(context)!.logsSettings,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
borderRadius: BorderRadius.circular(28),
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
@ -175,7 +177,7 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Material(
|
Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
@ -201,9 +203,9 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: DropdownButtonFormField(
|
child: DropdownButtonFormField(
|
||||||
items: retentionItems.map<DropdownMenuItem<String>>((Map<String, dynamic> item) {
|
items: retentionItems.map<DropdownMenuItem<String>>((Map<String, dynamic> item) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
|
@ -228,7 +230,7 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -308,7 +310,7 @@ class _LogsConfigModalWidgetState extends State<LogsConfigModalWidget> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 450,
|
height: 420,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(28),
|
topLeft: Radius.circular(28),
|
||||||
|
|
|
@ -171,7 +171,7 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 400,
|
height: 360,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
color: Theme.of(context).dialogBackgroundColor,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
|
@ -187,30 +187,33 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 24,
|
top: 24,
|
||||||
bottom: 20,
|
bottom: 16,
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.filter_list_rounded,
|
Icons.filter_list_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.filters,
|
AppLocalizations.of(context)!.filters,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
height: 1.3,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
Expanded(
|
||||||
width: MediaQuery.of(context).size.width - 108,
|
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: searchController,
|
controller: searchController,
|
||||||
onChanged: (value) => logsProvider.setSearchText(value),
|
onChanged: (value) => logsProvider.setSearchText(value),
|
||||||
|
@ -222,22 +225,22 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
labelText: AppLocalizations.of(context)!.search,
|
labelText: AppLocalizations.of(context)!.search,
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
searchController.text = '';
|
||||||
|
});
|
||||||
|
logsProvider.setSearchText(null);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.clear)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
searchController.text = '';
|
|
||||||
});
|
|
||||||
logsProvider.setSearchText(null);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.clear)
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
// Material(
|
// Material(
|
||||||
// color: Colors.transparent,
|
// color: Colors.transparent,
|
||||||
// child: InkWell(
|
// child: InkWell(
|
||||||
|
@ -284,12 +287,13 @@ class _LogsFiltersModalWidgetState extends State<LogsFiltersModalWidget> {
|
||||||
subtitle: "${translatedString[logsProvider.selectedResultStatus]}",
|
subtitle: "${translatedString[logsProvider.selectedResultStatus]}",
|
||||||
onTap: openSelectFilterStatus,
|
onTap: openSelectFilterStatus,
|
||||||
icon: Icons.shield_rounded,
|
icon: Icons.shield_rounded,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -88,9 +88,10 @@ class _ServersState extends State<Servers> {
|
||||||
right: 20,
|
right: 20,
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
onPressed: openAddServerModal,
|
onPressed: openAddServerModal,
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -91,36 +91,19 @@ class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with Ticker
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
isScrollable: true,
|
isScrollable: true,
|
||||||
|
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.check),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.allowedClients,
|
||||||
children: [
|
|
||||||
const Icon(Icons.check),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.allowedClients)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.block),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.disallowedClients,
|
||||||
children: [
|
|
||||||
const Icon(Icons.block),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.disallowedClients)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Tab(
|
Tab(
|
||||||
child: Row(
|
icon: const Icon(Icons.link_rounded),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
text: AppLocalizations.of(context)!.disallowedDomains,
|
||||||
children: [
|
|
||||||
const Icon(Icons.link_rounded),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
Text(AppLocalizations.of(context)!.disallowedDomains)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -134,9 +117,7 @@ class _AccessSettingsWidgetState extends State<AccessSettingsWidget> with Ticker
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
top: BorderSide(
|
||||||
color: Theme.of(context).brightness == Brightness.light
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.1)
|
||||||
? const Color.fromRGBO(220, 220, 220, 1)
|
|
||||||
: const Color.fromRGBO(50, 50, 50, 1)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
@ -66,8 +66,8 @@ class _AddClientModalState extends State<AddClientModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 322,
|
height: 305,
|
||||||
padding: const EdgeInsets.all(28),
|
padding: const EdgeInsets.all(24),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
color: Theme.of(context).dialogBackgroundColor,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
|
@ -85,17 +85,19 @@ class _AddClientModalState extends State<AddClientModal> {
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
icon(),
|
icon(),
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
title(),
|
title(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: fieldController,
|
controller: fieldController,
|
||||||
onChanged: (_) => checkValidValues(),
|
onChanged: (_) => checkValidValues(),
|
||||||
|
@ -117,7 +119,7 @@ class _AddClientModalState extends State<AddClientModal> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 20),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -244,11 +244,18 @@ class _ClientsListState extends State<ClientsList> {
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.info_rounded),
|
Icon(
|
||||||
|
Icons.info_rounded,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width-112,
|
child: Text(
|
||||||
child: Text(description()),
|
description(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -260,7 +267,13 @@ class _ClientsListState extends State<ClientsList> {
|
||||||
padding: const EdgeInsets.only(top: 0),
|
padding: const EdgeInsets.only(top: 0),
|
||||||
itemCount: widget.data.length,
|
itemCount: widget.data.length,
|
||||||
itemBuilder: (context, index) => ListTile(
|
itemBuilder: (context, index) => ListTile(
|
||||||
title: Text(widget.data[index]),
|
title: Text(
|
||||||
|
widget.data[index],
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed: () => {
|
onPressed: () => {
|
||||||
showDialog(
|
showDialog(
|
||||||
|
@ -308,6 +321,7 @@ class _ClientsListState extends State<ClientsList> {
|
||||||
: -70,
|
: -70,
|
||||||
right: 20,
|
right: 20,
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -321,7 +335,7 @@ class _ClientsListState extends State<ClientsList> {
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -68,7 +68,7 @@ class _AddStaticLeaseModalState extends State<AddStaticLeaseModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 550,
|
height: 510,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).dialogBackgroundColor,
|
color: Theme.of(context).dialogBackgroundColor,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
|
@ -84,22 +84,24 @@ class _AddStaticLeaseModalState extends State<AddStaticLeaseModal> {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.addStaticLease,
|
AppLocalizations.of(context)!.addStaticLease,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 28),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
|
|
|
@ -14,18 +14,27 @@ class DeleteStaticLeaseModal extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.delete_rounded,
|
Icons.delete_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.deleteStaticLease,
|
AppLocalizations.of(context)!.deleteStaticLease,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Text(AppLocalizations.of(context)!.deleteStaticLeaseDescription),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.deleteStaticLeaseDescription,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
|
|
|
@ -375,8 +375,8 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 10,
|
top: 10,
|
||||||
left: 12,
|
left: 24,
|
||||||
right: 12
|
right: 24
|
||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
|
@ -399,8 +399,9 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.enableDhcpServer,
|
AppLocalizations.of(context)!.enableDhcpServer,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (selectedInterface != null) ...[
|
if (selectedInterface != null) ...[
|
||||||
|
@ -408,7 +409,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
selectedInterface!.name,
|
selectedInterface!.name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -432,7 +433,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
label: AppLocalizations.of(context)!.ipv4settings,
|
label: AppLocalizations.of(context)!.ipv4settings,
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv4StartRangeController,
|
controller: ipv4StartRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
|
@ -451,7 +452,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv4EndRangeController,
|
controller: ipv4EndRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
|
@ -470,7 +471,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv4SubnetMaskController,
|
controller: ipv4SubnetMaskController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4SubnetMaskError', AppLocalizations.of(context)!.subnetMaskNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4SubnetMaskError', AppLocalizations.of(context)!.subnetMaskNotValid),
|
||||||
|
@ -489,7 +490,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv4GatewayController,
|
controller: ipv4GatewayController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv4GatewayError', AppLocalizations.of(context)!.gatewayNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv4GatewayError', AppLocalizations.of(context)!.gatewayNotValid),
|
||||||
|
@ -508,7 +509,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv4LeaseTimeController,
|
controller: ipv4LeaseTimeController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -538,7 +539,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
label: AppLocalizations.of(context)!.ipv6settings,
|
label: AppLocalizations.of(context)!.ipv6settings,
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv6StartRangeController,
|
controller: ipv6StartRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv6StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv6StartRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
|
@ -557,7 +558,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv6EndRangeController,
|
controller: ipv6EndRangeController,
|
||||||
onChanged: (value) => validateIpV4(value, 'ipv6EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
onChanged: (value) => validateIpV4(value, 'ipv6EndRangeError', AppLocalizations.of(context)!.ipNotValid),
|
||||||
|
@ -576,7 +577,7 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv6LeaseTimeController,
|
controller: ipv6LeaseTimeController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -617,18 +618,22 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.dhcpLeases,
|
AppLocalizations.of(context)!.dhcpLeases,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Icon(Icons.arrow_forward_rounded)
|
Icon(
|
||||||
|
Icons.arrow_forward_rounded,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -646,18 +651,22 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.dhcpStatic,
|
AppLocalizations.of(context)!.dhcpStatic,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Icon(Icons.arrow_forward_rounded)
|
Icon(
|
||||||
|
Icons.arrow_forward_rounded,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -678,9 +687,9 @@ class _DhcpWidgetState extends State<DhcpWidget> {
|
||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(context)!.neededSelectInterface,
|
AppLocalizations.of(context)!.neededSelectInterface,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
color: Colors.grey
|
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.5)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -184,9 +184,10 @@ class DhcpLeases extends StatelessWidget {
|
||||||
floatingActionButton: staticLeases == true
|
floatingActionButton: staticLeases == true
|
||||||
? FloatingActionButton(
|
? FloatingActionButton(
|
||||||
onPressed: openAddStaticLease,
|
onPressed: openAddStaticLease,
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
|
|
@ -31,22 +31,24 @@ class SelectInterfaceModal extends StatelessWidget {
|
||||||
child: ListView(
|
child: ListView(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.settings_ethernet_rounded,
|
Icons.settings_ethernet_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.selectInterface,
|
AppLocalizations.of(context)!.selectInterface,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
primary: false,
|
primary: false,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
@ -59,38 +61,54 @@ class SelectInterfaceModal extends StatelessWidget {
|
||||||
onSelect(interfaces[index]);
|
onSelect(interfaces[index]);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
interfaces[index].name,
|
interfaces[index].name,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${AppLocalizations.of(context)!.hardwareAddress}: ",
|
"${AppLocalizations.of(context)!.hardwareAddress}: ",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
interfaces[index].hardwareAddress,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(interfaces[index].hardwareAddress),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
if (interfaces[index].flags.isNotEmpty) ...[
|
if (interfaces[index].flags.isNotEmpty) ...[
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
"Flags: ",
|
"Flags: ",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
interfaces[index].flags.join(', '),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(interfaces[index].flags.join(', ')),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
|
@ -100,11 +118,18 @@ class SelectInterfaceModal extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${AppLocalizations.of(context)!.gatewayIp}: ",
|
"${AppLocalizations.of(context)!.gatewayIp}: ",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
interfaces[index].gatewayIp,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(interfaces[index].gatewayIp),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
|
@ -114,11 +139,18 @@ class SelectInterfaceModal extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${AppLocalizations.of(context)!.ipv4addresses}: ",
|
"${AppLocalizations.of(context)!.ipv4addresses}: ",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
interfaces[index].ipv4Addresses.join(', '),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(interfaces[index].ipv4Addresses.join(', ')),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
|
@ -128,11 +160,18 @@ class SelectInterfaceModal extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${AppLocalizations.of(context)!.ipv4addresses}: ",
|
"${AppLocalizations.of(context)!.ipv4addresses}: ",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
interfaces[index].ipv6Addresses.join(', '),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(interfaces[index].ipv6Addresses.join(', ')),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -140,11 +140,18 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.info_rounded),
|
Icon(
|
||||||
|
Icons.info_rounded,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width-132,
|
child: Text(
|
||||||
child: Text(AppLocalizations.of(context)!.bootstrapDnsServersInfo)
|
AppLocalizations.of(context)!.bootstrapDnsServersInfo,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -33,7 +33,7 @@ class _CommentModalState extends State<CommentModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 330,
|
height: 310,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(28),
|
topLeft: Radius.circular(28),
|
||||||
|
@ -49,24 +49,26 @@ class _CommentModalState extends State<CommentModal> {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.comment_rounded,
|
Icons.comment_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.comment,
|
AppLocalizations.of(context)!.comment,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: commentController,
|
controller: commentController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -94,7 +96,7 @@ class _CommentModalState extends State<CommentModal> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -173,11 +173,18 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.info_rounded),
|
Icon(
|
||||||
|
Icons.info_rounded,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
SizedBox(
|
Flexible(
|
||||||
width: MediaQuery.of(context).size.width-132,
|
child: Text(
|
||||||
child: Text(AppLocalizations.of(context)!.privateReverseDnsServersDescription)
|
AppLocalizations.of(context)!.privateReverseDnsServersDescription,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -51,7 +51,7 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: MediaQuery.of(context).viewInsets,
|
padding: MediaQuery.of(context).viewInsets,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 410,
|
height: 400,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(28),
|
topLeft: Radius.circular(28),
|
||||||
|
@ -67,24 +67,26 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
|
||||||
? const NeverScrollableScrollPhysics()
|
? const NeverScrollableScrollPhysics()
|
||||||
: null,
|
: null,
|
||||||
children: [
|
children: [
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 28),
|
padding: const EdgeInsets.only(top: 24),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.addDnsRewrite,
|
AppLocalizations.of(context)!.addDnsRewrite,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 16),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: domainController,
|
controller: domainController,
|
||||||
onChanged: validateDomain,
|
onChanged: validateDomain,
|
||||||
|
@ -102,7 +104,7 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: answerController,
|
controller: answerController,
|
||||||
onChanged: (_) => checkValidValues(),
|
onChanged: (_) => checkValidValues(),
|
||||||
|
@ -121,11 +123,7 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.all(24),
|
||||||
top: 20,
|
|
||||||
bottom: 20,
|
|
||||||
right: 28
|
|
||||||
),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
|
@ -151,7 +149,7 @@ class _AddDnsRewriteModalState extends State<AddDnsRewriteModal> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: validData == true
|
color: validData == true
|
||||||
? Theme.of(context).primaryColor
|
? Theme.of(context).primaryColor
|
||||||
: Colors.grey
|
: Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,18 +14,27 @@ class DeleteDnsRewrite extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.delete_rounded,
|
Icons.delete_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.deleteDnsRewrite,
|
AppLocalizations.of(context)!.deleteDnsRewrite,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: Text(AppLocalizations.of(context)!.deleteDnsRewriteMessage),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.deleteDnsRewriteMessage,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
|
|
|
@ -170,11 +170,12 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
|
||||||
padding: const EdgeInsets.only(top: 0),
|
padding: const EdgeInsets.only(top: 0),
|
||||||
itemCount: serversProvider.rewriteRules.data!.length,
|
itemCount: serversProvider.rewriteRules.data!.length,
|
||||||
itemBuilder: (context, index) => Container(
|
itemBuilder: (context, index) => Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
color: Colors.grey.shade200
|
width: 1,
|
||||||
|
color: Theme.of(context).colorScheme.outline.withOpacity(0.5)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -188,12 +189,16 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${AppLocalizations.of(context)!.domain}: ",
|
"${AppLocalizations.of(context)!.domain}: ",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
serversProvider.rewriteRules.data![index].domain,
|
serversProvider.rewriteRules.data![index].domain,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -202,12 +207,16 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"${AppLocalizations.of(context)!.answer}: ",
|
"${AppLocalizations.of(context)!.answer}: ",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w500
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
serversProvider.rewriteRules.data![index].answer,
|
serversProvider.rewriteRules.data![index].answer,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -277,6 +286,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
|
||||||
),
|
),
|
||||||
body: generateBody(),
|
body: generateBody(),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
|
backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
onPressed: () => {
|
onPressed: () => {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -289,7 +299,7 @@ class _DnsRewritesWidgetState extends State<DnsRewritesWidget> {
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).primaryColor.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,8 +12,18 @@ class EncryptionErrorModal extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(AppLocalizations.of(context)!.configError),
|
title: Text(
|
||||||
content: Text(error),
|
AppLocalizations.of(context)!.configError,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
error,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
|
|
|
@ -27,7 +27,7 @@ class EncryptionTextField extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxHeight: 200
|
maxHeight: 200
|
||||||
|
|
|
@ -369,15 +369,23 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
|
||||||
),
|
),
|
||||||
SectionLabel(label: AppLocalizations.of(context)!.certificates),
|
SectionLabel(label: AppLocalizations.of(context)!.certificates),
|
||||||
Card(
|
Card(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 20),
|
margin: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.info_rounded),
|
Icon(
|
||||||
|
Icons.info_rounded,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(AppLocalizations.of(context)!.certificatesDescription)
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.certificatesDescription,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -16,8 +16,8 @@ class EncryptionMasterSwitch extends StatelessWidget {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 10,
|
top: 10,
|
||||||
left: 12,
|
left: 24,
|
||||||
right: 12
|
right: 24
|
||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
|
@ -39,8 +39,9 @@ class EncryptionMasterSwitch extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.enableEncryption,
|
AppLocalizations.of(context)!.enableEncryption,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 3),
|
const SizedBox(height: 3),
|
||||||
|
@ -48,7 +49,7 @@ class EncryptionMasterSwitch extends StatelessWidget {
|
||||||
AppLocalizations.of(context)!.enableEncryptionTypes,
|
AppLocalizations.of(context)!.enableEncryptionTypes,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -14,9 +14,17 @@ class DnsAddressesModal extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.route_rounded),
|
Icon(
|
||||||
const SizedBox(height: 20),
|
Icons.route_rounded,
|
||||||
Text(AppLocalizations.of(context)!.dnsAddresses)
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.dnsAddresses,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
|
@ -27,8 +35,9 @@ class DnsAddressesModal extends StatelessWidget {
|
||||||
children: dnsAddresses.map((address) => ListTile(
|
children: dnsAddresses.map((address) => ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
address,
|
address,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.normal,
|
||||||
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)).toList(),
|
)).toList(),
|
||||||
|
|
|
@ -196,7 +196,7 @@ class Settings extends StatelessWidget {
|
||||||
onPressed: () => openWeb(Urls.playStore),
|
onPressed: () => openWeb(Urls.playStore),
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
'assets/resources/google-play.svg',
|
'assets/resources/google-play.svg',
|
||||||
color: Theme.of(context).textTheme.bodyText2!.color,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
),
|
),
|
||||||
|
@ -206,7 +206,7 @@ class Settings extends StatelessWidget {
|
||||||
onPressed: () => openWeb(Urls.gitHub),
|
onPressed: () => openWeb(Urls.gitHub),
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
'assets/resources/github.svg',
|
'assets/resources/github.svg',
|
||||||
color: Theme.of(context).textTheme.bodyText2!.color,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
),
|
),
|
||||||
|
|
|
@ -154,7 +154,12 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
|
|
||||||
return CustomListTile(
|
return CustomListTile(
|
||||||
title: screenData[index].keys.toList()[0],
|
title: screenData[index].keys.toList()[0],
|
||||||
trailing: Text(screenData[index].values.toList()[0].toString()),
|
trailing: Text(
|
||||||
|
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: [
|
||||||
|
@ -163,9 +168,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
name,
|
name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Theme.of(context).brightness == Brightness.light
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
? Colors.black
|
|
||||||
: Colors.white
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
|
@ -177,7 +180,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
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.iconColor
|
color: Theme.of(context).listTileTheme.textColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -191,7 +194,7 @@ class _TopItemsScreenState extends State<TopItemsScreen> {
|
||||||
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).primaryColor,
|
progressColor: Theme.of(context).primaryColor,
|
||||||
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15),
|
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
import 'package:material_segmented_control/material_segmented_control.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_radio_toggle.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/encode_base64.dart';
|
import 'package:adguard_home_manager/functions/encode_base64.dart';
|
||||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||||
|
@ -61,8 +60,8 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
Widget sectionLabel(String label) {
|
Widget sectionLabel(String label) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 20,
|
horizontal: 24,
|
||||||
vertical: 30
|
vertical: 24
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
label,
|
label,
|
||||||
|
@ -87,7 +86,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
String? helperText
|
String? helperText
|
||||||
}) {
|
}) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
|
@ -249,6 +248,33 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
|
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
|
Map<int, Widget> connectionTypes = {
|
||||||
|
0: Text(
|
||||||
|
'HTTP',
|
||||||
|
style: TextStyle(
|
||||||
|
color: appConfigProvider.useDynamicColor == true
|
||||||
|
? Theme.of(context).floatingActionButtonTheme.foregroundColor!
|
||||||
|
: connectionType == 'http'
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
),
|
||||||
|
1: Text(
|
||||||
|
'HTTPS',
|
||||||
|
style: TextStyle(
|
||||||
|
color: appConfigProvider.useDynamicColor == true
|
||||||
|
? Theme.of(context).floatingActionButtonTheme.foregroundColor!
|
||||||
|
: connectionType == 'https'
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500
|
||||||
|
),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
void connect() async {
|
void connect() async {
|
||||||
Server serverObj = Server(
|
Server serverObj = Server(
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
|
@ -461,11 +487,8 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Scaffold(
|
Scaffold(
|
||||||
backgroundColor: Theme.of(context).dialogBackgroundColor,
|
appBar: AppBar(
|
||||||
appBar: AppBar(
|
|
||||||
systemOverlayStyle: systemUiOverlayStyleConfig(context),
|
|
||||||
title: Text(AppLocalizations.of(context)!.createConnection),
|
title: Text(AppLocalizations.of(context)!.createConnection),
|
||||||
elevation: 5,
|
|
||||||
actions: [
|
actions: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 10),
|
padding: const EdgeInsets.only(right: 10),
|
||||||
|
@ -493,9 +516,9 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
margin: const EdgeInsets.only(
|
margin: const EdgeInsets.only(
|
||||||
top: 30,
|
top: 24,
|
||||||
left: 20,
|
left: 24,
|
||||||
right: 20
|
right: 24
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).primaryColor.withOpacity(0.05),
|
color: Theme.of(context).primaryColor.withOpacity(0.05),
|
||||||
|
@ -530,22 +553,23 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
sectionLabel(AppLocalizations.of(context)!.connection),
|
sectionLabel(AppLocalizations.of(context)!.connection),
|
||||||
Row(
|
Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
children: [
|
child: MaterialSegmentedControl(
|
||||||
CustomRadioToggle(
|
children: connectionTypes,
|
||||||
groupSelected: connectionType,
|
selectionIndex: connectionType == 'http' ? 0 : 1,
|
||||||
value: 'http',
|
onSegmentChosen: (value) => setState(() {
|
||||||
label: 'HTTP',
|
if (value == 0) {
|
||||||
onTap: (value) => setState(() => connectionType = value)
|
connectionType = 'http';
|
||||||
),
|
}
|
||||||
CustomRadioToggle(
|
else if (value == 1) {
|
||||||
groupSelected: connectionType,
|
connectionType = 'https';
|
||||||
value: 'https',
|
}
|
||||||
label: 'HTTPS',
|
}),
|
||||||
onTap: (value) => setState(() => connectionType = value)
|
selectedColor: Theme.of(context).floatingActionButtonTheme.backgroundColor!,
|
||||||
),
|
unselectedColor: Colors.transparent,
|
||||||
],
|
borderColor: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
textField(
|
textField(
|
||||||
|
@ -601,7 +625,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
? () => setState(() => defaultServer = !defaultServer)
|
? () => setState(() => defaultServer = !defaultServer)
|
||||||
: null,
|
: null,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -629,7 +653,7 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => setState(() => homeAssistant = !homeAssistant),
|
onTap: () => setState(() => homeAssistant = !homeAssistant),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -52,13 +52,9 @@ class BottomNavBar extends StatelessWidget {
|
||||||
destinations: screens.map((screen) => NavigationDestination(
|
destinations: screens.map((screen) => NavigationDestination(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
screen.icon,
|
screen.icon,
|
||||||
color: screens.indexOf(screen) == appConfigProvider.selectedScreen
|
color: screens[appConfigProvider.selectedScreen] == screen
|
||||||
? Theme.of(context).navigationBarTheme.indicatorColor!.computeLuminance() > 0.5 ?
|
? Theme.of(context).colorScheme.onSecondaryContainer
|
||||||
appConfigProvider.useDynamicColor == true
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: Colors.black
|
|
||||||
: Colors.white
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
label: translatedName(screen.name)
|
label: translatedName(screen.name)
|
||||||
)).toList(),
|
)).toList(),
|
||||||
|
|
|
@ -27,7 +27,7 @@ class CustomListTile extends StatelessWidget {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: padding ?? const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
padding: padding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
@ -38,8 +38,10 @@ class CustomListTile extends StatelessWidget {
|
||||||
if (icon != null) ...[
|
if (icon != null) ...[
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 16),
|
||||||
],
|
],
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -47,9 +49,10 @@ class CustomListTile extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.normal
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (subtitle != null || subtitleWidget != null) ...[
|
if (subtitle != null || subtitleWidget != null) ...[
|
||||||
|
@ -58,8 +61,9 @@ class CustomListTile extends StatelessWidget {
|
||||||
if (subtitle != null && subtitleWidget == null) Text(
|
if (subtitle != null && subtitleWidget == null) Text(
|
||||||
subtitle!,
|
subtitle!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 14
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -27,16 +27,18 @@ class CustomRadioListTile extends StatelessWidget {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onChanged(value),
|
onTap: () => onChanged(value),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
vertical: 12
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(width: 10),
|
|
||||||
CustomRadio(
|
CustomRadio(
|
||||||
value: value,
|
value: value,
|
||||||
groupValue: groupValue,
|
groupValue: groupValue,
|
||||||
backgroundColor: radioBackgroundColor,
|
backgroundColor: radioBackgroundColor,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 30),
|
const SizedBox(width: 24),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
@ -44,8 +46,9 @@ class CustomRadioListTile extends StatelessWidget {
|
||||||
width: MediaQuery.of(context).size.width-110,
|
width: MediaQuery.of(context).size.width-110,
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16
|
fontSize: 16,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -56,7 +59,7 @@ class CustomRadioListTile extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
subtitle!,
|
subtitle!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).listTileTheme.iconColor,
|
color: Theme.of(context).listTileTheme.textColor,
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -26,7 +26,7 @@ class CustomSwitchListTile extends StatelessWidget {
|
||||||
: () => onChanged(!value),
|
: () => onChanged(!value),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 15, left: 24, right: 15, bottom: 15
|
top: 12, left: 24, right: 12, bottom: 12
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -41,8 +41,8 @@ class CustomSwitchListTile extends StatelessWidget {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: disabled != null && disabled == true
|
color: disabled != null && disabled == true
|
||||||
? Colors.grey
|
? Theme.of(context).colorScheme.onSurface.withOpacity(0.38)
|
||||||
: null,
|
: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -55,8 +55,8 @@ class CustomSwitchListTile extends StatelessWidget {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: disabled != null && disabled == true
|
color: disabled != null && disabled == true
|
||||||
? Colors.grey
|
? Theme.of(context).listTileTheme.textColor!.withOpacity(0.38)
|
||||||
: Theme.of(context).listTileTheme.iconColor,
|
: Theme.of(context).listTileTheme.textColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -23,7 +23,12 @@ class ProcessDialog extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
const CircularProgressIndicator(),
|
const CircularProgressIndicator(),
|
||||||
const SizedBox(width: 40),
|
const SizedBox(width: 40),
|
||||||
Text(message)
|
Text(
|
||||||
|
message,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -16,7 +16,7 @@ class SectionLabel extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: padding ?? const EdgeInsets.all(25),
|
padding: padding ?? const EdgeInsets.all(24),
|
||||||
child: Text(
|
child: Text(
|
||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|
|
@ -46,16 +46,19 @@ class DeleteModal extends StatelessWidget {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.delete,
|
Icons.delete,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 20),
|
padding: const EdgeInsets.only(top: 16),
|
||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(context)!.remove,
|
AppLocalizations.of(context)!.remove,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -70,13 +73,17 @@ class DeleteModal extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.removeWarning,
|
AppLocalizations.of(context)!.removeWarning,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Center(
|
Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"${serverToDelete.connectionMethod}://${serverToDelete.domain}${serverToDelete.path ?? ""}${serverToDelete.port != null ? ':${serverToDelete.port}' : ""}",
|
"${serverToDelete.connectionMethod}://${serverToDelete.domain}${serverToDelete.path ?? ""}${serverToDelete.port != null ? ':${serverToDelete.port}' : ""}",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontStyle: FontStyle.italic
|
fontStyle: FontStyle.italic,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -187,12 +187,12 @@ class _ServersListState extends State<ServersList> with SingleTickerProviderStat
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(1),
|
padding: const EdgeInsets.all(1),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
borderRadius: BorderRadius.circular(20)
|
borderRadius: BorderRadius.circular(20)
|
||||||
),
|
),
|
||||||
child: const Icon(
|
child: Icon(
|
||||||
Icons.star,
|
Icons.star,
|
||||||
color: Colors.white,
|
color: Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
size: 10,
|
size: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -218,44 +218,49 @@ class _ServersListState extends State<ServersList> with SingleTickerProviderStat
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
|
||||||
width: 48,
|
|
||||||
margin: const EdgeInsets.only(right: 12),
|
|
||||||
child: leadingIcon(servers[index]),
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Container(
|
||||||
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
|
margin: const EdgeInsets.only(right: 16),
|
||||||
textAlign: TextAlign.center,
|
child: leadingIcon(servers[index]),
|
||||||
style: const TextStyle(
|
),
|
||||||
fontSize: 18,
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 3),
|
||||||
|
Text(
|
||||||
|
servers[index].name,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Text(
|
|
||||||
servers[index].name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Theme.of(context).listTileTheme.iconColor
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
RotationTransition(
|
||||||
padding: const EdgeInsets.only(right: 10),
|
turns: animation,
|
||||||
child: RotationTransition(
|
child: const Icon(Icons.keyboard_arrow_down_rounded),
|
||||||
turns: animation,
|
|
||||||
child: const Icon(Icons.keyboard_arrow_down_rounded),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -383,7 +388,7 @@ class _ServersListState extends State<ServersList> with SingleTickerProviderStat
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => widget.onChange(index),
|
onTap: () => widget.onChange(index),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: topRow(servers[index], index),
|
child: topRow(servers[index], index),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -393,7 +398,7 @@ class _ServersListState extends State<ServersList> with SingleTickerProviderStat
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => widget.onChange(index),
|
onTap: () => widget.onChange(index),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
topRow(servers[index], index),
|
topRow(servers[index], index),
|
||||||
|
|
|
@ -34,16 +34,18 @@ class _UpdateModalState extends State<UpdateModal> {
|
||||||
scrollable: true,
|
scrollable: true,
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.system_update_rounded,
|
Icons.system_update_rounded,
|
||||||
size: 26,
|
size: 24,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.updateAvailable,
|
AppLocalizations.of(context)!.updateAvailable,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 26
|
fontSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -51,11 +53,26 @@ class _UpdateModalState extends State<UpdateModal> {
|
||||||
content: Column(
|
content: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text("${AppLocalizations.of(context)!.installedVersion}: ${appConfigProvider.getAppInfo!.version}"),
|
Text(
|
||||||
|
"${AppLocalizations.of(context)!.installedVersion}: ${appConfigProvider.getAppInfo!.version}",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text("${AppLocalizations.of(context)!.newVersion}: ${widget.gitHubRelease.tagName}"),
|
Text(
|
||||||
|
"${AppLocalizations.of(context)!.newVersion}: ${widget.gitHubRelease.tagName}",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text("${AppLocalizations.of(context)!.source}: GitHub"),
|
Text(
|
||||||
|
"${AppLocalizations.of(context)!.source}: GitHub",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => setState(() => doNotRemember = !doNotRemember),
|
onTap: () => setState(() => doNotRemember = !doNotRemember),
|
||||||
|
@ -70,7 +87,14 @@ class _UpdateModalState extends State<UpdateModal> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Flexible(child: Text(AppLocalizations.of(context)!.doNotRememberAgainUpdate))
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context)!.doNotRememberAgainUpdate,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -329,6 +329,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.5"
|
||||||
|
material_segmented_control:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: material_segmented_control
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -50,6 +50,7 @@ dependencies:
|
||||||
bottom_sheet: ^3.1.2
|
bottom_sheet: ^3.1.2
|
||||||
percent_indicator: ^4.2.2
|
percent_indicator: ^4.2.2
|
||||||
store_checker: ^1.1.0
|
store_checker: ^1.1.0
|
||||||
|
material_segmented_control: ^4.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue