mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-22 14:59:12 +00:00
Implemented go router
This commit is contained in:
parent
2ad739ed4f
commit
621171c5b1
23 changed files with 614 additions and 234 deletions
|
@ -101,7 +101,7 @@ class _BaseState extends State<Base> with WidgetsBindingObserver {
|
||||||
child: child,
|
child: child,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
child: screens[appConfigProvider.selectedScreen].body,
|
child: SizedBox()
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -13,12 +13,10 @@ List<AppScreen> screensSelectServer = [
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "connect",
|
name: "connect",
|
||||||
icon: Icons.link_rounded,
|
icon: Icons.link_rounded,
|
||||||
body: Connect(),
|
|
||||||
),
|
),
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "settings",
|
name: "settings",
|
||||||
icon: Icons.settings_rounded,
|
icon: Icons.settings_rounded,
|
||||||
body: Settings()
|
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -26,26 +24,21 @@ List<AppScreen> screensServerConnected = [
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "home",
|
name: "home",
|
||||||
icon: Icons.home_rounded,
|
icon: Icons.home_rounded,
|
||||||
body: Home(),
|
|
||||||
),
|
),
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "clients",
|
name: "clients",
|
||||||
icon: Icons.devices,
|
icon: Icons.devices,
|
||||||
body: Clients()
|
|
||||||
),
|
),
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "logs",
|
name: "logs",
|
||||||
icon: Icons.list_alt_rounded,
|
icon: Icons.list_alt_rounded,
|
||||||
body: Logs(),
|
|
||||||
),
|
),
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "filters",
|
name: "filters",
|
||||||
icon: Icons.shield_rounded,
|
icon: Icons.shield_rounded,
|
||||||
body: Filters(),
|
|
||||||
),
|
),
|
||||||
const AppScreen(
|
const AppScreen(
|
||||||
name: "settings",
|
name: "settings",
|
||||||
icon: Icons.settings_rounded,
|
icon: Icons.settings_rounded,
|
||||||
body: Settings()
|
|
||||||
)
|
)
|
||||||
];
|
];
|
1
lib/config/sizes.dart
Normal file
1
lib/config/sizes.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
const double desktopBreakpoint = 1000;
|
19
lib/constants/routes_names.dart
Normal file
19
lib/constants/routes_names.dart
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
class RoutesNames {
|
||||||
|
static const String connect = "/connect";
|
||||||
|
|
||||||
|
static const String home = "/home";
|
||||||
|
static const String queriedDomains = "/home/queried-domains";
|
||||||
|
static const String blockedDomains = "/home/blocked-domains";
|
||||||
|
static const String recurrentClients = "/home/recurrent-clients";
|
||||||
|
|
||||||
|
static const String clients = "/clients";
|
||||||
|
static const String clientsList = "/clients/list";
|
||||||
|
static const String clientPlaceholder = "/clients/list/placeholder";
|
||||||
|
static const String client = "/clients/list:id";
|
||||||
|
|
||||||
|
static const String logs = "/logs";
|
||||||
|
|
||||||
|
static const String filters = "/filters";
|
||||||
|
|
||||||
|
static const String settings = "/settings";
|
||||||
|
}
|
5
lib/functions/desktop_mode.dart
Normal file
5
lib/functions/desktop_mode.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import 'package:adguard_home_manager/config/sizes.dart';
|
||||||
|
|
||||||
|
bool isDesktop(double width) {
|
||||||
|
return width > desktopBreakpoint;
|
||||||
|
}
|
|
@ -667,5 +667,7 @@
|
||||||
"showChart": "Show chart",
|
"showChart": "Show chart",
|
||||||
"hideChart": "Hide chart",
|
"hideChart": "Hide chart",
|
||||||
"showTopItemsChart": "Show top items chart",
|
"showTopItemsChart": "Show top items chart",
|
||||||
"showTopItemsChartDescription": "Shows by default the ring chart on the top items sections. Only affects to the mobile view."
|
"showTopItemsChartDescription": "Shows by default the ring chart on the top items sections. Only affects to the mobile view.",
|
||||||
|
"openMenu": "Open menu",
|
||||||
|
"closeMenu": "Close menu"
|
||||||
}
|
}
|
|
@ -667,5 +667,7 @@
|
||||||
"showChart": "Mostrar gráfico",
|
"showChart": "Mostrar gráfico",
|
||||||
"hideChart": "Ocultar gráfico",
|
"hideChart": "Ocultar gráfico",
|
||||||
"showTopItemsChart": "Mostrar gráfico en top de items",
|
"showTopItemsChart": "Mostrar gráfico en top de items",
|
||||||
"showTopItemsChartDescription": "Muestra por defecto el gráfico de anillo en las secciones de top de items. Sólo afecta a la vista móvil."
|
"showTopItemsChartDescription": "Muestra por defecto el gráfico de anillo en las secciones de top de items. Sólo afecta a la vista móvil.",
|
||||||
|
"openMenu": "Abrir menú",
|
||||||
|
"closeMenu": "Cerrar menú"
|
||||||
}
|
}
|
|
@ -15,8 +15,7 @@ import 'package:window_size/window_size.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/base.dart';
|
import 'package:adguard_home_manager/routes/router.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
import 'package:adguard_home_manager/providers/logs_provider.dart';
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.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/clients_provider.dart';
|
||||||
|
@ -204,7 +203,7 @@ class _MainState extends State<Main> {
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
return DynamicColorBuilder(
|
return DynamicColorBuilder(
|
||||||
builder: (lightDynamic, darkDynamic) => MaterialApp(
|
builder: (lightDynamic, darkDynamic) => MaterialApp.router(
|
||||||
title: 'AdGuard Home Manager',
|
title: 'AdGuard Home Manager',
|
||||||
theme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
|
theme: appConfigProvider.androidDeviceInfo != null && appConfigProvider.androidDeviceInfo!.version.sdkInt >= 31
|
||||||
? appConfigProvider.useDynamicColor == true
|
? appConfigProvider.useDynamicColor == true
|
||||||
|
@ -243,7 +242,7 @@ class _MainState extends State<Main> {
|
||||||
child: child!,
|
child: child!,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
home: const Base(),
|
routerConfig: goRouter,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,12 @@ class AppScreen {
|
||||||
final String name;
|
final String name;
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final PreferredSizeWidget? appBar;
|
final PreferredSizeWidget? appBar;
|
||||||
final Widget body;
|
|
||||||
final Widget? fab;
|
final Widget? fab;
|
||||||
|
|
||||||
const AppScreen({
|
const AppScreen({
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
this.appBar,
|
this.appBar,
|
||||||
required this.body,
|
|
||||||
this.fab
|
this.fab
|
||||||
});
|
});
|
||||||
}
|
}
|
20
lib/routes/router.dart
Normal file
20
lib/routes/router.dart
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/routes/router_globals.dart';
|
||||||
|
import 'package:adguard_home_manager/routes/routes.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/constants/routes_names.dart';
|
||||||
|
|
||||||
|
final goRouter = GoRouter(
|
||||||
|
navigatorKey: rootNavigatorKey,
|
||||||
|
redirect: (context, state) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
||||||
|
if (serversProvider.selectedServer == null) {
|
||||||
|
return RoutesNames.connect;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
initialLocation: RoutesNames.home,
|
||||||
|
routes: routes,
|
||||||
|
);
|
10
lib/routes/router_globals.dart
Normal file
10
lib/routes/router_globals.dart
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> connectNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> homeNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> clientsNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> clientsListNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> logsNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> filtersNavigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
final GlobalKey<NavigatorState> settingsNavigatorKey = GlobalKey<NavigatorState>();
|
113
lib/routes/routes.dart
Normal file
113
lib/routes/routes.dart
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import 'package:go_router/go_router.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/connect/connect.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/filters/filters.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/settings/settings.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/clients/client/client_placeholder.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/clients/client/logs_list_client.dart';
|
||||||
|
import 'package:adguard_home_manager/screens/logs/logs.dart';
|
||||||
|
import 'package:adguard_home_manager/widgets/layout.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/routes/router_globals.dart';
|
||||||
|
import 'package:adguard_home_manager/constants/routes_names.dart';
|
||||||
|
|
||||||
|
final List<RouteBase> routes = [
|
||||||
|
GoRoute(
|
||||||
|
path: "/",
|
||||||
|
redirect: (context, state) => RoutesNames.home,
|
||||||
|
),
|
||||||
|
StatefulShellRoute.indexedStack(
|
||||||
|
builder: (context, state, navigationShell) => Layout(
|
||||||
|
navigationShell: navigationShell
|
||||||
|
),
|
||||||
|
branches: [
|
||||||
|
StatefulShellBranch(
|
||||||
|
navigatorKey: homeNavigatorKey,
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
parentNavigatorKey: homeNavigatorKey,
|
||||||
|
path: RoutesNames.home,
|
||||||
|
builder: (context, state) => const Home(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
parentNavigatorKey: homeNavigatorKey,
|
||||||
|
path: RoutesNames.queriedDomains,
|
||||||
|
builder: (context, state) => const Home(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
parentNavigatorKey: homeNavigatorKey,
|
||||||
|
path: RoutesNames.blockedDomains,
|
||||||
|
builder: (context, state) => const Home(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
parentNavigatorKey: homeNavigatorKey,
|
||||||
|
path: RoutesNames.recurrentClients,
|
||||||
|
builder: (context, state) => const Home(),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
StatefulShellBranch(
|
||||||
|
navigatorKey: clientsNavigatorKey,
|
||||||
|
routes: [
|
||||||
|
ShellRoute(
|
||||||
|
parentNavigatorKey: clientsNavigatorKey,
|
||||||
|
navigatorKey: clientsListNavigatorKey,
|
||||||
|
builder: (context, state, child) => Clients(child: child),
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesNames.clientPlaceholder,
|
||||||
|
parentNavigatorKey: clientsListNavigatorKey,
|
||||||
|
builder: (context, state) => const ClientPlaceholder(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesNames.client,
|
||||||
|
parentNavigatorKey: clientsListNavigatorKey,
|
||||||
|
builder: (context, state) => LogsListClient(
|
||||||
|
id: (state.extra as Map?)?['id']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
StatefulShellBranch(
|
||||||
|
navigatorKey: logsNavigatorKey,
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesNames.logs,
|
||||||
|
builder: (context, state) => const Logs(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
StatefulShellBranch(
|
||||||
|
navigatorKey: filtersNavigatorKey,
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesNames.filters,
|
||||||
|
builder: (context, state) => const Filters(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
StatefulShellBranch(
|
||||||
|
navigatorKey: settingsNavigatorKey,
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesNames.settings,
|
||||||
|
builder: (context, state) => const Settings(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
StatefulShellBranch(
|
||||||
|
navigatorKey: connectNavigatorKey,
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: RoutesNames.connect,
|
||||||
|
builder: (context, state) => const Connect(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
];
|
|
@ -1,7 +1,5 @@
|
||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
|
@ -157,7 +155,6 @@ class _AddedListState extends State<AddedList> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return CustomTabContentList(
|
return CustomTabContentList(
|
||||||
noSliver: !(Platform.isAndroid || Platform.isIOS),
|
|
||||||
listPadding: widget.splitView == true
|
listPadding: widget.splitView == true
|
||||||
? const EdgeInsets.only(top: 8)
|
? const EdgeInsets.only(top: 8)
|
||||||
: null,
|
: null,
|
||||||
|
|
12
lib/screens/clients/client/client_placeholder.dart
Normal file
12
lib/screens/clients/client/client_placeholder.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ClientPlaceholder extends StatelessWidget {
|
||||||
|
const ClientPlaceholder({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Text("Select a client"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/constants/enums.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:async/async.dart';
|
import 'package:async/async.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
@ -12,18 +14,12 @@ import 'package:adguard_home_manager/models/logs.dart';
|
||||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
|
||||||
class LogsListClient extends StatefulWidget {
|
class LogsListClient extends StatefulHookWidget {
|
||||||
final String ip;
|
final String id;
|
||||||
final String? name;
|
|
||||||
final ServersProvider serversProvider;
|
|
||||||
final AppConfigProvider appConfigProvider;
|
|
||||||
|
|
||||||
const LogsListClient({
|
const LogsListClient({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.ip,
|
required this.id,
|
||||||
this.name,
|
|
||||||
required this.serversProvider,
|
|
||||||
required this.appConfigProvider
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -38,11 +34,9 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
int logsQuantity = 100;
|
int logsQuantity = 100;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
int loadStatus = 0;
|
LoadStatus loadStatus = LoadStatus.loading;
|
||||||
LogsData? logsData;
|
LogsData? logsData;
|
||||||
|
|
||||||
String previousIp = "";
|
|
||||||
|
|
||||||
bool showDivider = true;
|
bool showDivider = true;
|
||||||
|
|
||||||
CancelableOperation? cancelableRequest;
|
CancelableOperation? cancelableRequest;
|
||||||
|
@ -67,7 +61,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
serversProvider.apiClient!.getLogs(
|
serversProvider.apiClient!.getLogs(
|
||||||
count: logsQuantity,
|
count: logsQuantity,
|
||||||
offset: offst,
|
offset: offst,
|
||||||
search: '"${widget.ip}"'
|
search: '"${widget.id}"'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -90,11 +84,11 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
LogsData newLogsData = result['data'];
|
LogsData newLogsData = result['data'];
|
||||||
setState(() => logsData = newLogsData);
|
setState(() => logsData = newLogsData);
|
||||||
}
|
}
|
||||||
setState(() => loadStatus = 1);
|
setState(() => loadStatus = LoadStatus.loaded);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setState(() => loadStatus = 2);
|
setState(() => loadStatus = LoadStatus.error);
|
||||||
widget.appConfigProvider.addLog(result['log']);
|
Provider.of<AppConfigProvider>(context, listen: false).addLog(result['log']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,8 +110,6 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
scrollController = ScrollController()..addListener(scrollListener);
|
scrollController = ScrollController()..addListener(scrollListener);
|
||||||
fetchLogs(inOffset: 0);
|
|
||||||
setState(() => previousIp = widget.ip);
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,15 +117,15 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final width = MediaQuery.of(context).size.width;
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
if (widget.ip != previousIp) {
|
useEffect(() {
|
||||||
setState(() => loadStatus = 0);
|
setState(() => loadStatus = LoadStatus.loading);
|
||||||
fetchLogs(inOffset: 0);
|
fetchLogs(inOffset: 0);
|
||||||
setState(() => previousIp = widget.ip);
|
return null;
|
||||||
}
|
}, [widget.id]);
|
||||||
|
|
||||||
Widget status() {
|
Widget status() {
|
||||||
switch (loadStatus) {
|
switch (loadStatus) {
|
||||||
case 0:
|
case LoadStatus.loading:
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -154,7 +146,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
case 1:
|
case LoadStatus.loaded:
|
||||||
if (logsData!.data.isNotEmpty) {
|
if (logsData!.data.isNotEmpty) {
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: fetchLogs,
|
onRefresh: fetchLogs,
|
||||||
|
@ -217,7 +209,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case LoadStatus.error:
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -249,7 +241,7 @@ class _LogsListClientState extends State<LogsListClient> {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(widget.name != null && widget.name != '' ? widget.name! : widget.ip),
|
title: Text(widget.id),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
actions: [
|
actions: [
|
||||||
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
if (!(Platform.isAndroid || Platform.isIOS)) ...[
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_split_view/flutter_split_view.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.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/clients_list.dart';
|
||||||
import 'package:adguard_home_manager/screens/clients/search_clients.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/clients/client/logs_list_client.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/clients/clients_desktop_view.dart';
|
|
||||||
import 'package:adguard_home_manager/screens/clients/added_list.dart';
|
import 'package:adguard_home_manager/screens/clients/added_list.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/clients_provider.dart';
|
||||||
import 'package:adguard_home_manager/providers/app_config_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/constants/enums.dart';
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
|
||||||
|
|
||||||
class Clients extends StatefulWidget {
|
class Clients extends StatefulWidget {
|
||||||
const Clients({Key? key}) : super(key: key);
|
final Widget child;
|
||||||
|
|
||||||
|
const Clients({
|
||||||
|
Key? key,
|
||||||
|
required this.child,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Clients> createState() => _ClientsState();
|
State<Clients> createState() => _ClientsState();
|
||||||
|
@ -53,9 +54,7 @@ class _ClientsState extends State<Clients> with TickerProviderStateMixin {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final serversProvider = Provider.of<ServersProvider>(context);
|
|
||||||
final clientsProvider = Provider.of<ClientsProvider>(context);
|
final clientsProvider = Provider.of<ClientsProvider>(context);
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
|
||||||
|
|
||||||
final width = MediaQuery.of(context).size.width;
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
@ -96,163 +95,119 @@ class _ClientsState extends State<Clients> with TickerProviderStateMixin {
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||||
? clientsProvider.filteredActiveClients : [],
|
? clientsProvider.filteredActiveClients : [],
|
||||||
onClientSelected: (client) => Navigator.push(context, MaterialPageRoute(
|
onClientSelected: (client) => context.go(
|
||||||
builder: (context) => LogsListClient(
|
RoutesNames.client,
|
||||||
ip: client.ip,
|
extra: {
|
||||||
serversProvider: serversProvider,
|
"id": client.name != null && client.name != ""
|
||||||
appConfigProvider: appConfigProvider
|
? client.name
|
||||||
)
|
: client.ip
|
||||||
)),
|
}
|
||||||
splitView: false,
|
),
|
||||||
sliver: sliver,
|
splitView: isDesktop(width),
|
||||||
),
|
),
|
||||||
AddedList(
|
AddedList(
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
data: clientsProvider.loadStatus == LoadStatus.loaded
|
data: clientsProvider.loadStatus == LoadStatus.loaded
|
||||||
? clientsProvider.filteredAddedClients : [],
|
? clientsProvider.filteredAddedClients : [],
|
||||||
onClientSelected: (client) => Navigator.push(context, MaterialPageRoute(
|
onClientSelected: (client) => context.go(
|
||||||
builder: (context) => LogsListClient(
|
RoutesNames.client,
|
||||||
ip: client.ids[0],
|
extra: { "id": client.name }
|
||||||
serversProvider: serversProvider,
|
),
|
||||||
appConfigProvider: appConfigProvider
|
splitView: isDesktop(width),
|
||||||
)
|
|
||||||
)),
|
|
||||||
splitView: false,
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width > 900) {
|
return Row(
|
||||||
return SplitView.material(
|
children: [
|
||||||
hideDivider: true,
|
SizedBox(
|
||||||
flexWidth: const FlexWidth(mainViewFlexWidth: 1, secondaryViewFlexWidth: 2),
|
width: isDesktop(width) ? 300 : width,
|
||||||
placeholder: Center(
|
height: double.maxFinite,
|
||||||
child: Padding(
|
child: Material(
|
||||||
padding: const EdgeInsets.all(24),
|
child: DefaultTabController(
|
||||||
child: Text(
|
length: 2,
|
||||||
AppLocalizations.of(context)!.selectClientLeftColumn,
|
child: NestedScrollView(
|
||||||
textAlign: TextAlign.center,
|
controller: scrollController,
|
||||||
style: TextStyle(
|
headerSliverBuilder: ((context, innerBoxIsScrolled) {
|
||||||
fontSize: 24,
|
return [
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant
|
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)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: ClientsDesktopView(
|
if (isDesktop(width) == true) Expanded(
|
||||||
serversProvider: serversProvider,
|
child: widget.child,
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
)
|
)
|
||||||
);
|
],
|
||||||
}
|
);
|
||||||
else {
|
|
||||||
if (!(Platform.isAndroid || Platform.isIOS)) {
|
|
||||||
return DefaultTabController(
|
|
||||||
length: 2,
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(AppLocalizations.of(context)!.clients),
|
|
||||||
centerTitle: false,
|
|
||||||
actions: [
|
|
||||||
if (clientsProvider.loadStatus == LoadStatus.loaded) ...[
|
|
||||||
IconButton(
|
|
||||||
onPressed: () => {
|
|
||||||
Navigator.push(context, MaterialPageRoute(
|
|
||||||
builder: (context) => const SearchClients()
|
|
||||||
))
|
|
||||||
},
|
|
||||||
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: 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)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -97,18 +97,10 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
|
||||||
onClientSelected: (client) => setState(() {
|
onClientSelected: (client) => setState(() {
|
||||||
selectedAddedClient = null;
|
selectedAddedClient = null;
|
||||||
selectedActiveClient = client;
|
selectedActiveClient = client;
|
||||||
SplitView.of(context).setSecondary(
|
|
||||||
LogsListClient(
|
|
||||||
ip: client.ip,
|
|
||||||
name: client.name,
|
|
||||||
serversProvider: serversProvider,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
selectedClient: selectedActiveClient,
|
selectedClient: selectedActiveClient,
|
||||||
splitView: true,
|
splitView: true,
|
||||||
sliver: sliver,
|
|
||||||
),
|
),
|
||||||
AddedList(
|
AddedList(
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
|
@ -117,14 +109,7 @@ class _ClientsDesktopViewState extends State<ClientsDesktopView> with TickerPro
|
||||||
onClientSelected: (client) => setState(() {
|
onClientSelected: (client) => setState(() {
|
||||||
selectedActiveClient = null;
|
selectedActiveClient = null;
|
||||||
selectedAddedClient = client;
|
selectedAddedClient = client;
|
||||||
SplitView.of(context).setSecondary(
|
|
||||||
LogsListClient(
|
|
||||||
ip: client.ids[0],
|
|
||||||
name: client.name,
|
|
||||||
serversProvider: serversProvider,
|
|
||||||
appConfigProvider: appConfigProvider,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
selectedClient: selectedAddedClient,
|
selectedClient: selectedAddedClient,
|
||||||
splitView: true,
|
splitView: true,
|
||||||
|
|
|
@ -15,7 +15,6 @@ class ClientsList extends StatelessWidget {
|
||||||
final void Function(AutoClient) onClientSelected;
|
final void Function(AutoClient) onClientSelected;
|
||||||
final AutoClient? selectedClient;
|
final AutoClient? selectedClient;
|
||||||
final bool splitView;
|
final bool splitView;
|
||||||
final bool sliver;
|
|
||||||
|
|
||||||
const ClientsList({
|
const ClientsList({
|
||||||
Key? key,
|
Key? key,
|
||||||
|
@ -24,7 +23,6 @@ class ClientsList extends StatelessWidget {
|
||||||
required this.onClientSelected,
|
required this.onClientSelected,
|
||||||
this.selectedClient,
|
this.selectedClient,
|
||||||
required this.splitView,
|
required this.splitView,
|
||||||
required this.sliver
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -35,7 +33,6 @@ class ClientsList extends StatelessWidget {
|
||||||
listPadding: splitView == true
|
listPadding: splitView == true
|
||||||
? const EdgeInsets.only(top: 8)
|
? const EdgeInsets.only(top: 8)
|
||||||
: null,
|
: null,
|
||||||
noSliver: !sliver,
|
|
||||||
loadingGenerator: () => SizedBox(
|
loadingGenerator: () => SizedBox(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
height: MediaQuery.of(context).size.height-171,
|
height: MediaQuery.of(context).size.height-171,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:adguard_home_manager/functions/desktop_mode.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
@ -25,6 +26,8 @@ class HomeAppBar extends StatelessWidget {
|
||||||
final statusProvider = Provider.of<StatusProvider>(context);
|
final statusProvider = Provider.of<StatusProvider>(context);
|
||||||
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
final Server? server = serversProvider.selectedServer;
|
final Server? server = serversProvider.selectedServer;
|
||||||
|
|
||||||
void navigateServers() {
|
void navigateServers() {
|
||||||
|
@ -40,6 +43,7 @@ class HomeAppBar extends StatelessWidget {
|
||||||
floating: true,
|
floating: true,
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
forceElevated: innerBoxScrolled,
|
forceElevated: innerBoxScrolled,
|
||||||
|
surfaceTintColor: isDesktop(width) ? Colors.transparent : null,
|
||||||
leading: Stack(
|
leading: Stack(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
|
|
|
@ -84,21 +84,21 @@ class BottomNavBar extends StatelessWidget {
|
||||||
),
|
),
|
||||||
label: translatedName(screen.name)
|
label: translatedName(screen.name)
|
||||||
)).toList(),
|
)).toList(),
|
||||||
onDestinationSelected: (value) {
|
// onDestinationSelected: (value) {
|
||||||
// Reset clients tab to 0 when changing screen
|
// // Reset clients tab to 0 when changing screen
|
||||||
if (value != 1) {
|
// if (value != 1) {
|
||||||
appConfigProvider.setSelectedClientsTab(0);
|
// appConfigProvider.setSelectedClientsTab(0);
|
||||||
}
|
// }
|
||||||
// Reset logs filters when changing screen
|
// // Reset logs filters when changing screen
|
||||||
if (value != 2) {
|
// if (value != 2) {
|
||||||
logsProvider.resetFilters();
|
// logsProvider.resetFilters();
|
||||||
}
|
// }
|
||||||
// Reset settings selected screen
|
// // Reset settings selected screen
|
||||||
if (value != screens.length-1) {
|
// if (value != screens.length-1) {
|
||||||
appConfigProvider.setSelectedSettingsScreen(screen: null);
|
// appConfigProvider.setSelectedSettingsScreen(screen: null);
|
||||||
}
|
// }
|
||||||
appConfigProvider.setSelectedScreen(value);
|
// appConfigProvider.setSelectedScreen(value);
|
||||||
},
|
// },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
250
lib/widgets/layout.dart
Normal file
250
lib/widgets/layout.dart
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/config/app_screens.dart';
|
||||||
|
import 'package:adguard_home_manager/config/sizes.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
|
||||||
|
class Layout extends StatefulWidget {
|
||||||
|
final StatefulNavigationShell navigationShell;
|
||||||
|
|
||||||
|
const Layout({
|
||||||
|
Key? key,
|
||||||
|
required this.navigationShell,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Layout> createState() => _LayoutState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LayoutState extends State<Layout> {
|
||||||
|
bool _drawerExpanded = true;
|
||||||
|
|
||||||
|
void _goBranch(int index) {
|
||||||
|
widget.navigationShell.goBranch(
|
||||||
|
index,
|
||||||
|
initialLocation: index == widget.navigationShell.currentIndex,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final width = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
|
||||||
|
String translatedName(String key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'home':
|
||||||
|
return AppLocalizations.of(context)!.home;
|
||||||
|
|
||||||
|
case 'settings':
|
||||||
|
return AppLocalizations.of(context)!.settings;
|
||||||
|
|
||||||
|
case 'connect':
|
||||||
|
return AppLocalizations.of(context)!.connect;
|
||||||
|
|
||||||
|
case 'clients':
|
||||||
|
return AppLocalizations.of(context)!.clients;
|
||||||
|
|
||||||
|
case 'logs':
|
||||||
|
return AppLocalizations.of(context)!.logs;
|
||||||
|
|
||||||
|
case 'filters':
|
||||||
|
return AppLocalizations.of(context)!.filters;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width > desktopBreakpoint) {
|
||||||
|
return Material(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
curve: Curves.ease,
|
||||||
|
width: _drawerExpanded ? 250 : 90,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 16
|
||||||
|
),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () => setState(() => _drawerExpanded = !_drawerExpanded),
|
||||||
|
icon: const Icon(Icons.menu_open_rounded),
|
||||||
|
tooltip: _drawerExpanded == true
|
||||||
|
? AppLocalizations.of(context)!.closeMenu
|
||||||
|
: AppLocalizations.of(context)!.openMenu,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (serversProvider.selectedServer != null)
|
||||||
|
...screensServerConnected.asMap().entries.map(
|
||||||
|
(s) => DrawerTile(
|
||||||
|
icon: s.value.icon,
|
||||||
|
title: translatedName(s.value.name),
|
||||||
|
isSelected:
|
||||||
|
widget.navigationShell.currentIndex == s.key,
|
||||||
|
onSelect: () => _goBranch(s.key),
|
||||||
|
withoutTitle: !_drawerExpanded,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (serversProvider.selectedServer == null)
|
||||||
|
...screensSelectServer.asMap().entries.map(
|
||||||
|
(s) => DrawerTile(
|
||||||
|
icon: s.value.icon,
|
||||||
|
title: translatedName(s.value.name),
|
||||||
|
isSelected:
|
||||||
|
widget.navigationShell.currentIndex == s.key,
|
||||||
|
onSelect: () => _goBranch(s.key),
|
||||||
|
withoutTitle: !_drawerExpanded,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: widget.navigationShell
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final screens = serversProvider.selectedServer != null && serversProvider.apiClient != null
|
||||||
|
? screensServerConnected
|
||||||
|
: screensSelectServer;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
body: widget.navigationShell,
|
||||||
|
bottomNavigationBar: NavigationBar(
|
||||||
|
selectedIndex: (serversProvider.selectedServer == null || serversProvider.apiClient == null) && widget.navigationShell.currentIndex > 1
|
||||||
|
? 0
|
||||||
|
: widget.navigationShell.currentIndex,
|
||||||
|
onDestinationSelected: (s) => _goBranch(s),
|
||||||
|
destinations: screens.asMap().entries.map((screen) => NavigationDestination(
|
||||||
|
icon: Stack(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
screen.value.icon,
|
||||||
|
color: widget.navigationShell.currentIndex == screen.key
|
||||||
|
? Theme.of(context).colorScheme.onSecondaryContainer
|
||||||
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
if (
|
||||||
|
screen.value.name == 'settings' &&
|
||||||
|
serversProvider.updateAvailable.data != null &&
|
||||||
|
serversProvider.updateAvailable.data!.canAutoupdate == true
|
||||||
|
) Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
right: -12,
|
||||||
|
child: Container(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
margin: const EdgeInsets.only(right: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
color: Colors.red
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
label: translatedName(screen.value.name)
|
||||||
|
)).toList(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DrawerTile extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final String title;
|
||||||
|
final bool isSelected;
|
||||||
|
final void Function() onSelect;
|
||||||
|
final bool? withoutTitle;
|
||||||
|
|
||||||
|
const DrawerTile({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
required this.title,
|
||||||
|
required this.isSelected,
|
||||||
|
required this.onSelect,
|
||||||
|
this.withoutTitle,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Widget iconWidget = withoutTitle == true
|
||||||
|
? Tooltip(
|
||||||
|
message: title,
|
||||||
|
child: Icon(
|
||||||
|
icon,
|
||||||
|
color: isSelected
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Icon(
|
||||||
|
icon,
|
||||||
|
color: isSelected
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 16),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(30),
|
||||||
|
bottomRight: Radius.circular(30),
|
||||||
|
),
|
||||||
|
onTap: onSelect,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isSelected
|
||||||
|
? Theme.of(context).colorScheme.secondaryContainer
|
||||||
|
: null,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(30),
|
||||||
|
bottomRight: Radius.circular(30),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(children: [
|
||||||
|
iconWidget,
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 14,
|
||||||
|
color: isSelected
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
24
pubspec.lock
24
pubspec.lock
|
@ -222,6 +222,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.0"
|
version: "5.1.0"
|
||||||
|
flutter_hooks:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_hooks
|
||||||
|
sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.20.3"
|
||||||
flutter_html:
|
flutter_html:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -310,6 +318,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
go_router:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: go_router
|
||||||
|
sha256: e156bc1b2088eb5ece9351bccd48c3e1719a4858eacbd44e59162e98a68205d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "12.0.1"
|
||||||
html:
|
html:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -382,6 +398,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
markdown:
|
markdown:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -74,6 +74,8 @@ dependencies:
|
||||||
flutter_dotenv: ^5.0.2
|
flutter_dotenv: ^5.0.2
|
||||||
flutter_reorderable_list: ^1.3.1
|
flutter_reorderable_list: ^1.3.1
|
||||||
pie_chart: ^5.3.2
|
pie_chart: ^5.3.2
|
||||||
|
go_router: ^12.0.1
|
||||||
|
flutter_hooks: ^0.20.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Add table
Reference in a new issue