mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-22 14:59:12 +00:00
Added clients screen
This commit is contained in:
parent
576731b97f
commit
d4a792e5c8
10 changed files with 393 additions and 5 deletions
|
@ -5,6 +5,7 @@ import 'package:adguard_home_manager/screens/home/appbar.dart';
|
|||
import 'package:adguard_home_manager/screens/connect/appbar.dart';
|
||||
import 'package:adguard_home_manager/screens/connect/connect.dart';
|
||||
import 'package:adguard_home_manager/screens/home/home.dart';
|
||||
import 'package:adguard_home_manager/screens/clients/clients.dart';
|
||||
import 'package:adguard_home_manager/screens/settings/appbar.dart';
|
||||
import 'package:adguard_home_manager/screens/settings/settings.dart';
|
||||
import 'package:adguard_home_manager/screens/home/fab.dart';
|
||||
|
@ -35,6 +36,11 @@ List<AppScreen> screensServerConnected = [
|
|||
body: Home(),
|
||||
fab: HomeFab()
|
||||
),
|
||||
const AppScreen(
|
||||
name: "clients",
|
||||
icon: Icons.devices,
|
||||
body: Clients(),
|
||||
),
|
||||
const AppScreen(
|
||||
name: "settings",
|
||||
icon: Icons.settings_rounded,
|
||||
|
|
|
@ -77,5 +77,8 @@
|
|||
"helperPath": "If you are using a reverse proxy",
|
||||
"aboutApp": "About the application",
|
||||
"appVersion": "App version",
|
||||
"createdBy": "Created by"
|
||||
"createdBy": "Created by",
|
||||
"clients": "Clients",
|
||||
"allowed": "Allowed",
|
||||
"blocked": "Blocked"
|
||||
}
|
|
@ -77,5 +77,8 @@
|
|||
"helperPath": "Si estás usando un reverse proxy",
|
||||
"aboutApp": "Sobre la aplicación",
|
||||
"appVersion": "Versión de la app",
|
||||
"createdBy": "Creado por"
|
||||
"createdBy": "Creado por",
|
||||
"clients": "Clientes",
|
||||
"allowed": "Permitidos",
|
||||
"blocked": "Bloqueados"
|
||||
}
|
|
@ -3,14 +3,14 @@ import 'package:flutter/material.dart';
|
|||
class AppScreen {
|
||||
final String name;
|
||||
final IconData icon;
|
||||
final PreferredSizeWidget appBar;
|
||||
final PreferredSizeWidget? appBar;
|
||||
final Widget body;
|
||||
final Widget? fab;
|
||||
|
||||
const AppScreen({
|
||||
required this.name,
|
||||
required this.icon,
|
||||
required this.appBar,
|
||||
this.appBar,
|
||||
required this.body,
|
||||
this.fab
|
||||
});
|
||||
|
|
131
lib/models/clients.dart
Normal file
131
lib/models/clients.dart
Normal file
|
@ -0,0 +1,131 @@
|
|||
import 'dart:convert';
|
||||
|
||||
class Clients {
|
||||
int loadStatus;
|
||||
ClientsData? data;
|
||||
|
||||
Clients({
|
||||
required this.loadStatus,
|
||||
this.data
|
||||
});
|
||||
}
|
||||
|
||||
ClientsData clientsFromJson(String str) => ClientsData.fromJson(json.decode(str));
|
||||
|
||||
String clientsToJson(ClientsData data) => json.encode(data.toJson());
|
||||
|
||||
class ClientsData {
|
||||
final List<Client> clients;
|
||||
final List<AutoClient> autoClientsData;
|
||||
final List<String> supportedTags;
|
||||
|
||||
ClientsData({
|
||||
required this.clients,
|
||||
required this.autoClientsData,
|
||||
required this.supportedTags,
|
||||
});
|
||||
|
||||
factory ClientsData.fromJson(Map<String, dynamic> json) => ClientsData(
|
||||
clients: json["clients"] != null ? List<Client>.from(json["clients"].map((x) => Client.fromJson(x))) : [],
|
||||
autoClientsData: json["auto_clients"] != null ? List<AutoClient>.from(json["auto_clients"].map((x) => AutoClient.fromJson(x))) : [],
|
||||
supportedTags: json["supported_tags"] != null ? List<String>.from(json["supported_tags"].map((x) => x)) : [],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"clients": List<dynamic>.from(clients.map((x) => x.toJson())),
|
||||
"auto_clients": List<dynamic>.from(autoClientsData.map((x) => x.toJson())),
|
||||
"supported_tags": List<dynamic>.from(supportedTags.map((x) => x)),
|
||||
};
|
||||
}
|
||||
|
||||
class AutoClient {
|
||||
final WhoisInfo whoisInfo;
|
||||
final String? name;
|
||||
final String source;
|
||||
final String ip;
|
||||
|
||||
AutoClient({
|
||||
required this.whoisInfo,
|
||||
this.name,
|
||||
required this.source,
|
||||
required this.ip,
|
||||
});
|
||||
|
||||
factory AutoClient.fromJson(Map<String, dynamic> json) => AutoClient(
|
||||
whoisInfo: WhoisInfo.fromJson(json["whois_info"]),
|
||||
name: json["name"],
|
||||
source: json["source"],
|
||||
ip: json["ip"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"whois_info": whoisInfo.toJson(),
|
||||
"name": name,
|
||||
"source": source,
|
||||
"ip": ip,
|
||||
};
|
||||
}
|
||||
|
||||
class WhoisInfo {
|
||||
WhoisInfo();
|
||||
|
||||
factory WhoisInfo.fromJson(Map<String, dynamic> json) => WhoisInfo();
|
||||
|
||||
Map<String, dynamic> toJson() => {};
|
||||
}
|
||||
|
||||
class Client {
|
||||
final String name;
|
||||
final dynamic blockedServices;
|
||||
final List<String> ids;
|
||||
final List<String> tags;
|
||||
final List<dynamic> upstreams;
|
||||
final bool filteringEnabled;
|
||||
final bool parentalEnabled;
|
||||
final bool safebrowsingEnabled;
|
||||
final bool safesearchEnabled;
|
||||
final bool useGlobalBlockedServices;
|
||||
final bool useGlobalSettings;
|
||||
|
||||
Client({
|
||||
required this.name,
|
||||
required this.blockedServices,
|
||||
required this.ids,
|
||||
required this.tags,
|
||||
required this.upstreams,
|
||||
required this.filteringEnabled,
|
||||
required this.parentalEnabled,
|
||||
required this.safebrowsingEnabled,
|
||||
required this.safesearchEnabled,
|
||||
required this.useGlobalBlockedServices,
|
||||
required this.useGlobalSettings,
|
||||
});
|
||||
|
||||
factory Client.fromJson(Map<String, dynamic> json) => Client(
|
||||
name: json["name"],
|
||||
blockedServices: json["blocked_services"],
|
||||
ids: List<String>.from(json["ids"].map((x) => x)),
|
||||
tags: List<String>.from(json["tags"].map((x) => x)),
|
||||
upstreams: List<dynamic>.from(json["upstreams"].map((x) => x)),
|
||||
filteringEnabled: json["filtering_enabled"],
|
||||
parentalEnabled: json["parental_enabled"],
|
||||
safebrowsingEnabled: json["safebrowsing_enabled"],
|
||||
safesearchEnabled: json["safesearch_enabled"],
|
||||
useGlobalBlockedServices: json["use_global_blocked_services"],
|
||||
useGlobalSettings: json["use_global_settings"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"name": name,
|
||||
"blocked_services": blockedServices,
|
||||
"ids": List<dynamic>.from(ids.map((x) => x)),
|
||||
"tags": List<dynamic>.from(tags.map((x) => x)),
|
||||
"upstreams": List<dynamic>.from(upstreams.map((x) => x)),
|
||||
"filtering_enabled": filteringEnabled,
|
||||
"parental_enabled": parentalEnabled,
|
||||
"safebrowsing_enabled": safebrowsingEnabled,
|
||||
"safesearch_enabled": safesearchEnabled,
|
||||
"use_global_blocked_services": useGlobalBlockedServices,
|
||||
"use_global_settings": useGlobalSettings,
|
||||
};
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/clients.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';
|
||||
|
@ -17,6 +18,11 @@ class ServersProvider with ChangeNotifier {
|
|||
); // serverStatus != null means server is connected
|
||||
List<String> _protectionsManagementProcess = []; // protections that are currenty being enabled or disabled
|
||||
|
||||
final Clients _clients = Clients(
|
||||
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error
|
||||
data: null
|
||||
);
|
||||
|
||||
List<Server> get serversList {
|
||||
return _serversList;
|
||||
}
|
||||
|
@ -33,6 +39,10 @@ class ServersProvider with ChangeNotifier {
|
|||
return _protectionsManagementProcess;
|
||||
}
|
||||
|
||||
Clients get clients {
|
||||
return _clients;
|
||||
}
|
||||
|
||||
void setDbInstance(Database db) {
|
||||
_dbInstance = db;
|
||||
}
|
||||
|
@ -56,6 +66,18 @@ class ServersProvider with ChangeNotifier {
|
|||
_serverStatus.loadStatus = status;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setClientsLoadStatus(int status, bool notify) {
|
||||
_clients.loadStatus = status;
|
||||
if (notify == true) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void setClientsData(ClientsData data) {
|
||||
_clients.data = data;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<bool> createServer(Server server) async {
|
||||
final saved = await saveServerIntoDb(server);
|
||||
|
|
160
lib/screens/clients/clients.dart
Normal file
160
lib/screens/clients/clients.dart
Normal file
|
@ -0,0 +1,160 @@
|
|||
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/clients/clients_list.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/server.dart';
|
||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
class Clients extends StatelessWidget {
|
||||
const Clients({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
|
||||
return ClientsWidget(
|
||||
server: serversProvider.selectedServer!,
|
||||
setLoadingStatus: serversProvider.setClientsLoadStatus,
|
||||
setClientsData: serversProvider.setClientsData,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ClientsWidget extends StatefulWidget {
|
||||
final Server server;
|
||||
final void Function(int, bool) setLoadingStatus;
|
||||
final void Function(ClientsData) setClientsData;
|
||||
|
||||
const ClientsWidget({
|
||||
Key? key,
|
||||
required this.server,
|
||||
required this.setLoadingStatus,
|
||||
required this.setClientsData,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ClientsWidget> createState() => _ClientsWidgetState();
|
||||
}
|
||||
|
||||
class _ClientsWidgetState extends State<ClientsWidget> {
|
||||
void fetchClients() async {
|
||||
widget.setLoadingStatus(0, false);
|
||||
final result = await getClients(widget.server);
|
||||
if (result['result'] == 'success') {
|
||||
widget.setClientsData(result['data']);
|
||||
widget.setLoadingStatus(1, true);
|
||||
}
|
||||
else {
|
||||
widget.setLoadingStatus(2, true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
fetchClients();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
|
||||
switch (serversProvider.clients.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 DefaultTabController(
|
||||
length: 3,
|
||||
child: NestedScrollView(
|
||||
headerSliverBuilder: ((context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverAppBar(
|
||||
title: Text(AppLocalizations.of(context)!.clients),
|
||||
centerTitle: true,
|
||||
pinned: true,
|
||||
floating: true,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
bottom: TabBar(
|
||||
tabs: [
|
||||
Tab(
|
||||
icon: const Icon(Icons.devices),
|
||||
text: AppLocalizations.of(context)!.clients,
|
||||
),
|
||||
Tab(
|
||||
icon: const Icon(Icons.check),
|
||||
text: AppLocalizations.of(context)!.allowed,
|
||||
),
|
||||
Tab(
|
||||
icon: const Icon(Icons.block),
|
||||
text: AppLocalizations.of(context)!.blocked,
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
];
|
||||
}),
|
||||
body: TabBarView(
|
||||
children: [
|
||||
ClientsList(
|
||||
data: serversProvider.clients.data!.autoClientsData,
|
||||
),
|
||||
Container(),
|
||||
Container()
|
||||
],
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
33
lib/screens/clients/clients_list.dart
Normal file
33
lib/screens/clients/clients_list.dart
Normal file
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
|
||||
class ClientsList extends StatelessWidget {
|
||||
final List<AutoClient> data;
|
||||
|
||||
const ClientsList({
|
||||
Key? key,
|
||||
required this.data
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
itemCount: data.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
title: Text(
|
||||
data[index].name != ''
|
||||
? data[index].name!
|
||||
: data[index].ip
|
||||
),
|
||||
subtitle: data[index].name != ''
|
||||
? Text(
|
||||
data[index].ip
|
||||
)
|
||||
: null,
|
||||
trailing: Text(data[index].source),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import 'dart:io';
|
|||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:adguard_home_manager/models/server_status.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
import 'package:adguard_home_manager/models/server.dart';
|
||||
|
||||
Future<http.Response> getRequest({
|
||||
|
@ -241,4 +242,31 @@ Future updateGeneralProtection(Server server, bool enable) async {
|
|||
} catch (e) {
|
||||
return {'result': 'error'};
|
||||
}
|
||||
}
|
||||
|
||||
Future getClients(Server server) async {
|
||||
try {
|
||||
final result = await getRequest(
|
||||
urlPath: '/clients',
|
||||
server: server,
|
||||
);
|
||||
|
||||
if (result.statusCode == 200) {
|
||||
return {
|
||||
'result': 'success',
|
||||
'data': ClientsData.fromJson(jsonDecode(result.body))
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {'result': 'error'};
|
||||
}
|
||||
} on SocketException {
|
||||
return {'result': 'no_connection'};
|
||||
} on TimeoutException {
|
||||
return {'result': 'no_connection'};
|
||||
} on HandshakeException {
|
||||
return {'result': 'ssl_error'};
|
||||
} catch (e) {
|
||||
return {'result': 'error'};
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/app_screen.dart';
|
||||
import 'package:adguard_home_manager/config/app_screens.dart';
|
||||
|
||||
class BottomNavBar extends StatelessWidget {
|
||||
final List<AppScreen> screens;
|
||||
|
@ -29,6 +28,9 @@ class BottomNavBar extends StatelessWidget {
|
|||
case 'connect':
|
||||
return AppLocalizations.of(context)!.connect;
|
||||
|
||||
case 'clients':
|
||||
return AppLocalizations.of(context)!.clients;
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue