Merge branch 'ui-changes'

This commit is contained in:
Juan Gilsanz Polo 2022-11-05 02:35:48 +01:00
commit 05815af868
80 changed files with 2854 additions and 2661 deletions

View file

@ -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,

View file

@ -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."
} }

View file

@ -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."
} }

View file

@ -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
), ),
) )
], ],

View file

@ -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(

View file

@ -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: [

View file

@ -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
),
)
),
]
],
)
],
),
),
],
),
),
);
}
}

View 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)
],
),
);
}
}

View file

@ -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)
) )
) )
), ),

View file

@ -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
),
),
) )
); );
} }

View file

@ -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,
), ),
); );
} }

View file

@ -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(

View file

@ -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),

View file

@ -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,

View file

@ -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)
), ),
) )
), ),

View file

@ -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)
), ),
) )
), ),

View file

@ -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,
), ),
); );
} }

View file

@ -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
// ),
// )
// ),
// ],
// ),
// )

View file

@ -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: [

View file

@ -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(

View file

@ -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,

View file

@ -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,
), ),
), ),

View file

@ -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),

View file

@ -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,
), ),
); );
} }

View file

@ -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
), ),
), ),
], ],

View file

@ -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)
) )
) )
), ),

View file

@ -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
); );
} }

View file

@ -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)
)
],
),
),
],
),
);
}
}

View 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,
),
),
)
],
),
);
}
}

View file

@ -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),

View file

@ -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: [

View file

@ -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
), ),
) )
], ],

View file

@ -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),

View file

@ -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();

View file

@ -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),

View file

@ -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')
),
], ],
), ),
), ),

View file

@ -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),

View file

@ -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),

View file

@ -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: [

View file

@ -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)
),
],
),
)
],
),
);
}
}

View 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()
]
],
),
);
}
}

View file

@ -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!
] ]
], ],

View file

@ -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
), ),
), ),

View file

@ -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),

View file

@ -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),

View file

@ -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: [

View file

@ -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,
), ),
), ),
), ),

View file

@ -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)
) )
) )
), ),

View file

@ -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: [

View file

@ -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,
), ),
), ),
) )

View file

@ -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(

View file

@ -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),

View file

@ -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)
), ),
), ),
), ),

View file

@ -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,

View file

@ -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(', ')),
], ],
), ),
] ]

View file

@ -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
),
)
) )
], ],
), ),

View file

@ -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: [

View file

@ -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
),
)
) )
], ],
), ),

View file

@ -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)
), ),
), ),
), ),

View file

@ -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),

View file

@ -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,
), ),
), ),
); );

View file

@ -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),

View file

@ -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

View file

@ -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,
),
)
) )
], ],
), ),

View file

@ -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
), ),
) )
], ],

View file

@ -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(),

View file

@ -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,
), ),

View file

@ -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),

View file

@ -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: [

View file

@ -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(),

View file

@ -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
), ),
), ),
] ]

View file

@ -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
), ),
), ),

View file

@ -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
), ),
), ),
), ),

View file

@ -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
),
)
], ],
), ),
), ),

View file

@ -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(

View file

@ -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
), ),
), ),
), ),

View file

@ -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),

View file

@ -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
),
)
)
], ],
), ),
) )

View file

@ -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:

View file

@ -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: