mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-04 20:30:35 +00:00
Added new combined chart on home
This commit is contained in:
parent
8ca59d26c7
commit
cf5af1061f
10 changed files with 506 additions and 25 deletions
|
@ -280,7 +280,7 @@
|
|||
"accessSettingsDescription": "Configure access rules for the server",
|
||||
"loadingClients": "Loading clients...",
|
||||
"clientsNotLoaded": "Clients couldn't be loaded.",
|
||||
"noAllowedClients": "No hay clientes permitidos",
|
||||
"noAllowedClients": "No allowed clients",
|
||||
"allowedClientsDescription": "If this list has entries, AdGuard Home will accept requests only from these clients.",
|
||||
"blockedClientsDescription": "If this list has entries, AdGuard Home will drop requests from these clients. This field is ignored if there are entries in Allowed clients.",
|
||||
"disallowedDomainsDescription": "AdGuard Home drops DNS queries matching these domains, and these queries don't even appear in the query log.",
|
||||
|
@ -625,5 +625,8 @@
|
|||
"usingLatestVersion": "You are using the latest version",
|
||||
"ipLogs": "IP on logs",
|
||||
"ipLogsDescription": "Show always IP address on logs instead of client name",
|
||||
"application": "Application"
|
||||
"application": "Application",
|
||||
"combinedChart": "Combined chart",
|
||||
"combinedChartDescription": "Combine all charts into one",
|
||||
"statistics": "Statistics"
|
||||
}
|
|
@ -625,5 +625,8 @@
|
|||
"usingLatestVersion": "Estás usando la última versión",
|
||||
"ipLogs": "IP en registros",
|
||||
"ipLogsDescription": "Mostrar siempre dirección IP en vez del nombre del cliente",
|
||||
"application": "Aplicación"
|
||||
"application": "Aplicación",
|
||||
"combinedChart": "Gráfico combinado",
|
||||
"combinedChartDescription": "Combina todos los gráficos en uno solo",
|
||||
"statistics": "Estadísticas"
|
||||
}
|
|
@ -41,6 +41,8 @@ class AppConfigProvider with ChangeNotifier {
|
|||
|
||||
int _showIpLogs = 0;
|
||||
|
||||
int _combinedChartHome = 0;
|
||||
|
||||
String? _doNotRememberVersion;
|
||||
|
||||
GitHubRelease? _appUpdatesAvailable;
|
||||
|
@ -129,6 +131,10 @@ class AppConfigProvider with ChangeNotifier {
|
|||
return _showIpLogs == 1 ? true : false;
|
||||
}
|
||||
|
||||
bool get combinedChartHome {
|
||||
return _combinedChartHome == 1 ? true : false;
|
||||
}
|
||||
|
||||
String? get doNotRememberVersion {
|
||||
return _doNotRememberVersion;
|
||||
}
|
||||
|
@ -315,6 +321,22 @@ class AppConfigProvider with ChangeNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
Future<bool> setCombinedChartHome(bool value) async {
|
||||
final updated = await updateConfigQuery(
|
||||
db: _dbInstance!,
|
||||
column: 'combinedChart',
|
||||
value: value == true ? 1 : 0
|
||||
);
|
||||
if (updated == true) {
|
||||
_combinedChartHome = value == true ? 1 : 0;
|
||||
notifyListeners();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> setStaticColor(int value) async {
|
||||
final updated = await updateConfigQuery(
|
||||
db: _dbInstance!,
|
||||
|
@ -349,6 +371,7 @@ class AppConfigProvider with ChangeNotifier {
|
|||
_useThemeColorForStatus = dbData['useThemeColorForStatus'] != null ? convertFromIntToBool(dbData['useThemeColorForStatus'])! : false;
|
||||
_showTimeLogs = dbData['showTimeLogs'];
|
||||
_doNotRememberVersion = dbData['doNotRememberVersion'];
|
||||
_combinedChartHome = dbData['combinedChart'];
|
||||
|
||||
_dbInstance = dbInstance;
|
||||
notifyListeners();
|
||||
|
|
|
@ -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),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
285
lib/screens/home/combined_chart.dart
Normal file
285
lib/screens/home/combined_chart.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
@ -160,10 +161,14 @@ class _HomeState extends State<Home> {
|
|||
color: Colors.orange,
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
|
||||
if (appConfigProvider.combinedChartHome == true) const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: CombinedHomeChart(),
|
||||
),
|
||||
|
||||
if (width <= 700) ...[
|
||||
TopItems(
|
||||
label: AppLocalizations.of(context)!.topQueriedDomains,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -74,6 +74,7 @@ Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
|
|||
Future upgradeDbToV8(Database db) async {
|
||||
await db.execute("ALTER TABLE appConfig RENAME COLUMN showNameTimeLogs TO showTimeLogs");
|
||||
await db.execute("ALTER TABLE appConfig ADD COLUMN showIpLogs NUMERIC");
|
||||
await db.execute("ALTER TABLE appConfig ADD COLUMN combinedChart NUMERIC");
|
||||
|
||||
await db.transaction((txn) async{
|
||||
await txn.rawQuery(
|
||||
|
@ -87,8 +88,8 @@ Future<Map<String, dynamic>> loadDb(bool acceptsDynamicTheme) async {
|
|||
version: 8,
|
||||
onCreate: (Database db, int version) async {
|
||||
await db.execute("CREATE TABLE servers (id TEXT PRIMARY KEY, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER, authToken TEXT, runningOnHa INTEGER)");
|
||||
await db.execute("CREATE TABLE appConfig (theme NUMERIC, overrideSslCheck NUMERIC, hideZeroValues NUMERIC, useDynamicColor NUMERIC, staticColor NUMERIC, useThemeColorForStatus NUMERIC, showTimeLogs NUMERIC, showIpLogs, doNotRememberVersion TEXT)");
|
||||
await db.execute("INSERT INTO appConfig (theme, overrideSslCheck, hideZeroValues, useDynamicColor, staticColor, useThemeColorForStatus, showTimeLogs, showIpLogs) VALUES (0, 0, 0, ${acceptsDynamicTheme == true ? 1 : 0}, 0, 0, 0, 0)");
|
||||
await db.execute("CREATE TABLE appConfig (theme NUMERIC, overrideSslCheck NUMERIC, hideZeroValues NUMERIC, useDynamicColor NUMERIC, staticColor NUMERIC, useThemeColorForStatus NUMERIC, showTimeLogs NUMERIC, showIpLogs NUMERIC, combinedChart NUMERIC, doNotRememberVersion TEXT)");
|
||||
await db.execute("INSERT INTO appConfig (theme, overrideSslCheck, hideZeroValues, useDynamicColor, staticColor, useThemeColorForStatus, showTimeLogs, showIpLogs, combinedChart) VALUES (0, 0, 0, ${acceptsDynamicTheme == true ? 1 : 0}, 0, 0, 0, 0, 0)");
|
||||
},
|
||||
onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||
if (oldVersion == 1) {
|
||||
|
|
134
lib/widgets/combined_line_chart.dart
Normal file
134
lib/widgets/combined_line_chart.dart
Normal file
|
@ -0,0 +1,134 @@
|
|||
import 'package:adguard_home_manager/screens/home/combined_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
|
||||
|
||||
class CustomCombinedLineChart extends StatelessWidget {
|
||||
final CombinedChartData inputData;
|
||||
|
||||
const CustomCombinedLineChart({
|
||||
Key? key,
|
||||
required this.inputData,
|
||||
}) : super(key: key);
|
||||
|
||||
LineChartData mainData(Map<String, dynamic> data, ThemeMode selectedTheme) {
|
||||
return LineChartData(
|
||||
gridData: FlGridData(
|
||||
show: false,
|
||||
drawVerticalLine: false,
|
||||
),
|
||||
titlesData: FlTitlesData(
|
||||
show: false,
|
||||
),
|
||||
borderData: FlBorderData(
|
||||
show: false,
|
||||
),
|
||||
lineBarsData: List<LineChartBarData>.from(
|
||||
data["lines"].map((item) => LineChartBarData(
|
||||
spots: item['data'],
|
||||
color: item['color'],
|
||||
isCurved: true,
|
||||
barWidth: 2,
|
||||
isStrokeCapRound: true,
|
||||
preventCurveOverShooting: true,
|
||||
dotData: FlDotData(
|
||||
show: false,
|
||||
),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
color: item['color'].withOpacity(0.2)
|
||||
),
|
||||
))
|
||||
),
|
||||
lineTouchData: LineTouchData(
|
||||
enabled: true,
|
||||
touchTooltipData: LineTouchTooltipData(
|
||||
tooltipBgColor: selectedTheme == ThemeMode.light
|
||||
? const Color.fromRGBO(220, 220, 220, 0.9)
|
||||
: const Color.fromRGBO(35, 35, 35, 0.9),
|
||||
getTooltipItems: (items) => items.asMap().entries.map((item) => LineTooltipItem(
|
||||
"${data['lines'][item.key]['label']}: ${item.value.y.toInt().toString()}",
|
||||
TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
color: data['lines'][item.key]['color']
|
||||
)
|
||||
)).toList()
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||
|
||||
Map<String, dynamic> formatData(CombinedChartData unformattedData) {
|
||||
int topPoint = 0;
|
||||
|
||||
List<FlSpot> dataLine(List<int> data) {
|
||||
final List<FlSpot> formattedData = [];
|
||||
|
||||
int xPosition = 0;
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if (data[i] > topPoint) {
|
||||
topPoint = data[i];
|
||||
}
|
||||
formattedData.add(
|
||||
FlSpot(
|
||||
xPosition.toDouble(),
|
||||
data[i].toDouble()
|
||||
)
|
||||
);
|
||||
xPosition++;
|
||||
}
|
||||
|
||||
return formattedData;
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> toDraw = [];
|
||||
|
||||
toDraw.add({
|
||||
"data": dataLine(unformattedData.totalQueries.data),
|
||||
"color": unformattedData.totalQueries.color,
|
||||
"label": unformattedData.totalQueries.label
|
||||
});
|
||||
if (unformattedData.blockedFilters != null) {
|
||||
toDraw.add({
|
||||
"data": dataLine(unformattedData.blockedFilters!.data),
|
||||
"color": unformattedData.blockedFilters!.color,
|
||||
"label": unformattedData.blockedFilters!.label
|
||||
});
|
||||
}
|
||||
if (unformattedData.replacedSafeBrowsing != null) {
|
||||
toDraw.add({
|
||||
"data": dataLine(unformattedData.replacedSafeBrowsing!.data),
|
||||
"color": unformattedData.replacedSafeBrowsing!.color,
|
||||
"label": unformattedData.replacedSafeBrowsing!.label
|
||||
});
|
||||
}
|
||||
if (unformattedData.replacedParental != null) {
|
||||
toDraw.add({
|
||||
"data": dataLine(unformattedData.replacedParental!.data),
|
||||
"color": unformattedData.replacedParental!.color,
|
||||
"label": unformattedData.replacedParental!.label
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
'lines': toDraw,
|
||||
'topPoint': topPoint
|
||||
};
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||
child: LineChart(
|
||||
mainData(formatData(inputData), appConfigProvider.selectedTheme)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue