Added new combined chart on home

This commit is contained in:
Juan Gilsanz Polo 2023-05-20 22:57:38 +02:00
parent 8ca59d26c7
commit cf5af1061f
10 changed files with 506 additions and 25 deletions

View file

@ -37,7 +37,7 @@ class HomeChart extends StatelessWidget {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
Padding(
@ -115,13 +115,13 @@ class HomeChart extends StatelessWidget {
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 20),
const SizedBox(height: 16),
],
);
}

View file

@ -0,0 +1,285 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/combined_line_chart.dart';
import 'package:adguard_home_manager/functions/number_format.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
import 'package:adguard_home_manager/providers/app_config_provider.dart';
class CombinedChartData {
final CombinedChartItem totalQueries;
final CombinedChartItem? blockedFilters;
final CombinedChartItem? replacedSafeBrowsing;
final CombinedChartItem? replacedParental;
const CombinedChartData({
required this.totalQueries,
this.blockedFilters,
this.replacedSafeBrowsing,
this.replacedParental
});
}
class CombinedChartItem {
final String label;
final Color color;
final List<int> data;
const CombinedChartItem({
required this.label,
required this.color,
required this.data
});
}
class CombinedHomeChart extends StatelessWidget {
const CombinedHomeChart({Key? key}) : super(key: key);
List<int>? removeZero(List<int> list) {
final removed = list.where((i) => i > 0);
if (removed.isNotEmpty) {
return list;
}
else {
return null;
}
}
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
final appConfigProvider = Provider.of<AppConfigProvider>(context);
final width = MediaQuery.of(context).size.width;
if (serversProvider.serverStatus.data != null) {
final data = CombinedChartData(
totalQueries: CombinedChartItem(
label: AppLocalizations.of(context)!.dnsQueries,
color: Colors.blue,
data: serversProvider.serverStatus.data!.stats.dnsQueries
),
blockedFilters: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.blockedFiltering) != null
? CombinedChartItem(
label: AppLocalizations.of(context)!.blockedFilters,
color: Colors.red,
data: serversProvider.serverStatus.data!.stats.blockedFiltering
)
: null
: CombinedChartItem(
label: AppLocalizations.of(context)!.blockedFilters,
color: Colors.red,
data: serversProvider.serverStatus.data!.stats.blockedFiltering
) ,
replacedSafeBrowsing: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.replacedSafebrowsing) != null
? CombinedChartItem(
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
color: Colors.green,
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing
)
: null
: CombinedChartItem(
label: AppLocalizations.of(context)!.malwarePhisingBlocked,
color: Colors.green,
data: serversProvider.serverStatus.data!.stats.replacedSafebrowsing
) ,
replacedParental: appConfigProvider.hideZeroValues == true
? removeZero(serversProvider.serverStatus.data!.stats.replacedParental) != null
? CombinedChartItem(
label: AppLocalizations.of(context)!.blockedAdultWebsites,
color: Colors.orange,
data: serversProvider.serverStatus.data!.stats.replacedParental
)
: null
: CombinedChartItem(
label: AppLocalizations.of(context)!.blockedAdultWebsites,
color: Colors.orange,
data: serversProvider.serverStatus.data!.stats.replacedParental
) ,
);
Widget legend({
required String label,
required Color color,
required String primaryValue,
String? secondaryValue
}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
child: Text(
label,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: color
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
primaryValue,
style: TextStyle(
color: color,
fontSize: 16,
fontWeight: FontWeight.w500
),
),
if (secondaryValue != null) Text(
secondaryValue,
style: TextStyle(
fontSize: 10,
color: color
),
)
],
)
],
);
}
if (width > 900) {
return Column(
children: [
Text(
AppLocalizations.of(context)!.statistics,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
flex: 3,
child: SizedBox(
height: 300,
width: double.maxFinite,
child: CustomCombinedLineChart(
inputData: data,
),
),
),
const SizedBox(width: 16),
Expanded(
flex: 2,
child: SizedBox(
height: 300,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
legend(
label: data.totalQueries.label,
color: data.totalQueries.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
),
const SizedBox(height: 16),
if (data.blockedFilters != null) legend(
label: data.blockedFilters!.label,
color: data.blockedFilters!.color,
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}%",
),
const SizedBox(height: 16),
if (data.replacedSafeBrowsing != null) legend(
label: data.replacedSafeBrowsing!.label,
color: data.replacedSafeBrowsing!.color,
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}%",
),
const SizedBox(height: 16),
if (data.replacedParental != null) legend(
label: data.replacedParental!.label,
color: data.replacedParental!.color,
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}%",
),
],
),
)
),
],
)
],
);
}
else {
return Column(
children: [
Column(
children: [
Text(
AppLocalizations.of(context)!.statistics,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface
),
),
const SizedBox(height: 16),
SizedBox(
height: 300,
width: double.maxFinite,
child: CustomCombinedLineChart(
inputData: data,
),
),
const SizedBox(height: 16),
legend(
label: data.totalQueries.label,
color: data.totalQueries.color,
primaryValue: intFormat(serversProvider.serverStatus.data!.stats.numDnsQueries, Platform.localeName),
secondaryValue: "${doubleFormat(serversProvider.serverStatus.data!.stats.avgProcessingTime*1000, Platform.localeName)} ms",
),
const SizedBox(height: 16),
if (data.blockedFilters != null) legend(
label: data.blockedFilters!.label,
color: data.blockedFilters!.color,
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}%",
),
const SizedBox(height: 16),
if (data.replacedSafeBrowsing != null) legend(
label: data.replacedSafeBrowsing!.label,
color: data.replacedSafeBrowsing!.color,
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}%",
),
const SizedBox(height: 16),
if (data.replacedParental != null) legend(
label: data.replacedParental!.label,
color: data.replacedParental!.color,
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}%",
),
const SizedBox(height: 16),
],
),
Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
const SizedBox(height: 16)
],
);
}
}
else {
return const SizedBox();
}
}
}

View file

@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/home/server_status.dart';
import 'package:adguard_home_manager/screens/home/combined_chart.dart';
import 'package:adguard_home_manager/screens/home/appbar.dart';
import 'package:adguard_home_manager/screens/home/fab.dart';
import 'package:adguard_home_manager/screens/home/top_items.dart';
@ -110,15 +111,15 @@ class _HomeState extends State<Home> {
return [
ServerStatus(serverStatus: serversProvider.serverStatus.data!),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 20),
const SizedBox(height: 16),
Wrap(
if (appConfigProvider.combinedChartHome == false) Wrap(
children: [
FractionallySizedBox(
widthFactor: width > 700 ? 0.5 : 1,
@ -159,10 +160,14 @@ class _HomeState extends State<Home> {
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,
),
),
),
],
),
if (appConfigProvider.combinedChartHome == true) const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: CombinedHomeChart(),
),
if (width <= 700) ...[
TopItems(
@ -171,14 +176,14 @@ class _HomeState extends State<Home> {
type: 'topQueriedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 20),
const SizedBox(height: 16),
TopItems(
label: AppLocalizations.of(context)!.topBlockedDomains,
@ -186,13 +191,13 @@ class _HomeState extends State<Home> {
type: 'topBlockedDomains',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Divider(
thickness: 1,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.2),
),
),
const SizedBox(height: 20),
const SizedBox(height: 16),
TopItems(
label: AppLocalizations.of(context)!.topClients,

View file

@ -18,19 +18,24 @@ class ServerStatus extends StatelessWidget {
final width = MediaQuery.of(context).size.width;
return Container(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 10),
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
child: Column(
children: [
Text(
AppLocalizations.of(context)!.serverStatus,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface
Padding(
padding: width > 700
? const EdgeInsets.all(16)
: const EdgeInsets.all(0),
child: Text(
AppLocalizations.of(context)!.serverStatus,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.onSurface
),
),
),
SizedBox(
height: width > 700 ? 90 : 170,
height: width > 700 ? 70 : 170,
child: GridView(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(

View file

@ -156,6 +156,28 @@ class _GeneralSettingsState extends State<GeneralSettings> {
right: 10
)
),
CustomListTile(
icon: Icons.show_chart_rounded,
title: AppLocalizations.of(context)!.combinedChart,
subtitle: AppLocalizations.of(context)!.combinedChartDescription,
trailing: Switch(
value: appConfigProvider.combinedChartHome,
onChanged: (value) => updateSettings(
newStatus: value,
function: appConfigProvider.setCombinedChartHome
),
),
onTap: () => updateSettings(
newStatus: !appConfigProvider.combinedChartHome,
function: appConfigProvider.setCombinedChartHome
),
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
left: 16,
right: 10
)
),
SectionLabel(label: AppLocalizations.of(context)!.logs),
CustomListTile(
icon: Icons.timer_rounded,