diff --git a/assets/schema/ensemble_schema.json b/assets/schema/ensemble_schema.json index 83d9f16e3..3142fe2e4 100644 --- a/assets/schema/ensemble_schema.json +++ b/assets/schema/ensemble_schema.json @@ -5088,6 +5088,10 @@ "type": "boolean", "description": "Mark this item as a floating icon" }, + "switchScreen": { + "type": "boolean", + "description": "Disable the screen switching when clicking the bottom nav bar item. Default (True)" + }, "floatingMargin": { "$ref": "#/$defs/Margin-payload", "description": "The margin around the floating." diff --git a/lib/framework/menu.dart b/lib/framework/menu.dart index 0ac749304..b423537f9 100644 --- a/lib/framework/menu.dart +++ b/lib/framework/menu.dart @@ -71,6 +71,7 @@ abstract class Menu { floatingAlignment: Utils.optionalString(item['floatingAlignment']) ?? 'center', floatingMargin: Utils.optionalInt(item['floatingMargin']), + switchScreen: Utils.getBool(item['switchScreen'], fallback: true), onTap: item['onTap'], onTapHaptic: Utils.optionalString(item['onTapHaptic']), isExternal: Utils.getBool(item['isExternal'], fallback: false), @@ -207,6 +208,7 @@ class MenuItem { this.iconLibrary, this.selected, this.floating = false, + this.switchScreen = true, this.floatingAlignment = 'center', this.floatingMargin, this.onTap, @@ -223,6 +225,7 @@ class MenuItem { final String? iconLibrary; final dynamic selected; final bool floating; + final bool switchScreen; final String floatingAlignment; final int? floatingMargin; final dynamic onTap; diff --git a/lib/framework/view/bottom_nav_page_group.dart b/lib/framework/view/bottom_nav_page_group.dart index 91ff12059..5f82ff030 100644 --- a/lib/framework/view/bottom_nav_page_group.dart +++ b/lib/framework/view/bottom_nav_page_group.dart @@ -13,14 +13,17 @@ import 'package:ensemble/util/utils.dart'; import 'package:ensemble/framework/widget/icon.dart' as ensemble; import 'package:flutter/material.dart'; -class FABBottomAppBarItem { - FABBottomAppBarItem({ +class BottomNavBarItem { + BottomNavBarItem({ required this.icon, required this.text, required this.isCustom, this.activeIcon, this.isFloating = false, this.floatingMargin, + this.switchScreen = true, + this.onTap, + this.onTapHaptic, }); Widget icon; @@ -29,6 +32,9 @@ class FABBottomAppBarItem { bool isFloating; bool isCustom; double? floatingMargin; + bool? switchScreen; + EnsembleAction? onTap; + String? onTapHaptic; } enum FloatingAlignment { @@ -240,7 +246,7 @@ class _BottomNavPageGroupState extends State } Widget? _buildBottomNavBar() { - List navItems = []; + List navItems = []; final unselectedColor = Utils.getColor(widget.menu.styles?['color']) ?? Theme.of(context).unselectedWidgetColor; @@ -272,11 +278,14 @@ class _BottomNavPageGroupState extends State : null); navItems.add( - FABBottomAppBarItem( + BottomNavBarItem( icon: icon, activeIcon: activeIcon, isCustom: isCustom, text: label, + switchScreen: item.switchScreen, + onTap: EnsembleAction.fromYaml(item.onTap), + onTapHaptic: item.onTapHaptic, ), ); } @@ -309,11 +318,29 @@ class _BottomNavPageGroupState extends State Utils.getShadowBlurStyle(widget.menu.styles?['shadowStyle']), notchedShape: const CircularNotchedRectangle(), onTabSelected: (index) { - if (widget.menu.reloadView == true) { - viewGroupNotifier.updatePage(index); + final isSwitchScreen = + Utils.getBool(navItems[index].switchScreen, fallback: true); + if (isSwitchScreen) { + if (widget.menu.reloadView == true) { + viewGroupNotifier.updatePage(index); + } else { + PageGroupWidget.getPageController(context)!.jumpToPage(index); + viewGroupNotifier.updatePage(index); + } + + _onTap(navItems[index]); } else { - PageGroupWidget.getPageController(context)!.jumpToPage(index); - viewGroupNotifier.updatePage(index); + // Execute only onTap action. Page switching is handled by the developer with onTap + _onTap(navItems[index]); + } + + // Executing haptic feedback action + if (navItems[index].onTapHaptic != null) { + ScreenController().executeAction( + context, + HapticAction( + type: navItems[index].onTapHaptic!, onComplete: null), + ); } }, items: navItems, @@ -325,6 +352,13 @@ class _BottomNavPageGroupState extends State ); } + void _onTap(BottomNavBarItem menuItem) { + if (menuItem.onTap != null) { + ScreenController().executeActionWithScope( + context, widget.scopeManager, menuItem.onTap!); + } + } + Widget? _buildCustomIcon(MenuItem item, {bool isActive = false}) { dynamic customWidgetModel = isActive ? item.customActiveWidget : item.customWidget; @@ -360,7 +394,7 @@ class EnsembleBottomAppBar extends StatefulWidget { }) { // assert(items.length == 2 || items.length == 4); } - final List items; + final List items; final int selectedIndex; final double? height; final dynamic margin; @@ -391,9 +425,11 @@ class EnsembleBottomAppBarState extends State { void _updateIndex(int index) { widget.onTabSelected(index); - setState(() { - _selectedIndex = index; - }); + if (widget.items[index].switchScreen == true) { + setState(() { + _selectedIndex = index; + }); + } } int? getFabIndex() { @@ -484,7 +520,7 @@ class EnsembleBottomAppBarState extends State { } Widget _buildTabItem({ - required FABBottomAppBarItem item, + required BottomNavBarItem item, required int index, required ValueChanged onPressed, }) {