Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added modalAttemptedToDismiss event with tests and docs #5832

Merged
merged 7 commits into from
Jan 12, 2020
Merged
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
16 changes: 16 additions & 0 deletions docs/docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,22 @@ const modalDismissedListener = Navigation.events().registerModalDismissedListene
modalDismissedListener.remove();
```

## registerModalAttemptedToDismissListener(iOS 13+ only)
Invoked only on iOS pageSheet modal when swipeToDismiss flag is set to true and modal swiped down to dismiss.

```js
// Subscribe
const modalAttemptedToDismissListener = Navigation.events().registerModalAttemptedToDismissListener(({ componentId }) => {

});
...
// Unsubscribe
modalDismissedListener.remove();
```
| Parameter | Description |
|:--------------------:|:-----|
|**componentId** | Id of the modal tried to dismiss|

## registerScreenPoppedListener
Invoked when screen is popped.

Expand Down
4 changes: 4 additions & 0 deletions lib/ios/RNNCommandsHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ - (void)dismissedModal:(UIViewController *)viewController {
[_eventEmitter sendModalsDismissedEvent:viewController.layoutInfo.componentId numberOfModalsDismissed:@(1)];
}

- (void)attemptedToDismissModal:(UIViewController *)viewController {
[_eventEmitter sendModalAttemptedToDismissEvent:viewController.layoutInfo.componentId];
}

- (void)dismissedMultipleModals:(NSArray *)viewControllers {
if (viewControllers && viewControllers.count) {
[_eventEmitter sendModalsDismissedEvent:((UIViewController *)viewControllers.lastObject).layoutInfo.componentId numberOfModalsDismissed:@(viewControllers.count)];
Expand Down
2 changes: 2 additions & 0 deletions lib/ios/RNNEventEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

- (void)sendModalsDismissedEvent:(NSString *)componentId numberOfModalsDismissed:(NSNumber *)modalsDismissed;

- (void)sendModalAttemptedToDismissEvent:(NSString *)componentId;

- (void)sendScreenPoppedEvent:(NSString *)componentId;


Expand Down
10 changes: 9 additions & 1 deletion lib/ios/RNNEventEmitter.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ @implementation RNNEventEmitter {
static NSString* const ComponentDidDisappear = @"RNN.ComponentDidDisappear";
static NSString* const NavigationButtonPressed = @"RNN.NavigationButtonPressed";
static NSString* const ModalDismissed = @"RNN.ModalDismissed";
static NSString* const ModalAttemptedToDismiss = @"RNN.ModalAttemptedToDismiss";
static NSString* const SearchBarUpdated = @"RNN.SearchBarUpdated";
static NSString* const SearchBarCancelPressed = @"RNN.SearchBarCancelPressed";
static NSString* const PreviewCompleted = @"RNN.PreviewCompleted";
Expand All @@ -31,7 +32,8 @@ @implementation RNNEventEmitter {
SearchBarUpdated,
SearchBarCancelPressed,
PreviewCompleted,
ScreenPopped];
ScreenPopped,
ModalAttemptedToDismiss];
}

# pragma mark public
Expand Down Expand Up @@ -113,6 +115,12 @@ - (void)sendModalsDismissedEvent:(NSString *)componentId numberOfModalsDismissed
}];
}

- (void)sendModalAttemptedToDismissEvent:(NSString *)componentId {
[self send:ModalAttemptedToDismiss body:@{
@"componentId": componentId,
}];
}

- (void)sendScreenPoppedEvent:(NSString *)componentId {
[self send:ScreenPopped body:@{
@"componentId": componentId
Expand Down
1 change: 1 addition & 0 deletions lib/ios/RNNModalManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ typedef void (^RNNTransitionRejectionBlock)(NSString *code, NSString *message, N
@protocol RNNModalManagerDelegate <NSObject>

- (void)dismissedModal:(UIViewController *)viewController;
- (void)attemptedToDismissModal:(UIViewController *)viewController;
- (void)dismissedMultipleModals:(NSArray *)viewControllers;

@end
Expand Down
4 changes: 4 additions & 0 deletions lib/ios/RNNModalManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ - (void)presentationControllerDidDismiss:(UIPresentationController *)presentatio
[_delegate dismissedModal:presentationController.presentedViewController.presentedComponentViewController];
}

- (void)presentationControllerDidAttemptToDismiss:(UIPresentationController *)presentationController {
[_delegate attemptedToDismissModal:presentationController.presentedViewController.presentedComponentViewController];
}

-(UIViewController*)topPresentedVC {
UIViewController *root = UIApplication.sharedApplication.delegate.window.rootViewController;
while(root.presentedViewController) {
Expand Down
7 changes: 6 additions & 1 deletion lib/src/adapters/NativeEventsReceiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
SearchBarCancelPressedEvent,
PreviewCompletedEvent,
ModalDismissedEvent,
ScreenPoppedEvent
ScreenPoppedEvent,
ModalAttemptedToDismissEvent
} from '../interfaces/ComponentEvents';
import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';

Expand Down Expand Up @@ -49,6 +50,10 @@ export class NativeEventsReceiver {
return this.emitter.addListener('RNN.ModalDismissed', callback);
}

public registerModalAttemptedToDismissListener(callback: (event: ModalAttemptedToDismissEvent) => void): EmitterSubscription {
return this.emitter.addListener('RNN.ModalAttemptedToDismiss', callback);
}

public registerSearchBarUpdatedListener(callback: (event: SearchBarUpdatedEvent) => void): EmitterSubscription {
return this.emitter.addListener('RNN.SearchBarUpdated', callback);
}
Expand Down
19 changes: 16 additions & 3 deletions lib/src/events/ComponentEventsObserver.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe('ComponentEventsObserver', () => {
const searchBarCancelPressedFn = jest.fn();
const previewCompletedFn = jest.fn();
const modalDismissedFn = jest.fn();
const modalAttemptedToDismissFn = jest.fn();
const screenPoppedFn = jest.fn();
let subscription: EventSubscription;
let uut: ComponentEventsObserver;
Expand Down Expand Up @@ -57,6 +58,10 @@ describe('ComponentEventsObserver', () => {
modalDismissedFn(event);
}

modalAttemptedToDismiss(event: any) {
modalAttemptedToDismissFn(event);
}

searchBarUpdated(event: any) {
searchBarUpdatedFn(event);
}
Expand Down Expand Up @@ -108,6 +113,10 @@ describe('ComponentEventsObserver', () => {
modalDismissedFn(event);
}

modalAttemptedToDismiss(event: any) {
modalAttemptedToDismissFn(event);
}

searchBarUpdated(event: any) {
searchBarUpdatedFn(event);
}
Expand Down Expand Up @@ -153,14 +162,14 @@ describe('ComponentEventsObserver', () => {
});

it(`bindComponent should use optional componentId if component has a componentId in props`, () => {
const tree = renderer.create(<UnboundScreen componentId={'doNotUseThisId'} />);
const tree = renderer.create(<UnboundScreen componentId={'doNotUseThisId'} />);
uut.bindComponent(tree.getInstance() as any, 'myCompId')

expect(tree.toJSON()).toBeDefined();

uut.notifyComponentDidAppear({ componentId: 'dontUseThisId', componentName: 'doesnt matter', componentType: 'Component' });
expect(didAppearFn).not.toHaveBeenCalled();


uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter', componentType: 'Component' });
expect(didAppearFn).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -188,6 +197,10 @@ describe('ComponentEventsObserver', () => {
expect(modalDismissedFn).toHaveBeenCalledTimes(1);
expect(modalDismissedFn).toHaveBeenLastCalledWith({ componentId: 'myCompId', modalsDismissed: 1 })

uut.notifyModalAttemptedToDismiss({ componentId: 'myCompId' });
expect(modalAttemptedToDismissFn).toHaveBeenCalledTimes(1);
expect(modalAttemptedToDismissFn).toHaveBeenLastCalledWith({ componentId: 'myCompId' })

uut.notifySearchBarUpdated({ componentId: 'myCompId', text: 'theText', isFocused: true });
expect(searchBarUpdatedFn).toHaveBeenCalledTimes(1);
expect(searchBarUpdatedFn).toHaveBeenCalledWith({ componentId: 'myCompId', text: 'theText', isFocused: true });
Expand Down
9 changes: 8 additions & 1 deletion lib/src/events/ComponentEventsObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
ComponentEvent,
PreviewCompletedEvent,
ModalDismissedEvent,
ScreenPoppedEvent
ScreenPoppedEvent,
ModalAttemptedToDismissEvent
} from '../interfaces/ComponentEvents';
import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver';
import { Store } from '../components/Store';
Expand All @@ -32,6 +33,7 @@ export class ComponentEventsObserver {
this.notifyComponentDidDisappear = this.notifyComponentDidDisappear.bind(this);
this.notifyNavigationButtonPressed = this.notifyNavigationButtonPressed.bind(this);
this.notifyModalDismissed = this.notifyModalDismissed.bind(this);
this.notifyModalAttemptedToDismiss = this.notifyModalAttemptedToDismiss.bind(this);
this.notifySearchBarUpdated = this.notifySearchBarUpdated.bind(this);
this.notifySearchBarCancelPressed = this.notifySearchBarCancelPressed.bind(this);
this.notifyPreviewCompleted = this.notifyPreviewCompleted.bind(this);
Expand All @@ -45,6 +47,7 @@ export class ComponentEventsObserver {
this.nativeEventsReceiver.registerComponentDidDisappearListener(this.notifyComponentDidDisappear);
this.nativeEventsReceiver.registerNavigationButtonPressedListener(this.notifyNavigationButtonPressed);
this.nativeEventsReceiver.registerModalDismissedListener(this.notifyModalDismissed);
this.nativeEventsReceiver.registerModalAttemptedToDismissListener(this.notifyModalAttemptedToDismiss);
this.nativeEventsReceiver.registerSearchBarUpdatedListener(this.notifySearchBarUpdated);
this.nativeEventsReceiver.registerSearchBarCancelPressedListener(this.notifySearchBarCancelPressed);
this.nativeEventsReceiver.registerPreviewCompletedListener(this.notifyPreviewCompleted);
Expand Down Expand Up @@ -87,6 +90,10 @@ export class ComponentEventsObserver {
this.triggerOnAllListenersByComponentId(event, 'modalDismissed');
}

notifyModalAttemptedToDismiss(event: ModalAttemptedToDismissEvent) {
this.triggerOnAllListenersByComponentId(event, 'modalAttemptedToDismiss');
}

notifySearchBarUpdated(event: SearchBarUpdatedEvent) {
this.triggerOnAllListenersByComponentId(event, 'searchBarUpdated');
}
Expand Down
7 changes: 7 additions & 0 deletions lib/src/events/EventsRegistry.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ describe('EventsRegistry', () => {
expect(mockNativeEventsReceiver.registerModalDismissedListener).toHaveBeenCalledWith(cb);
});

it('delegates modalAttemptedToDimiss to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerModalAttemptedToDismissListener(cb);
expect(mockNativeEventsReceiver.registerModalAttemptedToDismissListener).toHaveBeenCalledTimes(1);
expect(mockNativeEventsReceiver.registerModalAttemptedToDismissListener).toHaveBeenCalledWith(cb);
});

it('delegates searchBarUpdated to nativeEventsReceiver', () => {
const cb = jest.fn();
uut.registerSearchBarUpdatedListener(cb);
Expand Down
7 changes: 6 additions & 1 deletion lib/src/events/EventsRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
SearchBarCancelPressedEvent,
PreviewCompletedEvent,
ModalDismissedEvent,
ScreenPoppedEvent
ScreenPoppedEvent,
ModalAttemptedToDismissEvent
} from '../interfaces/ComponentEvents';
import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';

Expand Down Expand Up @@ -47,6 +48,10 @@ export class EventsRegistry {
return this.nativeEventsReceiver.registerModalDismissedListener(callback);
}

public registerModalAttemptedToDismissListener(callback: (event: ModalAttemptedToDismissEvent) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerModalAttemptedToDismissListener(callback);
}

public registerSearchBarUpdatedListener(callback: (event: SearchBarUpdatedEvent) => void): EmitterSubscription {
return this.nativeEventsReceiver.registerSearchBarUpdatedListener(callback);
}
Expand Down
4 changes: 4 additions & 0 deletions lib/src/interfaces/ComponentEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export interface ModalDismissedEvent extends ComponentEvent {
modalsDismissed: number;
}

export interface ModalAttemptedToDismissEvent extends ComponentEvent {
componentId: string;
}

export interface SearchBarUpdatedEvent extends ComponentEvent {
text: string;
isFocused: boolean;
Expand Down
1 change: 1 addition & 0 deletions playground/ios/NavigationTests/RNNCommandsHandlerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ -(NSArray*) getPublicMethodNamesForObject:(NSObject*)obj{
[skipMethods addObject:@"readyToReceiveCommands"];
[skipMethods addObject:@".cxx_destruct"];
[skipMethods addObject:@"dismissedModal:"];
[skipMethods addObject:@"attemptedToDismissModal:"];
[skipMethods addObject:@"dismissedMultipleModals:"];

NSMutableArray* result = [NSMutableArray new];
Expand Down
12 changes: 12 additions & 0 deletions playground/src/screens/ModalScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ class ModalScreen extends React.Component {
};
}

state = {
dimissCounter: 0,
}

componentDidMount() {
Navigation.events().bindComponent(this);
}

modalAttemptedToDismiss() {
return this.setState(state => ({ dimissCounter: state.dimissCounter + 1 }))
}

render() {
return (
<Root componentId={this.props.componentId} footer={`Modal Stack Position: ${this.getModalPosition()}`}>
Expand Down
16 changes: 13 additions & 3 deletions playground/src/screens/NavigationScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ const React = require('react');
const Root = require('../components/Root');
const Button = require('../components/Button')
const Navigation = require('./../services/Navigation');
const { Platform } = require('react-native');
const {
NAVIGATION_TAB,
MODAL_BTN,
OVERLAY_BTN,
EXTERNAL_COMP_BTN,
SHOW_STATIC_EVENTS_SCREEN,
SHOW_ORIENTATION_SCREEN,
SET_ROOT_BTN
SET_ROOT_BTN,
PAGE_SHEET_MODAL_BTN
} = require('../testIDs');
const Screens = require('./Screens');

class NavigationScreen extends React.Component {
class NavigationScreen extends React.Component {
static options() {
return {
topBar: {
Expand All @@ -34,6 +36,7 @@ class NavigationScreen extends React.Component {
<Root componentId={this.props.componentId}>
<Button label='Set Root' testID={SET_ROOT_BTN} onPress={this.setRoot} />
<Button label='Modal' testID={MODAL_BTN} onPress={this.showModal} />
{Platform.OS === 'ios' && <Button label='PageSheet modal' testID={PAGE_SHEET_MODAL_BTN} onPress={this.showPageSheetModal} />}
<Button label='Overlay' testID={OVERLAY_BTN} onPress={this.showOverlay} />
<Button label='External Component' testID={EXTERNAL_COMP_BTN} onPress={this.externalComponent} />
<Button label='Static Events' testID={SHOW_STATIC_EVENTS_SCREEN} onPress={this.pushStaticEventsScreen} />
Expand All @@ -50,13 +53,20 @@ class NavigationScreen extends React.Component {

setRoot = () => Navigation.showModal(Screens.SetRoot);
showModal = () => Navigation.showModal(Screens.Modal);

showPageSheetModal = () => Navigation.showModal(Screens.Modal, {
modalPresentationStyle: 'pageSheet',
modal: {
swipeToDismiss: false,
}
});
showOverlay = () => Navigation.showModal(Screens.Overlay);
externalComponent = () => Navigation.showModal(Screens.ExternalComponent);
pushStaticEventsScreen = () => Navigation.showModal(Screens.EventsScreen)
orientation = () => Navigation.showModal(Screens.Orientation);
pushContextScreen = () => Navigation.push(this, Screens.ContextScreen);
sharedElement = () => Navigation.showModal(Screens.CocktailsListScreen)
preview = ({reactTag}) => {
preview = ({ reactTag }) => {
Navigation.push(this.props.componentId, {
component: {
name: Screens.Pushed,
Expand Down
3 changes: 2 additions & 1 deletion playground/src/testIDs.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
OVERLAY_BTN: 'OVERLAY_BTN',
SIDE_MENU_BTN: 'SIDE_MENU_BTN',
MODAL_BTN: 'SHOW_MODAL_BUTTON',
PAGE_SHEET_MODAL_BTN: 'SHOW_PAGE_SHEET_MODAL_BUTTON',
DISMISS_MODAL_BTN: 'DISMISS_MODAL_BUTTON',
MODAL_SCREEN_HEADER: 'MODAL_SCREEN_HEADER',
ALERT_BUTTON: 'ALERT_BUTTON',
Expand Down Expand Up @@ -129,7 +130,7 @@ module.exports = {
SET_INTERCEPT_TOUCH: `SET_INTERCEPT_TOUCH`,
PUSH_BOTTOM_TABS_BUTTON: `PUSH_BOTTOM_TABS_BUTTON`,
SET_STACK_ROOT_BUTTON: `SET_STACK_ROOT_BUTTON`,
SET_ROOT:'SET_ROOT',
SET_ROOT: 'SET_ROOT',
RESET_BUTTONS: 'RESET_BUTTONS',
SHOW_LIFECYCLE_BTN: 'SHOW_LIFECYCLE_BTN',
CHANGE_BUTTON_PROPS: 'CHANGE_BUTTON_PROPS',
Expand Down