Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions apps/src/tests/issue-tests/Test3168.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ function TabsStackComponent() {
const [config, setConfig] = React.useState<Configuration>(
DEFAULT_GLOBAL_CONFIGURATION,
);
const [activeFilterCount, setActiveFilterCount] = useState(2);
const { searchBarConfig } = useSearchBarConfig();

const TAB_CONFIGS: TabRouteConfig[] = [
Expand Down Expand Up @@ -237,6 +238,24 @@ function TabsStackComponent() {
name: 'magnifyingglass',
},
systemItem: searchBarConfig.useSystemItem ? 'search' : undefined,
toolbarItems: [
{
type: 'button',
icon: {
type: 'sfSymbol',
name: 'line.3.horizontal.decrease',
},
accessibilityLabel: 'Filters',
accessibilityHint: 'Updates active filters count',
badge: {
value: String(activeFilterCount),
},
onPress: () =>
setActiveFilterCount(currentFilterCount =>
currentFilterCount + 1,
),
},
],
},
},
},
Expand Down
6 changes: 6 additions & 0 deletions ios/RNSScreenStackHeaderConfig.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import "RNSDefines.h"
#import "RNSScreen.h"
#import "RNSSearchBar.h"
#import "RNSTabBarController.h"
#import "UINavigationBar+RNSUtility.h"

namespace react = facebook::react;
Expand Down Expand Up @@ -627,6 +628,11 @@ + (void)updateViewController:(UIViewController *)vc
if (!searchBarPresent) {
navitem.searchController = nil;
}
if ([vc.tabBarController isKindOfClass:RNSTabBarController.class]) {
RNSTabBarController *tabBarController = static_cast<RNSTabBarController *>(vc.tabBarController);
tabBarController.needsUpdateOfSearchToolbarItems = true;
[tabBarController updateSearchToolbarItemsIfNeeded];
}
#endif /* !TARGET_OS_TV */

// This assignment should be done after `navitem.titleView = ...` assignment (iOS 16.0 bug).
Expand Down
15 changes: 15 additions & 0 deletions ios/tabs/host/RNSTabBarController.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,16 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)updateTabBarAppearance;

/**
* Updates native toolbar items associated with the selected search tab.
*/
- (void)updateSearchToolbarItemsIfNeeded;

/**
* Updates native toolbar items associated with the selected search tab.
*/
- (void)updateSearchToolbarItems;

/**
* Updates the interface orientation based on selected tab screen and its children.
*
Expand Down Expand Up @@ -287,6 +297,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readwrite) bool needsUpdateOfTabBarAppearance;

/**
* Tell the controller that toolbar items associated with the selected search tab need an update.
*/
@property (nonatomic, readwrite) bool needsUpdateOfSearchToolbarItems;

/**
* Tell the controller that some configuration regarding interface orientation has changed & it
* requires update.
Expand Down
33 changes: 33 additions & 0 deletions ios/tabs/host/RNSTabBarController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#import "NSString+RNSUtility.h"
#import "RNSLog.h"
#import "RNSScreenWindowTraits.h"
#import "RNSTabsHostComponentView+RNSImageLoader.h"
#import "RNSTabsHostComponentView.h"
#import "RNSTabsNavigationStateObserverRegistry.h"

Expand Down Expand Up @@ -97,6 +98,7 @@ - (instancetype)init
_navigationState = nil;
_pendingStateUpdate = nil;
_shouldProgressStateOnMoreNavigationControllerPush = NO;
_needsUpdateOfSearchToolbarItems = false;
_observerRegistry = [RNSTabsNavigationStateObserverRegistry new];

// Delegate field retains weakly, no risk of cycle.
Expand Down Expand Up @@ -250,6 +252,7 @@ - (void)performContainerUpdate
_isHandlingExplicitSelectionUpdate = NO;

[self updateTabBarAppearanceIfNeeded];
[self updateSearchToolbarItemsIfNeeded];
[self updateTabBarA11yIfNeeded];
[self updateOrientationIfNeeded];
}
Expand Down Expand Up @@ -280,10 +283,12 @@ - (BOOL)updateSelectedViewControllerTo:(nullable UIViewController *)nextSelected
[self progressNavigationState:screenKey withOrigin:actionOrigin];

if (currSelectedViewController == nextSelectedViewController) {
self.needsUpdateOfSearchToolbarItems = true;
return YES;
}

[self setSelectedViewController:nextSelectedViewController];
self.needsUpdateOfSearchToolbarItems = true;
return YES;
}

Expand Down Expand Up @@ -342,6 +347,8 @@ - (void)userDidSelectViewController:(nonnull UIViewController *)viewController
actionOrigin:RNSTabsActionOriginUser];
[_observerRegistry emitDidUpdateStateTo:_navigationState withContext:updateContext sender:self];
}
self.needsUpdateOfSearchToolbarItems = true;
[self updateSearchToolbarItemsIfNeeded];
}

- (void)onDidPreventUserFromSelectingViewControllerWithKey:(nonnull NSString *)screenKey
Expand Down Expand Up @@ -582,6 +589,32 @@ - (void)updateTabBarAppearance
imageLoader:[self.tabsHostComponentView reactImageLoader]];
}

- (void)updateSearchToolbarItemsIfNeeded
{
if (_needsUpdateOfSearchToolbarItems) {
[self updateSearchToolbarItems];
}
}

- (void)updateSearchToolbarItems
{
_needsUpdateOfSearchToolbarItems = false;

RNSTabsScreenViewController *selectedScreenViewController = nil;
if (![self isSelectedViewControllerTheMoreNavigationController] &&
[self.selectedViewController isKindOfClass:RNSTabsScreenViewController.class]) {
selectedScreenViewController = [self selectedScreenViewController];
}

for (RNSTabsScreenViewController *screenViewController in _tabScreenControllers) {
if (screenViewController != selectedScreenViewController) {
[screenViewController clearSearchToolbarItems];
}
}

[selectedScreenViewController updateSearchToolbarItemsWithImageLoader:[self.tabsHostComponentView reactImageLoader]];
}

- (void)updateTabBarA11yIfNeeded
{
for (UIViewController *tabViewController in self.viewControllers) {
Expand Down
1 change: 1 addition & 0 deletions ios/tabs/screen/RNSTabsScreenComponentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) BOOL tabBarItemNeedsA11yUpdate;

@property (nonatomic, readonly) RNSTabsScreenSystemItem systemItem;
@property (nonatomic, copy, readonly, nullable) NSArray<NSDictionary<NSString *, id> *> *searchToolbarItems;

@end

Expand Down
18 changes: 18 additions & 0 deletions ios/tabs/screen/RNSTabsScreenComponentView.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "RNSTabsScreenComponentView.h"
#import "NSString+RNSUtility.h"
#import "RNSConversions.h"
#import "RNSConvert.h"
#import "RNSDefines.h"
#import "RNSLog.h"
#import "RNSSafeAreaViewNotifications.h"
Expand Down Expand Up @@ -80,6 +81,7 @@ - (void)resetProps
_selectedIconResourceName = nil;

_systemItem = RNSTabsScreenSystemItemNone;
_searchToolbarItems = nil;

_userInterfaceStyle = UIUserInterfaceStyleUnspecified;
}
Expand Down Expand Up @@ -338,6 +340,22 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props
_systemItem =
rnscreens::conversion::RNSTabsScreenSystemItemFromReactRNSTabsScreenSystemItem(newComponentProps.systemItem);
tabBarItemNeedsRecreation = YES;
RNSTabBarController *tabBarController = [self findTabBarController];
tabBarController.needsUpdateOfSearchToolbarItems = true;
}

if (newComponentProps.toolbarItems != oldComponentProps.toolbarItems) {
const auto &vec = newComponentProps.toolbarItems;
NSMutableArray<NSDictionary<NSString *, id> *> *array = [NSMutableArray arrayWithCapacity:vec.size()];
for (const auto &item : vec) {
NSDictionary *dict = [RNSConvert idFromFollyDynamic:item];
if ([dict isKindOfClass:NSDictionary.class]) {
[array addObject:dict];
}
}
_searchToolbarItems = array;
RNSTabBarController *tabBarController = [self findTabBarController];
tabBarController.needsUpdateOfSearchToolbarItems = true;
}

if (newComponentProps.userInterfaceStyle != oldComponentProps.userInterfaceStyle) {
Expand Down
1 change: 1 addition & 0 deletions ios/tabs/screen/RNSTabsScreenEventEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)emitOnDidAppear;
- (BOOL)emitOnWillDisappear;
- (BOOL)emitOnDidDisappear;
- (BOOL)emitOnPressToolbarItem:(NSString *)buttonId;

@end

Expand Down
14 changes: 14 additions & 0 deletions ios/tabs/screen/RNSTabsScreenEventEmitter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#import <React/RCTLog.h>
#import <react/renderer/components/rnscreens/EventEmitters.h>

namespace react = facebook::react;

@implementation RNSTabsScreenEventEmitter {
std::shared_ptr<const react::RNSTabsScreenIOSEventEmitter> _reactEventEmitter;
}
Expand Down Expand Up @@ -52,6 +54,18 @@ - (BOOL)emitOnDidDisappear
}
}

- (BOOL)emitOnPressToolbarItem:(NSString *)buttonId
{
if (_reactEventEmitter != nullptr) {
_reactEventEmitter->onPressToolbarItem(
react::RNSTabsScreenIOSEventEmitter::OnPressToolbarItem{.buttonId = std::string([buttonId UTF8String])});
return YES;
} else {
RCTLogWarn(@"[RNScreens] Skipped OnPressToolbarItem event emission due to nullish emitter");
return NO;
}
}

- (void)updateEventEmitter:(const std::shared_ptr<const react::RNSTabsScreenIOSEventEmitter> &)emitter
{
_reactEventEmitter = emitter;
Expand Down
11 changes: 11 additions & 0 deletions ios/tabs/screen/RNSTabsScreenViewController.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#import <React/RCTImageLoader.h>
#import <UIKit/UIKit.h>
#import "RNSTabsScreenComponentView.h"
#import "RNSTabsSpecialEffectsSupporting.h"
Expand Down Expand Up @@ -28,6 +29,16 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)tabScreenOrientationHasChanged;

/**
* Updates native toolbar items associated with this tab screen's search item.
*/
- (void)updateSearchToolbarItemsWithImageLoader:(nullable RCTImageLoader *)imageLoader;

/**
* Restores toolbar items previously replaced by this tab screen.
*/
- (void)clearSearchToolbarItems;

/**
* Tell the controller that the tab item related to this controller has been selected again after being presented.
* Returns boolean indicating whether the action has been handled.
Expand Down
Loading