diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 328f917..76ea468 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -43,5 +43,13 @@ "edit": "Edit", "delete": "Delete", "save": "Save", - "connectionNotUpdated": "Connection not updated" + "serverStatus": "Server status", + "connectionNotUpdated": "Connection not updated", + "ruleFiltering": "Rule\nfiltering", + "safeBrowsing": "Safe\nbrowsing", + "parentalFiltering": "Parental\nfiltering", + "safeSearch": "Safe\nsearch", + "serverStatusNotRefreshed": "Server status could not be refreshed", + "loadingStatus": "Loading status...", + "errorLoadServerStatus": "Server status could not be loaded" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index bb17c28..13648a2 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -43,5 +43,13 @@ "edit": "Editar", "delete": "Eliminar", "save": "Guardar", - "connectionNotUpdated": "Conexión no actualizada" + "connectionNotUpdated": "Conexión no actualizada", + "serverStatus": "Estado del servidor", + "ruleFiltering": "Bloqueo por\nfiltros", + "safeBrowsing": "Navegación\nsegura", + "parentalFiltering": "Control\nparental", + "safeSearch": "Búsqueda\nsegura", + "serverStatusNotRefreshed": "No se ha podido actualizar el estado del servidor", + "loadingStatus": "Cargando estado...", + "errorLoadServerStatus": "Error al cargar el estado" } \ No newline at end of file diff --git a/lib/models/server_status.dart b/lib/models/server_status.dart index d6380a9..2fb45e0 100644 --- a/lib/models/server_status.dart +++ b/lib/models/server_status.dart @@ -1,6 +1,15 @@ import 'package:adguard_home_manager/models/dns_statistics.dart'; class ServerStatus { + int loadStatus; + ServerStatusData? data; + + ServerStatus({ + required this.loadStatus, + this.data + }); +} +class ServerStatusData { final DnsStatistics stats; final bool generalEnabled; final bool filteringEnabled; @@ -8,7 +17,7 @@ class ServerStatus { final bool safeBrowsingEnabled; final bool parentalControlEnabled; - const ServerStatus({ + const ServerStatusData({ required this.stats, required this.generalEnabled, required this.filteringEnabled, @@ -17,7 +26,7 @@ class ServerStatus { required this.parentalControlEnabled }); - factory ServerStatus.fromJson(Map json) => ServerStatus( + factory ServerStatusData.fromJson(Map json) => ServerStatusData( stats: DnsStatistics.fromJson(json['stats']), generalEnabled: json['generalEnabled']['protection_enabled'], filteringEnabled: json['filteringEnabled']['enabled'], diff --git a/lib/providers/servers_provider.dart b/lib/providers/servers_provider.dart index b703931..ed86354 100644 --- a/lib/providers/servers_provider.dart +++ b/lib/providers/servers_provider.dart @@ -1,9 +1,8 @@ -import 'package:adguard_home_manager/models/dns_statistics.dart'; -import 'package:adguard_home_manager/models/server_status.dart'; -import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:flutter/material.dart'; import 'package:sqflite/sqflite.dart'; +import 'package:adguard_home_manager/services/http_requests.dart'; +import 'package:adguard_home_manager/models/server_status.dart'; import 'package:adguard_home_manager/functions/conversions.dart'; import 'package:adguard_home_manager/models/server.dart'; @@ -12,8 +11,10 @@ class ServersProvider with ChangeNotifier { List _serversList = []; Server? _selectedServer; - bool? _isServerConnected; - ServerStatus? _serverStatus; + final ServerStatus _serverStatus = ServerStatus( + loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error + data: null + ); // serverStatus != null means server is connected List get serversList { return _serversList; @@ -23,11 +24,7 @@ class ServersProvider with ChangeNotifier { return _selectedServer; } - bool? get isServerConnected { - return _isServerConnected; - } - - ServerStatus? get serverStatus { + ServerStatus get serverStatus { return _serverStatus; } @@ -45,13 +42,13 @@ class ServersProvider with ChangeNotifier { notifyListeners(); } - void setIsServerConnected(bool status) { - _isServerConnected = status; + void setServerStatusData(ServerStatusData data) { + _serverStatus.data = data; notifyListeners(); } - void setServerStatus(ServerStatus data) { - _serverStatus = data; + void setServerStatusLoad(int status) { + _serverStatus.loadStatus = status; notifyListeners(); } @@ -209,13 +206,14 @@ class ServersProvider with ChangeNotifier { _serversList.add(serverObj); if (convertFromIntToBool(server['defaultServer']) == true) { _selectedServer = serverObj; + _serverStatus.loadStatus = 0; final serverStatus = await getServerStatus(serverObj); if (serverStatus['result'] == 'success') { - _serverStatus = serverStatus['data']; - _isServerConnected = true; + _serverStatus.data = serverStatus['data']; + _serverStatus.loadStatus = 1; } else { - _isServerConnected = false; + _serverStatus.loadStatus = 2; } } } diff --git a/lib/screens/home/appbar.dart b/lib/screens/home/appbar.dart index b54fba1..5116215 100644 --- a/lib/screens/home/appbar.dart +++ b/lib/screens/home/appbar.dart @@ -1,13 +1,71 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:adguard_home_manager/models/server.dart'; +import 'package:adguard_home_manager/providers/servers_provider.dart'; + class HomeAppBar extends StatelessWidget with PreferredSizeWidget { const HomeAppBar({Key? key}) : super(key: key); @override PreferredSizeWidget build(BuildContext context) { + final serversProvider = Provider.of(context); + + final Server server = serversProvider.selectedServer!; + return AppBar( - title: Text(AppLocalizations.of(context)!.home), + title: Padding( + padding: const EdgeInsets.only(bottom: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Icon( + serversProvider.serverStatus.data != null + ? serversProvider.serverStatus.data!.generalEnabled == true + ? Icons.gpp_good_rounded + : Icons.gpp_bad_rounded + : Icons.shield, + size: 30, + color: serversProvider.serverStatus.data != null + ? serversProvider.serverStatus.data!.generalEnabled == true + ? Colors.green + : Colors.red + : Colors.grey, + ), + const SizedBox(width: 20), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + server.name, + style: const TextStyle( + fontSize: 20 + ), + ), + const SizedBox(height: 5), + Text( + "${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}", + style: const TextStyle( + fontSize: 14, + color: Color.fromRGBO(140, 140, 140, 1) + ), + ) + ], + ), + ], + ), + PopupMenuButton( + itemBuilder: (context) => [ + + ] + ) + ], + ), + ), ); } diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart index d9a30c4..f41951e 100644 --- a/lib/screens/home/home.dart +++ b/lib/screens/home/home.dart @@ -1,6 +1,12 @@ +// 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/home/server_status.dart'; + +import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; class Home extends StatelessWidget { @@ -10,6 +16,88 @@ class Home extends StatelessWidget { Widget build(BuildContext context) { final serversProvider = Provider.of(context); - return Container(); + Widget status() { + switch (serversProvider.serverStatus.loadStatus) { + case 0: + return SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 30), + Text( + AppLocalizations.of(context)!.loadingStatus, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + fontWeight: FontWeight.w500 + ), + ) + ], + ), + ); + + case 1: + return ListView( + children: [ + ServerStatus(serverStatus: serversProvider.serverStatus.data!), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Divider( + thickness: 1, + ), + ) + ], + ); + + case 2: + return SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Icon( + Icons.error, + color: Colors.red, + size: 50, + ), + const SizedBox(height: 30), + Text( + AppLocalizations.of(context)!.errorLoadServerStatus, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + fontWeight: FontWeight.w500 + ), + ) + ], + ), + ); + + default: + return const SizedBox(); + } + } + + return RefreshIndicator( + onRefresh: () async { + final result = await getServerStatus(serversProvider.selectedServer!); + if (result['result'] == 'success') { + serversProvider.setServerStatusData(result['data']); + } + else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.serverStatusNotRefreshed), + backgroundColor: Colors.red, + ) + ); + } + }, + child: status() + ); } } \ No newline at end of file diff --git a/lib/screens/home/server_status.dart b/lib/screens/home/server_status.dart new file mode 100644 index 0000000..2fc42c0 --- /dev/null +++ b/lib/screens/home/server_status.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +import 'package:adguard_home_manager/screens/home/status_box.dart'; + +import 'package:adguard_home_manager/models/server_status.dart'; + +class ServerStatus extends StatelessWidget { + final ServerStatusData serverStatus; + + const ServerStatus({ + Key? key, + required this.serverStatus, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + Text( + AppLocalizations.of(context)!.serverStatus, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500 + ), + ), + const SizedBox(height: 20), + SizedBox( + height: 140, + child: GridView( + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + mainAxisExtent: 65 + ), + children: [ + StatusBox( + icon: Icons.filter_list_rounded, + label: AppLocalizations.of(context)!.ruleFiltering, + isEnabled: serverStatus.filteringEnabled + ), + StatusBox( + icon: Icons.vpn_lock_rounded, + label: AppLocalizations.of(context)!.safeBrowsing, + isEnabled: serverStatus.safeBrowsingEnabled + ), + StatusBox( + icon: Icons.block, + label: AppLocalizations.of(context)!.parentalFiltering, + isEnabled: serverStatus.parentalControlEnabled + ), + StatusBox( + icon: Icons.search_rounded, + label: AppLocalizations.of(context)!.safeSearch, + isEnabled: serverStatus.safeSearchEnabled + ), + ], + ), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/home/status_box.dart b/lib/screens/home/status_box.dart new file mode 100644 index 0000000..37fda48 --- /dev/null +++ b/lib/screens/home/status_box.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class StatusBox extends StatelessWidget { + final IconData icon; + final String label; + final bool isEnabled; + + const StatusBox({ + Key? key, + required this.icon, + required this.label, + required this.isEnabled + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final width = MediaQuery.of(context).size.width; + + return Container( + padding: const EdgeInsets.all(12), + width: double.maxFinite, + height: double.maxFinite, + decoration: BoxDecoration( + color: isEnabled == true + ? Colors.green + : Colors.red, + borderRadius: BorderRadius.circular(10) + ), + child: Row( + children: [ + Icon( + icon, + color: Colors.white, + ), + const SizedBox(width: 12), + Text( + label, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500 + ), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/services/http_requests.dart b/lib/services/http_requests.dart index a64da16..f4ebc05 100644 --- a/lib/services/http_requests.dart +++ b/lib/services/http_requests.dart @@ -87,7 +87,7 @@ Future getServerStatus(Server server) async { return { 'result': 'success', - 'data': ServerStatus.fromJson(mappedData) + 'data': ServerStatusData.fromJson(mappedData) }; } else { diff --git a/lib/widgets/add_server_modal.dart b/lib/widgets/add_server_modal.dart index 27307b3..24fbaf6 100644 --- a/lib/widgets/add_server_modal.dart +++ b/lib/widgets/add_server_modal.dart @@ -225,13 +225,14 @@ class _AddServerModalState extends State { serverObj.authToken = encodeBase64UserPass(serverObj.user, serverObj.password); final serverCreated = await serversProvider.createServer(serverObj); if (serverCreated == true) { + serversProvider.setServerStatusLoad(0); final serverStatus = await getServerStatus(serverObj); if (serverStatus['result'] == 'success') { - serversProvider.setServerStatus(serverStatus['data']); - serversProvider.setIsServerConnected(true); + serversProvider.setServerStatusData(serverStatus['data']); + serversProvider.setServerStatusLoad(1); } else { - serversProvider.setIsServerConnected(false); + serversProvider.setServerStatusLoad(2); } Navigator.pop(context); } diff --git a/lib/widgets/servers_list/servers_list.dart b/lib/widgets/servers_list/servers_list.dart index fdaaba5..2d10865 100644 --- a/lib/widgets/servers_list/servers_list.dart +++ b/lib/widgets/servers_list/servers_list.dart @@ -62,13 +62,14 @@ class ServersList extends StatelessWidget { if (result['result'] == 'success') { serversProvider.setSelectedServer(server); + serversProvider.setServerStatusLoad(0); final serverStatus = await getServerStatus(server); if (serverStatus['result'] == 'success') { - serversProvider.setServerStatus(serverStatus['data']); - serversProvider.setIsServerConnected(true); + serversProvider.setServerStatusData(serverStatus['data']); + serversProvider.setServerStatusLoad(1); } else { - serversProvider.setIsServerConnected(false); + serversProvider.setServerStatusLoad(2); } process.close(); @@ -112,7 +113,7 @@ class ServersList extends StatelessWidget { Icon( Icons.storage_rounded, color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id - ? serversProvider.isServerConnected == true + ? serversProvider.serverStatus.data != null ? Colors.green : Colors.orange : null, @@ -145,7 +146,7 @@ class ServersList extends StatelessWidget { return Icon( Icons.storage_rounded, color: serversProvider.selectedServer != null && serversProvider.selectedServer?.id == server.id - ? serversProvider.isServerConnected == true + ? serversProvider.serverStatus.data != null ? Colors.green : Colors.orange : null, @@ -258,7 +259,7 @@ class ServersList extends StatelessWidget { margin: const EdgeInsets.only(right: 12), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), decoration: BoxDecoration( - color: serversProvider.isServerConnected == true + color: serversProvider.serverStatus.data != null ? Colors.green : Colors.orange, borderRadius: BorderRadius.circular(30) @@ -266,14 +267,14 @@ class ServersList extends StatelessWidget { child: Row( children: [ Icon( - serversProvider.isServerConnected == true + serversProvider.serverStatus.data != null ? Icons.check : Icons.warning, color: Colors.white, ), const SizedBox(width: 10), Text( - serversProvider.isServerConnected == true + serversProvider.serverStatus.data != null ? AppLocalizations.of(context)!.connected : AppLocalizations.of(context)!.selectedDisconnected, style: const TextStyle(