cobrowse-sdk-react-native 2.13.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,133 @@
1
+ package io.cobrowse.reactnative;
2
+
3
+ import android.app.Activity;
4
+ import android.util.Log;
5
+ import android.view.View;
6
+ import android.view.ViewGroup;
7
+ import android.view.ViewParent;
8
+
9
+ import androidx.annotation.NonNull;
10
+ import androidx.core.util.Predicate;
11
+
12
+ import com.facebook.react.bridge.Promise;
13
+ import com.facebook.react.bridge.ReactApplicationContext;
14
+ import com.facebook.react.bridge.ReadableArray;
15
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
16
+ import com.facebook.react.uimanager.NativeViewHierarchyManager;
17
+ import com.facebook.react.uimanager.UIBlock;
18
+ import com.facebook.react.uimanager.UIManagerModule;
19
+
20
+ import java.util.ArrayList;
21
+ import java.util.HashSet;
22
+ import java.util.List;
23
+ import java.util.Set;
24
+
25
+ import io.cobrowse.Session;
26
+
27
+ class CommonDelegates implements CobrowseIOCommonDelegates {
28
+
29
+ private static final String SESSION_LOADED = "session.loaded";
30
+ private static final String SESSION_UPDATED = "session.updated";
31
+ private static final String SESSION_ENDED = "session.ended";
32
+ private static final String SESSION_REQUESTED = "session.requested";
33
+
34
+ private final HashSet<Integer> unredactedTags = new HashSet<>();
35
+ private ReactApplicationContext reactApplicationContext;
36
+ private NativeViewHierarchyManager nodeManager;
37
+
38
+ CommonDelegates(ReactApplicationContext context) {
39
+ this.reactApplicationContext = context;
40
+ }
41
+
42
+ @Override
43
+ public void handleFullDeviceRequest(@NonNull Activity activity, @NonNull Session session) {
44
+ // no-op, this will be handed on the JS side via an "updated" event handler
45
+ // this stub just disables the default native prompt in the SDK
46
+ }
47
+
48
+ @Override
49
+ public List<View> redactedViews(@NonNull Activity activity) {
50
+ HashSet<View> redacted = new HashSet<>(RedactedViewManager.redactedViews.keySet());
51
+ if (CobrowseIOModule.delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
52
+ List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).redactedViews(activity);
53
+ if (views != null) redacted.addAll(views);
54
+ }
55
+
56
+ return new ArrayList<>(redacted);
57
+ }
58
+
59
+ @Override
60
+ public List<View> unredactedViews(@NonNull Activity activity) {
61
+ synchronized (unredactedTags) {
62
+ HashSet<View> unredacted = new HashSet<>();
63
+ for (Integer i : unredactedTags) {
64
+ try {
65
+ unredacted.add(nodeManager.resolveView(i));
66
+ } catch (Exception e) {
67
+ Log.i("CobrowseIO", "Failed to find unredacted view for tag " + i + ", error = " + e.getMessage());
68
+ }
69
+ }
70
+ if (CobrowseIOModule.delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
71
+ List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).unredactedViews(activity);
72
+ if (views != null) unredacted.addAll(views);
73
+ }
74
+
75
+ return new ArrayList<>(unredacted);
76
+ }
77
+ }
78
+
79
+ @Override
80
+ public void handleRemoteControlRequest(@NonNull Activity activity, @NonNull Session session) {
81
+ // no-op, this will be handed on the JS side via an "updated" event handler
82
+ // this stub just disables the default native prompt in the SDK
83
+ }
84
+
85
+ @Override
86
+ public void sessionDidLoad(@NonNull Session session) {
87
+ reactApplicationContext
88
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
89
+ .emit(SESSION_LOADED, Conversion.convert(session));
90
+ }
91
+
92
+ @Override
93
+ public void handleSessionRequest(@NonNull Activity activity, @NonNull Session session) {
94
+ reactApplicationContext
95
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
96
+ .emit(SESSION_REQUESTED, Conversion.convert(session));
97
+ }
98
+
99
+ @Override
100
+ public void sessionDidUpdate(@NonNull Session session) {
101
+ reactApplicationContext
102
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
103
+ .emit(SESSION_UPDATED, Conversion.convert(session));
104
+ }
105
+
106
+ @Override
107
+ public void sessionDidEnd(@NonNull Session session) {
108
+ reactApplicationContext
109
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
110
+ .emit(SESSION_ENDED, Conversion.convert(session));
111
+ }
112
+
113
+ public void findNodeManager() {
114
+ if (nodeManager != null) return;
115
+ final UIManagerModule uiManager = reactApplicationContext.getNativeModule(UIManagerModule.class);
116
+ assert uiManager != null;
117
+ uiManager.prependUIBlock(new UIBlock() {
118
+ @Override
119
+ public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
120
+ nodeManager = nativeViewHierarchyManager;
121
+ }
122
+ });
123
+ }
124
+
125
+ public void setUnredactedTags(final ReadableArray reactTags, final Promise promise) {
126
+ synchronized (unredactedTags) {
127
+ unredactedTags.clear();
128
+ for (int i = 0; i < reactTags.size(); i++)
129
+ unredactedTags.add(reactTags.getInt(i));
130
+ promise.resolve(null);
131
+ }
132
+ }
133
+ }
@@ -6,62 +6,93 @@ import com.facebook.react.bridge.WritableMap;
6
6
  import io.cobrowse.Agent;
7
7
  import io.cobrowse.Session;
8
8
  import io.cobrowse.Session.RemoteControlState;
9
+ import io.cobrowse.Session.FullDeviceState;
9
10
 
10
11
  final class Conversion {
11
12
 
12
- static WritableMap convert(Session session) {
13
- WritableMap map = Arguments.createMap();
14
- if (session == null) return null;
15
- map.putString("code", session.code());
16
- map.putString("state", session.state());
17
- map.putString("id", session.id());
18
- map.putBoolean("full_device", session.fullDevice());
19
- map.putString("remote_control", Conversion.remoteControl(session.remoteControl()));
13
+ static WritableMap convert(Session session) {
14
+ WritableMap map = Arguments.createMap();
15
+ if (session == null) return null;
16
+ map.putString("code", session.code());
17
+ map.putString("state", session.state());
18
+ map.putString("id", session.id());
19
+ map.putBoolean("full_device", session.fullDevice());
20
+ map.putString("full_device_state", Conversion.fullDeviceState(session.fullDeviceState()));
21
+ map.putString("remote_control", Conversion.remoteControl(session.remoteControl()));
20
22
 
21
- Agent agent = session.agent();
22
- if (agent != null) {
23
- WritableMap agentMap = Arguments.createMap();
24
- agentMap.putString("name", agent.name);
25
- agentMap.putString("id", agent.id);
26
- map.putMap("agent", agentMap);
27
- }
23
+ Agent agent = session.agent();
24
+ if (agent != null) {
25
+ WritableMap agentMap = Arguments.createMap();
26
+ agentMap.putString("name", agent.name);
27
+ agentMap.putString("id", agent.id);
28
+ map.putMap("agent", agentMap);
29
+ }
30
+
31
+ return map;
32
+ }
28
33
 
29
- return map;
34
+ static String convert(Error error) {
35
+ if (error == null) return null;
36
+ return error.getMessage();
37
+ }
38
+
39
+ static String remoteControl(RemoteControlState state) {
40
+ switch (state) {
41
+ case On:
42
+ return "on";
43
+ case Requested:
44
+ return "requested";
45
+ case Rejected:
46
+ return "rejected";
47
+ case Off:
48
+ return "off";
30
49
  }
31
50
 
32
- static String convert(Error error) {
33
- if (error == null) return null;
34
- return error.getMessage();
51
+ return "off";
52
+ }
53
+
54
+ static RemoteControlState remoteControl(String state) {
55
+ switch (state) {
56
+ case "on":
57
+ return RemoteControlState.On;
58
+ case "requested":
59
+ return RemoteControlState.Requested;
60
+ case "rejected":
61
+ return RemoteControlState.Rejected;
62
+ case "off":
63
+ return RemoteControlState.Off;
35
64
  }
36
65
 
37
- static String remoteControl (RemoteControlState state) {
38
- switch (state) {
39
- case On:
40
- return "on";
41
- case Requested:
42
- return "requested";
43
- case Rejected:
44
- return "rejected";
45
- case Off:
46
- return "off";
47
- }
66
+ return RemoteControlState.Off;
67
+ }
48
68
 
69
+ static String fullDeviceState(FullDeviceState state) {
70
+ switch (state) {
71
+ case On:
72
+ return "on";
73
+ case Requested:
74
+ return "requested";
75
+ case Rejected:
76
+ return "rejected";
77
+ case Off:
49
78
  return "off";
50
79
  }
51
80
 
52
- static RemoteControlState remoteControl (String state) {
53
- switch (state) {
54
- case "on":
55
- return RemoteControlState.On;
56
- case "requested":
57
- return RemoteControlState.Requested;
58
- case "rejected":
59
- return RemoteControlState.Rejected;
60
- case "off":
61
- return RemoteControlState.Off;
62
- }
81
+ return "off";
82
+ }
63
83
 
64
- return RemoteControlState.Off;
84
+ static FullDeviceState fullDeviceState(String state) {
85
+ switch (state) {
86
+ case "on":
87
+ return FullDeviceState.On;
88
+ case "requested":
89
+ return FullDeviceState.Requested;
90
+ case "rejected":
91
+ return FullDeviceState.Rejected;
92
+ case "off":
93
+ return FullDeviceState.Off;
65
94
  }
66
95
 
96
+ return FullDeviceState.Off;
97
+ }
67
98
  }
@@ -0,0 +1,31 @@
1
+ package io.cobrowse.reactnative;
2
+
3
+ import java.lang.reflect.InvocationHandler;
4
+ import java.lang.reflect.Method;
5
+ import java.util.HashMap;
6
+ import java.util.Map;
7
+
8
+ class DynamicSessionControlInvocationHandler implements InvocationHandler {
9
+ private CobrowseIOCommonDelegates delegates;
10
+ private final Map<String, Method> methods = new HashMap<>();
11
+
12
+ DynamicSessionControlInvocationHandler(CobrowseIOCommonDelegates delegates) {
13
+ this.delegates = delegates;
14
+
15
+ for(Method method: delegates.getClass().getDeclaredMethods()) {
16
+ this.methods.put(method.getName(), method);
17
+ }
18
+ }
19
+
20
+ @Override
21
+ public Object invoke(Object proxy, Method method, Object[] args)
22
+ throws Throwable {
23
+
24
+ if (method.getName() == "showSessionControls" || method.getName() == "hideSessionControls") {
25
+ return null;
26
+ }
27
+
28
+ Object result = methods.get(method.getName()).invoke(delegates, args);
29
+ return result;
30
+ }
31
+ }
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
11
11
  s.homepage = package["homepage"]
12
12
  s.source = { :git => 'https://github.com/cobrowseio/cobrowse-sdk-react-native.git' }
13
13
  s.platform = :ios, '11.0'
14
- s.dependency 'CobrowseIO/XCFramework', '2.22.1'
14
+ s.dependency 'CobrowseIO/XCFramework', '2.25.0'
15
15
  s.dependency 'React'
16
16
  s.source_files = 'ios/*.{h,m}'
17
17
  end
@@ -0,0 +1,5 @@
1
+ #import <React/RCTViewManager.h>
2
+
3
+ @interface CBIOBroadcastPickerView : RCTViewManager
4
+
5
+ @end
@@ -0,0 +1,52 @@
1
+ #import <ReplayKit/ReplayKit.h>
2
+ #import "CBIOBroadcastPickerView.h"
3
+
4
+ @import CobrowseIO;
5
+
6
+ @implementation CBIOBroadcastPickerView
7
+
8
+ RCT_EXPORT_MODULE(CBIOBroadcastPickerView)
9
+
10
+ - (UIView *)view
11
+ {
12
+ NSString* broadcastExtension = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CBIOBroadcastExtension"];
13
+ NSString* warningMsg = @"";
14
+
15
+ if (!broadcastExtension) {
16
+ warningMsg = @"CBIOBroadcastExtension not set on Info.plist.";
17
+ } else if (@available(iOS 12.0, *)) {
18
+ RPSystemBroadcastPickerView* systemPicker = [[RPSystemBroadcastPickerView alloc] initWithFrame: CGRectMake(0, 0, 50, 50)];
19
+ systemPicker.showsMicrophoneButton = NO;
20
+ systemPicker.preferredExtension = broadcastExtension;
21
+
22
+ return systemPicker;
23
+ } else {
24
+ // Fallback on earlier versions
25
+ warningMsg = @"This version of iOS doesn't support RPSystemBroadcastPickerView.";
26
+ }
27
+
28
+ RCTLogWarn(@"%@", warningMsg);
29
+ return [[UIView alloc] initWithFrame: CGRectMake(0, 0, 0, 0)];
30
+ }
31
+
32
+ RCT_CUSTOM_VIEW_PROPERTY(buttonColor, NSString, UIView)
33
+ {
34
+ UIButton* button = view.subviews.firstObject;
35
+ if ([button isKindOfClass:UIButton.class]) button.imageView.tintColor = [self hexStringToColor:json];
36
+ }
37
+
38
+ - hexStringToColor:(NSString *)stringToConvert
39
+ {
40
+ NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
41
+ NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
42
+
43
+ unsigned hex;
44
+ if (![stringScanner scanHexInt:&hex]) return nil;
45
+ int r = (hex >> 16) & 0xFF;
46
+ int g = (hex >> 8) & 0xFF;
47
+ int b = (hex) & 0xFF;
48
+
49
+ return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
50
+ }
51
+
52
+ @end
package/ios/CBIORCTUtil.h CHANGED
@@ -4,5 +4,6 @@
4
4
  @interface CBIORCTUtil : NSObject
5
5
 
6
6
  +(NSString*) remoteControl: (CBIORemoteControlState) state;
7
+ +(NSString*) fullDeviceState: (CBIOFullDeviceState) state;
7
8
 
8
9
  @end
package/ios/CBIORCTUtil.m CHANGED
@@ -12,4 +12,14 @@
12
12
  }
13
13
  }
14
14
 
15
+ + (NSString *)fullDeviceState:(CBIOFullDeviceState)state {
16
+ switch(state) {
17
+ case kCBIOFullDeviceStateOn: return @"on";
18
+ case kCBIOFullDeviceStateOff: return @"off";
19
+ case kCBIOFullDeviceStateRejected: return @"rejected";
20
+ case kCBIOFullDeviceStateRequested: return @"requested";
21
+ default: return @"off";
22
+ }
23
+ }
24
+
15
25
  @end
@@ -10,6 +10,7 @@
10
10
  @"code": self.code ? self.code : NSNull.null,
11
11
  @"state": self.state ? self.state : NSNull.null,
12
12
  @"full_device": @(self.fullDevice),
13
+ @"full_device_state": [CBIORCTUtil fullDeviceState: self.fullDeviceState],
13
14
  @"remote_control": [CBIORCTUtil remoteControl: self.remoteControl],
14
15
  @"agent": self.hasAgent ? @{
15
16
  @"name": self.agent.name,
@@ -8,6 +8,7 @@
8
8
  #import <React/RCTUIManager.h>
9
9
  #import "RCTCobrowseIO.h"
10
10
  #import "RCTCBIOTreeUtils.h"
11
+ #import <objc/runtime.h>
11
12
 
12
13
  #define SESSION_LOADED "session.loaded"
13
14
  #define SESSION_UPDATED "session.updated"
@@ -47,7 +48,7 @@ RCT_EXPORT_MODULE();
47
48
  }
48
49
 
49
50
  -(dispatch_queue_t) methodQueue {
50
- return dispatch_get_main_queue();
51
+ return dispatch_get_main_queue();
51
52
  }
52
53
 
53
54
  -(void)startObserving {
@@ -66,28 +67,6 @@ RCT_EXPORT_MODULE();
66
67
  if (hasListeners) [self sendEventWithName:@SESSION_LOADED body:[session toDict]];
67
68
  }
68
69
 
69
- -(NSSet<UIView*>*) redactedViews: (UIViewController*) vc {
70
- NSMutableSet* views = [CBIOCobrowseRedactedManager.redactedViews mutableCopy];
71
- if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseRedactedViewsForViewController:)]) {
72
- [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseRedactedViewsForViewController:vc]];
73
- }
74
- return views;
75
- }
76
-
77
- -(NSSet<UIView*>*) unredactedViews: (UIViewController*) vc {
78
- NSMutableSet* views = [NSMutableSet set];
79
- @synchronized(unredactedTags) {
80
- for (id tag in unredactedTags) {
81
- UIView* v = [self.bridge.uiManager viewForReactTag: tag];
82
- if (v != nil) [views addObject:v];
83
- }
84
- }
85
- if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseUnredactedViewsForViewController:)]) {
86
- [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseUnredactedViewsForViewController:vc]];
87
- }
88
- return views;
89
- }
90
-
91
70
  -(void)cobrowseSessionDidUpdate:(CBIOSession *)session {
92
71
  if (hasListeners) [self sendEventWithName:@SESSION_UPDATED body:[session toDict]];
93
72
  }
@@ -106,60 +85,27 @@ RCT_EXPORT_MODULE();
106
85
  }
107
86
 
108
87
  -(NSArray<UIView *> *)cobrowseRedactedViewsForViewController:(UIViewController *)vc {
109
- NSSet* redacted = [self redactedViews: vc];
110
- NSSet* unredacted = [self unredactedViews: vc];
111
-
112
- // Project all unredactions to the root to get the full set of unredacted nodes
113
- NSMutableSet* projectedUnredacted = [NSMutableSet set];
114
- for (id view in unredacted) {
115
- [projectedUnredacted addObject:view];
116
- [projectedUnredacted addObjectsFromArray: [RCTCBIOTreeUtils allParents: view]];
88
+ NSMutableSet* views = [CBIOCobrowseRedactedManager.redactedViews mutableCopy];
89
+ if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseRedactedViewsForViewController:)]) {
90
+ [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseRedactedViewsForViewController:vc]];
117
91
  }
118
-
119
- // Work out which nodes are explicitly redacted but need to be unredacted
120
- // due to a nested unredaction tag (these redactions will be moved towards the
121
- // leaves of the view hierarchy instead)
122
- NSMutableSet* redactedProjectedUnredactions = [redacted mutableCopy];
123
- [redactedProjectedUnredactions intersectSet: projectedUnredacted];
124
-
125
- // Start to build the set of redactions we should actually apply. We start off with
126
- // the set of explicitly redacted nodes
127
- NSMutableSet* toRedact = [redacted mutableCopy];
128
-
129
- // remove any redactions that have unredacted decendants (i.e. any that appear in the
130
- // projection of the unredaction). These are the redacted nodes we need to move towards
131
- // the leaves of the tree
132
- [toRedact minusSet: redactedProjectedUnredactions];
133
92
 
134
- // Work out the set of all nodes that are siblings of any projected unredacted node
135
- NSMutableSet* projectedUnredactionSiblings = [NSMutableSet set];
136
- for (UIView* view in projectedUnredacted) {
137
- [projectedUnredactionSiblings addObjectsFromArray: view.superview.subviews];
93
+ return [views allObjects];
94
+ }
95
+
96
+ - (NSArray<UIView *> *)cobrowseUnredactedViewsForViewController:(UIViewController *)vc {
97
+ NSMutableSet* views = [NSMutableSet set];
98
+ @synchronized(unredactedTags) {
99
+ for (id tag in unredactedTags) {
100
+ UIView* v = [self.bridge.uiManager viewForReactTag: tag];
101
+ if (v != nil) [views addObject:v];
102
+ }
138
103
  }
139
-
140
- // Subtract the projected unredactions from the set of all siblings of projected
141
- // unredactions. i.e. subtract things that should be definitely unredacted to leave
142
- // a set we're not sure yet whether to redact or not
143
- NSMutableSet* potentiallyRedactedUnredactedSiblings = [projectedUnredactionSiblings mutableCopy];
144
- [potentiallyRedactedUnredactedSiblings minusSet:projectedUnredacted];
145
-
146
- // for each node we're not sure about yet, check if the closest redacted or unredacted ancestor
147
- // is a redacted node, if so this descendant should also be redacted
148
- for (UIView* view in potentiallyRedactedUnredactedSiblings) {
149
- UIView* closest = [RCTCBIOTreeUtils closest:^BOOL(UIView *v) {
150
- return [redacted containsObject:v] || [unredacted containsObject:v];
151
- } from: view];
152
- if ([redacted containsObject: closest]) [toRedact addObject: view];
104
+ if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseUnredactedViewsForViewController:)]) {
105
+ [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseUnredactedViewsForViewController:vc]];
153
106
  }
154
107
 
155
- // Remove any empty RCTViews from the redacted set, they're often used for wrapping
156
- // or sizing other elements, and do not usually need to be redacted
157
- // If it's absolutely necessary they are redacted, they can always be replaced with
158
- // a <Redacted> tag instead
159
- for (UIView* v in [toRedact copy])
160
- if ([v isKindOfClass:RCTView.class] && v.subviews.count == 0) [toRedact removeObject: v];
161
-
162
- return toRedact.allObjects;
108
+ return [views allObjects];
163
109
  }
164
110
 
165
111
  - (bool) cobrowseShouldCaptureWindow:(UIWindow *)window {
@@ -280,4 +226,18 @@ RCT_REMAP_METHOD(updateSession,
280
226
  }];
281
227
  }
282
228
 
229
+ void noopImplementation(id self, SEL _cmd, CBIOSession* session) {
230
+ // no-op function which will overwrite the default full device UI when enabled so
231
+ // it can be handled on RN side
232
+ }
233
+
234
+ RCT_EXPORT_METHOD(overwriteFullControlUI) {
235
+ class_addMethod([self class], @selector(cobrowseHandleFullDeviceRequest:), (IMP) noopImplementation, "v@:");
236
+ }
237
+
238
+ RCT_EXPORT_METHOD(overwriteSessionIndicator) {
239
+ class_addMethod([self class], @selector(cobrowseShowSessionControls:), (IMP) noopImplementation, "v@:");
240
+ class_addMethod([self class], @selector(cobrowseHideSessionControls:), (IMP) noopImplementation, "v@:");
241
+ }
242
+
283
243
  @end
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+ import { Platform, requireNativeComponent } from 'react-native'
3
+
4
+ const CBIOBroadcastPickerView = requireNativeComponent(
5
+ 'CBIOBroadcastPickerView'
6
+ )
7
+
8
+ export default function (props) {
9
+ // this native component is only available on iOS
10
+ return Platform.OS === 'ios' ? <CBIOBroadcastPickerView {...props} /> : null
11
+ }
package/js/CobrowseIO.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Alert } from 'react-native'
1
+ import { Platform, Alert } from 'react-native'
2
2
  import Session from './Session'
3
3
  const CobrowseIONative = require('react-native').NativeModules.CobrowseIO
4
4
  const NativeEventEmitter = require('react-native').NativeEventEmitter
@@ -72,18 +72,22 @@ export default class CobrowseIO {
72
72
  return CobrowseIONative.stop()
73
73
  }
74
74
 
75
+ // eslint-disable-next-line accessor-pairs
75
76
  static set api (api) {
76
77
  CobrowseIONative.api(api)
77
78
  }
78
79
 
80
+ // eslint-disable-next-line accessor-pairs
79
81
  static set license (license) {
80
82
  CobrowseIONative.license(license)
81
83
  }
82
84
 
85
+ // eslint-disable-next-line accessor-pairs
83
86
  static set customData (customData) {
84
87
  CobrowseIONative.customData(customData)
85
88
  }
86
89
 
90
+ // eslint-disable-next-line accessor-pairs
87
91
  static set deviceToken (token) {
88
92
  CobrowseIONative.deviceToken(token)
89
93
  }
@@ -114,6 +118,14 @@ export default class CobrowseIO {
114
118
  // the session.requested event is considered internal, it should
115
119
  // not be used outside these bindings
116
120
  CobrowseIO.addListener('session.requested', (session) => {
121
+ if (CobrowseIO.showSessionControls === false) {
122
+ CobrowseIONative.overwriteSessionIndicator()
123
+ }
124
+
125
+ if (Platform.OS === 'ios' && CobrowseIO.handleFullDeviceRequest) {
126
+ CobrowseIONative.overwriteFullControlUI()
127
+ }
128
+
117
129
  CobrowseIO.handleSessionRequest(session)
118
130
  })
119
131
 
@@ -121,4 +133,13 @@ CobrowseIO.addListener('session.updated', (session) => {
121
133
  if (session.isActive() && session.remote_control === 'requested') {
122
134
  CobrowseIO.handleRemoteControlRequest(session)
123
135
  }
136
+
137
+ if (session.isActive() && session.full_device_state === 'requested') {
138
+ if (CobrowseIO.handleFullDeviceRequest) {
139
+ CobrowseIO.handleFullDeviceRequest(session)
140
+ } else if (Platform.OS === 'android') {
141
+ // accept the incoming connection by default
142
+ session.setFullDevice('on')
143
+ }
144
+ }
124
145
  })
@@ -60,6 +60,7 @@ export default class CobrowseView extends Component {
60
60
  })
61
61
  this.endListener = CobrowseIO.addListener('session.ended', (session) => {
62
62
  if (this.props.onEnded) this.props.onEnded()
63
+ this.setState({ session: null })
63
64
  })
64
65
  }
65
66
 
@@ -99,7 +100,7 @@ export default class CobrowseView extends Component {
99
100
  renderManageSession () {
100
101
  return (
101
102
  <View>
102
- <Text style={[styles.text]}>You{"'"}re sharing screens from this app with a support agent.</Text>
103
+ <Text style={[styles.text]}>You're sharing screens from this app with a support agent.</Text>
103
104
  <TouchableOpacity onPress={() => this.endSession()}>
104
105
  <Text style={[styles.text, styles.button]}>End Session</Text>
105
106
  </TouchableOpacity>
package/js/Session.js CHANGED
@@ -61,6 +61,10 @@ export default class Session {
61
61
  return this._session.full_device
62
62
  }
63
63
 
64
+ get full_device_state () {
65
+ return this._session.full_device_state
66
+ }
67
+
64
68
  get remote_control () {
65
69
  return this._session.remote_control
66
70
  }
package/js/Unredacted.js CHANGED
@@ -69,8 +69,8 @@ export const useUnredaction = (shouldWarnUnhandledRefs = true, componentName = '
69
69
  }
70
70
 
71
71
  // HOC for adding unredaction to a whole component class
72
- export function unredact(Component) {
73
- return React.forwardRef(function Redacted(props, ref) {
72
+ export function unredact (Component) {
73
+ return React.forwardRef(function Redacted (props, ref) {
74
74
  const localRef = useUnredaction(true, Component?.name)
75
75
  const refs = useMemo(() => mergeRefs([localRef, ref]), [localRef, ref])
76
76
  return <Component {...props} collapsable={false} ref={refs} />
package/js/index.js CHANGED
@@ -4,3 +4,5 @@ export { default as Redacted } from './Redacted'
4
4
  export { default as Unredacted, unredact, useUnredaction } from './Unredacted'
5
5
  export { default as SessionControl } from './SessionControl'
6
6
  export { default as CobrowseAccessibilityService } from './CobrowseAccessibilityService'
7
+ export { default as CBIOBroadcastPickerView } from './CBIOBroadcastPickerView'
8
+ export { useSession } from './useSession'