diff --git a/lib/config/app_screens.dart b/lib/config/app_screens.dart index f009893..b05ef19 100644 --- a/lib/config/app_screens.dart +++ b/lib/config/app_screens.dart @@ -35,9 +35,7 @@ List screensServerConnected = [ const AppScreen( name: "home", icon: Icons.home_rounded, - appBar: HomeAppBar(), body: Home(), - fab: HomeFab() ), const AppScreen( name: "clients", @@ -48,7 +46,6 @@ List screensServerConnected = [ name: "logs", icon: Icons.list_alt_rounded, body: Logs(), - appBar: LogsAppBar() ), const AppScreen( name: "filters", diff --git a/lib/screens/clients/added_list.dart b/lib/screens/clients/added_list.dart index b974b41..08f3df1 100644 --- a/lib/screens/clients/added_list.dart +++ b/lib/screens/clients/added_list.dart @@ -17,11 +17,13 @@ import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; class AddedList extends StatelessWidget { + final int loadStatus; final List data; final Future Function() fetchClients; const AddedList({ Key? key, + required this.loadStatus, required this.data, required this.fetchClients }) : super(key: key); @@ -133,94 +135,144 @@ class AddedList extends StatelessWidget { ); } - return Stack( - children: [ - if (data.isNotEmpty) RefreshIndicator( - onRefresh: () async {}, - child: ListView.builder( - padding: const EdgeInsets.only(top: 0), - itemCount: data.length, - itemBuilder: (context, index) => ListTile( - isThreeLine: true, - onLongPress: () => openOptionsModal(data[index]), - onTap: () => openClientModal(data[index]), - title: Padding( - padding: const EdgeInsets.only(bottom: 5), - child: Text(data[index].name), - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(data[index].ids.toString().replaceAll(RegExp(r'^\[|\]$'), '')), - const SizedBox(height: 7), - Row( - children: [ - Icon( - Icons.filter_list_rounded, - size: 19, - color: data[index].filteringEnabled == true - ? Colors.green - : Colors.red, - ), - const SizedBox(width: 10), - Icon( - Icons.vpn_lock_rounded, - size: 18, - color: data[index].safebrowsingEnabled == true - ? Colors.green - : Colors.red, - ), - const SizedBox(width: 10), - Icon( - Icons.block, - size: 18, - color: data[index].parentalEnabled == true - ? Colors.green - : Colors.red, - ), - const SizedBox(width: 10), - Icon( - Icons.search_rounded, - size: 19, - color: data[index].safesearchEnabled == true - ? Colors.green - : Colors.red, - ) - ], - ) - ], - ), - ) - ), - ), - if (data.isEmpty) SizedBox( + switch (loadStatus) { + case 0: + return SizedBox( width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - AppLocalizations.of(context)!.noClientsList, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 24, - color: Colors.grey - ), - ), + const CircularProgressIndicator(), const SizedBox(height: 30), - TextButton.icon( - onPressed: fetchClients, - icon: const Icon(Icons.refresh_rounded), - label: Text(AppLocalizations.of(context)!.refresh), + Text( + AppLocalizations.of(context)!.loadingStatus, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), ) ], ), - ), - const Positioned( - bottom: 20, - right: 20, - child: ClientsFab(tab: 1), - ), - ], - ); + ); + + case 1: + return Stack( + children: [ + if (data.isNotEmpty) ListView.builder( + padding: const EdgeInsets.only(top: 0), + itemCount: data.length, + itemBuilder: (context, index) => ListTile( + isThreeLine: true, + onLongPress: () => openOptionsModal(data[index]), + onTap: () => openClientModal(data[index]), + title: Padding( + padding: const EdgeInsets.only(bottom: 5), + child: Text(data[index].name), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(data[index].ids.toString().replaceAll(RegExp(r'^\[|\]$'), '')), + const SizedBox(height: 7), + Row( + children: [ + Icon( + Icons.filter_list_rounded, + size: 19, + color: data[index].filteringEnabled == true + ? Colors.green + : Colors.red, + ), + const SizedBox(width: 10), + Icon( + Icons.vpn_lock_rounded, + size: 18, + color: data[index].safebrowsingEnabled == true + ? Colors.green + : Colors.red, + ), + const SizedBox(width: 10), + Icon( + Icons.block, + size: 18, + color: data[index].parentalEnabled == true + ? Colors.green + : Colors.red, + ), + const SizedBox(width: 10), + Icon( + Icons.search_rounded, + size: 19, + color: data[index].safesearchEnabled == true + ? Colors.green + : Colors.red, + ) + ], + ) + ], + ), + ) + ), + if (data.isEmpty) SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context)!.noClientsList, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24, + color: Colors.grey + ), + ), + const SizedBox(height: 30), + TextButton.icon( + onPressed: fetchClients, + icon: const Icon(Icons.refresh_rounded), + label: Text(AppLocalizations.of(context)!.refresh), + ) + ], + ), + ), + const Positioned( + bottom: 20, + right: 20, + child: ClientsFab(tab: 1), + ), + ], + ); + + case 2: + return SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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, + ), + ) + ], + ), + ); + + default: + return const SizedBox(); + } + } } \ No newline at end of file diff --git a/lib/screens/clients/blocked_list.dart b/lib/screens/clients/blocked_list.dart index c929894..a9ab9a5 100644 --- a/lib/screens/clients/blocked_list.dart +++ b/lib/screens/clients/blocked_list.dart @@ -14,11 +14,13 @@ import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/classes/process_modal.dart'; class BlockedList extends StatelessWidget { + final int loadStatus; final List data; final Future Function() fetchClients; const BlockedList({ Key? key, + required this.loadStatus, required this.data, required this.fetchClients }) : super(key: key); @@ -71,54 +73,107 @@ class BlockedList extends StatelessWidget { } } - return Stack( - children: [ - if (data.isNotEmpty) ListView.builder( - padding: const EdgeInsets.only(top: 0), - itemCount: data.length, - itemBuilder: (context, index) => ListTile( - title: Text(data[index]), - trailing: IconButton( - onPressed: () => { - showDialog( - context: context, - builder: (context) => RemoveDomainModal( - onConfirm: () => confirmRemoveDomain(data[index]), - ) - ) - }, - icon: const Icon(Icons.delete_rounded) - ), - ) - ), - if (data.isEmpty) SizedBox( + switch (loadStatus) { + case 0: + return SizedBox( width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - AppLocalizations.of(context)!.noCustomFilters, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 24, - color: Colors.grey - ), - ), + const CircularProgressIndicator(), const SizedBox(height: 30), - TextButton.icon( - onPressed: fetchClients, - icon: const Icon(Icons.refresh_rounded), - label: Text(AppLocalizations.of(context)!.refresh), + Text( + AppLocalizations.of(context)!.loadingStatus, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), ) ], ), - ), - const Positioned( - bottom: 20, - right: 20, - child: ClientsFab(tab: 2), - ), - ] - ); + ); + + case 1: + return Stack( + children: [ + if (data.isNotEmpty) ListView.builder( + padding: const EdgeInsets.only(top: 0), + itemCount: data.length, + itemBuilder: (context, index) => ListTile( + title: Text(data[index]), + trailing: IconButton( + onPressed: () => { + showDialog( + context: context, + builder: (context) => RemoveDomainModal( + onConfirm: () => confirmRemoveDomain(data[index]), + ) + ) + }, + icon: const Icon(Icons.delete_rounded) + ), + ) + ), + if (data.isEmpty) SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context)!.noCustomFilters, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24, + color: Colors.grey + ), + ), + const SizedBox(height: 30), + TextButton.icon( + onPressed: fetchClients, + icon: const Icon(Icons.refresh_rounded), + label: Text(AppLocalizations.of(context)!.refresh), + ) + ], + ), + ), + const Positioned( + bottom: 20, + right: 20, + child: ClientsFab(tab: 2), + ), + ] + ); + + case 2: + return SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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, + ), + ) + ], + ), + ); + + default: + return const SizedBox(); + } + } } \ No newline at end of file diff --git a/lib/screens/clients/clients.dart b/lib/screens/clients/clients.dart index 319210c..2920bf1 100644 --- a/lib/screens/clients/clients.dart +++ b/lib/screens/clients/clients.dart @@ -89,144 +89,146 @@ class _ClientsWidgetState extends State with TickerProviderStateM Widget build(BuildContext context) { final serversProvider = Provider.of(context); - switch (serversProvider.clients.loadStatus) { + Widget generateBody() { + switch (serversProvider.clients.loadStatus) { case 0: - return Column( - mainAxisSize: MainAxisSize.max, - children: [ - AppBar( - title: Text(AppLocalizations.of(context)!.clients), - centerTitle: true, - ), - SizedBox( - width: double.maxFinite, - height: MediaQuery.of(context).size.height-171, - 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, - ), - ) - ], - ), - ), - ], - ); - - 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( - controller: tabController, - tabs: [ - Tab( - icon: const Icon(Icons.devices), - text: AppLocalizations.of(context)!.activeClients, + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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, ), - Tab( - icon: const Icon(Icons.add), - text: AppLocalizations.of(context)!.added, - ), - Tab( - icon: const Icon(Icons.block), - text: AppLocalizations.of(context)!.blocked, - ), - ] - ) - ) - ]; - }), - body: Container( - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: Theme.of(context).brightness == Brightness.light - ? const Color.fromRGBO(220, 220, 220, 1) - : const Color.fromRGBO(50, 50, 50, 1) - ) - ) - ), - child: TabBarView( - controller: tabController, - children: [ - RefreshIndicator( - onRefresh: fetchClients, - child: ClientsList( - data: serversProvider.clients.data!.autoClientsData, - fetchClients: fetchClients, - ), - ), - RefreshIndicator( - onRefresh: fetchClients, - child: AddedList( - data: serversProvider.clients.data!.clients, - fetchClients: fetchClients, ) - ), - RefreshIndicator( - onRefresh: fetchClients, - child: BlockedList( - data: serversProvider.clients.data!.clientsAllowedBlocked!.disallowedClients, - fetchClients: fetchClients, - ), - ), - ], + ], + ), ), - ) - ) - ); + ], + ); - case 2: - return Column( - children: [ - AppBar( + case 1: + return Container(); + + case 2: + return Column( + children: [ + SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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, + ), + ) + ], + ), + ), + ], + ); + + default: + return const SizedBox(); + } + } + + return DefaultTabController( + length: 3, + child: NestedScrollView( + headerSliverBuilder: ((context, innerBoxIsScrolled) { + return [ + SliverAppBar( title: Text(AppLocalizations.of(context)!.clients), centerTitle: true, - ), - SizedBox( - width: double.maxFinite, - height: MediaQuery.of(context).size.height-171, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Icon( - Icons.error, - color: Colors.red, - size: 50, + pinned: true, + floating: true, + forceElevated: innerBoxIsScrolled, + bottom: TabBar( + controller: tabController, + tabs: [ + Tab( + icon: const Icon(Icons.devices), + text: AppLocalizations.of(context)!.activeClients, ), - const SizedBox(height: 30), - Text( - AppLocalizations.of(context)!.errorLoadServerStatus, - style: const TextStyle( - fontSize: 22, - color: Colors.grey, - ), - ) - ], + Tab( + icon: const Icon(Icons.add), + text: AppLocalizations.of(context)!.added, + ), + Tab( + icon: const Icon(Icons.block), + text: AppLocalizations.of(context)!.blocked, + ), + ] + ) + ) + ]; + }), + body: Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(220, 220, 220, 1) + : const Color.fromRGBO(50, 50, 50, 1) + ) + ) + ), + child: TabBarView( + controller: tabController, + children: [ + RefreshIndicator( + onRefresh: fetchClients, + child: ClientsList( + loadStatus: serversProvider.clients.loadStatus, + data: serversProvider.clients.loadStatus == 1 + ? serversProvider.clients.data!.autoClientsData : [], + fetchClients: fetchClients, + ), ), - ), - ], - ); - - default: - return const SizedBox(); - } + RefreshIndicator( + onRefresh: fetchClients, + child: AddedList( + loadStatus: serversProvider.clients.loadStatus, + data: serversProvider.clients.loadStatus == 1 + ? serversProvider.clients.data!.clients : [], + fetchClients: fetchClients, + ) + ), + RefreshIndicator( + onRefresh: fetchClients, + child: BlockedList( + loadStatus: serversProvider.clients.loadStatus, + data: serversProvider.clients.loadStatus == 1 + ? serversProvider.clients.data!.clientsAllowedBlocked!.disallowedClients : [], + fetchClients: fetchClients, + ) + ), + ] + ) + ), + ) + ); } } \ No newline at end of file diff --git a/lib/screens/clients/clients_list.dart b/lib/screens/clients/clients_list.dart index b02146e..84f3fde 100644 --- a/lib/screens/clients/clients_list.dart +++ b/lib/screens/clients/clients_list.dart @@ -4,59 +4,113 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:adguard_home_manager/models/clients.dart'; class ClientsList extends StatelessWidget { + final int loadStatus; final List data; final Future Function() fetchClients; const ClientsList({ Key? key, + required this.loadStatus, required this.data, required this.fetchClients }) : super(key: key); @override Widget build(BuildContext context) { - if (data.isNotEmpty) { - 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 + switch (loadStatus) { + case 0: + return SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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, + ), ) - : null, - trailing: Text(data[index].source), - ) - ); - } - else { - return SizedBox( - width: double.maxFinite, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context)!.noClientsList, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 24, - color: Colors.grey + ], + ), + ); + + case 1: + if (data.isNotEmpty) { + 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 ), - ), - const SizedBox(height: 30), - TextButton.icon( - onPressed: fetchClients, - icon: const Icon(Icons.refresh_rounded), - label: Text(AppLocalizations.of(context)!.refresh) + subtitle: data[index].name != '' + ? Text( + data[index].ip + ) + : null, + trailing: Text(data[index].source), ) - ], - ), - ); + ); + } + else { + return SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context)!.noClientsList, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24, + color: Colors.grey + ), + ), + const SizedBox(height: 30), + TextButton.icon( + onPressed: fetchClients, + icon: const Icon(Icons.refresh_rounded), + label: Text(AppLocalizations.of(context)!.refresh) + ) + ], + ), + ); + } + + case 2: + return SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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, + ), + ) + ], + ), + ); + + default: + return const SizedBox(); } } } \ No newline at end of file diff --git a/lib/screens/filters/custom_rules_list.dart b/lib/screens/filters/custom_rules_list.dart index 62595a7..ab87df6 100644 --- a/lib/screens/filters/custom_rules_list.dart +++ b/lib/screens/filters/custom_rules_list.dart @@ -15,12 +15,14 @@ import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/classes/process_modal.dart'; class CustomRulesList extends StatefulWidget { + final int loadStatus; final ScrollController scrollController; final List data; final void Function() fetchData; const CustomRulesList({ Key? key, + required this.loadStatus, required this.scrollController, required this.data, required this.fetchData @@ -100,51 +102,104 @@ class _CustomRulesListState extends State { ); } - return Stack( - children: [ - if (widget.data.isNotEmpty) ListView.builder( - padding: const EdgeInsets.only(top: 0), - itemCount: widget.data.length, - itemBuilder: (context, index) => ListTile( - title: Text(widget.data[index]), - trailing: IconButton( - onPressed: () => openRemoveCustomRuleModal(widget.data[index]), - icon: const Icon(Icons.delete) - ), - ) - ), - if (widget.data.isEmpty) SizedBox( + switch (widget.loadStatus) { + case 0: + return SizedBox( width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - AppLocalizations.of(context)!.noBlackLists, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 24, - color: Colors.grey - ), - ), + const CircularProgressIndicator(), const SizedBox(height: 30), - TextButton.icon( - onPressed: widget.fetchData, - icon: const Icon(Icons.refresh_rounded), - label: Text(AppLocalizations.of(context)!.refresh), + Text( + AppLocalizations.of(context)!.loadingFilters, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), ) ], ), - ), - AnimatedPositioned( - duration: const Duration(milliseconds: 100), - curve: Curves.easeInOut, - bottom: isVisible ? 20 : -70, - right: 20, - child: const FiltersFab( - type: 'custom_rule', - ) - ) - ], - ); + ); + + case 1: + return Stack( + children: [ + if (widget.data.isNotEmpty) ListView.builder( + padding: const EdgeInsets.only(top: 0), + itemCount: widget.data.length, + itemBuilder: (context, index) => ListTile( + title: Text(widget.data[index]), + trailing: IconButton( + onPressed: () => openRemoveCustomRuleModal(widget.data[index]), + icon: const Icon(Icons.delete) + ), + ) + ), + if (widget.data.isEmpty) SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context)!.noBlackLists, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24, + color: Colors.grey + ), + ), + const SizedBox(height: 30), + TextButton.icon( + onPressed: widget.fetchData, + icon: const Icon(Icons.refresh_rounded), + label: Text(AppLocalizations.of(context)!.refresh), + ) + ], + ), + ), + AnimatedPositioned( + duration: const Duration(milliseconds: 100), + curve: Curves.easeInOut, + bottom: isVisible ? 20 : -70, + right: 20, + child: const FiltersFab( + type: 'custom_rule', + ) + ) + ], + ); + + case 2: + return SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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)!.filtersNotLoaded, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), + ) + ], + ), + ); + + default: + return const SizedBox(); + } + } } \ No newline at end of file diff --git a/lib/screens/filters/filters.dart b/lib/screens/filters/filters.dart index ebf2701..2f6dac0 100644 --- a/lib/screens/filters/filters.dart +++ b/lib/screens/filters/filters.dart @@ -80,150 +80,86 @@ class _FiltersWidgetState extends State with TickerProviderStateM Widget build(BuildContext context) { final serversProvider = Provider.of(context); - switch (serversProvider.filtering.loadStatus) { - case 0: - return Column( - mainAxisSize: MainAxisSize.max, - children: [ - AppBar( + return DefaultTabController( + length: 3, + child: NestedScrollView( + headerSliverBuilder: ((context, innerBoxIsScrolled) { + return [ + SliverAppBar( title: Text(AppLocalizations.of(context)!.filters), centerTitle: true, - ), - SizedBox( - width: double.maxFinite, - height: MediaQuery.of(context).size.height-171, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - const SizedBox(height: 30), - Text( - AppLocalizations.of(context)!.loadingFilters, - style: const TextStyle( - fontSize: 22, - color: Colors.grey, - ), - ) - ], - ), - ), - ], - ); - - case 1: - return DefaultTabController( - length: 3, - child: NestedScrollView( - controller: scrollController, - headerSliverBuilder: ((context, innerBoxIsScrolled) { - return [ - SliverAppBar( - title: Text(AppLocalizations.of(context)!.filters), - centerTitle: true, - pinned: true, - floating: true, - forceElevated: innerBoxIsScrolled, - bottom: TabBar( - controller: tabController, - tabs: [ - Tab( - icon: const Icon(Icons.verified_user_rounded), - text: AppLocalizations.of(context)!.whitelists, - ), - Tab( - icon: const Icon(Icons.gpp_bad_rounded), - text: AppLocalizations.of(context)!.blacklists, - ), - Tab( - icon: const Icon(Icons.shield_rounded), - text: AppLocalizations.of(context)!.customRules, - ), - ] - ) - ) - ]; - }), - body: Container( - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: Theme.of(context).brightness == Brightness.light - ? const Color.fromRGBO(220, 220, 220, 1) - : const Color.fromRGBO(50, 50, 50, 1) - ) - ) - ), - child: TabBarView( + pinned: true, + floating: true, + forceElevated: innerBoxIsScrolled, + bottom: TabBar( controller: tabController, - children: [ - RefreshIndicator( - onRefresh: fetchFilters, - child: FiltersList( - scrollController: scrollController, - type: 'whitelist', - data: serversProvider.filtering.data!.whitelistFilters, - fetchData: fetchFilters, - ) + tabs: [ + Tab( + icon: const Icon(Icons.verified_user_rounded), + text: AppLocalizations.of(context)!.whitelists, ), - RefreshIndicator( - onRefresh: fetchFilters, - child: FiltersList( - scrollController: scrollController, - type: 'blacklist', - data: serversProvider.filtering.data!.filters, - fetchData: fetchFilters, - ) + Tab( + icon: const Icon(Icons.gpp_bad_rounded), + text: AppLocalizations.of(context)!.blacklists, ), - RefreshIndicator( - onRefresh: fetchFilters, - child: CustomRulesList( - scrollController: scrollController, - data: serversProvider.filtering.data!.userRules, - fetchData: fetchFilters, - ) + Tab( + icon: const Icon(Icons.shield_rounded), + text: AppLocalizations.of(context)!.customRules, ), - ], - ), + ] + ) ) - ) - ); - - case 2: - return Column( - children: [ - AppBar( - title: Text(AppLocalizations.of(context)!.filters), - centerTitle: true, - ), - SizedBox( - width: double.maxFinite, - height: MediaQuery.of(context).size.height-171, - 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)!.filtersNotLoaded, - style: const TextStyle( - fontSize: 22, - color: Colors.grey, - ), - ) - ], + ]; + }), + body: Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: Theme.of(context).brightness == Brightness.light + ? const Color.fromRGBO(220, 220, 220, 1) + : const Color.fromRGBO(50, 50, 50, 1) + ) + ) + ), + child: TabBarView( + controller: tabController, + children: [ + RefreshIndicator( + onRefresh: fetchFilters, + child: FiltersList( + loadStatus: serversProvider.filtering.loadStatus, + scrollController: scrollController, + type: 'whitelist', + data: serversProvider.filtering.loadStatus == 1 + ? serversProvider.filtering.data!.whitelistFilters : [], + fetchData: fetchFilters, + ) ), - ), - ], - ); - - default: - return const SizedBox(); - } + RefreshIndicator( + onRefresh: fetchFilters, + child: FiltersList( + loadStatus: serversProvider.filtering.loadStatus, + scrollController: scrollController, + type: 'blacklist', + data: serversProvider.filtering.loadStatus == 1 + ? serversProvider.filtering.data!.filters : [], + fetchData: fetchFilters, + ) + ), + RefreshIndicator( + onRefresh: fetchFilters, + child: CustomRulesList( + loadStatus: serversProvider.filtering.loadStatus, + scrollController: scrollController, + data: serversProvider.filtering.loadStatus == 1 + ? serversProvider.filtering.data!.userRules : [], + fetchData: fetchFilters, + ) + ), + ] + ) + ), + ) + ); } } \ No newline at end of file diff --git a/lib/screens/filters/filters_list.dart b/lib/screens/filters/filters_list.dart index cb77d64..a3bee6a 100644 --- a/lib/screens/filters/filters_list.dart +++ b/lib/screens/filters/filters_list.dart @@ -18,6 +18,7 @@ import 'package:adguard_home_manager/functions/number_format.dart'; import 'package:adguard_home_manager/models/filtering.dart'; class FiltersList extends StatefulWidget { + final int loadStatus; final ScrollController scrollController; final List data; final void Function() fetchData; @@ -25,6 +26,7 @@ class FiltersList extends StatefulWidget { const FiltersList({ Key? key, + required this.loadStatus, required this.scrollController, required this.data, required this.fetchData, @@ -127,94 +129,147 @@ class _FiltersListState extends State { ); } - return Stack( - children: [ - if (widget.data.isNotEmpty) ListView.builder( - padding: const EdgeInsets.only(top: 0), - itemCount: widget.data.length, - itemBuilder: (context, index) => Material( - color: Colors.transparent, - child: InkWell( - onTap: () => openDetailsModal(widget.data[index]), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: MediaQuery.of(context).size.width-130, - child: Text( - widget.data[index].name, - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 16 - ), - ), - ), - const SizedBox(height: 5), - Text( - "${intFormat(widget.data[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}", - style: const TextStyle( - fontSize: 14, - color: Colors.grey - ), - ), - ], - ), - Text( - widget.data[index].enabled == true - ? AppLocalizations.of(context)!.enabled - : AppLocalizations.of(context)!.disabled, - style: TextStyle( - color: widget.data[index].enabled == true - ? Colors.green - : Colors.red, - fontWeight: FontWeight.w500 - ), - ) - ], - ), - ), - ), - ), - ), - if (widget.data.isEmpty) if (widget.data.isEmpty) SizedBox( + switch (widget.loadStatus) { + case 0: + return SizedBox( width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - widget.type == 'blacklist' - ? AppLocalizations.of(context)!.noBlackLists - : AppLocalizations.of(context)!.noWhiteLists, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 24, - color: Colors.grey - ), - ), + const CircularProgressIndicator(), const SizedBox(height: 30), - TextButton.icon( - onPressed: widget.fetchData, - icon: const Icon(Icons.refresh_rounded), - label: Text(AppLocalizations.of(context)!.refresh), + Text( + AppLocalizations.of(context)!.loadingFilters, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), ) ], ), - ), - AnimatedPositioned( - duration: const Duration(milliseconds: 100), - curve: Curves.easeInOut, - bottom: isVisible ? 20 : -70, - right: 20, - child: FiltersFab( - type: widget.type - ) - ) - ], - ); + ); + + case 1: + return Stack( + children: [ + if (widget.data.isNotEmpty) ListView.builder( + padding: const EdgeInsets.only(top: 0), + itemCount: widget.data.length, + itemBuilder: (context, index) => Material( + color: Colors.transparent, + child: InkWell( + onTap: () => openDetailsModal(widget.data[index]), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width-130, + child: Text( + widget.data[index].name, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16 + ), + ), + ), + const SizedBox(height: 5), + Text( + "${intFormat(widget.data[index].rulesCount, Platform.localeName)} ${AppLocalizations.of(context)!.enabledRules}", + style: const TextStyle( + fontSize: 14, + color: Colors.grey + ), + ), + ], + ), + Text( + widget.data[index].enabled == true + ? AppLocalizations.of(context)!.enabled + : AppLocalizations.of(context)!.disabled, + style: TextStyle( + color: widget.data[index].enabled == true + ? Colors.green + : Colors.red, + fontWeight: FontWeight.w500 + ), + ) + ], + ), + ), + ), + ), + ), + if (widget.data.isEmpty) if (widget.data.isEmpty) SizedBox( + width: double.maxFinite, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + widget.type == 'blacklist' + ? AppLocalizations.of(context)!.noBlackLists + : AppLocalizations.of(context)!.noWhiteLists, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 24, + color: Colors.grey + ), + ), + const SizedBox(height: 30), + TextButton.icon( + onPressed: widget.fetchData, + icon: const Icon(Icons.refresh_rounded), + label: Text(AppLocalizations.of(context)!.refresh), + ) + ], + ), + ), + AnimatedPositioned( + duration: const Duration(milliseconds: 100), + curve: Curves.easeInOut, + bottom: isVisible ? 20 : -70, + right: 20, + child: FiltersFab( + type: widget.type + ) + ) + ], + ); + + case 2: + return SizedBox( + width: double.maxFinite, + height: MediaQuery.of(context).size.height-171, + 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)!.filtersNotLoaded, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), + ) + ], + ), + ); + + default: + return const SizedBox(); + } + } } \ No newline at end of file diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart index 97d056e..eca5d6b 100644 --- a/lib/screens/home/home.dart +++ b/lib/screens/home/home.dart @@ -7,6 +7,7 @@ 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/screens/home/appbar.dart'; import 'package:adguard_home_manager/screens/home/top_items.dart'; import 'package:adguard_home_manager/screens/home/chart.dart'; @@ -154,24 +155,27 @@ class Home extends StatelessWidget { } } - return RefreshIndicator( - color: Theme.of(context).primaryColor, - onRefresh: () async { - final result = await getServerStatus(serversProvider.selectedServer!); - if (result['result'] == 'success') { - serversProvider.setServerStatusData(result['data']); - } - else { - appConfigProvider.addLog(result['log']); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppLocalizations.of(context)!.serverStatusNotRefreshed), - backgroundColor: Colors.red, - ) - ); - } - }, - child: status() + return Scaffold( + appBar: const HomeAppBar(), + body: RefreshIndicator( + color: Theme.of(context).primaryColor, + onRefresh: () async { + final result = await getServerStatus(serversProvider.selectedServer!); + if (result['result'] == 'success') { + serversProvider.setServerStatusData(result['data']); + } + else { + appConfigProvider.addLog(result['log']); + 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/logs/logs.dart b/lib/screens/logs/logs.dart index 515e50a..8dbcf5c 100644 --- a/lib/screens/logs/logs.dart +++ b/lib/screens/logs/logs.dart @@ -5,14 +5,12 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:adguard_home_manager/screens/logs/log_tile.dart'; +import 'package:adguard_home_manager/screens/logs/appbar.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart'; -import 'package:adguard_home_manager/models/filtering_status.dart'; -import 'package:adguard_home_manager/models/app_log.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/models/logs.dart'; -import 'package:adguard_home_manager/models/server.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; class Logs extends StatelessWidget { @@ -132,114 +130,121 @@ class _LogsWidgetState extends State { Widget build(BuildContext context) { final logsProvider = Provider.of(context); - switch (logsProvider.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)!.loadingLogs, - style: const TextStyle( - fontSize: 22, - color: Colors.grey, - ), - ) - ], - ), - ); - - case 1: - return RefreshIndicator( - onRefresh: () async { - await fetchLogs(inOffset: 0); - }, - child: logsProvider.logsData!.data.isNotEmpty - ? ListView.builder( - controller: scrollController, - padding: const EdgeInsets.only(top: 0), - itemCount: isLoadingMore == true - ? logsProvider.logsData!.data.length+1 - : logsProvider.logsData!.data.length, - itemBuilder: (context, index) { - if (isLoadingMore == true && index == logsProvider.logsData!.data.length) { - return const Padding( - padding: EdgeInsets.symmetric(vertical: 20), - child: Center( - child: CircularProgressIndicator(), - ), - ); + Widget generateBody() { + switch (logsProvider.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)!.loadingLogs, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), + ) + ], + ), + ); + + case 1: + return RefreshIndicator( + onRefresh: () async { + await fetchLogs(inOffset: 0); + }, + child: logsProvider.logsData!.data.isNotEmpty + ? ListView.builder( + controller: scrollController, + padding: const EdgeInsets.only(top: 0), + itemCount: isLoadingMore == true + ? logsProvider.logsData!.data.length+1 + : logsProvider.logsData!.data.length, + itemBuilder: (context, index) { + if (isLoadingMore == true && index == logsProvider.logsData!.data.length) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: Center( + child: CircularProgressIndicator(), + ), + ); + } + else { + return LogTile( + log: logsProvider.logsData!.data[index], + index: index, + length: logsProvider.logsData!.data.length, + ); + } } - else { - return LogTile( - log: logsProvider.logsData!.data[index], - index: index, - length: logsProvider.logsData!.data.length, - ); - } - } - ) - : Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.of(context)!.noLogsDisplay, - style: const TextStyle( - fontSize: 24, - color: Colors.grey - ), - ), - if (logsProvider.logsOlderThan != null) Padding( - padding: const EdgeInsets.only( - top: 30, - left: 20, - right: 20 - ), - child: Text( - AppLocalizations.of(context)!.noLogsThatOld, - textAlign: TextAlign.center, + ) + : Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + AppLocalizations.of(context)!.noLogsDisplay, style: const TextStyle( - fontSize: 16, + fontSize: 24, color: Colors.grey ), ), - ), - ] + if (logsProvider.logsOlderThan != null) Padding( + padding: const EdgeInsets.only( + top: 30, + left: 20, + right: 20 + ), + child: Text( + AppLocalizations.of(context)!.noLogsThatOld, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 16, + color: Colors.grey + ), + ), + ), + ] + ), + ) + ); + + 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, ), - ) - ); - - 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)!.logsNotLoaded, - style: const TextStyle( - fontSize: 22, - color: Colors.grey, - ), - ) - ], - ), - ); + const SizedBox(height: 30), + Text( + AppLocalizations.of(context)!.logsNotLoaded, + style: const TextStyle( + fontSize: 22, + color: Colors.grey, + ), + ) + ], + ), + ); - default: - return const SizedBox(); + default: + return const SizedBox(); + } } + + return Scaffold( + appBar: const LogsAppBar(), + body: generateBody(), + ); } } \ No newline at end of file