Adapted home screen

This commit is contained in:
Juan Gilsanz Polo 2023-05-01 14:38:46 +02:00
parent 4531e15566
commit aacf68569d
10 changed files with 612 additions and 162 deletions

View file

@ -48,12 +48,15 @@ class HomeChart extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface
Flexible(
child: Text(
label,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface
),
),
),
!isEmpty

View file

@ -12,13 +12,27 @@ class HomeFab extends StatelessWidget {
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final width = MediaQuery.of(context).size.width;
void openManagementBottomSheet() {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => const ManagementModal(),
backgroundColor: Colors.transparent,
);
if (width > 700) {
showDialog(
context: context,
builder: (context) => const ManagementModal(
dialog: true,
),
);
}
else {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => const ManagementModal(
dialog: false,
),
backgroundColor: Colors.transparent,
);
}
}
return serversProvider.serverStatus.loadStatus == 1

View file

@ -55,6 +55,8 @@ class _HomeState extends State<Home> {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
Widget status() {
switch (serversProvider.serverStatus.loadStatus) {
case 0:
@ -92,72 +94,138 @@ class _HomeState extends State<Home> {
),
const SizedBox(height: 20),
HomeChart(
data: serversProvider.serverStatus.data!.stats.dnsQueries,
label: AppLocalizations.of(context)!.dnsQueries,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
color: Colors.blue,
),
HomeChart(
data: serversProvider.serverStatus.data!.stats.blockedFiltering,
label: AppLocalizations.of(context)!.blockedFilters,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numBlockedFiltering/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.red,
Wrap(
children: [
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.dnsQueries,
label: AppLocalizations.of(context)!.dnsQueries,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
color: Colors.blue,
),
),
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.blockedFiltering,
label: AppLocalizations.of(context)!.blockedFilters,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numBlockedFiltering, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numBlockedFiltering/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.red,
),
),
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing,
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.green,
),
),
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
child: HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedParental,
label: AppLocalizations.of(context)!.blockedAdultWebsites,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedParental/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.orange,
),
),
],
),
HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing,
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedSafebrowsing/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.green,
),
HomeChart(
data: serversProvider.serverStatus.data!.stats.replacedParental,
label: AppLocalizations.of(context)!.blockedAdultWebsites,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numReplacedParental, Platform.localeName),
secondaryValue: "${serversProvider.serverStatus.data!.stats.numDnsQueries > 0 ? doubleFormat((serversProvider.serverStatus.data!.stats.numReplacedParental/serversProvider.serverStatus.data!.stats.numDnsQueries)*100, Platform.localeName) : 0}%",
color: Colors.orange,
),
TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
if (width <= 700) ...[
TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
),
const SizedBox(height: 20),
TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
),
const SizedBox(height: 20),
TopItems(
label: AppLocalizations.of(context)!.topClients,
data: serversProvider.serverStatus.data!.stats.topClients,
type: 'topClients',
clients: true,
),
const SizedBox(height: 20),
TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 20),
TopItems(
label: AppLocalizations.of(context)!.topClients,
data: serversProvider.serverStatus.data!.stats.topClients,
type: 'topClients',
clients: true,
),
],
if (width > 700) Column(
children: [
const SizedBox(height: 16),
Wrap(
alignment: WrapAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topQueriedDomains,
data: serversProvider.serverStatus.data!.stats.topQueriedDomains,
type: 'topQueriedDomains',
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500
),
child: TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
data: serversProvider.serverStatus.data!.stats.topBlockedDomains,
type: 'topBlockedDomains',
),
),
),
],
),
],
)
],
);

View file

@ -15,7 +15,12 @@ import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class ManagementModal extends StatefulWidget {
const ManagementModal({Key? key}) : super(key: key);
final bool dialog;
const ManagementModal({
Key? key,
required this.dialog
}) : super(key: key);
@override
State<ManagementModal> createState() => _ManagementModalState();
@ -364,8 +369,112 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
);
}
return SafeArea(
child: Container(
Widget header() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 24),
child: Icon(
Icons.shield_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text(
AppLocalizations.of(context)!.manageServer,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
color: Theme.of(context).colorScheme.onSurface,
),
),
),
],
),
],
);
}
List<Widget> toggles() {
return [
mainSwitch(),
Container(height: 10),
smallSwitch(
AppLocalizations.of(context)!.ruleFiltering,
Icons.filter_list_rounded,
serversProvider.serverStatus.data!.filteringEnabled,
(value) => updateBlocking(value: value, filter: 'filtering'),
serversProvider.protectionsManagementProcess.contains('filtering')
),
smallSwitch(
AppLocalizations.of(context)!.safeBrowsing,
Icons.vpn_lock_rounded,
serversProvider.serverStatus.data!.safeBrowsingEnabled,
(value) => updateBlocking(value: value, filter: 'safeBrowsing'),
serversProvider.protectionsManagementProcess.contains('safeBrowsing')
),
smallSwitch(
AppLocalizations.of(context)!.parentalFiltering,
Icons.block,
serversProvider.serverStatus.data!.parentalControlEnabled,
(value) => updateBlocking(value: value, filter: 'parentalControl'),
serversProvider.protectionsManagementProcess.contains('parentalControl')
),
smallSwitch(
AppLocalizations.of(context)!.safeSearch,
Icons.search_rounded,
serversProvider.serverStatus.data!.safeSearchEnabled,
(value) => updateBlocking(value: value, filter: 'safeSearch'),
serversProvider.protectionsManagementProcess.contains('safeSearch')
),
];
}
if (widget.dialog == true) {
return Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 400
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: Wrap(
children: [
header(),
...toggles()
],
),
),
),
Padding(
padding: const EdgeInsets.all(24),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)!.close),
),
],
),
),
if (Platform.isIOS) const SizedBox(height: 16)
],
),
),
);
}
else {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.only(
@ -373,66 +482,18 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
topRight: Radius.circular(28)
)
),
child: Wrap(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
Flexible(
child: SingleChildScrollView(
child: Wrap(
children: [
Padding(
padding: const EdgeInsets.only(top: 24),
child: Icon(
Icons.shield_rounded,
size: 24,
color: Theme.of(context).listTileTheme.iconColor
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text(
AppLocalizations.of(context)!.manageServer,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
color: Theme.of(context).colorScheme.onSurface,
),
),
),
header(),
...toggles()
],
),
],
),
mainSwitch(),
const SizedBox(height: 10),
smallSwitch(
AppLocalizations.of(context)!.ruleFiltering,
Icons.filter_list_rounded,
serversProvider.serverStatus.data!.filteringEnabled,
(value) => updateBlocking(value: value, filter: 'filtering'),
serversProvider.protectionsManagementProcess.contains('filtering')
),
smallSwitch(
AppLocalizations.of(context)!.safeBrowsing,
Icons.vpn_lock_rounded,
serversProvider.serverStatus.data!.safeBrowsingEnabled,
(value) => updateBlocking(value: value, filter: 'safeBrowsing'),
serversProvider.protectionsManagementProcess.contains('safeBrowsing')
),
smallSwitch(
AppLocalizations.of(context)!.parentalFiltering,
Icons.block,
serversProvider.serverStatus.data!.parentalControlEnabled,
(value) => updateBlocking(value: value, filter: 'parentalControl'),
serversProvider.protectionsManagementProcess.contains('parentalControl')
),
smallSwitch(
AppLocalizations.of(context)!.safeSearch,
Icons.search_rounded,
serversProvider.serverStatus.data!.safeSearchEnabled,
(value) => updateBlocking(value: value, filter: 'safeSearch'),
serversProvider.protectionsManagementProcess.contains('safeSearch')
),
),
Padding(
padding: const EdgeInsets.all(24),
@ -449,7 +510,7 @@ class _ManagementModalState extends State<ManagementModal> with SingleTickerProv
if (Platform.isIOS) const SizedBox(height: 16)
],
),
),
);
);
}
}
}

View file

@ -15,8 +15,12 @@ class ServerStatus extends StatelessWidget {
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return Container(
padding: const EdgeInsets.all(20),
padding: width > 700
? const EdgeInsets.only(left: 20, right: 20, bottom: 20)
: const EdgeInsets.all(20),
child: Column(
children: [
Text(
@ -29,11 +33,11 @@ class ServerStatus extends StatelessWidget {
),
const SizedBox(height: 20),
SizedBox(
height: 140,
height: width > 700 ? 70 : 140,
child: GridView(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: width > 700 ? 4 : 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
mainAxisExtent: 65

View file

@ -44,13 +44,15 @@ class StatusBox extends StatelessWidget {
: Colors.grey.computeLuminance() > 0.5 ? Colors.black : Colors.white,
),
const SizedBox(width: 12),
Text(
label,
style: TextStyle(
color: appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary.computeLuminance() > 0.5 ? Colors.black : Colors.white
: Colors.grey.computeLuminance() > 0.5 ? Colors.black : Colors.white,
fontWeight: FontWeight.w500
Flexible(
child: Text(
label,
style: TextStyle(
color: appConfigProvider.useThemeColorForStatus == true
? Theme.of(context).colorScheme.primary.computeLuminance() > 0.5 ? Colors.black : Colors.white
: Colors.grey.computeLuminance() > 0.5 ? Colors.black : Colors.white,
fontWeight: FontWeight.w500
),
),
)
],

View file

@ -1,5 +1,9 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:adguard_home_manager/screens/top_items/top_items_modal.dart';
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
@ -35,6 +39,8 @@ class TopItems extends StatelessWidget {
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final logsProvider = Provider.of<LogsProvider>(context);
final width = MediaQuery.of(context).size.width;
bool? getIsBlocked() {
if (type == 'topBlockedDomains') {
return true;
@ -266,16 +272,32 @@ class TopItems extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TopItemsScreen(
type: type,
title: label,
isClient: clients,
data: generateData(),
onPressed: () => {
if (width > 700 || !(Platform.isAndroid || Platform.isIOS)) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => TopItemsModal(
type: type,
title: label,
isClient: clients,
data: generateData(),
)
)
)
),
}
else {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TopItemsScreen(
type: type,
title: label,
isClient: clients,
data: generateData(),
)
)
)
}
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [