From 212dd31d9171af22a412287091a920db2bba271a Mon Sep 17 00:00:00 2001 From: monsieurtanuki Date: Thu, 25 Nov 2021 09:50:17 +0100 Subject: [PATCH] feat: #678 - added bottom navigation bar to product page (#679) The previous bottom navigation bottom bar was refactored, in order to be reused anywhere. Then it was added to the product page. Deleted files: * `home_page.dart` * `smooth_ui_library/smooth_bottom_navigation_bar.dart` * `smooth_ui_library/smooth_bottom_navigation_bar_item.dart` New file: * `smooth_bottom_navigation_bar.dart` Impacted files: * `continuous_scan_page.dart`: added an explicit bottom navigation bar (was implicit through `HomePage`), explicitly on the "scan" tab * `main.dart`: not using `HomePage` anymore; opens the "scan" page by default * `new_product_page.dart`: added an explicit bottom navigation bar (was not there), implicitly on the "default" tab * `product_list_page.dart`: added an explicit bottom navigation bar (was implicit through `HomePage`), explicitly on the "history" tab * `product_page.dart`: added an explicit bottom navigation bar (was not there), implicitly on the "default" tab * `smooth_ui_library.dart`: removed "UI" version of smooth bottom navigation bar * `user_preferences_page.dart`: added an explicit bottom navigation bar (was implicit through `HomePage`), explicitly on the "profile" tab --- packages/smooth_app/lib/main.dart | 4 +- packages/smooth_app/lib/pages/home_page.dart | 66 -------- .../product/common/product_list_page.dart | 4 + .../lib/pages/product/new_product_page.dart | 2 + .../lib/pages/product/product_page.dart | 2 + .../lib/pages/scan/continuous_scan_page.dart | 4 + .../pages/smooth_bottom_navigation_bar.dart | 85 ++++++++++ .../lib/pages/user_preferences_page.dart | 4 + .../smooth_bottom_navigation_bar_item.dart | 9 -- .../smooth_bottom_navigation_bar.dart | 151 ------------------ .../lib/smooth_ui_library.dart | 2 - 11 files changed, 103 insertions(+), 230 deletions(-) delete mode 100644 packages/smooth_app/lib/pages/home_page.dart create mode 100644 packages/smooth_app/lib/pages/smooth_bottom_navigation_bar.dart delete mode 100644 packages/smooth_ui_library/lib/navigation/models/smooth_bottom_navigation_bar_item.dart delete mode 100644 packages/smooth_ui_library/lib/navigation/smooth_bottom_navigation_bar.dart diff --git a/packages/smooth_app/lib/main.dart b/packages/smooth_app/lib/main.dart index 2cc0e182b8c..0f80b8d8cdd 100644 --- a/packages/smooth_app/lib/main.dart +++ b/packages/smooth_app/lib/main.dart @@ -11,7 +11,7 @@ import 'package:smooth_app/data_models/product_preferences.dart'; import 'package:smooth_app/data_models/user_preferences.dart'; import 'package:smooth_app/database/local_database.dart'; import 'package:smooth_app/database/search_history.dart'; -import 'package:smooth_app/pages/home_page.dart'; +import 'package:smooth_app/pages/smooth_bottom_navigation_bar.dart'; import 'package:smooth_app/themes/smooth_theme.dart'; import 'package:smooth_app/themes/theme_provider.dart'; @@ -171,7 +171,7 @@ class SmoothAppGetLanguage extends StatelessWidget { DefaultAssetBundle.of(context), languageCode, ); - return const HomePage(); + return SmoothBottomNavigationBar.getDefaultPage(); } Future _refresh( diff --git a/packages/smooth_app/lib/pages/home_page.dart b/packages/smooth_app/lib/pages/home_page.dart deleted file mode 100644 index 0b53ef4e22e..00000000000 --- a/packages/smooth_app/lib/pages/home_page.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:smooth_app/pages/history_page.dart'; -import 'package:smooth_app/pages/scan/scan_page.dart'; -import 'package:smooth_app/pages/user_preferences_page.dart'; - -class HomePage extends StatefulWidget { - const HomePage(); - - @override - State createState() => _HomePageState(); -} - -class _Page { - const _Page({required this.name, required this.icon, required this.body}); - final String name; - final IconData icon; - final Widget body; -} - -class _HomePageState extends State { - static const List<_Page> _pages = <_Page>[ - _Page( - name: 'Profile', - icon: Icons.account_circle, - body: UserPreferencesPage(), - ), - _Page( - name: 'Scan or Search', - icon: Icons.search, - body: ScanPage(), - ), - _Page( - name: 'History', - icon: Icons.history, - body: HistoryPage(), - ), - ]; - int _currentPage = 1; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: _pages[_currentPage].body, - bottomNavigationBar: BottomNavigationBar( - showSelectedLabels: false, - showUnselectedLabels: false, - selectedItemColor: Colors.white, - backgroundColor: Theme.of(context).appBarTheme.backgroundColor, - currentIndex: _currentPage, - onTap: _onTap, - items: _pages - .map((_Page p) => BottomNavigationBarItem( - icon: Icon(p.icon, size: 28), - label: p.name, - )) - .toList(), - ), - ); - } - - void _onTap(int index) { - setState(() { - _currentPage = index; - }); - } -} diff --git a/packages/smooth_app/lib/pages/product/common/product_list_page.dart b/packages/smooth_app/lib/pages/product/common/product_list_page.dart index 427231b4b31..de9e7aff73a 100644 --- a/packages/smooth_app/lib/pages/product/common/product_list_page.dart +++ b/packages/smooth_app/lib/pages/product/common/product_list_page.dart @@ -10,6 +10,7 @@ import 'package:smooth_app/pages/personalized_ranking_page.dart'; import 'package:smooth_app/pages/product/common/product_list_dialog_helper.dart'; import 'package:smooth_app/pages/product/common/product_list_item.dart'; import 'package:smooth_app/pages/product/common/product_query_page_helper.dart'; +import 'package:smooth_app/pages/smooth_bottom_navigation_bar.dart'; import 'package:smooth_app/themes/smooth_theme.dart'; class ProductListPage extends StatefulWidget { @@ -87,6 +88,9 @@ class _ProductListPageState extends State { throw Exception('unknown list type ${productList.listType}'); } return Scaffold( + bottomNavigationBar: const SmoothBottomNavigationBar( + tab: SmoothBottomNavigationTab.History, + ), appBar: AppBar( backgroundColor: SmoothTheme.getColor( colorScheme, diff --git a/packages/smooth_app/lib/pages/product/new_product_page.dart b/packages/smooth_app/lib/pages/product/new_product_page.dart index ce0754468f9..9790440d4e7 100644 --- a/packages/smooth_app/lib/pages/product/new_product_page.dart +++ b/packages/smooth_app/lib/pages/product/new_product_page.dart @@ -14,6 +14,7 @@ import 'package:smooth_app/helpers/launch_url_helper.dart'; import 'package:smooth_app/helpers/product_cards_helper.dart'; import 'package:smooth_app/pages/product/common/product_dialog_helper.dart'; import 'package:smooth_app/pages/product/summary_card.dart'; +import 'package:smooth_app/pages/smooth_bottom_navigation_bar.dart'; import 'package:smooth_app/themes/smooth_theme.dart'; import 'package:smooth_app/themes/theme_provider.dart'; import 'package:smooth_ui_library/util/ui_helpers.dart'; @@ -52,6 +53,7 @@ class _ProductPageState extends State { final MaterialColor materialColor = SmoothTheme.getMaterialColor(themeProvider); return Scaffold( + bottomNavigationBar: const SmoothBottomNavigationBar(), backgroundColor: SmoothTheme.getColor( colorScheme, materialColor, diff --git a/packages/smooth_app/lib/pages/product/product_page.dart b/packages/smooth_app/lib/pages/product/product_page.dart index 1e3a45669e2..2e2f56386ae 100644 --- a/packages/smooth_app/lib/pages/product/product_page.dart +++ b/packages/smooth_app/lib/pages/product/product_page.dart @@ -25,6 +25,7 @@ import 'package:smooth_app/helpers/product_translation_helper.dart'; import 'package:smooth_app/pages/product/common/product_dialog_helper.dart'; import 'package:smooth_app/pages/product/common/product_query_page_helper.dart'; import 'package:smooth_app/pages/product/new_product_page.dart'; +import 'package:smooth_app/pages/smooth_bottom_navigation_bar.dart'; import 'package:smooth_app/pages/user_preferences_page.dart'; import 'package:smooth_app/themes/constant_icons.dart'; import 'package:smooth_app/themes/smooth_theme.dart'; @@ -106,6 +107,7 @@ class _ProductPageState extends State { } } return Scaffold( + bottomNavigationBar: const SmoothBottomNavigationBar(), appBar: AppBar( title: Text(_getProductName(appLocalizations)), actions: [ diff --git a/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart b/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart index 6a495145c1e..fd8c446a4f5 100644 --- a/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart +++ b/packages/smooth_app/lib/pages/scan/continuous_scan_page.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:smooth_app/data_models/continuous_scan_model.dart'; import 'package:smooth_app/pages/personalized_ranking_page.dart'; +import 'package:smooth_app/pages/smooth_bottom_navigation_bar.dart'; import 'package:smooth_app/widgets/smooth_product_carousel.dart'; import 'package:smooth_ui_library/smooth_ui_library.dart'; import 'package:smooth_ui_library/util/ui_helpers.dart'; @@ -33,6 +34,9 @@ class ContinuousScanPage extends StatelessWidget { final double viewFinderBottomOffset = carouselHeight / 2.0; return Scaffold( appBar: AppBar(toolbarHeight: 0.0), + bottomNavigationBar: const SmoothBottomNavigationBar( + tab: SmoothBottomNavigationTab.Scan, + ), body: Stack( children: [ Container( diff --git a/packages/smooth_app/lib/pages/smooth_bottom_navigation_bar.dart b/packages/smooth_app/lib/pages/smooth_bottom_navigation_bar.dart new file mode 100644 index 00000000000..d28492f0312 --- /dev/null +++ b/packages/smooth_app/lib/pages/smooth_bottom_navigation_bar.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:smooth_app/pages/history_page.dart'; +import 'package:smooth_app/pages/scan/scan_page.dart'; +import 'package:smooth_app/pages/user_preferences_page.dart'; + +class _Page { + const _Page({required this.name, required this.icon, required this.body}); + final String name; + final IconData icon; + final Widget body; +} + +enum SmoothBottomNavigationTab { + Profile, + Scan, + History, +} + +class SmoothBottomNavigationBar extends StatelessWidget { + const SmoothBottomNavigationBar({ + this.tab = _defaultTab, + }); + + final SmoothBottomNavigationTab tab; + + static const SmoothBottomNavigationTab _defaultTab = + SmoothBottomNavigationTab.Scan; + + static const List _tabs = + [ + SmoothBottomNavigationTab.Profile, + SmoothBottomNavigationTab.Scan, + SmoothBottomNavigationTab.History, + ]; + + static const Map _pages = + { + SmoothBottomNavigationTab.Profile: _Page( + name: 'Profile', // TODO(monsieurtanuki): translate + icon: Icons.account_circle, + body: UserPreferencesPage(), + ), + SmoothBottomNavigationTab.Scan: _Page( + name: 'Scan or Search', + icon: Icons.search, + body: ScanPage(), + ), + SmoothBottomNavigationTab.History: _Page( + name: 'History', + icon: Icons.history, + body: HistoryPage(), + ), + }; + + static Widget getDefaultPage() => _getTabPage(_defaultTab); + + static Widget _getTabPage(final SmoothBottomNavigationTab tab) => + _pages[tab]!.body; + + @override + Widget build(BuildContext context) => BottomNavigationBar( + showSelectedLabels: false, + showUnselectedLabels: false, + selectedItemColor: Colors.white, + backgroundColor: Theme.of(context).appBarTheme.backgroundColor, + currentIndex: _tabs.indexOf(tab), + onTap: (final int index) async => Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => _getTabPage(_tabs[index]), + ), + ), + items: [ + _buildItem(_pages[_tabs[0]]!), + _buildItem(_pages[_tabs[1]]!), + _buildItem(_pages[_tabs[2]]!), + ], + ); + + BottomNavigationBarItem _buildItem(final _Page page) => + BottomNavigationBarItem( + icon: Icon(page.icon, size: 28), + label: page.name, + ); +} diff --git a/packages/smooth_app/lib/pages/user_preferences_page.dart b/packages/smooth_app/lib/pages/user_preferences_page.dart index 744d842a747..c0ef2c9a64f 100644 --- a/packages/smooth_app/lib/pages/user_preferences_page.dart +++ b/packages/smooth_app/lib/pages/user_preferences_page.dart @@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; import 'package:smooth_app/data_models/product_preferences.dart'; import 'package:smooth_app/data_models/user_preferences.dart'; import 'package:smooth_app/pages/settings_page.dart'; +import 'package:smooth_app/pages/smooth_bottom_navigation_bar.dart'; import 'package:smooth_app/themes/smooth_theme.dart'; import 'package:smooth_app/widgets/attribute_button.dart'; @@ -35,6 +36,9 @@ class UserPreferencesPage extends StatelessWidget { final List orderedImportantAttributeIds = productPreferences.getOrderedImportantAttributeIds(); return Scaffold( + bottomNavigationBar: const SmoothBottomNavigationBar( + tab: SmoothBottomNavigationTab.Profile, + ), appBar: AppBar( title: Text(appLocalizations.myPreferences), actions: [ diff --git a/packages/smooth_ui_library/lib/navigation/models/smooth_bottom_navigation_bar_item.dart b/packages/smooth_ui_library/lib/navigation/models/smooth_bottom_navigation_bar_item.dart deleted file mode 100644 index 17f836144bd..00000000000 --- a/packages/smooth_ui_library/lib/navigation/models/smooth_bottom_navigation_bar_item.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter/material.dart'; - -class SmoothBottomNavigationBarItem { - SmoothBottomNavigationBarItem( - {required this.name, required this.iconPath, required this.body}); - String name; - String iconPath; - Widget body; -} diff --git a/packages/smooth_ui_library/lib/navigation/smooth_bottom_navigation_bar.dart b/packages/smooth_ui_library/lib/navigation/smooth_bottom_navigation_bar.dart deleted file mode 100644 index 6e02bc917ac..00000000000 --- a/packages/smooth_ui_library/lib/navigation/smooth_bottom_navigation_bar.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:smooth_ui_library/navigation/models/smooth_bottom_navigation_bar_item.dart'; - -class SmoothBottomNavigationBar extends StatefulWidget { - const SmoothBottomNavigationBar(this.items, {required this.fabAction}); - final List items; - final VoidCallback fabAction; - - @override - State createState() => SmoothBottomNavigationBarState(); -} - -class SmoothBottomNavigationBarState extends State - with SingleTickerProviderStateMixin { - late AnimationController _controller; - late Animation _offsetAnimation; - int _selectedIndex = 0; - - void _onItemTapped(int index) { - setState(() { - _selectedIndex = index; - _controller.forward(from: 0.0); - }); - } - - @override - void initState() { - super.initState(); - _controller = AnimationController( - vsync: this, duration: const Duration(milliseconds: 250)); - _offsetAnimation = - Tween(begin: const Offset(0.0, 2.0), end: Offset.zero) - .animate(_controller); - _controller.forward(from: 0.0); - } - - @override - void dispose() { - super.dispose(); - _controller.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - extendBody: true, - floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, - body: Center( - child: widget.items[_selectedIndex].body, - ), - floatingActionButton: FloatingActionButton( - heroTag: 'action_button', - child: SvgPicture.asset( - 'assets/actions/scanner_alt_2.svg', - height: 25, - color: Theme.of(context).colorScheme.primary, - ), - onPressed: () => widget.fabAction(), - ), - bottomNavigationBar: BottomAppBar( - elevation: 0, - color: Colors.transparent, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(20)), - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 4.0, - sigmaY: 4.0, - ), - child: Container( - color: Colors.transparent, - child: Row( - //mainAxisAlignment: MainAxisAlignment.spaceAround, - children: getBottomAppBarIcons(), - ), - ), - ), - ), - ), - ); - } - - List getBottomAppBarIcons() { - return List.generate( - widget.items.length, - (int _index) { - if (_index == _selectedIndex) { - return buildSelectedItem(_index); - } else { - return buildUnselectedItem(_index); - } - }, - ); - } - - Widget buildUnselectedItem(int i) { - return Expanded( - child: GestureDetector( - onTap: () => _onItemTapped(i), - child: SizedBox( - height: 60, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - SvgPicture.asset( - widget.items[i].iconPath, - height: 30, - color: Theme.of(context).colorScheme.secondary, - ), - Text(widget.items[i].name), - ], - ), - ), - ), - ); - } - - Widget buildSelectedItem(int i) { - return Expanded( - child: GestureDetector( - onTap: () => _onItemTapped(i), - child: SizedBox( - height: 60, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - SvgPicture.asset( - widget.items[i].iconPath, - height: 30, - color: Theme.of(context).colorScheme.secondary, - ), - SlideTransition( - position: _offsetAnimation, - child: Text( - widget.items[i].name, - style: Theme.of(context).textTheme.bodyText2!.copyWith( - fontWeight: FontWeight.w500, - fontSize: 15, - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/packages/smooth_ui_library/lib/smooth_ui_library.dart b/packages/smooth_ui_library/lib/smooth_ui_library.dart index 81851677e80..2874115ced8 100644 --- a/packages/smooth_ui_library/lib/smooth_ui_library.dart +++ b/packages/smooth_ui_library/lib/smooth_ui_library.dart @@ -9,8 +9,6 @@ export 'buttons/smooth_main_button.dart'; export 'buttons/smooth_simple_button.dart'; export 'dialogs/smooth_alert_dialog.dart'; export 'dialogs/smooth_category_picker.dart'; -export 'navigation/models/smooth_bottom_navigation_bar_item.dart'; -export 'navigation/smooth_bottom_navigation_bar.dart'; export 'page_routes/smooth_sneak_peek_route.dart'; export 'widgets/models/single_boolean_model.dart'; export 'widgets/smooth_card.dart';