From 7219150e6c54e6e71b1eb531e0fa63e5582be3e6 Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Sat, 8 Oct 2022 22:16:35 +0200 Subject: [PATCH] Fab improvements and changed screens scaffolds --- lib/base.dart | 27 ++++---- lib/l10n/app_en.arb | 1 + lib/l10n/app_es.arb | 5 +- lib/providers/app_config_provider.dart | 25 +++++++ lib/screens/clients/added_list.dart | 78 ++++++++++++++++------ lib/screens/clients/blocked_list.dart | 62 +++++++++++++---- lib/screens/clients/clients.dart | 71 ++------------------ lib/screens/clients/clients_list.dart | 2 + lib/screens/clients/fab.dart | 5 ++ lib/screens/filters/custom_rules_list.dart | 7 +- lib/screens/filters/fab.dart | 7 ++ lib/screens/filters/filters.dart | 1 + lib/screens/filters/filters_list.dart | 7 +- lib/screens/home/home.dart | 35 +++++++++- lib/screens/logs/logs.dart | 3 +- lib/widgets/bottom_nav_bar.dart | 23 +++---- 16 files changed, 232 insertions(+), 127 deletions(-) diff --git a/lib/base.dart b/lib/base.dart index c309385..ed649a0 100644 --- a/lib/base.dart +++ b/lib/base.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:animations/animations.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart'; +import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/models/app_screen.dart'; import 'package:adguard_home_manager/config/app_screens.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; @@ -21,15 +23,12 @@ class _BaseState extends State { @override Widget build(BuildContext context) { final serversProvider = Provider.of(context); + final appConfigProvider = Provider.of(context); List screens = serversProvider.selectedServer != null ? screensServerConnected : screensSelectServer; - if (selectedScreen > screens.length-1) { - setState(() => selectedScreen = 0); - } - return AnnotatedRegion( value: SystemUiOverlayStyle( statusBarColor: Colors.transparent, @@ -45,15 +44,19 @@ class _BaseState extends State { : Brightness.light, ), child: Scaffold( - appBar: screens[selectedScreen].appBar, - body: screens[selectedScreen].body, - bottomNavigationBar: BottomNavBar( - screens: screens, - selectedScreen: selectedScreen, - onSelect: (value) => setState(() => selectedScreen = value), + body: PageTransitionSwitcher( + duration: const Duration(milliseconds: 200), + transitionBuilder: ( + (child, primaryAnimation, secondaryAnimation) => FadeThroughTransition( + animation: primaryAnimation, + secondaryAnimation: secondaryAnimation, + child: child, + ) + ), + child: screens[appConfigProvider.selectedScreen].body, ), - floatingActionButton: screens[selectedScreen].fab, - ), + bottomNavigationBar: const BottomNavBar(), + ) ); } } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 6e73c2d..f4c3042 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -218,6 +218,7 @@ "ruleAddedSuccessfully": "Rule added successfully", "ruleNotAdded": "Couldn't add the rule", "noCustomFilters": "No custom filters", + "noBlockedClients": "No blocked clients", "noBlackLists": "No blacklists", "noWhiteLists": "No whitelists", "addWhitelist": "Add whitelist", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index c83db03..303fbff 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -196,7 +196,7 @@ "added": "Añadidos", "clientUpdatedSuccessfully": "Cliente actualizado correctamente", "clientNotUpdated": "El cliente no pudo ser actualizado", - "clientRemovedSuccessfully": "Cliente eliminado correctamente", + "clientDeletedSuccessfully": "Cliente eliminado correctamente", "clientNotDeleted": "El cliente no pudo ser eliminado", "options": "Opciones", "loadingFilters": "Cargando filtros...", @@ -217,7 +217,8 @@ "ruleNotRemoved": "No se ha podido eliminar la regla", "ruleAddedSuccessfully": "Regla añadida correctamente", "ruleNotAdded": "No se ha podido añadir la regla", - "noCustomFilters": "No custom filters", + "noCustomFilters": "No hay filtros personalizados", + "noBlockedClients": "No hay clientes bloqueados", "noBlackLists": "No hay listas negras", "noWhiteLists": "No hay listas blancas", "addWhitelist": "Añadir lista blanca", diff --git a/lib/providers/app_config_provider.dart b/lib/providers/app_config_provider.dart index 57bcd20..fe26bee 100644 --- a/lib/providers/app_config_provider.dart +++ b/lib/providers/app_config_provider.dart @@ -13,6 +13,10 @@ class AppConfigProvider with ChangeNotifier { AndroidDeviceInfo? _androidDeviceInfo; IosDeviceInfo? _iosDeviceInfo; + int _selectedScreen = 0; + + bool _showingSnackbar = false; + int _selectedTheme = 0; int _selectedClientsTab = 0; @@ -78,6 +82,14 @@ class AppConfigProvider with ChangeNotifier { return _hideZeroValues == 1 ? true : false; } + int get selectedScreen { + return _selectedScreen; + } + + bool get showingSnackbar { + return _showingSnackbar; + } + void setDbInstance(Database db) { _dbInstance = db; } @@ -109,6 +121,19 @@ class AppConfigProvider with ChangeNotifier { notifyListeners(); } + void setSelectedScreen(int screen) { + _selectedScreen = screen; + notifyListeners(); + } + + void setShowingSnackbar() async { + _showingSnackbar = true; + notifyListeners(); + await Future.delayed(const Duration(milliseconds: 4500)); + _showingSnackbar = false; + notifyListeners(); + } + Future setOverrideSslCheck(bool status) async { final updated = await _updateOverrideSslCheck(status == true ? 1 : 0); if (updated == true) { diff --git a/lib/screens/clients/added_list.dart b/lib/screens/clients/added_list.dart index 08f3df1..aa7bdac 100644 --- a/lib/screens/clients/added_list.dart +++ b/lib/screens/clients/added_list.dart @@ -1,11 +1,12 @@ // ignore_for_file: use_build_context_synchronously -import 'package:adguard_home_manager/screens/clients/remove_domain_modal.dart'; import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:adguard_home_manager/screens/clients/remove_domain_modal.dart'; import 'package:adguard_home_manager/screens/clients/fab.dart'; import 'package:adguard_home_manager/screens/clients/options_modal.dart'; import 'package:adguard_home_manager/screens/clients/client_modal.dart'; @@ -16,18 +17,48 @@ import 'package:adguard_home_manager/models/clients.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; -class AddedList extends StatelessWidget { +class AddedList extends StatefulWidget { + final ScrollController scrollController; final int loadStatus; final List data; final Future Function() fetchClients; const AddedList({ Key? key, + required this.scrollController, required this.loadStatus, required this.data, required this.fetchClients }) : super(key: key); + @override + State createState() => _AddedListState(); +} + +class _AddedListState extends State { + late bool isVisible; + + @override + initState(){ + super.initState(); + + isVisible = true; + widget.scrollController.addListener(() { + if (widget.scrollController.position.userScrollDirection == ScrollDirection.reverse) { + if (mounted && isVisible == true) { + setState(() => isVisible = false); + } + } + else { + if (widget.scrollController.position.userScrollDirection == ScrollDirection.forward) { + if (mounted && isVisible == false) { + setState(() => isVisible = true); + } + } + } + }); + } + @override Widget build(BuildContext context) { final serversProvider = Provider.of(context); @@ -55,6 +86,7 @@ class AddedList extends StatelessWidget { } }).toList(); serversProvider.setClientsData(clientsData); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientUpdatedSuccessfully), @@ -64,6 +96,7 @@ class AddedList extends StatelessWidget { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientNotUpdated), @@ -85,6 +118,7 @@ class AddedList extends StatelessWidget { ClientsData clientsData = serversProvider.clients.data!; clientsData.clients = clientsData.clients.where((c) => c.name != client.name).toList(); serversProvider.setClientsData(clientsData); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientDeletedSuccessfully), @@ -94,6 +128,7 @@ class AddedList extends StatelessWidget { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientNotDeleted), @@ -135,7 +170,7 @@ class AddedList extends StatelessWidget { ); } - switch (loadStatus) { + switch (widget.loadStatus) { case 0: return SizedBox( width: double.maxFinite, @@ -160,28 +195,28 @@ class AddedList extends StatelessWidget { case 1: return Stack( children: [ - if (data.isNotEmpty) ListView.builder( + if (widget.data.isNotEmpty) ListView.builder( padding: const EdgeInsets.only(top: 0), - itemCount: data.length, + itemCount: widget.data.length, itemBuilder: (context, index) => ListTile( isThreeLine: true, - onLongPress: () => openOptionsModal(data[index]), - onTap: () => openClientModal(data[index]), + onLongPress: () => openOptionsModal(widget.data[index]), + onTap: () => openClientModal(widget.data[index]), title: Padding( padding: const EdgeInsets.only(bottom: 5), - child: Text(data[index].name), + child: Text(widget.data[index].name), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(data[index].ids.toString().replaceAll(RegExp(r'^\[|\]$'), '')), + Text(widget.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 + color: widget.data[index].filteringEnabled == true ? Colors.green : Colors.red, ), @@ -189,7 +224,7 @@ class AddedList extends StatelessWidget { Icon( Icons.vpn_lock_rounded, size: 18, - color: data[index].safebrowsingEnabled == true + color: widget.data[index].safebrowsingEnabled == true ? Colors.green : Colors.red, ), @@ -197,7 +232,7 @@ class AddedList extends StatelessWidget { Icon( Icons.block, size: 18, - color: data[index].parentalEnabled == true + color: widget.data[index].parentalEnabled == true ? Colors.green : Colors.red, ), @@ -205,7 +240,7 @@ class AddedList extends StatelessWidget { Icon( Icons.search_rounded, size: 19, - color: data[index].safesearchEnabled == true + color: widget.data[index].safesearchEnabled == true ? Colors.green : Colors.red, ) @@ -215,7 +250,7 @@ class AddedList extends StatelessWidget { ), ) ), - if (data.isEmpty) SizedBox( + if (widget.data.isEmpty) SizedBox( width: double.maxFinite, child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -230,18 +265,23 @@ class AddedList extends StatelessWidget { ), const SizedBox(height: 30), TextButton.icon( - onPressed: fetchClients, + onPressed: widget.fetchClients, icon: const Icon(Icons.refresh_rounded), label: Text(AppLocalizations.of(context)!.refresh), ) ], ), ), - const Positioned( - bottom: 20, + AnimatedPositioned( + duration: const Duration(milliseconds: 100), + curve: Curves.easeInOut, + bottom: isVisible ? + appConfigProvider.showingSnackbar + ? 70 : 20 + : -70, right: 20, - child: ClientsFab(tab: 1), - ), + child: const ClientsFab(tab: 1), + ) ], ); diff --git a/lib/screens/clients/blocked_list.dart b/lib/screens/clients/blocked_list.dart index a9ab9a5..fae1691 100644 --- a/lib/screens/clients/blocked_list.dart +++ b/lib/screens/clients/blocked_list.dart @@ -1,6 +1,7 @@ // ignore_for_file: use_build_context_synchronously import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -13,18 +14,48 @@ import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/classes/process_modal.dart'; -class BlockedList extends StatelessWidget { +class BlockedList extends StatefulWidget { + final ScrollController scrollController; final int loadStatus; final List data; final Future Function() fetchClients; const BlockedList({ Key? key, + required this.scrollController, required this.loadStatus, required this.data, required this.fetchClients }) : super(key: key); + @override + State createState() => _BlockedListState(); +} + +class _BlockedListState extends State { + late bool isVisible; + + @override + initState(){ + super.initState(); + + isVisible = true; + widget.scrollController.addListener(() { + if (widget.scrollController.position.userScrollDirection == ScrollDirection.reverse) { + if (mounted && isVisible == true) { + setState(() => isVisible = false); + } + } + else { + if (widget.scrollController.position.userScrollDirection == ScrollDirection.forward) { + if (mounted && isVisible == false) { + setState(() => isVisible = true); + } + } + } + }); + } + @override Widget build(BuildContext context) { final serversProvider = Provider.of(context); @@ -73,7 +104,7 @@ class BlockedList extends StatelessWidget { } } - switch (loadStatus) { + switch (widget.loadStatus) { case 0: return SizedBox( width: double.maxFinite, @@ -98,17 +129,17 @@ class BlockedList extends StatelessWidget { case 1: return Stack( children: [ - if (data.isNotEmpty) ListView.builder( + if (widget.data.isNotEmpty) ListView.builder( padding: const EdgeInsets.only(top: 0), - itemCount: data.length, + itemCount: widget.data.length, itemBuilder: (context, index) => ListTile( - title: Text(data[index]), + title: Text(widget.data[index]), trailing: IconButton( onPressed: () => { showDialog( context: context, builder: (context) => RemoveDomainModal( - onConfirm: () => confirmRemoveDomain(data[index]), + onConfirm: () => confirmRemoveDomain(widget.data[index]), ) ) }, @@ -116,13 +147,13 @@ class BlockedList extends StatelessWidget { ), ) ), - if (data.isEmpty) SizedBox( + if (widget.data.isEmpty) SizedBox( width: double.maxFinite, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - AppLocalizations.of(context)!.noCustomFilters, + AppLocalizations.of(context)!.noBlockedClients, textAlign: TextAlign.center, style: const TextStyle( fontSize: 24, @@ -131,18 +162,23 @@ class BlockedList extends StatelessWidget { ), const SizedBox(height: 30), TextButton.icon( - onPressed: fetchClients, + onPressed: widget.fetchClients, icon: const Icon(Icons.refresh_rounded), label: Text(AppLocalizations.of(context)!.refresh), ) ], ), ), - const Positioned( - bottom: 20, + AnimatedPositioned( + duration: const Duration(milliseconds: 100), + curve: Curves.easeInOut, + bottom: isVisible ? + appConfigProvider.showingSnackbar + ? 70 : 20 + : -70, right: 20, - child: ClientsFab(tab: 2), - ), + child: const ClientsFab(tab: 2), + ) ] ); diff --git a/lib/screens/clients/clients.dart b/lib/screens/clients/clients.dart index 2920bf1..451d2f8 100644 --- a/lib/screens/clients/clients.dart +++ b/lib/screens/clients/clients.dart @@ -1,3 +1,4 @@ +import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -53,6 +54,7 @@ class ClientsWidget extends StatefulWidget { class _ClientsWidgetState extends State with TickerProviderStateMixin { late TabController tabController; + final ScrollController scrollController = ScrollController(); Future fetchClients() async { widget.setLoadingStatus(0, false); @@ -89,74 +91,10 @@ class _ClientsWidgetState extends State with TickerProviderStateM Widget build(BuildContext context) { final serversProvider = Provider.of(context); - Widget generateBody() { - switch (serversProvider.clients.loadStatus) { - case 0: - 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, - ), - ) - ], - ), - ), - ], - ); - - 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( + controller: scrollController, headerSliverBuilder: ((context, innerBoxIsScrolled) { return [ SliverAppBar( @@ -201,6 +139,7 @@ class _ClientsWidgetState extends State with TickerProviderStateM RefreshIndicator( onRefresh: fetchClients, child: ClientsList( + scrollController: scrollController, loadStatus: serversProvider.clients.loadStatus, data: serversProvider.clients.loadStatus == 1 ? serversProvider.clients.data!.autoClientsData : [], @@ -210,6 +149,7 @@ class _ClientsWidgetState extends State with TickerProviderStateM RefreshIndicator( onRefresh: fetchClients, child: AddedList( + scrollController: scrollController, loadStatus: serversProvider.clients.loadStatus, data: serversProvider.clients.loadStatus == 1 ? serversProvider.clients.data!.clients : [], @@ -219,6 +159,7 @@ class _ClientsWidgetState extends State with TickerProviderStateM RefreshIndicator( onRefresh: fetchClients, child: BlockedList( + scrollController: scrollController, loadStatus: serversProvider.clients.loadStatus, data: serversProvider.clients.loadStatus == 1 ? serversProvider.clients.data!.clientsAllowedBlocked!.disallowedClients : [], diff --git a/lib/screens/clients/clients_list.dart b/lib/screens/clients/clients_list.dart index 84f3fde..2ecf533 100644 --- a/lib/screens/clients/clients_list.dart +++ b/lib/screens/clients/clients_list.dart @@ -4,12 +4,14 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:adguard_home_manager/models/clients.dart'; class ClientsList extends StatelessWidget { + final ScrollController scrollController; final int loadStatus; final List data; final Future Function() fetchClients; const ClientsList({ Key? key, + required this.scrollController, required this.loadStatus, required this.data, required this.fetchClients diff --git a/lib/screens/clients/fab.dart b/lib/screens/clients/fab.dart index de5e177..6e12df7 100644 --- a/lib/screens/clients/fab.dart +++ b/lib/screens/clients/fab.dart @@ -52,6 +52,7 @@ class ClientsFab extends StatelessWidget { blockedHosts: body['blocked_hosts'] ?? [], ) ); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientAddedSuccessfully), @@ -61,6 +62,7 @@ class ClientsFab extends StatelessWidget { } else if (result['result'] == 'error' && result['message'] == 'client_another_list') { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientAnotherList), @@ -70,6 +72,7 @@ class ClientsFab extends StatelessWidget { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientNotAdded), @@ -91,6 +94,7 @@ class ClientsFab extends StatelessWidget { ClientsData clientsData = serversProvider.clients.data!; clientsData.clients.add(client); serversProvider.setClientsData(clientsData); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientAddedSuccessfully), @@ -100,6 +104,7 @@ class ClientsFab extends StatelessWidget { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.clientNotAdded), diff --git a/lib/screens/filters/custom_rules_list.dart b/lib/screens/filters/custom_rules_list.dart index ab87df6..245c4c2 100644 --- a/lib/screens/filters/custom_rules_list.dart +++ b/lib/screens/filters/custom_rules_list.dart @@ -75,6 +75,7 @@ class _CustomRulesListState extends State { FilteringData filteringData = serversProvider.filtering.data!; filteringData.userRules = newRules; serversProvider.setFilteringData(filteringData); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.ruleRemovedSuccessfully), @@ -84,6 +85,7 @@ class _CustomRulesListState extends State { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.ruleNotRemoved), @@ -163,7 +165,10 @@ class _CustomRulesListState extends State { AnimatedPositioned( duration: const Duration(milliseconds: 100), curve: Curves.easeInOut, - bottom: isVisible ? 20 : -70, + bottom: isVisible ? + appConfigProvider.showingSnackbar + ? 70 : 20 + : -70, right: 20, child: const FiltersFab( type: 'custom_rule', diff --git a/lib/screens/filters/fab.dart b/lib/screens/filters/fab.dart index 55aabe1..39f7d04 100644 --- a/lib/screens/filters/fab.dart +++ b/lib/screens/filters/fab.dart @@ -41,6 +41,7 @@ class FiltersFab extends StatelessWidget { FilteringData filteringData = serversProvider.filtering.data!; filteringData.userRules = newRules; serversProvider.setFilteringData(filteringData); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.ruleAddedSuccessfully), @@ -50,6 +51,7 @@ class FiltersFab extends StatelessWidget { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.ruleNotAdded), @@ -96,6 +98,7 @@ class FiltersFab extends StatelessWidget { processModal.close(); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text("${AppLocalizations.of(context)!.listAdded} $items."), @@ -105,6 +108,7 @@ class FiltersFab extends StatelessWidget { } else { processModal.close(); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.listNotAdded), @@ -116,6 +120,7 @@ class FiltersFab extends StatelessWidget { else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains("Couldn't fetch filter from url")) { processModal.close(); appConfigProvider.addLog(result1['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.listUrlInvalid), @@ -126,6 +131,7 @@ class FiltersFab extends StatelessWidget { else if (result1['result'] == 'error' && result1['log'].statusCode == '400' && result1['log'].resBody.toString().contains('Filter URL already added')) { processModal.close(); appConfigProvider.addLog(result1['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.listAlreadyAdded), @@ -136,6 +142,7 @@ class FiltersFab extends StatelessWidget { else { processModal.close(); appConfigProvider.addLog(result1['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.listNotAdded), diff --git a/lib/screens/filters/filters.dart b/lib/screens/filters/filters.dart index 2f6dac0..40e04f4 100644 --- a/lib/screens/filters/filters.dart +++ b/lib/screens/filters/filters.dart @@ -83,6 +83,7 @@ class _FiltersWidgetState extends State with TickerProviderStateM return DefaultTabController( length: 3, child: NestedScrollView( + controller: scrollController, headerSliverBuilder: ((context, innerBoxIsScrolled) { return [ SliverAppBar( diff --git a/lib/screens/filters/filters_list.dart b/lib/screens/filters/filters_list.dart index a3bee6a..497a2e1 100644 --- a/lib/screens/filters/filters_list.dart +++ b/lib/screens/filters/filters_list.dart @@ -96,6 +96,7 @@ class _FiltersListState extends State { processModal.close(); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.listDataUpdated), @@ -105,6 +106,7 @@ class _FiltersListState extends State { } else { appConfigProvider.addLog(result['log']); + appConfigProvider.setShowingSnackbar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context)!.listDataNotUpdated), @@ -233,7 +235,10 @@ class _FiltersListState extends State { AnimatedPositioned( duration: const Duration(milliseconds: 100), curve: Curves.easeInOut, - bottom: isVisible ? 20 : -70, + bottom: isVisible ? + appConfigProvider.showingSnackbar + ? 70 : 20 + : -70, right: 20, child: FiltersFab( type: widget.type diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart index eca5d6b..b5f7ceb 100644 --- a/lib/screens/home/home.dart +++ b/lib/screens/home/home.dart @@ -3,11 +3,13 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:adguard_home_manager/screens/home/server_status.dart'; import 'package:adguard_home_manager/screens/home/appbar.dart'; +import 'package:adguard_home_manager/screens/home/fab.dart'; import 'package:adguard_home_manager/screens/home/top_items.dart'; import 'package:adguard_home_manager/screens/home/chart.dart'; @@ -16,9 +18,38 @@ import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/services/http_requests.dart'; import 'package:adguard_home_manager/providers/servers_provider.dart'; -class Home extends StatelessWidget { +class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + final ScrollController scrollController = ScrollController(); + late bool isVisible; + + @override + initState(){ + super.initState(); + + isVisible = true; + scrollController.addListener(() { + if (scrollController.position.userScrollDirection == ScrollDirection.reverse) { + if (mounted && isVisible == true) { + setState(() => isVisible = false); + } + } + else { + if (scrollController.position.userScrollDirection == ScrollDirection.forward) { + if (mounted && isVisible == false) { + setState(() => isVisible = true); + } + } + } + }); + } + @override Widget build(BuildContext context) { final serversProvider = Provider.of(context); @@ -48,6 +79,7 @@ class Home extends StatelessWidget { case 1: return ListView( + controller: scrollController, children: [ ServerStatus(serverStatus: serversProvider.serverStatus.data!), const Padding( @@ -176,6 +208,7 @@ class Home extends StatelessWidget { }, child: status() ), + floatingActionButton: isVisible ? const HomeFab() : null ); } } \ No newline at end of file diff --git a/lib/screens/logs/logs.dart b/lib/screens/logs/logs.dart index 8dbcf5c..d2ae1c5 100644 --- a/lib/screens/logs/logs.dart +++ b/lib/screens/logs/logs.dart @@ -1,5 +1,6 @@ // ignore_for_file: use_build_context_synchronously +import 'package:adguard_home_manager/widgets/bottom_nav_bar.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -244,7 +245,7 @@ class _LogsWidgetState extends State { return Scaffold( appBar: const LogsAppBar(), - body: generateBody(), + body: generateBody() ); } } \ No newline at end of file diff --git a/lib/widgets/bottom_nav_bar.dart b/lib/widgets/bottom_nav_bar.dart index b563743..e6cd29c 100644 --- a/lib/widgets/bottom_nav_bar.dart +++ b/lib/widgets/bottom_nav_bar.dart @@ -2,27 +2,26 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:adguard_home_manager/config/app_screens.dart'; import 'package:adguard_home_manager/providers/logs_provider.dart'; +import 'package:adguard_home_manager/providers/servers_provider.dart'; import 'package:adguard_home_manager/providers/app_config_provider.dart'; import 'package:adguard_home_manager/models/app_screen.dart'; class BottomNavBar extends StatelessWidget { - final List screens; - final int selectedScreen; - final void Function(int) onSelect; - - const BottomNavBar({ - Key? key, - required this.screens, - required this.selectedScreen, - required this.onSelect, - }) : super(key: key); + const BottomNavBar({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final serversProvider = Provider.of(context); final appConfigProvider = Provider.of(context); final logsProvider = Provider.of(context); + List screens = serversProvider.selectedServer != null + ? screensServerConnected + : screensSelectServer; + + String translatedName(String key) { switch (key) { case 'home': @@ -49,7 +48,7 @@ class BottomNavBar extends StatelessWidget { } return NavigationBar( - selectedIndex: selectedScreen, + selectedIndex: appConfigProvider.selectedScreen, destinations: screens.map((screen) => NavigationDestination( icon: Icon(screen.icon), label: translatedName(screen.name) @@ -63,7 +62,7 @@ class BottomNavBar extends StatelessWidget { if (value != 2) { logsProvider.resetFilters(); } - onSelect(value); + appConfigProvider.setSelectedScreen(value); }, ); }