Browse Source

Currently visible screen (#1581)

* added method for getting the currently visible screen ID. Can be useful to decide if logic should be applied according to screen visibility, for example: set buttons/title dynamically, or even determine that you don’t need to show the same screen again if it’s the current one that’s showing

* Implement getCurrentlyVisibleScreenId on Android

Can be used statically:
Navigation.getCurrentlyVisibleScreenId() - returns the unique screen
instance id

With a navigator instance:
await this.props.navigator.screenIsCurrentlyVisible() - resolves a
promise that checks if the current screen is visible
Guy Carmeli 7 years ago
parent
commit
0c4d40bd23

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java View File

263
     public void isAppLaunched(Promise promise) {
263
     public void isAppLaunched(Promise promise) {
264
         NavigationCommandsHandler.isAppLaunched(promise);
264
         NavigationCommandsHandler.isAppLaunched(promise);
265
     }
265
     }
266
+
267
+    @ReactMethod
268
+    public void getCurrentlyVisibleScreenId(Promise promise) {
269
+        NavigationCommandsHandler.getCurrentlyVisibleScreenId(promise);
270
+    }
266
 }
271
 }

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/Modal.java View File

96
         layout.selectTopTabByTabIndex(screenInstanceId, index);
96
         layout.selectTopTabByTabIndex(screenInstanceId, index);
97
     }
97
     }
98
 
98
 
99
+    String getCurrentlyVisibleScreenId() {
100
+        return layout.getCurrentlyVisibleScreenId();
101
+    }
102
+
99
     interface OnModalDismissedListener {
103
     interface OnModalDismissedListener {
100
         void onModalDismissed(Modal modal);
104
         void onModalDismissed(Modal modal);
101
     }
105
     }

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java View File

183
             modal.selectTopTabByScreen(screenInstanceId);
183
             modal.selectTopTabByScreen(screenInstanceId);
184
         }
184
         }
185
     }
185
     }
186
+
187
+    String getCurrentlyVisibleScreenId() {
188
+        return stack.peek().getCurrentlyVisibleScreenId();
189
+    }
186
 }
190
 }

+ 5
- 2
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java View File

392
     public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) {
392
     public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) {
393
         if (modalController.isShowing()) {
393
         if (modalController.isShowing()) {
394
             modalController.showContextualMenu(screenInstanceId, params, onButtonClicked);
394
             modalController.showContextualMenu(screenInstanceId, params, onButtonClicked);
395
-        } else
396
-        {
395
+        } else {
397
             layout.showContextualMenu(screenInstanceId, params, onButtonClicked);
396
             layout.showContextualMenu(screenInstanceId, params, onButtonClicked);
398
         }
397
         }
399
     }
398
     }
449
             mPermissionListener = null;
448
             mPermissionListener = null;
450
         }
449
         }
451
     }
450
     }
451
+
452
+    public String getCurrentlyVisibleScreenId() {
453
+        return modalController.isShowing() ? modalController.getCurrentlyVisibleScreenId() : layout.getCurrentlyVisibleScreenId();
454
+    }
452
 }
455
 }

+ 18
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java View File

3
 import android.content.Intent;
3
 import android.content.Intent;
4
 import android.os.Bundle;
4
 import android.os.Bundle;
5
 
5
 
6
+import com.facebook.react.bridge.Arguments;
6
 import com.facebook.react.bridge.Callback;
7
 import com.facebook.react.bridge.Callback;
7
 import com.facebook.react.bridge.Promise;
8
 import com.facebook.react.bridge.Promise;
9
+import com.facebook.react.bridge.WritableMap;
8
 import com.reactnativenavigation.NavigationApplication;
10
 import com.reactnativenavigation.NavigationApplication;
9
 import com.reactnativenavigation.params.ActivityParams;
11
 import com.reactnativenavigation.params.ActivityParams;
10
 import com.reactnativenavigation.params.ContextualMenuParams;
12
 import com.reactnativenavigation.params.ContextualMenuParams;
540
         final boolean isAppLaunched = SplashActivity.isResumed || NavigationActivity.currentActivity != null;
542
         final boolean isAppLaunched = SplashActivity.isResumed || NavigationActivity.currentActivity != null;
541
         promise.resolve(isAppLaunched);
543
         promise.resolve(isAppLaunched);
542
     }
544
     }
545
+
546
+    public static void getCurrentlyVisibleScreenId(final Promise promise) {
547
+        final NavigationActivity currentActivity = NavigationActivity.currentActivity;
548
+        if (currentActivity == null) {
549
+            promise.resolve("");
550
+            return;
551
+        }
552
+        NavigationApplication.instance.runOnMainThread(new Runnable() {
553
+            @Override
554
+            public void run() {
555
+                WritableMap map = Arguments.createMap();
556
+                map.putString("screenId", currentActivity.getCurrentlyVisibleScreenId());
557
+                promise.resolve(map);
558
+            }
559
+        });
560
+    }
543
 }
561
 }

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java View File

211
         }
211
         }
212
     }
212
     }
213
 
213
 
214
+    @Override
215
+    public String getCurrentlyVisibleScreenId() {
216
+        return getCurrentScreen().getScreenInstanceId();
217
+    }
218
+
214
     @Override
219
     @Override
215
     public void selectTopTabByTabIndex(String screenInstanceId, int index) {
220
     public void selectTopTabByTabIndex(String screenInstanceId, int index) {
216
         for (int i = 0; i < bottomTabs.getItemsCount(); i++) {
221
         for (int i = 0; i < bottomTabs.getItemsCount(); i++) {

+ 2
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java View File

66
     void selectTopTabByScreen(String screenInstanceId);
66
     void selectTopTabByScreen(String screenInstanceId);
67
 
67
 
68
     void updateScreenStyle(String screenInstanceId, Bundle styleParams);
68
     void updateScreenStyle(String screenInstanceId, Bundle styleParams);
69
+
70
+    String getCurrentlyVisibleScreenId();
69
 }
71
 }

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java View File

274
         stack.updateScreenStyle(screenInstanceId, styleParams);
274
         stack.updateScreenStyle(screenInstanceId, styleParams);
275
     }
275
     }
276
 
276
 
277
+    @Override
278
+    public String getCurrentlyVisibleScreenId() {
279
+        return stack.peek().getScreenInstanceId();
280
+    }
281
+
277
     @Override
282
     @Override
278
     public void showSlidingOverlay(final SlidingOverlayParams params) {
283
     public void showSlidingOverlay(final SlidingOverlayParams params) {
279
         slidingOverlaysQueue.add(new SlidingOverlay(this, params));
284
         slidingOverlaysQueue.add(new SlidingOverlay(this, params));

+ 1
- 0
ios/RCCManager.h View File

15
 -(void)registerController:(UIViewController*)controller componentId:(NSString*)componentId componentType:(NSString*)componentType;
15
 -(void)registerController:(UIViewController*)controller componentId:(NSString*)componentId componentType:(NSString*)componentType;
16
 -(id)getControllerWithId:(NSString*)componentId componentType:(NSString*)componentType;
16
 -(id)getControllerWithId:(NSString*)componentId componentType:(NSString*)componentType;
17
 -(void)unregisterController:(UIViewController*)vc;
17
 -(void)unregisterController:(UIViewController*)vc;
18
+-(NSString*) getIdForController:(UIViewController*)vc;
18
 
19
 
19
 -(void)clearModuleRegistry;
20
 -(void)clearModuleRegistry;
20
 
21
 

+ 27
- 0
ios/RCCManager.m View File

1
 #import "RCCManager.h"
1
 #import "RCCManager.h"
2
+#import "RCCViewController.h"
2
 #import <React/RCTBridge.h>
3
 #import <React/RCTBridge.h>
3
 #import <React/RCTRedBox.h>
4
 #import <React/RCTRedBox.h>
4
 #import <Foundation/Foundation.h>
5
 #import <Foundation/Foundation.h>
116
   return component;
117
   return component;
117
 }
118
 }
118
 
119
 
120
+-(NSString*) getIdForController:(UIViewController*)vc
121
+{
122
+  if([vc isKindOfClass:[RCCViewController class]])
123
+  {
124
+    NSString *controllerId = ((RCCViewController*)vc).controllerId;
125
+    if(controllerId != nil)
126
+    {
127
+      return controllerId;
128
+    }
129
+  }
130
+  
131
+  for (NSString *key in [self.modulesRegistry allKeys])
132
+  {
133
+    NSMutableDictionary *componentsDic = self.modulesRegistry[key];
134
+    for (NSString *componentID in [componentsDic allKeys])
135
+    {
136
+      UIViewController *tmpVc = componentsDic[componentID];
137
+      if (tmpVc == vc)
138
+      {
139
+        return componentID;
140
+      }
141
+    }
142
+  }
143
+  return nil;
144
+}
145
+
119
 -(void)initBridgeWithBundleURL:(NSURL *)bundleURL
146
 -(void)initBridgeWithBundleURL:(NSURL *)bundleURL
120
 {
147
 {
121
   [self initBridgeWithBundleURL :bundleURL launchOptions:nil];
148
   [self initBridgeWithBundleURL :bundleURL launchOptions:nil];

+ 29
- 0
ios/RCCManagerModule.m View File

351
                                                                     completion:^(){ resolve(nil); }];
351
                                                                     completion:^(){ resolve(nil); }];
352
 }
352
 }
353
 
353
 
354
+- (UIViewController *) getVisibleViewControllerFor:(UIViewController *)vc
355
+{
356
+    if ([vc isKindOfClass:[UINavigationController class]])
357
+    {
358
+        return [self getVisibleViewControllerFor:[((UINavigationController*)vc) visibleViewController]];
359
+    }
360
+    else if ([vc isKindOfClass:[UITabBarController class]])
361
+    {
362
+        return [self getVisibleViewControllerFor:[((UITabBarController*)vc) selectedViewController]];
363
+    }
364
+    else if (vc.presentedViewController)
365
+    {
366
+        return [self getVisibleViewControllerFor:vc.presentedViewController];
367
+    }
368
+    else
369
+    {
370
+        return vc;
371
+    }
372
+}
373
+
374
+RCT_EXPORT_METHOD(getCurrentlyVisibleScreenId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
375
+{
376
+    UIViewController *rootVC = [UIApplication sharedApplication].delegate.window.rootViewController;
377
+    UIViewController *visibleVC = [self getVisibleViewControllerFor:rootVC];
378
+    NSString *controllerId = [[RCCManager sharedIntance] getIdForController:visibleVC];
379
+    id result = (controllerId != nil) ? @{@"screenId": controllerId} : nil;
380
+    resolve(result);
381
+}
382
+
354
 -(BOOL)viewControllerIsModal:(UIViewController*)viewController
383
 -(BOOL)viewControllerIsModal:(UIViewController*)viewController
355
 {
384
 {
356
     BOOL viewControllerIsModal = (viewController.presentingViewController.presentedViewController == viewController)
385
     BOOL viewControllerIsModal = (viewController.presentingViewController.presentedViewController == viewController)

+ 3
- 0
ios/RCCNavigationController.m View File

34
   
34
   
35
   RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:globalProps bridge:bridge];
35
   RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:globalProps bridge:bridge];
36
   if (!viewController) return nil;
36
   if (!viewController) return nil;
37
+  viewController.controllerId = props[@"id"];
37
   
38
   
38
   NSArray *leftButtons = props[@"leftButtons"];
39
   NSArray *leftButtons = props[@"leftButtons"];
39
   if (leftButtons)
40
   if (leftButtons)
106
     }
107
     }
107
     
108
     
108
     RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:nil bridge:bridge];
109
     RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:nil bridge:bridge];
110
+    viewController.controllerId = passProps[@"screenInstanceID"];
109
     
111
     
110
     [self processTitleView:viewController
112
     [self processTitleView:viewController
111
                      props:actionParams
113
                      props:actionParams
213
     NSDictionary *navigatorStyle = actionParams[@"style"];
215
     NSDictionary *navigatorStyle = actionParams[@"style"];
214
     
216
     
215
     RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:nil bridge:bridge];
217
     RCCViewController *viewController = [[RCCViewController alloc] initWithComponent:component passProps:passProps navigatorStyle:navigatorStyle globalProps:nil bridge:bridge];
218
+    viewController.controllerId = passProps[@"screenInstanceID"];
216
     
219
     
217
     [self processTitleView:viewController
220
     [self processTitleView:viewController
218
                      props:actionParams
221
                      props:actionParams

+ 1
- 0
ios/RCCViewController.h View File

15
 
15
 
16
 @property (nonatomic) NSMutableDictionary *navigatorStyle;
16
 @property (nonatomic) NSMutableDictionary *navigatorStyle;
17
 @property (nonatomic) BOOL navBarHidden;
17
 @property (nonatomic) BOOL navBarHidden;
18
+@property (nonatomic, strong) NSString *controllerId;
18
 @property (nonatomic, strong) NSString *commandType;
19
 @property (nonatomic, strong) NSString *commandType;
19
 @property (nonatomic, strong) NSString *timestamp;
20
 @property (nonatomic, strong) NSString *timestamp;
20
 
21
 

+ 5
- 0
ios/RCCViewController.m View File

94
   if (controller && componentId)
94
   if (controller && componentId)
95
   {
95
   {
96
     [[RCCManager sharedInstance] registerController:controller componentId:componentId componentType:type];
96
     [[RCCManager sharedInstance] registerController:controller componentId:componentId componentType:type];
97
+    
98
+    if([controller isKindOfClass:[RCCViewController class]])
99
+    {
100
+      ((RCCViewController*)controller).controllerId = componentId;
101
+    }
97
   }
102
   }
98
   
103
   
99
   // set background image at root level
104
   // set background image at root level

+ 5
- 0
src/Navigation.js View File

166
   return await platformSpecific.isAppLaunched();
166
   return await platformSpecific.isAppLaunched();
167
 }
167
 }
168
 
168
 
169
+function getCurrentlyVisibleScreenId() {
170
+  return platformSpecific.getCurrentlyVisibleScreenId();
171
+}
172
+
169
 export default {
173
 export default {
170
   getRegisteredScreen,
174
   getRegisteredScreen,
175
+  getCurrentlyVisibleScreenId,
171
   registerComponent,
176
   registerComponent,
172
   showModal: showModal,
177
   showModal: showModal,
173
   dismissModal: dismissModal,
178
   dismissModal: dismissModal,

+ 8
- 0
src/Screen.js View File

165
       Navigation.clearEventHandler(this.navigatorEventID);
165
       Navigation.clearEventHandler(this.navigatorEventID);
166
     }
166
     }
167
   }
167
   }
168
+
169
+  async screenIsCurrentlyVisible() {
170
+    const res = await Navigation.getCurrentlyVisibleScreenId();
171
+    if (!res) {
172
+      return false;
173
+    }
174
+    return res.screenId === this.screenInstanceID;
175
+  }
168
 }
176
 }
169
 
177
 
170
 export default class Screen extends Component {
178
 export default class Screen extends Component {

+ 6
- 0
src/deprecated/controllers/index.js View File

313
     }
313
     }
314
   },
314
   },
315
 
315
 
316
+  ScreenUtils: {
317
+    getCurrentlyVisibleScreenId: async function() {
318
+      return await RCCManager.getCurrentlyVisibleScreenId();
319
+    }
320
+  },
321
+
316
   NavigationToolBarIOS: OriginalReactNative.requireNativeComponent('RCCToolBar', null),
322
   NavigationToolBarIOS: OriginalReactNative.requireNativeComponent('RCCToolBar', null),
317
 
323
 
318
   Constants: Constants
324
   Constants: Constants

+ 6
- 1
src/deprecated/platformSpecificDeprecated.android.js View File

688
   return await newPlatformSpecific.isAppLaunched();
688
   return await newPlatformSpecific.isAppLaunched();
689
 }
689
 }
690
 
690
 
691
+async function getCurrentlyVisibleScreenId() {
692
+  return await newPlatformSpecific.getCurrentlyVisibleScreenId();
693
+}
694
+
691
 export default {
695
 export default {
692
   startTabBasedApp,
696
   startTabBasedApp,
693
   startSingleScreenApp,
697
   startSingleScreenApp,
718
   dismissSnackbar,
722
   dismissSnackbar,
719
   showContextualMenu,
723
   showContextualMenu,
720
   dismissContextualMenu,
724
   dismissContextualMenu,
721
-  isAppLaunched
725
+  isAppLaunched,
726
+  getCurrentlyVisibleScreenId
722
 };
727
 };

+ 7
- 2
src/deprecated/platformSpecificDeprecated.ios.js View File

1
 /*eslint-disable*/
1
 /*eslint-disable*/
2
 import Navigation from './../Navigation';
2
 import Navigation from './../Navigation';
3
-import Controllers, {Modal, Notification} from './controllers';
3
+import Controllers, {Modal, Notification, ScreenUtils} from './controllers';
4
 const React = Controllers.hijackReact();
4
 const React = Controllers.hijackReact();
5
 const {
5
 const {
6
   ControllerRegistry,
6
   ControllerRegistry,
620
   // Android only
620
   // Android only
621
 }
621
 }
622
 
622
 
623
+async function getCurrentlyVisibleScreenId() {
624
+  return await ScreenUtils.getCurrentlyVisibleScreenId();
625
+}
626
+
623
 export default {
627
 export default {
624
   startTabBasedApp,
628
   startTabBasedApp,
625
   startSingleScreenApp,
629
   startSingleScreenApp,
647
   navigatorSwitchToTab,
651
   navigatorSwitchToTab,
648
   navigatorToggleNavBar,
652
   navigatorToggleNavBar,
649
   showContextualMenu,
653
   showContextualMenu,
650
-  dismissContextualMenu
654
+  dismissContextualMenu,
655
+  getCurrentlyVisibleScreenId
651
 };
656
 };

+ 6
- 1
src/platformSpecific.android.js View File

181
   return await NativeReactModule.isAppLaunched();
181
   return await NativeReactModule.isAppLaunched();
182
 }
182
 }
183
 
183
 
184
+async function getCurrentlyVisibleScreenId() {
185
+  return await NativeReactModule.getCurrentlyVisibleScreenId();
186
+}
187
+
184
 module.exports = {
188
 module.exports = {
185
   startApp,
189
   startApp,
186
   push,
190
   push,
215
   showContextualMenu,
219
   showContextualMenu,
216
   dismissContextualMenu,
220
   dismissContextualMenu,
217
   setScreenStyle,
221
   setScreenStyle,
218
-  isAppLaunched
222
+  isAppLaunched,
223
+  getCurrentlyVisibleScreenId
219
 };
224
 };