From edcc0dc4b43e00fc784abbb85513b4fed285d28e Mon Sep 17 00:00:00 2001 From: Alec Larson Date: Wed, 16 Oct 2019 15:44:44 -0400 Subject: [PATCH] feat: add "AppState.windows" and new AppState events The new events are: "rootViewWillAppear" and "windowDidChangeScreen" --- @types/index.d.ts | 21 ++++++++++++++--- Libraries/AppState/AppState.js | 42 +++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/@types/index.d.ts b/@types/index.d.ts index 5201fac48..950f588f1 100644 --- a/@types/index.d.ts +++ b/@types/index.d.ts @@ -6863,22 +6863,37 @@ export interface AlertIOSStatic { * * @see https://facebook.github.io/react-native/docs/appstateios.html#content */ -export type AppStateEvent = "change" | "memoryWarning"; +export type AppStateEvent = "change" | "memoryWarning" | "rootViewWillAppear" | "windowDidChangeScreen"; export type AppStateStatus = "active" | "background" | "inactive"; export interface AppStateStatic { currentState: AppStateStatus; + windows: { [rootTag: number]: WindowState }; /** * Add a handler to AppState changes by listening to the change event * type and providing the handler */ - addEventListener(type: AppStateEvent, listener: (state: AppStateStatus) => void): void; + addEventListener(type: 'change', listener: (state: AppStateStatus) => void): void; + addEventListener(type: 'memoryWarning', listener: () => void): void; + addEventListener(type: 'rootViewWillAppear', listener: (state: WindowState) => void): void; + addEventListener(type: 'windowDidChangeScreen', listener: (state: WindowState) => void): void; /** * Remove a handler by passing the change event type and the handler */ - removeEventListener(type: AppStateEvent, listener: (state: AppStateStatus) => void): void; + removeEventListener(type: AppStateEvent, listener: Function): void; +} + +export interface WindowState { + rootTag: number; + screen: Screen; +} + +export interface Screen { + id: number; + scale: number; + layout: LayoutRectangle; } /** diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index ebdb6d549..b375485c2 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -19,6 +19,16 @@ const RCTAppState = NativeModules.AppState; const logError = require('logError'); const invariant = require('fbjs/lib/invariant'); +import type {Layout} from 'CoreEventTypes'; + +type Screen = {| + +rootTag: number, + +bounds: Layout, + +scale: number, +|}; + +const eventTypes = ['change', 'memoryWarning', 'rootViewWillAppear', 'windowDidChangeScreen']; + /** * `AppState` can tell you if the app is in the foreground or background, * and notify you when the state changes. @@ -30,15 +40,16 @@ class AppState extends NativeEventEmitter { _eventHandlers: Object; currentState: ?string; isAvailable: boolean = true; + windows: { [rootTag: number]: Screen }; constructor() { super(RCTAppState); this.isAvailable = true; - this._eventHandlers = { - change: new Map(), - memoryWarning: new Map(), - }; + this._eventHandlers = eventTypes.reduce((out, type) => { + out[type] = new Map(); + return out; + }, {}); // TODO: Remove the 'active' fallback after `initialAppState` is exported by // the Android implementation. @@ -58,6 +69,18 @@ class AppState extends NativeEventEmitter { } ); + this.windows = RCTAppState.windows.reduce((acc, state) => { + acc[state.rootTag] = state; + return acc; + }, {}); + + const onWindowChange = state => { + this.windows[state.rootTag] = state; + } + + this.addListener('rootViewWillAppear', onWindowChange); + this.addListener('windowDidChangeScreen', onWindowChange); + // 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. @@ -87,7 +110,7 @@ class AppState extends NativeEventEmitter { handler: Function ) { invariant( - ['change', 'memoryWarning'].indexOf(type) !== -1, + eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type ); if (type === 'change') { @@ -97,11 +120,8 @@ class AppState extends NativeEventEmitter { handler(appStateData.app_state); } )); - } else if (type === 'memoryWarning') { - this._eventHandlers[type].set(handler, this.addListener( - 'memoryWarning', - handler - )); + } else { + this._eventHandlers[type].set(handler, this.addListener(type, handler)); } } @@ -115,7 +135,7 @@ class AppState extends NativeEventEmitter { handler: Function ) { invariant( - ['change', 'memoryWarning'].indexOf(type) !== -1, + eventTypes.indexOf(type) !== -1, 'Trying to remove listener for unknown event: "%s"', type ); if (!this._eventHandlers[type].has(handler)) {