Updated AppState module to use new emitter system
Summary: AppState now subclasses NativeEventEmitter instead of using global RCTDeviceEventEmitter. Reviewed By: javache Differential Revision: D3310488 fbshipit-source-id: f0116599223f4411307385c0dab683659d8d63b6
This commit is contained in:
parent
c87b737ca1
commit
d9737571c4
|
@ -66,9 +66,13 @@ typedef void (^ControlBlock)(RCTRootView*);
|
|||
|
||||
- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
[rootView.bridge.eventDispatcher sendAppEventWithName:@"rootViewDidChangeIntrinsicSize"
|
||||
body:@{@"width": @(rootView.intrinsicSize.width),
|
||||
@"height": @(rootView.intrinsicSize.height)}];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -103,8 +103,13 @@
|
|||
[[_bridge expect] enqueueJSCall:_JSMethod
|
||||
args:[_testEvent arguments]];
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
[_eventDispatcher sendDeviceEventWithName:_eventName body:_body];
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
[_bridge verify];
|
||||
}
|
||||
|
||||
|
|
|
@ -41,11 +41,16 @@
|
|||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
|
||||
- (NSArray<NSString *> *)customDirectEventTypes
|
||||
{
|
||||
return @[@"foo"];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -11,18 +11,12 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
var Map = require('Map');
|
||||
var NativeModules = require('NativeModules');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTAppState = NativeModules.AppState;
|
||||
const NativeEventEmitter = require('NativeEventEmitter');
|
||||
const NativeModules = require('NativeModules');
|
||||
const RCTAppState = NativeModules.AppState;
|
||||
|
||||
var logError = require('logError');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
var _eventHandlers = {
|
||||
change: new Map(),
|
||||
memoryWarning: new Map(),
|
||||
};
|
||||
const logError = require('logError');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
/**
|
||||
* `AppState` can tell you if the app is in the foreground or background,
|
||||
|
@ -36,8 +30,9 @@ var _eventHandlers = {
|
|||
* - `active` - The app is running in the foreground
|
||||
* - `background` - The app is running in the background. The user is either
|
||||
* in another app or on the home screen
|
||||
* - `inactive` - This is a transition state that currently never happens for
|
||||
* typical React Native apps.
|
||||
* - `inactive` - This is a state that occurs when transitioning between
|
||||
* foreground & background, and during periods of inactivity such as
|
||||
* entering the Multitasking view or in the event of an incoming call
|
||||
*
|
||||
* For more information, see
|
||||
* [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)
|
||||
|
@ -75,13 +70,58 @@ var _eventHandlers = {
|
|||
* state will happen only momentarily.
|
||||
*/
|
||||
|
||||
var AppState = {
|
||||
class AppState extends NativeEventEmitter {
|
||||
|
||||
/**
|
||||
_eventHandlers: Object;
|
||||
currentState: ?string;
|
||||
|
||||
constructor() {
|
||||
super(RCTAppState);
|
||||
|
||||
this._eventHandlers = {
|
||||
change: new Map(),
|
||||
memoryWarning: new Map(),
|
||||
};
|
||||
|
||||
// TODO: getCurrentAppState callback seems to be called at a really late stage
|
||||
// after app launch. Trying to get currentState when mounting App component
|
||||
// will likely to have the initial value here.
|
||||
// Initialize to 'active' instead of null.
|
||||
this.currentState = 'active';
|
||||
|
||||
// TODO: this is a terrible solution - in order to ensure `currentState` prop
|
||||
// is up to date, we have to register an observer that updates it whenever
|
||||
// the state changes, even if nobody cares. We should just deprecate the
|
||||
// `currentState` property and get rid of this.
|
||||
this.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
this.currentState = appStateData.app_state;
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: see above - this request just populates the value of `currentState`
|
||||
// when the module is first initialized. Would be better to get rid of the prop
|
||||
// and expose `getCurrentAppState` method directly.
|
||||
RCTAppState.getCurrentAppState(
|
||||
(appStateData) => {
|
||||
this.currentState = appStateData.app_state;
|
||||
},
|
||||
logError
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a handler to AppState changes by listening to the `change` event type
|
||||
* and providing the handler
|
||||
*
|
||||
* TODO: now that AppState is a subclass of NativeEventEmitter, we could deprecate
|
||||
* `addEventListener` and `removeEventListener` and just use `addListener` and
|
||||
* `listener.remove()` directly. That will be a breaking change though, as both
|
||||
* the method and event names are different (addListener events are currently
|
||||
* required to be globally unique).
|
||||
*/
|
||||
addEventListener: function(
|
||||
addEventListener(
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
|
@ -90,24 +130,24 @@ var AppState = {
|
|||
'Trying to subscribe to unknown event: "%s"', type
|
||||
);
|
||||
if (type === 'change') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
this._eventHandlers[type].set(handler, this.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
handler(appStateData.app_state);
|
||||
}
|
||||
));
|
||||
} else if (type === 'memoryWarning') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
this._eventHandlers[type].set(handler, this.addListener(
|
||||
'memoryWarning',
|
||||
handler
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a handler by passing the `change` event type and the handler
|
||||
*/
|
||||
removeEventListener: function(
|
||||
removeEventListener(
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
|
@ -115,28 +155,14 @@ var AppState = {
|
|||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to remove listener for unknown event: "%s"', type
|
||||
);
|
||||
if (!_eventHandlers[type].has(handler)) {
|
||||
if (!this._eventHandlers[type].has(handler)) {
|
||||
return;
|
||||
}
|
||||
_eventHandlers[type].get(handler).remove();
|
||||
_eventHandlers[type].delete(handler);
|
||||
},
|
||||
|
||||
currentState: ('active' : ?string),
|
||||
this._eventHandlers[type].get(handler).remove();
|
||||
this._eventHandlers[type].delete(handler);
|
||||
}
|
||||
};
|
||||
|
||||
RCTDeviceEventEmitter.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
AppState.currentState = appStateData.app_state;
|
||||
}
|
||||
);
|
||||
|
||||
RCTAppState.getCurrentAppState(
|
||||
(appStateData) => {
|
||||
AppState.currentState = appStateData.app_state;
|
||||
},
|
||||
logError
|
||||
);
|
||||
AppState = new AppState();
|
||||
|
||||
module.exports = AppState;
|
||||
|
|
|
@ -11,20 +11,8 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
var warning = require('fbjs/lib/warning');
|
||||
const AppState = require('AppState');
|
||||
|
||||
class AppStateIOS {
|
||||
console.warn('AppStateIOS is deprecated. Use AppState instead');
|
||||
|
||||
static addEventListener(type, handler) {
|
||||
warning(false, 'Cannot listen to AppStateIOS events on Android.');
|
||||
}
|
||||
|
||||
static removeEventListener(type, handler) {
|
||||
warning(false, 'Cannot remove AppStateIOS listener on Android.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AppStateIOS.currentState = null;
|
||||
|
||||
module.exports = AppStateIOS;
|
||||
module.exports = AppState;
|
|
@ -1,147 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AppStateIOS
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeModules = require('NativeModules');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTAppState = NativeModules.AppState;
|
||||
|
||||
var logError = require('logError');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
var _eventHandlers = {
|
||||
change: new Map(),
|
||||
memoryWarning: new Map(),
|
||||
};
|
||||
|
||||
/**
|
||||
* `AppStateIOS` can tell you if the app is in the foreground or background,
|
||||
* and notify you when the state changes.
|
||||
*
|
||||
* AppStateIOS is frequently used to determine the intent and proper behavior when
|
||||
* handling push notifications.
|
||||
*
|
||||
* ### iOS App States
|
||||
*
|
||||
* - `active` - The app is running in the foreground
|
||||
* - `background` - The app is running in the background. The user is either
|
||||
* in another app or on the home screen
|
||||
* - `inactive` - This is a state that occurs when transitioning between
|
||||
* foreground & background, and during periods of inactivity such as
|
||||
* entering the Multitasking view or in the event of an incoming call
|
||||
*
|
||||
* For more information, see
|
||||
* [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)
|
||||
*
|
||||
* ### Basic Usage
|
||||
*
|
||||
* To see the current state, you can check `AppStateIOS.currentState`, which
|
||||
* will be kept up-to-date. However, `currentState` will be null at launch
|
||||
* while `AppStateIOS` retrieves it over the bridge.
|
||||
*
|
||||
* ```
|
||||
* getInitialState: function() {
|
||||
* return {
|
||||
* currentAppState: AppStateIOS.currentState,
|
||||
* };
|
||||
* },
|
||||
* componentDidMount: function() {
|
||||
* AppStateIOS.addEventListener('change', this._handleAppStateChange);
|
||||
* },
|
||||
* componentWillUnmount: function() {
|
||||
* AppStateIOS.removeEventListener('change', this._handleAppStateChange);
|
||||
* },
|
||||
* _handleAppStateChange: function(currentAppState) {
|
||||
* this.setState({ currentAppState, });
|
||||
* },
|
||||
* render: function() {
|
||||
* return (
|
||||
* <Text>Current state is: {this.state.currentAppState}</Text>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*
|
||||
* This example will only ever appear to say "Current state is: active" because
|
||||
* the app is only visible to the user when in the `active` state, and the null
|
||||
* state will happen only momentarily.
|
||||
*/
|
||||
|
||||
var AppStateIOS = {
|
||||
|
||||
/**
|
||||
* Add a handler to AppState changes by listening to the `change` event type
|
||||
* and providing the handler
|
||||
*/
|
||||
addEventListener: function(
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to subscribe to unknown event: "%s"', type
|
||||
);
|
||||
if (type === 'change') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
handler(appStateData.app_state);
|
||||
}
|
||||
));
|
||||
} else if (type === 'memoryWarning') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
'memoryWarning',
|
||||
handler
|
||||
));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a handler by passing the `change` event type and the handler
|
||||
*/
|
||||
removeEventListener: function(
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to remove listener for unknown event: "%s"', type
|
||||
);
|
||||
if (!_eventHandlers[type].has(handler)) {
|
||||
return;
|
||||
}
|
||||
_eventHandlers[type].get(handler).remove();
|
||||
_eventHandlers[type].delete(handler);
|
||||
},
|
||||
|
||||
// TODO: getCurrentAppState callback seems to be called at a really late stage
|
||||
// after app launch. Trying to get currentState when mounting App component
|
||||
// will likely to have the initial value here.
|
||||
// Initialize to 'active' instead of null.
|
||||
currentState: ('active' : ?string),
|
||||
|
||||
};
|
||||
|
||||
RCTDeviceEventEmitter.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
AppStateIOS.currentState = appStateData.app_state;
|
||||
}
|
||||
);
|
||||
|
||||
RCTAppState.getCurrentAppState(
|
||||
(appStateData) => {
|
||||
AppStateIOS.currentState = appStateData.app_state;
|
||||
},
|
||||
logError
|
||||
);
|
||||
|
||||
module.exports = AppStateIOS;
|
|
@ -30,31 +30,35 @@ class RCTDeviceEventEmitter extends EventEmitter {
|
|||
super(sharedSubscriber);
|
||||
this.sharedSubscriber = sharedSubscriber;
|
||||
}
|
||||
|
||||
_nativeEventModule(eventType: ?string) {
|
||||
if (eventType) {
|
||||
if (eventType.lastIndexOf('statusBar', 0) === 0) {
|
||||
console.warn('`%s` event should be registered via the StatusBarIOS module', eventType);
|
||||
return require('StatusBarIOS');
|
||||
}
|
||||
if (eventType.lastIndexOf('keyboard', 0) === 0) {
|
||||
console.warn('`%s` event should be registered via the Keyboard module', eventType);
|
||||
return require('Keyboard');
|
||||
}
|
||||
if (eventType === 'appStateDidChange' || eventType === 'memoryWarning') {
|
||||
console.warn('`%s` event should be registered via the AppState module', eventType);
|
||||
return require('AppState');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
addListener(eventType: string, listener: Function, context: ?Object): EmitterSubscription {
|
||||
if (eventType.lastIndexOf('statusBar', 0) === 0) {
|
||||
console.warn('`%s` event should be registered via the StatusBarIOS module', eventType);
|
||||
return require('StatusBarIOS').addListener(eventType, listener, context);
|
||||
}
|
||||
if (eventType.lastIndexOf('keyboard', 0) === 0) {
|
||||
console.warn('`%s` event should be registered via the Keyboard module', eventType);
|
||||
return require('Keyboard').addListener(eventType, listener, context);
|
||||
}
|
||||
return super.addListener(eventType, listener, context);
|
||||
const eventModule = this._nativeEventModule(eventType);
|
||||
return eventModule ? eventModule.addListener(eventType, listener, context)
|
||||
: super.addListener(eventType, listener, context);
|
||||
}
|
||||
|
||||
removeAllListeners(eventType: ?string) {
|
||||
if (eventType) {
|
||||
if (eventType.lastIndexOf('statusBar', 0) === 0) {
|
||||
console.warn('statusBar events should be unregistered via the StatusBarIOS module');
|
||||
return require('StatusBarIOS').removeAllListeners(eventType);
|
||||
}
|
||||
if (eventType.lastIndexOf('keyboard', 0) === 0) {
|
||||
console.warn('keyboard events should be unregistered via the Keyboard module');
|
||||
return require('Keyboard').removeAllListeners(eventType);
|
||||
}
|
||||
}
|
||||
super.removeAllListeners(eventType);
|
||||
const eventModule = this._nativeEventModule(eventType);
|
||||
(eventModule && eventType) ? eventModule.removeAllListeners(eventType)
|
||||
: super.removeAllListeners(eventType);
|
||||
}
|
||||
|
||||
removeSubscription(subscription: EmitterSubscription) {
|
||||
|
|
|
@ -279,8 +279,11 @@ RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
|
|||
|
||||
// Send event
|
||||
if (_observingLocation) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"geolocationDidChange"
|
||||
body:_lastLocationEvent];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
// Fire all queued callbacks
|
||||
|
@ -321,8 +324,11 @@ RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
|
|||
|
||||
// Send event
|
||||
if (_observingLocation) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"geolocationError"
|
||||
body:jsError];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
// Fire all queued error callbacks
|
||||
|
|
|
@ -51,8 +51,11 @@ static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SC
|
|||
|
||||
if (![status isEqualToString:self->_status]) {
|
||||
self->_status = status;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[self->_bridge.eventDispatcher sendDeviceEventWithName:@"networkStatusDidChange"
|
||||
body:@{@"network_info": status}];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -346,8 +346,11 @@ RCT_EXPORT_MODULE()
|
|||
}
|
||||
|
||||
NSArray<id> *responseJSON = @[task.requestID, responseText ?: @""];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkData"
|
||||
body:responseJSON];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
- (void)sendRequest:(NSURLRequest *)request
|
||||
|
@ -361,7 +364,10 @@ RCT_EXPORT_MODULE()
|
|||
RCTURLRequestProgressBlock uploadProgressBlock = ^(int64_t progress, int64_t total) {
|
||||
dispatch_async(_methodQueue, ^{
|
||||
NSArray *responseJSON = @[task.requestID, @((double)progress), @((double)total)];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"didSendNetworkData" body:responseJSON];
|
||||
#pragma clang diagnostic pop
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -379,8 +385,11 @@ RCT_EXPORT_MODULE()
|
|||
}
|
||||
id responseURL = response.URL ? response.URL.absoluteString : [NSNull null];
|
||||
NSArray<id> *responseJSON = @[task.requestID, @(status), headers, responseURL];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkResponse"
|
||||
body:responseJSON];
|
||||
#pragma clang diagnostic pop
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -401,8 +410,11 @@ RCT_EXPORT_MODULE()
|
|||
error.code == kCFURLErrorTimedOut ? @YES : @NO
|
||||
];
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"didCompleteNetworkResponse"
|
||||
body:responseJSON];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
[_tasksByRequestID removeObjectForKey:task.requestID];
|
||||
});
|
||||
|
|
|
@ -52,7 +52,10 @@ RCT_EXPORT_METHOD(verifySnapshot:(RCTResponseSenderBlock)callback)
|
|||
|
||||
RCT_EXPORT_METHOD(sendAppEvent:(NSString *)name body:(nullable id)body)
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher sendAppEventWithName:name body:body];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
RCT_REMAP_METHOD(shouldResolve, shouldResolve_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
||||
|
|
|
@ -62,9 +62,12 @@ RCT_EXPORT_MODULE()
|
|||
return;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_bridge.eventDispatcher
|
||||
sendDeviceEventWithName:@"settingsUpdated"
|
||||
body:RCTJSONClean([_defaults dictionaryRepresentation])];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
@property (nonatomic, assign) NSInteger mostRecentEventCount;
|
||||
@property (nonatomic, strong) NSNumber *maxLength;
|
||||
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onChange;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onSelectionChange;
|
||||
|
||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||
|
|
|
@ -472,7 +472,7 @@ static NSAttributedString *removeReactTagFromString(NSAttributedString *string)
|
|||
[self _setPlaceholderVisibility];
|
||||
_nativeEventCount++;
|
||||
|
||||
if (!self.reactTag) {
|
||||
if (!self.reactTag || !_onChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -490,8 +490,7 @@ static NSAttributedString *removeReactTagFromString(NSAttributedString *string)
|
|||
}
|
||||
_previousTextLength = textLength;
|
||||
_previousContentHeight = contentHeight;
|
||||
|
||||
NSDictionary *event = @{
|
||||
_onChange(@{
|
||||
@"text": self.text,
|
||||
@"contentSize": @{
|
||||
@"height": @(contentHeight),
|
||||
|
@ -499,8 +498,7 @@ static NSAttributedString *removeReactTagFromString(NSAttributedString *string)
|
|||
},
|
||||
@"target": self.reactTag,
|
||||
@"eventCount": @(_nativeEventCount),
|
||||
};
|
||||
[_eventDispatcher sendInputEventWithName:@"change" body:event];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView
|
||||
|
|
|
@ -35,7 +35,6 @@ RCT_EXTERN const NSInteger RCTTextUpdateLagWarningThreshold;
|
|||
RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
|
||||
|
||||
@protocol RCTEvent <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
@property (nonatomic, strong, readonly) NSNumber *viewTag;
|
||||
|
@ -60,25 +59,25 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
|
|||
@interface RCTEventDispatcher : NSObject <RCTBridgeModule>
|
||||
|
||||
/**
|
||||
* Send an application-specific event that does not relate to a specific
|
||||
* view, e.g. a navigation or data update notification.
|
||||
* Deprecated, do not use.
|
||||
*/
|
||||
- (void)sendAppEventWithName:(NSString *)name body:(id)body;
|
||||
- (void)sendAppEventWithName:(NSString *)name body:(id)body
|
||||
__deprecated_msg("Subclass RCTEventEmitter instead");
|
||||
|
||||
/**
|
||||
* Send a device or iOS event that does not relate to a specific view,
|
||||
* e.g.rotation, location, keyboard show/hide, background/awake, etc.
|
||||
* Deprecated, do not use.
|
||||
*/
|
||||
- (void)sendDeviceEventWithName:(NSString *)name body:(id)body;
|
||||
- (void)sendDeviceEventWithName:(NSString *)name body:(id)body
|
||||
__deprecated_msg("Subclass RCTEventEmitter instead");
|
||||
|
||||
/**
|
||||
* Send a user input event. The body dictionary must contain a "target"
|
||||
* parameter, representing the React tag of the view sending the event
|
||||
* Deprecated, do not use.
|
||||
*/
|
||||
- (void)sendInputEventWithName:(NSString *)name body:(NSDictionary *)body;
|
||||
- (void)sendInputEventWithName:(NSString *)name body:(NSDictionary *)body
|
||||
__deprecated_msg("Use RCTDirectEventBlock or RCTBubblingEventBlock instead");
|
||||
|
||||
/**
|
||||
* Send a text input/focus event.
|
||||
* Send a text input/focus event. For internal use only.
|
||||
*/
|
||||
- (void)sendTextEventWithType:(RCTTextEventType)type
|
||||
reactTag:(NSNumber *)reactTag
|
||||
|
|
|
@ -126,7 +126,10 @@ RCT_EXPORT_MODULE()
|
|||
body[@"key"] = key;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[self sendInputEventWithName:events[type] body:body];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
- (void)sendEvent:(id<RCTEvent>)event
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTEventEmitter.h"
|
||||
|
||||
@interface RCTAppState : NSObject<RCTBridgeModule>
|
||||
@interface RCTAppState : RCTEventEmitter
|
||||
|
||||
@end
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
static NSString *RCTCurrentAppBackgroundState()
|
||||
{
|
||||
RCTAssertMainThread();
|
||||
|
||||
static NSDictionary *states;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
@ -37,26 +39,22 @@ static NSString *RCTCurrentAppBackgroundState()
|
|||
NSString *_lastKnownState;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
- (NSArray<NSString *> *)supportedEvents
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
||||
// Needs to be called on the main thread, as it accesses UIApplication
|
||||
_lastKnownState = RCTCurrentAppBackgroundState();
|
||||
}
|
||||
return self;
|
||||
return @[@"appStateDidChange", @"memoryWarning"];
|
||||
}
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
- (void)startObserving
|
||||
{
|
||||
_bridge = bridge;
|
||||
|
||||
for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
|
||||
UIApplicationDidEnterBackgroundNotification,
|
||||
UIApplicationDidFinishLaunchingNotification,
|
||||
|
@ -75,19 +73,18 @@ RCT_EXPORT_MODULE()
|
|||
object:nil];
|
||||
}
|
||||
|
||||
- (void)handleMemoryWarning
|
||||
{
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"memoryWarning"
|
||||
body:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
- (void)stopObserving
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - App Notification Methods
|
||||
|
||||
- (void)handleMemoryWarning
|
||||
{
|
||||
[self sendEventWithName:@"memoryWarning" body:nil];
|
||||
}
|
||||
|
||||
- (void)handleAppStateDidChange:(NSNotification *)notification
|
||||
{
|
||||
NSString *newState;
|
||||
|
@ -102,8 +99,8 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
if (![newState isEqualToString:_lastKnownState]) {
|
||||
_lastKnownState = newState;
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"appStateDidChange"
|
||||
body:@{@"app_state": _lastKnownState}];
|
||||
[self sendEventWithName:@"appStateDidChange"
|
||||
body:@{@"app_state": _lastKnownState}];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +112,7 @@ RCT_EXPORT_MODULE()
|
|||
RCT_EXPORT_METHOD(getCurrentAppState:(RCTResponseSenderBlock)callback
|
||||
error:(__unused RCTResponseSenderBlock)error)
|
||||
{
|
||||
callback(@[@{@"app_state": _lastKnownState}]);
|
||||
callback(@[@{@"app_state": RCTCurrentAppBackgroundState()}]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#import "RCTEventEmitter.h"
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
@implementation RCTEventEmitter
|
||||
|
@ -21,9 +22,16 @@
|
|||
return @"";
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [RCTEventEmitter class]) {
|
||||
RCTAssert(RCTClassOverridesInstanceMethod(self, @selector(supportedEvents)),
|
||||
@"You must override the `supportedEvents` method of %@", self);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents
|
||||
{
|
||||
RCTAssert(NO, @"You must override the `supportedEvents` method of %@", [self class]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -32,7 +40,8 @@
|
|||
RCTAssert(_bridge != nil, @"bridge is not set.");
|
||||
|
||||
if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) {
|
||||
RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]);
|
||||
RCTLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`",
|
||||
eventName, [self class], [[self supportedEvents] componentsJoinedByString:@"`, `"]);
|
||||
}
|
||||
if (_listenerCount > 0) {
|
||||
[_bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit"
|
||||
|
@ -62,7 +71,8 @@
|
|||
RCT_EXPORT_METHOD(addListener:(NSString *)eventName)
|
||||
{
|
||||
if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) {
|
||||
RCTLogError(@"`%@` is not a supported event type for %@", eventName, [self class]);
|
||||
RCTLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`",
|
||||
eventName, [self class], [[self supportedEvents] componentsJoinedByString:@"`, `"]);
|
||||
}
|
||||
if (_listenerCount == 0) {
|
||||
[self startObserving];
|
||||
|
|
|
@ -180,7 +180,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
((void (*)(id, SEL, id))objc_msgSend)(target, setter, [RCTConvert BOOL:json] ? ^(NSDictionary *body) {
|
||||
body = [NSMutableDictionary dictionaryWithDictionary:body];
|
||||
((NSMutableDictionary *)body)[@"target"] = weakTarget.reactTag;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[weakManager.bridge.eventDispatcher sendInputEventWithName:RCTNormalizeInputEventName(name) body:body];
|
||||
#pragma clang diagnostic pop
|
||||
} : nil);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue