diff --git a/lib/models/server_status.dart b/lib/models/server_status.dart index 5799054..e44ec9c 100644 --- a/lib/models/server_status.dart +++ b/lib/models/server_status.dart @@ -1,3 +1,4 @@ +import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/models/dns_statistics.dart'; class ServerStatus { @@ -11,6 +12,7 @@ class ServerStatus { } class ServerStatusData { final DnsStatistics stats; + final List clients; bool generalEnabled; bool filteringEnabled; bool safeSearchEnabled; @@ -19,6 +21,7 @@ class ServerStatusData { ServerStatusData({ required this.stats, + required this.clients, required this.generalEnabled, required this.filteringEnabled, required this.safeSearchEnabled, @@ -28,6 +31,7 @@ class ServerStatusData { factory ServerStatusData.fromJson(Map json) => ServerStatusData( stats: DnsStatistics.fromJson(json['stats']), + clients: json["clients"] != null ? List.from(json["clients"].map((x) => Client.fromJson(x))) : [], generalEnabled: json['generalEnabled']['protection_enabled'], filteringEnabled: json['filteringEnabled']['enabled'], safeSearchEnabled: json['safeSearchEnabled']['enabled'], diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart index eefbc12..b23c083 100644 --- a/lib/screens/home/home.dart +++ b/lib/screens/home/home.dart @@ -153,6 +153,7 @@ class _HomeState extends State { label: AppLocalizations.of(context)!.topClients, data: serversProvider.serverStatus.data!.stats.topClients, type: 'topClients', + clients: true, ), ], ); diff --git a/lib/screens/home/top_items.dart b/lib/screens/home/top_items.dart index 3a76f73..03fd4c7 100644 --- a/lib/screens/home/top_items.dart +++ b/lib/screens/home/top_items.dart @@ -1,25 +1,38 @@ 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/top_items/top_items.dart'; +import 'package:adguard_home_manager/providers/servers_provider.dart'; class TopItems extends StatelessWidget { final String type; final String label; final List> data; + final bool? clients; const TopItems({ Key? key, required this.type, required this.label, required this.data, + this.clients }) : super(key: key); @override Widget build(BuildContext context) { - final width = MediaQuery.of(context).size.width; + final serversProvider = Provider.of(context); Widget rowItem(Map item) { + String? name; + if (clients != null && clients == true) { + try { + name = serversProvider.serverStatus.data!.clients.firstWhere((c) => c.ids.contains(item.keys.toList()[0])).name; + } catch (e) { + // ---- // + } + } + return Padding( padding: const EdgeInsets.symmetric( horizontal: 20, @@ -28,14 +41,29 @@ class TopItems extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: width-100, - child: Text( - item.keys.toList()[0], - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 16 - ), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.keys.toList()[0], + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 16 + ), + ), + if (name != null) ...[ + const SizedBox(height: 5), + Text( + name, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 14, + color: Theme.of(context).listTileTheme.iconColor + ), + ), + ] + ], ), ), Text(item.values.toList()[0].toString()) @@ -86,6 +114,7 @@ class TopItems extends StatelessWidget { builder: (context) => TopItemsScreen( type: type, title: label, + isClient: clients, ) ) ), diff --git a/lib/screens/top_items/top_items.dart b/lib/screens/top_items/top_items.dart index 64fb1ea..402aefc 100644 --- a/lib/screens/top_items/top_items.dart +++ b/lib/screens/top_items/top_items.dart @@ -6,6 +6,8 @@ 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/custom_list_tile.dart'; + import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; @@ -14,11 +16,13 @@ import 'package:adguard_home_manager/services/http_requests.dart'; class TopItemsScreen extends StatelessWidget { final String type; final String title; + final bool? isClient; const TopItemsScreen({ Key? key, required this.type, required this.title, + this.isClient, }) : super(key: key); @override @@ -49,6 +53,7 @@ class TopItemsScreen extends StatelessWidget { total = total + int.parse(element.values.toList()[0].toString()); } + return Scaffold( appBar: AppBar( title: Text(title), @@ -71,11 +76,44 @@ class TopItemsScreen extends StatelessWidget { }, child: ListView.builder( itemCount: data.length, - itemBuilder: (context, index) => ListTile( - title: Text(data[index].keys.toList()[0]), - trailing: Text(data[index].values.toList()[0].toString()), - subtitle: Text("${doubleFormat((data[index].values.toList()[0]/total*100), Platform.localeName)}%") - ) + itemBuilder: (context, index) { + String? name; + if (isClient != null && isClient == true) { + try { + name = serversProvider.serverStatus.data!.clients.firstWhere((c) => c.ids.contains(data[index].keys.toList()[0])).name; + } catch (e) { + // ---- // + } + } + + return CustomListTile( + title: data[index].keys.toList()[0], + trailing: Text(data[index].values.toList()[0].toString()), + subtitleWidget: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (name != null) ...[ + Text( + name, + style: TextStyle( + fontSize: 14, + color: Theme.of(context).brightness == Brightness.light + ? Colors.black + : Colors.white + ), + ), + const SizedBox(height: 5), + ], + Text( + "${doubleFormat((data[index].values.toList()[0]/total*100), Platform.localeName)}%", + style: TextStyle( + color: Theme.of(context).listTileTheme.iconColor + ), + ), + ], + ) + ); + } ), ), ); diff --git a/lib/services/http_requests.dart b/lib/services/http_requests.dart index a7a943b..6286dce 100644 --- a/lib/services/http_requests.dart +++ b/lib/services/http_requests.dart @@ -246,6 +246,7 @@ Future getServerStatus(Server server) async { apiRequest(server: server, method: 'get', urlPath: '/safesearch/status', type: 'server_status'), apiRequest(server: server, method: 'get', urlPath: '/safebrowsing/status', type: 'server_status'), apiRequest(server: server, method: 'get', urlPath: '/parental/status', type: 'server_status'), + apiRequest(server: server, method: 'get', urlPath: '/clients', type: 'server_status'), ]); if ( @@ -254,7 +255,8 @@ Future getServerStatus(Server server) async { result[2]['hasResponse'] == true && result[3]['hasResponse'] == true && result[4]['hasResponse'] == true && - result[5]['hasResponse'] == true + result[5]['hasResponse'] == true && + result[6]['hasResponse'] == true ) { if ( result[0]['statusCode'] == 200 && @@ -262,10 +264,12 @@ Future getServerStatus(Server server) async { result[2]['statusCode'] == 200 && result[3]['statusCode'] == 200 && result[4]['statusCode'] == 200 && - result[5]['statusCode'] == 200 + result[5]['statusCode'] == 200 && + result[6]['statusCode'] == 200 ) { final Map mappedData = { 'stats': jsonDecode(result[0]['body']), + 'clients': jsonDecode(result[6]['body'])['clients'], 'generalEnabled': jsonDecode(result[1]['body']), 'filteringEnabled': jsonDecode(result[2]['body']), 'safeSearchEnabled': jsonDecode(result[3]['body']), diff --git a/lib/widgets/custom_list_tile.dart b/lib/widgets/custom_list_tile.dart index 14a8207..89b01a8 100644 --- a/lib/widgets/custom_list_tile.dart +++ b/lib/widgets/custom_list_tile.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; class CustomListTile extends StatelessWidget { final String title; final String? subtitle; + final Widget? subtitleWidget; final void Function()? onTap; final IconData? icon; final Widget? trailing; @@ -12,6 +13,7 @@ class CustomListTile extends StatelessWidget { Key? key, required this.title, this.subtitle, + this.subtitleWidget, this.onTap, this.icon, this.trailing, @@ -50,9 +52,10 @@ class CustomListTile extends StatelessWidget { fontWeight: FontWeight.normal ), ), - if (subtitle != null) ...[ + if (subtitle != null || subtitleWidget != null) ...[ const SizedBox(height: 5), - Text( + if (subtitle == null && subtitleWidget != null) subtitleWidget!, + if (subtitle != null && subtitleWidget == null) Text( subtitle!, style: TextStyle( color: Theme.of(context).listTileTheme.iconColor,