mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-14 05:52:51 +00:00
Implemented new router
This commit is contained in:
parent
621171c5b1
commit
96fe7eb730
17 changed files with 985 additions and 1090 deletions
|
@ -1,9 +1,7 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:async/async.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
|
@ -14,12 +12,20 @@ import 'package:adguard_home_manager/models/logs.dart';
|
|||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
class LogsListClient extends StatefulHookWidget {
|
||||
final String id;
|
||||
class LogsListClient extends StatefulWidget {
|
||||
final String ip;
|
||||
final String? name;
|
||||
final ServersProvider serversProvider;
|
||||
final AppConfigProvider appConfigProvider;
|
||||
final bool splitView;
|
||||
|
||||
const LogsListClient({
|
||||
Key? key,
|
||||
required this.id,
|
||||
required this.ip,
|
||||
this.name,
|
||||
required this.serversProvider,
|
||||
required this.appConfigProvider,
|
||||
required this.splitView,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -34,9 +40,11 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
int logsQuantity = 100;
|
||||
int offset = 0;
|
||||
|
||||
LoadStatus loadStatus = LoadStatus.loading;
|
||||
int loadStatus = 0;
|
||||
LogsData? logsData;
|
||||
|
||||
String previousIp = "";
|
||||
|
||||
bool showDivider = true;
|
||||
|
||||
CancelableOperation? cancelableRequest;
|
||||
|
@ -61,7 +69,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
serversProvider.apiClient!.getLogs(
|
||||
count: logsQuantity,
|
||||
offset: offst,
|
||||
search: '"${widget.id}"'
|
||||
search: '"${widget.ip}"'
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -84,11 +92,11 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
LogsData newLogsData = result['data'];
|
||||
setState(() => logsData = newLogsData);
|
||||
}
|
||||
setState(() => loadStatus = LoadStatus.loaded);
|
||||
setState(() => loadStatus = 1);
|
||||
}
|
||||
else {
|
||||
setState(() => loadStatus = LoadStatus.error);
|
||||
Provider.of<AppConfigProvider>(context, listen: false).addLog(result['log']);
|
||||
setState(() => loadStatus = 2);
|
||||
widget.appConfigProvider.addLog(result['log']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +118,8 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
@override
|
||||
void initState() {
|
||||
scrollController = ScrollController()..addListener(scrollListener);
|
||||
fetchLogs(inOffset: 0);
|
||||
setState(() => previousIp = widget.ip);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -117,15 +127,15 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
Widget build(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
|
||||
useEffect(() {
|
||||
setState(() => loadStatus = LoadStatus.loading);
|
||||
if (widget.ip != previousIp) {
|
||||
setState(() => loadStatus = 0);
|
||||
fetchLogs(inOffset: 0);
|
||||
return null;
|
||||
}, [widget.id]);
|
||||
setState(() => previousIp = widget.ip);
|
||||
}
|
||||
|
||||
Widget status() {
|
||||
switch (loadStatus) {
|
||||
case LoadStatus.loading:
|
||||
case 0:
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
|
@ -146,7 +156,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
),
|
||||
);
|
||||
|
||||
case LoadStatus.loaded:
|
||||
case 1:
|
||||
if (logsData!.data.isNotEmpty) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: fetchLogs,
|
||||
|
@ -189,7 +199,8 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
},
|
||||
twoColumns: widget.splitView,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +220,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
);
|
||||
}
|
||||
|
||||
case LoadStatus.error:
|
||||
case 2:
|
||||
return SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
|
@ -241,7 +252,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
|||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.id),
|
||||
title: Text(widget.name != null && widget.name != '' ? widget.name! : widget.ip),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
||||
|
|
|
@ -1,213 +1,55 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_split_view/flutter_split_view.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/screens/clients/added_list.dart';
|
||||
import 'package:adguard_home_manager/screens/clients/clients_lists.dart';
|
||||
|
||||
import 'package:adguard_home_manager/constants/routes_names.dart';
|
||||
import 'package:adguard_home_manager/functions/desktop_mode.dart';
|
||||
import 'package:adguard_home_manager/providers/clients_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
|
||||
class Clients extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const Clients({
|
||||
Key? key,
|
||||
required this.child,
|
||||
}) : super(key: key);
|
||||
const Clients({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<Clients> createState() => _ClientsState();
|
||||
}
|
||||
|
||||
class _ClientsState extends State<Clients> with TickerProviderStateMixin {
|
||||
late TabController tabController;
|
||||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
bool searchMode = false;
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
|
||||
clientsProvider.fetchClients(updateLoading: true);
|
||||
|
||||
super.initState();
|
||||
tabController = TabController(
|
||||
initialIndex: 0,
|
||||
length: 2,
|
||||
vsync: this,
|
||||
);
|
||||
tabController.addListener(
|
||||
() => Provider.of<AppConfigProvider>(context, listen: false).setSelectedClientsTab(tabController.index)
|
||||
);
|
||||
}
|
||||
|
||||
List<AutoClient> generateClientsList(List<AutoClient> clients, List<String> ips) {
|
||||
return clients.where((client) => ips.contains(client.ip)).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final clientsProvider = Provider.of<ClientsProvider>(context);
|
||||
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
|
||||
PreferredSizeWidget tabBar() {
|
||||
return TabBar(
|
||||
controller: tabController,
|
||||
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
tabs: [
|
||||
Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.devices),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.activeClients)
|
||||
],
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (constraints.maxWidth > 1000) {
|
||||
return SplitView.material(
|
||||
hideDivider: true,
|
||||
flexWidth: const FlexWidth(mainViewFlexWidth: 1, secondaryViewFlexWidth: 2),
|
||||
placeholder: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.selectClientLeftColumn,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.add_rounded),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.added)
|
||||
],
|
||||
),
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget tabBarView(bool sliver) {
|
||||
return TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
ClientsList(
|
||||
scrollController: scrollController,
|
||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||
? clientsProvider.filteredActiveClients : [],
|
||||
onClientSelected: (client) => context.go(
|
||||
RoutesNames.client,
|
||||
extra: {
|
||||
"id": client.name != null && client.name != ""
|
||||
? client.name
|
||||
: client.ip
|
||||
}
|
||||
),
|
||||
splitView: isDesktop(width),
|
||||
),
|
||||
AddedList(
|
||||
scrollController: scrollController,
|
||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||
? clientsProvider.filteredAddedClients : [],
|
||||
onClientSelected: (client) => context.go(
|
||||
RoutesNames.client,
|
||||
extra: { "id": client.name }
|
||||
),
|
||||
splitView: isDesktop(width),
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: isDesktop(width) ? 300 : width,
|
||||
height: double.maxFinite,
|
||||
child: Material(
|
||||
child: DefaultTabController(
|
||||
length: 2,
|
||||
child: NestedScrollView(
|
||||
controller: scrollController,
|
||||
headerSliverBuilder: ((context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar(
|
||||
title: searchMode == true
|
||||
? Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchMode = false;
|
||||
searchController.text = "";
|
||||
clientsProvider.setSearchTermClients(null);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back_rounded),
|
||||
tooltip: AppLocalizations.of(context)!.exitSearch,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: (value) => clientsProvider.setSearchTermClients(value),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchController.text = "";
|
||||
clientsProvider.setSearchTermClients(null);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.clear_rounded)
|
||||
),
|
||||
hintText: AppLocalizations.of(context)!.search,
|
||||
hintStyle: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
autofocus: true,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Text(AppLocalizations.of(context)!.clients),
|
||||
pinned: true,
|
||||
floating: true,
|
||||
centerTitle: false,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
actions: [
|
||||
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
|
||||
IconButton(
|
||||
onPressed: () => setState(() => searchMode = true),
|
||||
icon: const Icon(Icons.search),
|
||||
tooltip: AppLocalizations.of(context)!.searchClients,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
]
|
||||
],
|
||||
bottom: tabBar()
|
||||
),
|
||||
)
|
||||
];
|
||||
}),
|
||||
body: tabBarView(true)
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isDesktop(width) == true) Expanded(
|
||||
child: widget.child,
|
||||
)
|
||||
],
|
||||
child: const ClientsLists(
|
||||
splitView: true,
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
return const ClientsLists(
|
||||
splitView: false,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_split_view/flutter_split_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/clients/client/logs_list_client.dart';
|
||||
import 'package:adguard_home_manager/screens/clients/added_list.dart';
|
||||
import 'package:adguard_home_manager/screens/clients/clients_list.dart';
|
||||
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/clients_provider.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
|
||||
class ClientsDesktopView extends StatefulWidget {
|
||||
final ServersProvider serversProvider;
|
||||
final AppConfigProvider appConfigProvider;
|
||||
|
||||
const ClientsDesktopView({
|
||||
Key? key,
|
||||
required this.serversProvider,
|
||||
required this.appConfigProvider,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ClientsDesktopView> createState() => _ClientsDesktopViewState();
|
||||
}
|
||||
|
||||
class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerProviderStateMixin {
|
||||
late TabController tabController;
|
||||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
AutoClient? selectedActiveClient;
|
||||
Client? selectedAddedClient;
|
||||
|
||||
bool searchMode = false;
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
tabController = TabController(
|
||||
initialIndex: 0,
|
||||
length: 2,
|
||||
vsync: this,
|
||||
);
|
||||
tabController.addListener(() => widget.appConfigProvider.setSelectedClientsTab(tabController.index));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
final clientsProvider = Provider.of<ClientsProvider>(context);
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||
|
||||
PreferredSizeWidget tabBar() {
|
||||
return TabBar(
|
||||
controller: tabController,
|
||||
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
tabs: [
|
||||
Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.devices),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.activeClients)
|
||||
],
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.add_rounded),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.added)
|
||||
],
|
||||
),
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget tabBarView(bool sliver) {
|
||||
return TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
ClientsList(
|
||||
scrollController: scrollController,
|
||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||
? clientsProvider.filteredActiveClients : [],
|
||||
onClientSelected: (client) => setState(() {
|
||||
selectedAddedClient = null;
|
||||
selectedActiveClient = client;
|
||||
|
||||
}),
|
||||
selectedClient: selectedActiveClient,
|
||||
splitView: true,
|
||||
),
|
||||
AddedList(
|
||||
scrollController: scrollController,
|
||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||
? clientsProvider.filteredAddedClients : [],
|
||||
onClientSelected: (client) => setState(() {
|
||||
selectedActiveClient = null;
|
||||
selectedAddedClient = client;
|
||||
|
||||
}),
|
||||
selectedClient: selectedAddedClient,
|
||||
splitView: true,
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Widget title() {
|
||||
if (searchMode == true) {
|
||||
return Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchMode = false;
|
||||
searchController.text = "";
|
||||
clientsProvider.setSearchTermClients(null);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back_rounded)
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: (value) => clientsProvider.setSearchTermClients(value),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchController.text = "";
|
||||
clientsProvider.setSearchTermClients(null);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.clear_rounded)
|
||||
),
|
||||
hintText: AppLocalizations.of(context)!.search,
|
||||
hintStyle: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
else {
|
||||
return Text(AppLocalizations.of(context)!.clients);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Platform.isAndroid || Platform.isIOS)) {
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: title(),
|
||||
centerTitle: false,
|
||||
actions: [
|
||||
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
|
||||
IconButton(
|
||||
onPressed: () => setState(() => searchMode = true),
|
||||
icon: const Icon(Icons.search),
|
||||
tooltip: AppLocalizations.of(context)!.searchClients,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
]
|
||||
],
|
||||
bottom: tabBar()
|
||||
),
|
||||
body: tabBarView(false),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: NestedScrollView(
|
||||
controller: scrollController,
|
||||
headerSliverBuilder: ((context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar(
|
||||
title: title(),
|
||||
pinned: true,
|
||||
floating: true,
|
||||
centerTitle: false,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
actions: [
|
||||
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
|
||||
IconButton(
|
||||
onPressed: () => setState(() => searchMode = true),
|
||||
icon: const Icon(Icons.search),
|
||||
tooltip: AppLocalizations.of(context)!.searchClients,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
]
|
||||
],
|
||||
bottom: tabBar()
|
||||
),
|
||||
)
|
||||
];
|
||||
}),
|
||||
body: tabBarView(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import 'package:adguard_home_manager/providers/clients_provider.dart';
|
|||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
|
||||
class ClientsList extends StatelessWidget {
|
||||
final ScrollController scrollController;
|
||||
final List<AutoClient> data;
|
||||
final void Function(AutoClient) onClientSelected;
|
||||
final AutoClient? selectedClient;
|
||||
|
@ -18,7 +17,6 @@ class ClientsList extends StatelessWidget {
|
|||
|
||||
const ClientsList({
|
||||
Key? key,
|
||||
required this.scrollController,
|
||||
required this.data,
|
||||
required this.onClientSelected,
|
||||
this.selectedClient,
|
||||
|
|
222
lib/screens/clients/clients_lists.dart
Normal file
222
lib/screens/clients/clients_lists.dart
Normal file
|
@ -0,0 +1,222 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_split_view/flutter_split_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/screens/clients/added_list.dart';
|
||||
import 'package:adguard_home_manager/screens/clients/client/logs_list_client.dart';
|
||||
import 'package:adguard_home_manager/screens/clients/clients_list.dart';
|
||||
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/functions/desktop_mode.dart';
|
||||
import 'package:adguard_home_manager/models/clients.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/clients_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
|
||||
class ClientsLists extends StatefulWidget {
|
||||
final bool splitView;
|
||||
|
||||
const ClientsLists({
|
||||
Key? key,
|
||||
required this.splitView,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ClientsLists> createState() => _ClientsListsState();
|
||||
}
|
||||
|
||||
class _ClientsListsState extends State<ClientsLists> with TickerProviderStateMixin {
|
||||
late TabController tabController;
|
||||
final ScrollController scrollController = ScrollController();
|
||||
|
||||
bool searchMode = false;
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
AutoClient? _selectedAutoClient;
|
||||
Client? _selectedClient;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
final clientsProvider = Provider.of<ClientsProvider>(context, listen: false);
|
||||
clientsProvider.fetchClients(updateLoading: true);
|
||||
|
||||
super.initState();
|
||||
tabController = TabController(
|
||||
initialIndex: 0,
|
||||
length: 2,
|
||||
vsync: this,
|
||||
);
|
||||
tabController.addListener(
|
||||
() => Provider.of<AppConfigProvider>(context, listen: false).setSelectedClientsTab(tabController.index)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context);
|
||||
final clientsProvider = Provider.of<ClientsProvider>(context);
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||
|
||||
void onAutoClientSelected(AutoClient client) {
|
||||
setState(() => _selectedAutoClient = client);
|
||||
final w = LogsListClient(
|
||||
ip: client.ip,
|
||||
serversProvider: serversProvider,
|
||||
appConfigProvider: appConfigProvider,
|
||||
splitView: widget.splitView,
|
||||
);
|
||||
if (widget.splitView) {
|
||||
SplitView.of(context).push(w);
|
||||
}
|
||||
else {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
builder: (context) => w,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void onClientSelected(Client client) {
|
||||
setState(() => _selectedClient = client);
|
||||
final w = LogsListClient(
|
||||
ip: client.ids[0],
|
||||
serversProvider: serversProvider,
|
||||
appConfigProvider: appConfigProvider,
|
||||
splitView: widget.splitView,
|
||||
);
|
||||
if (widget.splitView) {
|
||||
SplitView.of(context).push(w);
|
||||
}
|
||||
else {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
builder: (context) => w,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: NestedScrollView(
|
||||
headerSliverBuilder: ((context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar(
|
||||
title: searchMode == true
|
||||
? Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchMode = false;
|
||||
searchController.text = "";
|
||||
clientsProvider.setSearchTermClients(null);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back_rounded),
|
||||
tooltip: AppLocalizations.of(context)!.exitSearch,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: (value) => clientsProvider.setSearchTermClients(value),
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
searchController.text = "";
|
||||
clientsProvider.setSearchTermClients(null);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.clear_rounded)
|
||||
),
|
||||
hintText: AppLocalizations.of(context)!.search,
|
||||
hintStyle: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 18
|
||||
),
|
||||
autofocus: true,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Text(AppLocalizations.of(context)!.clients),
|
||||
pinned: true,
|
||||
floating: true,
|
||||
centerTitle: false,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
surfaceTintColor: isDesktop(MediaQuery.of(context).size.width)
|
||||
? Colors.transparent
|
||||
: null,
|
||||
actions: [
|
||||
if (clientsProvider.loadStatus == LoadStatus.loaded && searchMode == false) ...[
|
||||
IconButton(
|
||||
onPressed: () => setState(() => searchMode = true),
|
||||
icon: const Icon(Icons.search),
|
||||
tooltip: AppLocalizations.of(context)!.searchClients,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
]
|
||||
],
|
||||
bottom: TabBar(
|
||||
controller: tabController,
|
||||
unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
tabs: [
|
||||
Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.devices),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.activeClients)
|
||||
],
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.add_rounded),
|
||||
const SizedBox(width: 8),
|
||||
Text(AppLocalizations.of(context)!.added)
|
||||
],
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
)
|
||||
];
|
||||
}),
|
||||
body: TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
ClientsList(
|
||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||
? clientsProvider.filteredActiveClients : [],
|
||||
onClientSelected: onAutoClientSelected,
|
||||
selectedClient: _selectedAutoClient,
|
||||
splitView: widget.splitView,
|
||||
),
|
||||
AddedList(
|
||||
scrollController: scrollController,
|
||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||
? clientsProvider.filteredAddedClients : [],
|
||||
onClientSelected: onClientSelected,
|
||||
selectedClient: _selectedClient,
|
||||
splitView: widget.splitView,
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue