cobrowse-sdk-react-native 2.14.0 → 2.16.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.
Files changed (97) hide show
  1. package/.vscode/settings.json +7 -0
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/io/cobrowse/reactnative/CobrowseIOCommonDelegates.java +3 -3
  4. package/android/src/main/java/io/cobrowse/reactnative/CobrowseIOModule.java +23 -0
  5. package/android/src/main/java/io/cobrowse/reactnative/CommonDelegates.java +20 -83
  6. package/cobrowse-sdk-react-native.podspec +1 -1
  7. package/ios/RCTCobrowseIO.m +20 -71
  8. package/js/CBIOBroadcastPickerView.tsx +15 -0
  9. package/js/CobrowseAccessibilityService.ts +15 -0
  10. package/js/CobrowseIO.ts +156 -0
  11. package/js/CobrowseView.tsx +150 -0
  12. package/js/{Redacted.js → Redacted.tsx} +3 -2
  13. package/js/Session.ts +128 -0
  14. package/js/SessionControl.ts +38 -0
  15. package/js/Unredacted.tsx +106 -0
  16. package/js/{index.js → index.ts} +1 -0
  17. package/js/{useSession.js → useSession.ts} +5 -4
  18. package/lib/commonjs/CBIOBroadcastPickerView.js +15 -0
  19. package/lib/commonjs/CBIOBroadcastPickerView.js.map +1 -0
  20. package/lib/commonjs/CobrowseAccessibilityService.js +22 -0
  21. package/lib/commonjs/CobrowseAccessibilityService.js.map +1 -0
  22. package/lib/commonjs/CobrowseIO.js +149 -0
  23. package/lib/commonjs/CobrowseIO.js.map +1 -0
  24. package/lib/commonjs/CobrowseView.js +146 -0
  25. package/lib/commonjs/CobrowseView.js.map +1 -0
  26. package/lib/commonjs/Redacted.js +14 -0
  27. package/lib/commonjs/Redacted.js.map +1 -0
  28. package/lib/commonjs/Session.js +100 -0
  29. package/lib/commonjs/Session.js.map +1 -0
  30. package/lib/commonjs/SessionControl.js +39 -0
  31. package/lib/commonjs/SessionControl.js.map +1 -0
  32. package/lib/commonjs/Unredacted.js +82 -0
  33. package/lib/commonjs/Unredacted.js.map +1 -0
  34. package/lib/commonjs/index.js +77 -0
  35. package/lib/commonjs/index.js.map +1 -0
  36. package/lib/commonjs/useSession.js +35 -0
  37. package/lib/commonjs/useSession.js.map +1 -0
  38. package/lib/module/CBIOBroadcastPickerView.js +8 -0
  39. package/lib/module/CBIOBroadcastPickerView.js.map +1 -0
  40. package/lib/module/CobrowseAccessibilityService.js +13 -0
  41. package/lib/module/CobrowseAccessibilityService.js.map +1 -0
  42. package/lib/module/CobrowseIO.js +141 -0
  43. package/lib/module/CobrowseIO.js.map +1 -0
  44. package/lib/module/CobrowseView.js +136 -0
  45. package/lib/module/CobrowseView.js.map +1 -0
  46. package/lib/module/Redacted.js +7 -0
  47. package/lib/module/Redacted.js.map +1 -0
  48. package/lib/module/Session.js +93 -0
  49. package/lib/module/Session.js.map +1 -0
  50. package/lib/module/SessionControl.js +31 -0
  51. package/lib/module/SessionControl.js.map +1 -0
  52. package/lib/module/Unredacted.js +71 -0
  53. package/lib/module/Unredacted.js.map +1 -0
  54. package/lib/module/index.js +9 -0
  55. package/lib/module/index.js.map +1 -0
  56. package/lib/module/useSession.js +28 -0
  57. package/lib/module/useSession.js.map +1 -0
  58. package/lib/typescript/CBIOBroadcastPickerView.d.ts +8 -0
  59. package/lib/typescript/CBIOBroadcastPickerView.d.ts.map +1 -0
  60. package/lib/typescript/CobrowseAccessibilityService.d.ts +8 -0
  61. package/lib/typescript/CobrowseAccessibilityService.d.ts.map +1 -0
  62. package/lib/typescript/CobrowseIO.d.ts +30 -0
  63. package/lib/typescript/CobrowseIO.d.ts.map +1 -0
  64. package/lib/typescript/CobrowseView.d.ts +25 -0
  65. package/lib/typescript/CobrowseView.d.ts.map +1 -0
  66. package/lib/typescript/Redacted.d.ts +4 -0
  67. package/lib/typescript/Redacted.d.ts.map +1 -0
  68. package/lib/typescript/Session.d.ts +42 -0
  69. package/lib/typescript/Session.d.ts.map +1 -0
  70. package/lib/typescript/SessionControl.d.ts +17 -0
  71. package/lib/typescript/SessionControl.d.ts.map +1 -0
  72. package/lib/typescript/Unredacted.d.ts +10 -0
  73. package/lib/typescript/Unredacted.d.ts.map +1 -0
  74. package/lib/typescript/index.d.ts +10 -0
  75. package/lib/typescript/index.d.ts.map +1 -0
  76. package/lib/typescript/useSession.d.ts +3 -0
  77. package/lib/typescript/useSession.d.ts.map +1 -0
  78. package/package.json +35 -7
  79. package/tsconfig.build.json +5 -0
  80. package/tsconfig.json +28 -0
  81. package/js/CBIOBroadcastPickerView.js +0 -11
  82. package/js/CobrowseAccessibilityService.js +0 -11
  83. package/js/CobrowseIO.js +0 -141
  84. package/js/CobrowseView.js +0 -129
  85. package/js/Session.js +0 -107
  86. package/js/SessionControl.js +0 -26
  87. package/js/Unredacted.js +0 -82
  88. package/ts/CBIOBroadcastPickerView.d.ts +0 -8
  89. package/ts/CobrowseAccessibilityService.d.ts +0 -6
  90. package/ts/CobrowseIO.d.ts +0 -29
  91. package/ts/CobrowseView.d.ts +0 -20
  92. package/ts/Redacted.d.ts +0 -8
  93. package/ts/Session.d.ts +0 -58
  94. package/ts/SessionControl.d.ts +0 -9
  95. package/ts/Unredacted.d.ts +0 -15
  96. package/ts/index.d.ts +0 -7
  97. package/ts/useSession.d.ts +0 -3
@@ -0,0 +1,7 @@
1
+ {
2
+ "eslint.enable": false,
3
+ "prettier.enable": false,
4
+ "standard.enable": true,
5
+ "standard.autoFixOnSave": true,
6
+ "standard.engine": "standard"
7
+ }
@@ -30,5 +30,5 @@ android {
30
30
 
31
31
  dependencies {
32
32
  implementation 'com.facebook.react:react-native:+' // support react-native-v0.22-rc+
33
- implementation 'io.cobrowse:cobrowse-sdk-android:2.23.0'
33
+ implementation 'io.cobrowse:cobrowse-sdk-android:2.25.1'
34
34
  }
@@ -5,9 +5,9 @@ import com.facebook.react.bridge.ReadableArray;
5
5
 
6
6
  import io.cobrowse.CobrowseIO;
7
7
 
8
- interface CobrowseIOCommonDelegates extends io.cobrowse.CobrowseIO.Delegate, io.cobrowse.CobrowseIO.SessionRequestDelegate,
9
- io.cobrowse.CobrowseIO.SessionLoadDelegate, io.cobrowse.CobrowseIO.RedactionDelegate,
10
- io.cobrowse.CobrowseIO.RemoteControlRequestDelegate, CobrowseIO.FullDeviceRequestDelegate {
8
+ interface CobrowseIOCommonDelegates extends CobrowseIO.Delegate, CobrowseIO.SessionRequestDelegate,
9
+ CobrowseIO.SessionLoadDelegate, CobrowseIO.RedactionDelegate, CobrowseIO.UnredactionDelegate,
10
+ CobrowseIO.RemoteControlRequestDelegate, CobrowseIO.FullDeviceRequestDelegate {
11
11
 
12
12
  public void findNodeManager();
13
13
  public void setUnredactedTags(final ReadableArray reactTags, final Promise promise);
@@ -79,6 +79,19 @@ public class CobrowseIOModule extends ReactContextBaseJavaModule {
79
79
  CobrowseIO.instance().customData(customData.toHashMap());
80
80
  }
81
81
 
82
+ @ReactMethod
83
+ public void capabilities(ReadableArray capabilities) {
84
+ String[] capabilitiesArray = new String[capabilities.size()];
85
+ for (int i = 0; i < capabilities.size(); i++) {
86
+ try {
87
+ capabilitiesArray[i] = capabilities.getString(i);
88
+ } catch (UnexpectedNativeTypeException e) {
89
+ Log.w("CobrowseIO", "Failed to process capabilities: " + e.getMessage());
90
+ }
91
+ }
92
+ CobrowseIO.instance().capabilities(capabilitiesArray);
93
+ }
94
+
82
95
  @ReactMethod
83
96
  public void deviceToken(String token) {
84
97
  if (getReactApplicationContext().getCurrentActivity() != null)
@@ -240,4 +253,14 @@ public class CobrowseIOModule extends ReactContextBaseJavaModule {
240
253
 
241
254
  CobrowseIO.instance().setDelegate(delegatesWithSessionControls);
242
255
  }
256
+
257
+ @ReactMethod
258
+ public void addListener(String eventName) {
259
+ // Keep: Required for RN built in Event Emitter Calls.
260
+ }
261
+
262
+ @ReactMethod
263
+ public void removeListeners(Integer count) {
264
+ // Keep: Required for RN built in Event Emitter Calls.
265
+ }
243
266
  }
@@ -7,7 +7,6 @@ import android.view.ViewGroup;
7
7
  import android.view.ViewParent;
8
8
 
9
9
  import androidx.annotation.NonNull;
10
- import androidx.annotation.Nullable;
11
10
  import androidx.core.util.Predicate;
12
11
 
13
12
  import com.facebook.react.bridge.Promise;
@@ -40,7 +39,25 @@ class CommonDelegates implements CobrowseIOCommonDelegates {
40
39
  this.reactApplicationContext = context;
41
40
  }
42
41
 
43
- private Set<View> getUnredactedViews(@NonNull final Activity activity) {
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) {
44
61
  synchronized (unredactedTags) {
45
62
  HashSet<View> unredacted = new HashSet<>();
46
63
  for (Integer i : unredactedTags) {
@@ -54,89 +71,9 @@ class CommonDelegates implements CobrowseIOCommonDelegates {
54
71
  List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).unredactedViews(activity);
55
72
  if (views != null) unredacted.addAll(views);
56
73
  }
57
- return unredacted;
58
- }
59
- }
60
74
 
61
- private Set<View> getRedactedViews(@NonNull final Activity activity) {
62
- HashSet<View> redacted = new HashSet<>(RedactedViewManager.redactedViews.keySet());
63
- if (CobrowseIOModule.delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
64
- List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).redactedViews(activity);
65
- if (views != null) redacted.addAll(views);
75
+ return new ArrayList<>(unredacted);
66
76
  }
67
- return redacted;
68
- }
69
-
70
- @Override
71
- public void handleFullDeviceRequest(@NonNull Activity activity, @NonNull Session session) {
72
- // no-op, this will be handed on the JS side via an "updated" event handler
73
- // this stub just disables the default native prompt in the SDK
74
- }
75
-
76
- @Override
77
- public List<View> redactedViews(@NonNull Activity activity) {
78
- final Set<View> redacted = this.getRedactedViews(activity);
79
- final Set<View> unredacted = this.getUnredactedViews(activity);
80
-
81
- // Project all unredactions to the root to get the full set of unredacted nodes
82
- HashSet<View> projectedUnredacted = new HashSet<>();
83
- for (View view : unredacted) {
84
- projectedUnredacted.add(view);
85
- projectedUnredacted.addAll(TreeUtils.allParents(view));
86
- }
87
-
88
- // Work out which nodes are explicitly redacted but need to be unredacted
89
- // due to a nested unredaction tag (these redactions will be moved towards the
90
- // leaves of the view hierarchy instead)
91
- HashSet<View> redactedProjectedUnredactions = new HashSet<>(redacted);
92
- redactedProjectedUnredactions.retainAll(projectedUnredacted);
93
-
94
- // Start to build the set of redactions we should actually apply. We start off with
95
- // the set of explicitly redacted nodes
96
- HashSet<View> toRedact = new HashSet<>(redacted);
97
-
98
- // remove any redactions that have unredacted decendants (i.e. any that appear in the
99
- // projection of the unredaction). These are the redacted nodes we need to move towards
100
- // the leaves of the tree
101
- toRedact.removeAll(redactedProjectedUnredactions);
102
-
103
- // Work out the set of all nodes that are siblings of any projected unredacted node
104
- HashSet<View> projectedUnredactionSiblings = new HashSet<>();
105
- for (View view : projectedUnredacted) {
106
- ViewParent parent = view.getParent();
107
- if (parent instanceof ViewGroup)
108
- projectedUnredactionSiblings.addAll(TreeUtils.directChildren((ViewGroup) parent));
109
- }
110
-
111
- // Subtract the projected unredactions from the set of all siblings of projected
112
- // unredactions. i.e. subtract things that should be definitely unredacted to leave
113
- // a set we're not sure yet whether to redact or not
114
- HashSet<View> potentiallyRedactedUnredactedSiblings = new HashSet<View>(projectedUnredactionSiblings);
115
- potentiallyRedactedUnredactedSiblings.removeAll(projectedUnredacted);
116
-
117
- // for each node we're not sure about yet, check if the closest redacted or unredacted ancestor
118
- // is a redacted node, if so this descendant should also be redacted
119
- for (View view : potentiallyRedactedUnredactedSiblings) {
120
- View closest = TreeUtils.closest(view, new Predicate<View>() {
121
- @Override
122
- public boolean test(View view) {
123
- return redacted.contains(view) || unredacted.contains(view);
124
- }
125
- });
126
- if (redacted.contains(closest)) toRedact.add(view);
127
- }
128
-
129
- // Remove any empty ViewGroup from the redacted set, they're often used for wrapping
130
- // or sizing other elements, and do not usually need to be redacted
131
- // If it's absolutely necessary they are redacted, they can always be replaced with
132
- // a <Redacted> tag instead
133
- for (View v : new HashSet<>(toRedact)) {
134
- if (v instanceof ViewGroup && ((ViewGroup) v).getChildCount() == 0) {
135
- toRedact.remove(v);
136
- }
137
- }
138
-
139
- return new ArrayList<>(toRedact);
140
77
  }
141
78
 
142
79
  @Override
@@ -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
@@ -67,28 +67,6 @@ RCT_EXPORT_MODULE();
67
67
  if (hasListeners) [self sendEventWithName:@SESSION_LOADED body:[session toDict]];
68
68
  }
69
69
 
70
- -(NSSet<UIView*>*) redactedViews: (UIViewController*) vc {
71
- NSMutableSet* views = [CBIOCobrowseRedactedManager.redactedViews mutableCopy];
72
- if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseRedactedViewsForViewController:)]) {
73
- [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseRedactedViewsForViewController:vc]];
74
- }
75
- return views;
76
- }
77
-
78
- -(NSSet<UIView*>*) unredactedViews: (UIViewController*) vc {
79
- NSMutableSet* views = [NSMutableSet set];
80
- @synchronized(unredactedTags) {
81
- for (id tag in unredactedTags) {
82
- UIView* v = [self.bridge.uiManager viewForReactTag: tag];
83
- if (v != nil) [views addObject:v];
84
- }
85
- }
86
- if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseUnredactedViewsForViewController:)]) {
87
- [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseUnredactedViewsForViewController:vc]];
88
- }
89
- return views;
90
- }
91
-
92
70
  -(void)cobrowseSessionDidUpdate:(CBIOSession *)session {
93
71
  if (hasListeners) [self sendEventWithName:@SESSION_UPDATED body:[session toDict]];
94
72
  }
@@ -107,60 +85,27 @@ RCT_EXPORT_MODULE();
107
85
  }
108
86
 
109
87
  -(NSArray<UIView *> *)cobrowseRedactedViewsForViewController:(UIViewController *)vc {
110
- NSSet* redacted = [self redactedViews: vc];
111
- NSSet* unredacted = [self unredactedViews: vc];
112
-
113
- // Project all unredactions to the root to get the full set of unredacted nodes
114
- NSMutableSet* projectedUnredacted = [NSMutableSet set];
115
- for (id view in unredacted) {
116
- [projectedUnredacted addObject:view];
117
- [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]];
118
91
  }
119
92
 
120
- // Work out which nodes are explicitly redacted but need to be unredacted
121
- // due to a nested unredaction tag (these redactions will be moved towards the
122
- // leaves of the view hierarchy instead)
123
- NSMutableSet* redactedProjectedUnredactions = [redacted mutableCopy];
124
- [redactedProjectedUnredactions intersectSet: projectedUnredacted];
125
-
126
- // Start to build the set of redactions we should actually apply. We start off with
127
- // the set of explicitly redacted nodes
128
- NSMutableSet* toRedact = [redacted mutableCopy];
129
-
130
- // remove any redactions that have unredacted decendants (i.e. any that appear in the
131
- // projection of the unredaction). These are the redacted nodes we need to move towards
132
- // the leaves of the tree
133
- [toRedact minusSet: redactedProjectedUnredactions];
134
-
135
- // Work out the set of all nodes that are siblings of any projected unredacted node
136
- NSMutableSet* projectedUnredactionSiblings = [NSMutableSet set];
137
- for (UIView* view in projectedUnredacted) {
138
- [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
+ }
139
103
  }
140
-
141
- // Subtract the projected unredactions from the set of all siblings of projected
142
- // unredactions. i.e. subtract things that should be definitely unredacted to leave
143
- // a set we're not sure yet whether to redact or not
144
- NSMutableSet* potentiallyRedactedUnredactedSiblings = [projectedUnredactionSiblings mutableCopy];
145
- [potentiallyRedactedUnredactedSiblings minusSet:projectedUnredacted];
146
-
147
- // for each node we're not sure about yet, check if the closest redacted or unredacted ancestor
148
- // is a redacted node, if so this descendant should also be redacted
149
- for (UIView* view in potentiallyRedactedUnredactedSiblings) {
150
- UIView* closest = [RCTCBIOTreeUtils closest:^BOOL(UIView *v) {
151
- return [redacted containsObject:v] || [unredacted containsObject:v];
152
- } from: view];
153
- if ([redacted containsObject: closest]) [toRedact addObject: view];
104
+ if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseUnredactedViewsForViewController:)]) {
105
+ [views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseUnredactedViewsForViewController:vc]];
154
106
  }
155
107
 
156
- // Remove any empty RCTViews from the redacted set, they're often used for wrapping
157
- // or sizing other elements, and do not usually need to be redacted
158
- // If it's absolutely necessary they are redacted, they can always be replaced with
159
- // a <Redacted> tag instead
160
- for (UIView* v in [toRedact copy])
161
- if ([v isKindOfClass:RCTView.class] && v.subviews.count == 0) [toRedact removeObject: v];
162
-
163
- return toRedact.allObjects;
108
+ return [views allObjects];
164
109
  }
165
110
 
166
111
  - (bool) cobrowseShouldCaptureWindow:(UIWindow *)window {
@@ -216,6 +161,10 @@ RCT_EXPORT_METHOD(customData: (NSDictionary*) customData) {
216
161
  CobrowseIO.instance.customData = customData;
217
162
  }
218
163
 
164
+ RCT_EXPORT_METHOD(capabilities: (NSArray*) capabilities) {
165
+ CobrowseIO.instance.capabilities = capabilities;
166
+ }
167
+
219
168
  RCT_EXPORT_METHOD(deviceToken: (NSString*) token) {
220
169
  CobrowseIO.instance.device.token = [token dataUsingEncoding:NSUTF16StringEncoding];
221
170
  }
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+ import { Platform, requireNativeComponent, type ViewProps } from 'react-native'
3
+
4
+ const CBIOBroadcastPickerViewNativeView = requireNativeComponent(
5
+ 'CBIOBroadcastPickerView'
6
+ )
7
+
8
+ type CBIOBroadcastPickerViewProps = {
9
+ buttonColor: string
10
+ } & ViewProps
11
+
12
+ export default function CBIOBroadcastPickerView (props: CBIOBroadcastPickerViewProps): JSX.Element | null {
13
+ // this native component is only available on iOS
14
+ return Platform.OS === 'ios' ? <CBIOBroadcastPickerViewNativeView {...props} /> : null
15
+ }
@@ -0,0 +1,15 @@
1
+ import { NativeModules } from 'react-native'
2
+ const CobrowseIONative = NativeModules.CobrowseIO
3
+
4
+ export function showSetup (): void {
5
+ return CobrowseIONative.accessibilityServiceShowSetup()
6
+ }
7
+
8
+ export function isRunning (): boolean {
9
+ return CobrowseIONative.accessibilityServiceIsRunning()
10
+ }
11
+
12
+ export default {
13
+ showSetup,
14
+ isRunning
15
+ }
@@ -0,0 +1,156 @@
1
+ import { Platform, Alert, NativeEventEmitter, EmitterSubscription, NativeModules } from 'react-native'
2
+ import Session, { type CobrowseSessionEvents, type SessionLike } from './Session'
3
+ const CobrowseIONative = NativeModules.CobrowseIO
4
+
5
+ const emitter = new NativeEventEmitter(CobrowseIONative)
6
+
7
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
8
+ export default class CobrowseIO {
9
+ private static sessionRequestShown = false
10
+ private static remoteControlRequestShown = false
11
+
12
+ /** @deprecated */
13
+ static get SESSION_UPDATED (): 'session.updated' {
14
+ return 'session.updated' as const
15
+ }
16
+
17
+ /** @deprecated */
18
+ static get SESSION_ENDED (): 'session.ended' {
19
+ return 'session.ended' as const
20
+ }
21
+
22
+ static handleSessionRequest (session: Session): void {
23
+ if (this.sessionRequestShown) return
24
+ this.sessionRequestShown = true
25
+ Alert.alert(
26
+ 'Support Request',
27
+ 'A support agent would like to use this app with you. Do you accept?',
28
+ [{
29
+ text: 'Reject',
30
+ onPress: () => {
31
+ this.sessionRequestShown = false
32
+ void session.end()
33
+ },
34
+ style: 'cancel'
35
+ }, {
36
+ text: 'Accept',
37
+ onPress: () => {
38
+ this.sessionRequestShown = false
39
+ void session.activate()
40
+ }
41
+ }], { cancelable: false })
42
+ }
43
+
44
+ static handleRemoteControlRequest (session: Session): void {
45
+ if (this.remoteControlRequestShown) return
46
+ this.remoteControlRequestShown = true
47
+ Alert.alert(
48
+ 'Remote Control Request',
49
+ 'A support agent would like to take remote control of this app. Do you accept?',
50
+ [{
51
+ text: 'Reject',
52
+ onPress: () => {
53
+ this.remoteControlRequestShown = false
54
+ void session.setRemoteControl('rejected')
55
+ },
56
+ style: 'cancel'
57
+ }, {
58
+ text: 'Accept',
59
+ onPress: () => {
60
+ this.remoteControlRequestShown = false
61
+ void session.setRemoteControl('on')
62
+ }
63
+ }], { cancelable: false })
64
+ }
65
+
66
+ static addListener (event: CobrowseSessionEvents | 'session.requested', cb: (session: Session) => void): EmitterSubscription {
67
+ return emitter.addListener(event, (session: SessionLike) => cb(new Session(session)))
68
+ }
69
+
70
+ static start (): void {
71
+ CobrowseIONative.start()
72
+ }
73
+
74
+ static stop (): void {
75
+ CobrowseIONative.stop()
76
+ }
77
+
78
+ // eslint-disable-next-line accessor-pairs
79
+ static set api (api: string) {
80
+ CobrowseIONative.api(api)
81
+ }
82
+
83
+ // eslint-disable-next-line accessor-pairs
84
+ static set license (license: string) {
85
+ CobrowseIONative.license(license)
86
+ }
87
+
88
+ // eslint-disable-next-line accessor-pairs
89
+ static set customData (customData: Record<string, unknown>) {
90
+ CobrowseIONative.customData(customData)
91
+ }
92
+
93
+ // eslint-disable-next-line accessor-pairs
94
+ static set capabilities (capabilities: Array<'drawing' | 'full_device' | 'keypress' | 'laser' | 'pointer'>) {
95
+ CobrowseIONative.capabilities(capabilities)
96
+ }
97
+
98
+ // eslint-disable-next-line accessor-pairs
99
+ static set deviceToken (token: string) {
100
+ CobrowseIONative.deviceToken(token)
101
+ }
102
+
103
+ static currentSession (): Session | null {
104
+ return CobrowseIONative.currentSession().then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
105
+ }
106
+
107
+ static createSession (): Session | null {
108
+ return CobrowseIONative.createSession().then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
109
+ }
110
+
111
+ static getSession (codeOrId: string): Session | null {
112
+ return CobrowseIONative.getSession(codeOrId).then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
113
+ }
114
+
115
+ /** @deprecated */
116
+ static activateSession (): Session | null {
117
+ return CobrowseIONative.activateSession().then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
118
+ }
119
+
120
+ /** @deprecated */
121
+ static endSession (): void {
122
+ return CobrowseIONative.endSession()
123
+ }
124
+
125
+ static showSessionControls: Boolean | null = null
126
+ static handleFullDeviceRequest: null | ((s: Session) => void) = null
127
+ }
128
+
129
+ // the session.requested event is considered internal, it should
130
+ // not be used outside these bindings
131
+ CobrowseIO.addListener('session.requested', (session) => {
132
+ if (CobrowseIO.showSessionControls === false) {
133
+ CobrowseIONative.overwriteSessionIndicator()
134
+ }
135
+
136
+ if (Platform.OS === 'ios' && (CobrowseIO.handleFullDeviceRequest != null)) {
137
+ CobrowseIONative.overwriteFullControlUI()
138
+ }
139
+
140
+ CobrowseIO.handleSessionRequest(session)
141
+ })
142
+
143
+ CobrowseIO.addListener('session.updated', (session) => {
144
+ if (session.isActive() && session.remote_control === 'requested') {
145
+ CobrowseIO.handleRemoteControlRequest(session)
146
+ }
147
+
148
+ if (session.isActive() && session.full_device_state === 'requested') {
149
+ if (CobrowseIO.handleFullDeviceRequest != null) {
150
+ CobrowseIO.handleFullDeviceRequest(session)
151
+ } else if (Platform.OS === 'android') {
152
+ // accept the incoming connection by default
153
+ void session.setFullDevice('on')
154
+ }
155
+ }
156
+ })
@@ -0,0 +1,150 @@
1
+ import React, { Component } from 'react'
2
+ import {
3
+ View,
4
+ Text,
5
+ ActivityIndicator,
6
+ TouchableOpacity,
7
+ StyleSheet,
8
+ EmitterSubscription
9
+ } from 'react-native'
10
+ import CobrowseIO from './CobrowseIO'
11
+ import type Session from './Session'
12
+
13
+ const styles = StyleSheet.create({
14
+ container: {
15
+ flex: 1,
16
+ justifyContent: 'flex-end'
17
+ },
18
+ text: {
19
+ textAlign: 'center',
20
+ margin: 15,
21
+ fontSize: 15,
22
+ lineHeight: 20
23
+ },
24
+ code: {
25
+ fontSize: 29,
26
+ padding: 20,
27
+ fontWeight: 'bold',
28
+ textAlign: 'center'
29
+ },
30
+ button: {
31
+ color: 'rgb(0, 122, 255)',
32
+ fontSize: 18,
33
+ margin: 10
34
+ }
35
+ })
36
+
37
+ interface CobrowseViewProps {
38
+ // @deprecated
39
+ license?: string
40
+ onEnded?: () => void
41
+ }
42
+
43
+ interface CobrowseViewState {
44
+ error: Error | null
45
+ session: Session | null
46
+ }
47
+
48
+ export default class CobrowseView extends Component<CobrowseViewProps, CobrowseViewState> {
49
+ private _updateListener: EmitterSubscription | null = null
50
+ private _endListener: EmitterSubscription | null = null
51
+
52
+ constructor (props: CobrowseViewProps) {
53
+ super(props)
54
+ this.state = { error: null, session: null }
55
+ }
56
+
57
+ async componentDidMount (): Promise<void> {
58
+ if (this.props.license != null) {
59
+ console.warn('Passing license to view is deprecated. Use CobrowseIO.license = "..." instead')
60
+ CobrowseIO.license = this.props.license
61
+ }
62
+
63
+ try {
64
+ const current = await CobrowseIO.currentSession()
65
+ if (current != null) this.setState({ session: current })
66
+ else {
67
+ const session = await CobrowseIO.createSession()
68
+ this.setState({ session })
69
+ }
70
+ } catch (error) {
71
+ this.setState({ error: error as Error })
72
+ }
73
+
74
+ this._updateListener = CobrowseIO.addListener('session.updated', (session) => {
75
+ this.setState({ session })
76
+ })
77
+ this._endListener = CobrowseIO.addListener('session.ended', () => {
78
+ if (this.props.onEnded != null) this.props.onEnded()
79
+ this.setState({ session: null })
80
+ })
81
+ }
82
+
83
+ componentWillUnmount (): void {
84
+ if (this._updateListener != null) this._updateListener.remove()
85
+ if (this._endListener != null) this._endListener.remove()
86
+ }
87
+
88
+ async endSession (): Promise<void> {
89
+ try {
90
+ const { session } = this.state
91
+
92
+ if (session == null) {
93
+ throw new Error('No session to end')
94
+ }
95
+
96
+ await session.end()
97
+ this.setState({ session: null })
98
+ } catch (error) {
99
+ this.setState({ error: error as Error })
100
+ }
101
+ }
102
+
103
+ renderError (error: Error): JSX.Element {
104
+ return (
105
+ <Text style={[styles.text]}>{error.message}</Text>
106
+ )
107
+ }
108
+
109
+ renderCode (): JSX.Element {
110
+ let code = this.state.session?.code
111
+ if (code != null) code = code.substr(0, 3) + '-' + code.substr(3)
112
+ return (
113
+ <View>
114
+ <Text style={[styles.code, { opacity: code != null ? 1 : 0.2 }]}>{code ?? '000-000'}</Text>
115
+ <Text style={[styles.text]}>Provide this code to your support agent to begin screen sharing.</Text>
116
+ <ActivityIndicator />
117
+ </View>
118
+ )
119
+ }
120
+
121
+ renderManageSession (): JSX.Element {
122
+ return (
123
+ <View>
124
+ <Text style={[styles.text]}>You're sharing screens from this app with a support agent.</Text>
125
+ <TouchableOpacity onPress={() => this.endSession}>
126
+ <Text style={[styles.text, styles.button]}>End Session</Text>
127
+ </TouchableOpacity>
128
+ </View>
129
+ )
130
+ }
131
+
132
+ renderContent (): JSX.Element {
133
+ const { error, session } = this.state
134
+ if (error != null) {
135
+ return this.renderError(error)
136
+ } else if ((session == null) || (session.state === 'pending' || session.state === 'authorizing')) {
137
+ return this.renderCode()
138
+ } else {
139
+ return this.renderManageSession()
140
+ }
141
+ }
142
+
143
+ render (): JSX.Element {
144
+ return (
145
+ <View style={styles.container}>
146
+ {this.renderContent()}
147
+ </View>
148
+ )
149
+ }
150
+ }
@@ -1,7 +1,8 @@
1
1
  import React from 'react'
2
- import { requireNativeComponent } from 'react-native'
2
+ import { requireNativeComponent, type ViewProps } from 'react-native'
3
+
3
4
  const CBIOCobrowseRedacted = requireNativeComponent('CBIOCobrowseRedacted')
4
5
 
5
- module.exports = function (props) {
6
+ export default function Redacted (props: ViewProps): JSX.Element {
6
7
  return <CBIOCobrowseRedacted {...props}>{props.children}</CBIOCobrowseRedacted>
7
8
  }