Skip to content

Commit

Permalink
Apply topBar appearance options on current child navigationItem (#5994)
Browse files Browse the repository at this point in the history
This commit changes how stack child options are applied on iOS 13. Until now, options were applied directly to the navigationItem of the stack which is shared between all children.
This commit applies options on the navigationItem of each child instead. This fixes issues with color transitions when popping and pushing children to the stack.
  • Loading branch information
yogevbd authored Mar 4, 2020
1 parent 54b2855 commit 5210848
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 41 deletions.
2 changes: 2 additions & 0 deletions lib/ios/RNNBasePresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ typedef void (^RNNReactViewReadyCompletionBlock)(void);

- (void)componentDidDisappear;

- (UINavigationItem *)currentNavigationItem;

- (UIStatusBarStyle)getStatusBarStyle:(RNNNavigationOptions *)resolvedOptions;

- (UIInterfaceOrientationMask)getOrientation:(RNNNavigationOptions *)options;
Expand Down
4 changes: 4 additions & 0 deletions lib/ios/RNNBasePresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ - (UIStatusBarStyle)getStatusBarStyle:(RNNNavigationOptions *)resolvedOptions {
}
}

- (UINavigationItem *)currentNavigationItem {
return self.boundViewController.getCurrentChild.navigationItem;
}

- (UIInterfaceOrientationMask)getOrientation:(RNNNavigationOptions *)options {
return [options withDefault:[self defaultOptions]].layout.supportedOrientations;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/ios/RNNComponentViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ @implementation RNNComponentViewController
- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo rootViewCreator:(id<RNNComponentViewCreator>)creator eventEmitter:(RNNEventEmitter *)eventEmitter presenter:(RNNComponentPresenter *)presenter options:(RNNNavigationOptions *)options defaultOptions:(RNNNavigationOptions *)defaultOptions {
self = [super initWithLayoutInfo:layoutInfo creator:creator options:options defaultOptions:defaultOptions presenter:presenter eventEmitter:eventEmitter childViewControllers:nil];
self.extendedLayoutIncludesOpaqueBars = YES;
if (@available(iOS 13.0, *)) {
self.navigationItem.standardAppearance = [UINavigationBarAppearance new];
}
return self;
}

Expand Down
39 changes: 24 additions & 15 deletions lib/ios/TopBarAppearancePresenter.m
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
#import "TopBarAppearancePresenter.h"
#import "RNNFontAttributesCreator.h"
#import "UIViewController+LayoutProtocol.h"

@interface TopBarAppearancePresenter ()

@end


@implementation TopBarAppearancePresenter {
UINavigationBarAppearance* _appearance;
@implementation TopBarAppearancePresenter

- (void)applyOptions:(RNNTopBarOptions *)options {
[self setTranslucent:[options.background.translucent getWithDefaultValue:NO]];
[self setBackgroundColor:[options.background.color getWithDefaultValue:nil]];
[self setTitleAttributes:options.title];
[self setLargeTitleAttributes:options.largeTitle];
[self showBorder:![options.noBorder getWithDefaultValue:NO]];
[self setBackButtonOptions:options.backButton];
}

- (instancetype)initWithNavigationController:(UINavigationController *)boundNavigationController {
self = [super initWithNavigationController:boundNavigationController];
_appearance = boundNavigationController.navigationBar.standardAppearance ?: [UINavigationBarAppearance new];
boundNavigationController.navigationBar.standardAppearance = _appearance;
return self;
- (void)applyOptionsBeforePopping:(RNNTopBarOptions *)options {
[self setBackgroundColor:[options.background.color getWithDefaultValue:nil]];
}

- (void)setTranslucent:(BOOL)translucent {
Expand All @@ -28,23 +33,23 @@ - (void)setTransparent:(BOOL)transparent {

- (void)updateBackgroundAppearance {
if (self.transparent) {
[_appearance configureWithTransparentBackground];
[self.getAppearance configureWithTransparentBackground];
} else if (self.backgroundColor) {
[_appearance setBackgroundColor:self.backgroundColor];
[self.getAppearance setBackgroundColor:self.backgroundColor];
} else if (self.translucent) {
[_appearance configureWithDefaultBackground];
[self.getAppearance configureWithDefaultBackground];
} else {
[_appearance configureWithOpaqueBackground];
[self.getAppearance configureWithOpaqueBackground];
}
}

- (void)showBorder:(BOOL)showBorder {
UIColor* shadowColor = showBorder ? [[UINavigationBarAppearance new] shadowColor] : nil;
_appearance.shadowColor = shadowColor;
self.getAppearance.shadowColor = shadowColor;
}

- (void)setBackIndicatorImage:(UIImage *)image withColor:(UIColor *)color {
[_appearance setBackIndicatorImage:image transitionMaskImage:image];
[self.getAppearance setBackIndicatorImage:image transitionMaskImage:image];
}

- (void)setTitleAttributes:(RNNTitleOptions *)titleOptions {
Expand All @@ -53,7 +58,7 @@ - (void)setTitleAttributes:(RNNTitleOptions *)titleOptions {
NSNumber* fontSize = [titleOptions.fontSize getWithDefaultValue:nil];
UIColor* fontColor = [titleOptions.color getWithDefaultValue:nil];

_appearance.titleTextAttributes = [RNNFontAttributesCreator createFromDictionary:_appearance.titleTextAttributes fontFamily:fontFamily fontSize:fontSize defaultFontSize:nil fontWeight:fontWeight color:fontColor defaultColor:nil];
self.getAppearance.titleTextAttributes = [RNNFontAttributesCreator createFromDictionary:self.getAppearance.titleTextAttributes fontFamily:fontFamily fontSize:fontSize defaultFontSize:nil fontWeight:fontWeight color:fontColor defaultColor:nil];
}

- (void)setLargeTitleAttributes:(RNNLargeTitleOptions *)largeTitleOptions {
Expand All @@ -62,7 +67,11 @@ - (void)setLargeTitleAttributes:(RNNLargeTitleOptions *)largeTitleOptions {
NSNumber* fontSize = [largeTitleOptions.fontSize getWithDefaultValue:nil];
UIColor* fontColor = [largeTitleOptions.color getWithDefaultValue:nil];

_appearance.largeTitleTextAttributes = [RNNFontAttributesCreator createFromDictionary:_appearance.largeTitleTextAttributes fontFamily:fontFamily fontSize:fontSize defaultFontSize:nil fontWeight:fontWeight color:fontColor defaultColor:nil];
self.getAppearance.largeTitleTextAttributes = [RNNFontAttributesCreator createFromDictionary:self.getAppearance.largeTitleTextAttributes fontFamily:fontFamily fontSize:fontSize defaultFontSize:nil fontWeight:fontWeight color:fontColor defaultColor:nil];
}

- (UINavigationBarAppearance *)getAppearance {
return self.currentNavigationItem.standardAppearance;
}

@end
2 changes: 2 additions & 0 deletions lib/ios/TopBarPresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

- (BOOL)transparent;

- (void)setBackButtonOptions:(RNNBackButtonOptions *)backButtonOptions;

@property (nonatomic) BOOL translucent;
@property (nonatomic, strong) UIColor* backgroundColor;

Expand Down
36 changes: 18 additions & 18 deletions playground/ios/NavigationTests/RNNRootViewControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ - (void)testTopBarBackgroundColor_validColor {
[self.uut viewWillAppear:false];
UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];

XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.backgroundColor isEqual:expectedColor]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.backgroundColor isEqual:expectedColor]);
}

- (void)testTopBarBackgroundColorWithoutNavigationController {
Expand Down Expand Up @@ -127,7 +127,7 @@ - (void)testTopBarTextColor_validColor{
__unused RNNStackController* nav = [self createNavigationController];
[self.uut viewWillAppear:false];
UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
}

- (void)testBackgroundColor_validColor {
Expand All @@ -149,7 +149,7 @@ - (void)testTopBarTextFontFamily_validFont{
self.options.topBar.title.fontFamily = [[Text alloc] initWithValue:inputFont];
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithName:inputFont size:17];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
}

- (void)testTopBarHideOnScroll_true {
Expand All @@ -165,8 +165,8 @@ - (void)testTopBarTranslucent {
self.options.topBar.background.translucent = [[Bool alloc] initWithValue:topBarTranslucentInput];
__unused RNNStackController* nav = [self createNavigationController];
[self.uut viewWillAppear:false];
XCTAssertTrue(CGColorEqualToColor(self.uut.navigationController.navigationBar.standardAppearance.shadowColor.CGColor, [UINavigationBarAppearance new].shadowColor.CGColor));
XCTAssertTrue(CGColorEqualToColor(self.uut.navigationController.navigationBar.standardAppearance.backgroundColor.CGColor, UIColor.systemBackgroundColor.CGColor));
XCTAssertTrue(CGColorEqualToColor(self.uut.navigationItem.standardAppearance.shadowColor.CGColor, [UINavigationBarAppearance new].shadowColor.CGColor));
XCTAssertTrue(CGColorEqualToColor(self.uut.navigationItem.standardAppearance.backgroundColor.CGColor, UIColor.systemBackgroundColor.CGColor));
}

- (void)testTopBarTransparent {
Expand Down Expand Up @@ -218,7 +218,7 @@ - (void)testTopBarLargeTitleFontSize_withoutTextFontFamily_withoutTextColor {
UIFont* initialFont = self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSFont"];
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithDescriptor:initialFont.fontDescriptor size:topBarTextFontSizeInput.floatValue];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
}

- (void)testTopBarLargeTitleFontSize_withoutTextFontFamily_withTextColor {
Expand All @@ -231,8 +231,8 @@ - (void)testTopBarLargeTitleFontSize_withoutTextFontFamily_withTextColor {
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithDescriptor:initialFont.fontDescriptor size:topBarTextFontSizeInput.floatValue];
UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSColor"] isEqual:expectedColor]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.largeTitleTextAttributes[@"NSColor"] isEqual:expectedColor]);
}

- (void)testTopBarLargeTitleFontSize_withTextFontFamily_withTextColor {
Expand All @@ -247,8 +247,8 @@ - (void)testTopBarLargeTitleFontSize_withTextFontFamily_withTextColor {
[self.uut viewWillAppear:false];
UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSColor"] isEqual:expectedColor]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.largeTitleTextAttributes[@"NSColor"] isEqual:expectedColor]);
}

- (void)testTopBarLargeTitleFontSize_withTextFontFamily_withoutTextColor {
Expand All @@ -259,7 +259,7 @@ - (void)testTopBarLargeTitleFontSize_withTextFontFamily_withoutTextColor {
__unused RNNStackController* nav = [self createNavigationController];
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.largeTitleTextAttributes[@"NSFont"] isEqual:expectedFont]);
}


Expand All @@ -270,7 +270,7 @@ - (void)testTopBarTextFontSize_withoutTextFontFamily_withoutTextColor {
UIFont* initialFont = self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSFont"];
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithDescriptor:initialFont.fontDescriptor size:topBarTextFontSizeInput.floatValue];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
}

- (void)testTopBarTextFontSize_withoutTextFontFamily_withTextColor {
Expand All @@ -283,8 +283,8 @@ - (void)testTopBarTextFontSize_withoutTextFontFamily_withTextColor {
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithDescriptor:initialFont.fontDescriptor size:topBarTextFontSizeInput.floatValue];
UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
}

- (void)testTopBarTextFontSize_withTextFontFamily_withTextColor {
Expand All @@ -298,8 +298,8 @@ - (void)testTopBarTextFontSize_withTextFontFamily_withTextColor {
[self.uut viewWillAppear:false];
UIColor* expectedColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSColor"] isEqual:expectedColor]);
}

- (void)testTopBarTextFontSize_withTextFontFamily_withoutTextColor {
Expand All @@ -310,7 +310,7 @@ - (void)testTopBarTextFontSize_withTextFontFamily_withoutTextColor {
__unused RNNStackController* nav = [self createNavigationController];
[self.uut viewWillAppear:false];
UIFont* expectedFont = [UIFont fontWithName:inputFont size:15];
XCTAssertTrue([self.uut.navigationController.navigationBar.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
XCTAssertTrue([self.uut.navigationItem.standardAppearance.titleTextAttributes[@"NSFont"] isEqual:expectedFont]);
}

// TODO: Currently not passing
Expand Down Expand Up @@ -468,7 +468,7 @@ - (void)testTopBarNoBorderOn {
self.options.topBar.noBorder = [[Bool alloc] initWithValue:topBarNoBorderInput];
__unused RNNStackController* nav = [self createNavigationController];
[self.uut viewWillAppear:false];
XCTAssertNil(self.uut.navigationController.navigationBar.standardAppearance.shadowColor);
XCTAssertNil(self.uut.navigationItem.standardAppearance.shadowColor);
}

- (void)testTopBarNoBorderOff {
Expand Down
3 changes: 2 additions & 1 deletion playground/ios/NavigationTests/RNNStackControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ - (void)testPopViewControllerSetTopBarBackgroundForPoppingViewController {
[_vc1 overrideOptions:_options];

[self.uut popViewControllerAnimated:NO];
XCTAssertEqual(_vc1.resolveOptions.topBar.background.color.get, self.uut.navigationBar.standardAppearance.backgroundColor);
[_vc1 viewWillAppear:YES];
XCTAssertEqual(_vc1.resolveOptions.topBar.background.color.get, self.uut.childViewControllers.lastObject.navigationItem.standardAppearance.backgroundColor);
}

- (void)testPopViewControllerSetDefaultTopBarBackgroundForPoppingViewController {
Expand Down
9 changes: 5 additions & 4 deletions playground/ios/NavigationTests/RNNStackPresenterTest.m
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "RNNStackPresenter.h"
#import <ReactNativeNavigation/RNNStackPresenter.h>
#import "UINavigationController+RNNOptions.h"
#import "RNNStackController.h"
#import "UIImage+Utils.h"
#import "RNNComponentViewController+Utils.h"

@interface RNNStackPresenterTest : XCTestCase

Expand All @@ -18,7 +19,7 @@ @implementation RNNStackPresenterTest
- (void)setUp {
[super setUp];
self.uut = [[RNNStackPresenter alloc] init];
RNNStackController* stackController = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:self.uut eventEmitter:nil childViewControllers:@[[UIViewController new], [UIViewController new]]];
RNNStackController* stackController = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil presenter:self.uut eventEmitter:nil childViewControllers:@[[RNNComponentViewController createWithComponentId:@"component1"], [RNNComponentViewController createWithComponentId:@"component2"]]];
self.boundViewController = [OCMockObject partialMockForObject:stackController];
[self.uut bindViewController:self.boundViewController];
self.options = [[RNNNavigationOptions alloc] initEmptyOptions];
Expand All @@ -41,7 +42,7 @@ - (void)testApplyOptionsBeforePoppingShouldSetTopBarBackgroundForPoppingViewCont
_options.topBar.background.color = [[Color alloc] initWithValue:[UIColor redColor]];

[self.uut applyOptionsBeforePopping:self.options];
XCTAssertTrue([_boundViewController.navigationBar.standardAppearance.backgroundColor isEqual:[UIColor redColor]]);
XCTAssertTrue([_boundViewController.childViewControllers.lastObject.navigationItem.standardAppearance.backgroundColor isEqual:[UIColor redColor]]);
}

- (void)testApplyOptionsShouldSetLargeTitleVisible {
Expand Down Expand Up @@ -98,7 +99,7 @@ - (void)testSetBackButtonIcon_withColor_shouldSetIcon {
self.options.topBar.backButton.icon = icon;
[self.uut applyOptions:self.options];
XCTAssertEqual(self.boundViewController.viewControllers.firstObject.navigationItem.backBarButtonItem.tintColor, UIColor.redColor);
XCTAssertTrue([self.boundViewController.navigationBar.standardAppearance.backIndicatorImage isEqual:image]);
XCTAssertTrue([self.boundViewController.viewControllers.lastObject.navigationItem.standardAppearance.backIndicatorImage isEqual:image]);
}

- (void)testBackgroundColor_validColor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#import "UIViewController+RNNOptions.h"
#import <ReactNativeNavigation/RNNStackController.h>
#import <ReactNativeNavigation/RNNComponentViewController.h>
#import "RNNComponentViewController+Utils.h"

@interface TopBarAppearancePresenterTest : XCTestCase

Expand All @@ -17,7 +18,7 @@ @implementation TopBarAppearancePresenterTest {

- (void)setUp {
[super setUp];
_componentViewController = [[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:nil];
_componentViewController = [RNNComponentViewController createWithComponentId:@"componentId"];
_stack = [[RNNStackController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:[[RNNNavigationOptions alloc] initEmptyOptions] presenter:_uut eventEmitter:nil childViewControllers:@[_componentViewController]];
_uut = [[TopBarAppearancePresenter alloc] initWithNavigationController:_stack];
}
Expand All @@ -30,8 +31,8 @@ - (void)testMergeOptions_shouldMergeWithDefault {
mergeOptions.topBar.title.fontSize = [Number withValue:@(21)];
RNNNavigationOptions* withDefault = [mergeOptions withDefault:defaultOptions];
[_uut mergeOptions:mergeOptions.topBar withDefault:withDefault.topBar];
XCTAssertEqual(_stack.navigationBar.standardAppearance.titleTextAttributes[NSForegroundColorAttributeName], UIColor.redColor);
UIFont* font = _stack.navigationBar.standardAppearance.titleTextAttributes[NSFontAttributeName];
XCTAssertEqual(_stack.childViewControllers.lastObject.navigationItem.standardAppearance.titleTextAttributes[NSForegroundColorAttributeName], UIColor.redColor);
UIFont* font = _stack.childViewControllers.lastObject.navigationItem.standardAppearance.titleTextAttributes[NSFontAttributeName];
XCTAssertEqual(font.pointSize, 21);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#import <ReactNativeNavigation/ReactNativeNavigation.h>
#import <ReactNativeNavigation/RNNComponentViewController.h>

@interface RNNComponentViewController (Utils)

+ (RNNComponentViewController *)createWithComponentId:(NSString *)componentId;

@end
Loading

0 comments on commit 5210848

Please sign in to comment.