Browse Source

watchos: add watchOS app

Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
j8
Saúl Ibarra Corretgé 7 years ago
parent
commit
a26bb2c1a6
44 changed files with 1580 additions and 1 deletions
  1. 1
    0
      ios/Podfile
  2. 7
    1
      ios/Podfile.lock
  3. 364
    0
      ios/app/app.xcodeproj/project.pbxproj
  4. 92
    0
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Contents.json
  5. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-100@2x.png
  6. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-1024@1x.png
  7. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-216@2x.png
  8. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-24@2x.png
  9. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-27.5@2x.png
  10. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png
  11. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png
  12. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
  13. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-86@2x.png
  14. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-88@2x.png
  15. BIN
      ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-98@2x.png
  16. 6
    0
      ios/app/watchos/app/Assets.xcassets/Contents.json
  17. 21
    0
      ios/app/watchos/app/Assets.xcassets/hangup.imageset/Contents.json
  18. BIN
      ios/app/watchos/app/Assets.xcassets/hangup.imageset/hangup@2x.png
  19. 21
    0
      ios/app/watchos/app/Assets.xcassets/mute-off.imageset/Contents.json
  20. BIN
      ios/app/watchos/app/Assets.xcassets/mute-off.imageset/mute-off@2x.png
  21. 21
    0
      ios/app/watchos/app/Assets.xcassets/mute-on.imageset/Contents.json
  22. BIN
      ios/app/watchos/app/Assets.xcassets/mute-on.imageset/mute-on@2x.png
  23. 83
    0
      ios/app/watchos/app/Base.lproj/Interface.storyboard
  24. 33
    0
      ios/app/watchos/app/Info.plist
  25. 6
    0
      ios/app/watchos/extension/Assets.xcassets/Contents.json
  26. 21
    0
      ios/app/watchos/extension/Assets.xcassets/jitsi.imageset/Contents.json
  27. BIN
      ios/app/watchos/extension/Assets.xcassets/jitsi.imageset/jitsi@2x.png
  28. 81
    0
      ios/app/watchos/extension/ComplicationController.swift
  29. 103
    0
      ios/app/watchos/extension/ExtensionDelegate.swift
  30. 109
    0
      ios/app/watchos/extension/InCallController.swift
  31. 44
    0
      ios/app/watchos/extension/Info.plist
  32. 80
    0
      ios/app/watchos/extension/InterfaceController.swift
  33. 27
    0
      ios/app/watchos/extension/JitsiMeetCommands.swift
  34. 71
    0
      ios/app/watchos/extension/JitsiMeetContext.swift
  35. 27
    0
      ios/app/watchos/extension/MeetingRowController.swift
  36. 5
    0
      package-lock.json
  37. 1
    0
      package.json
  38. 1
    0
      react/features/app/components/App.native.js
  39. 28
    0
      react/features/mobile/watchos/actionTypes.js
  40. 55
    0
      react/features/mobile/watchos/actions.js
  41. 11
    0
      react/features/mobile/watchos/constants.js
  42. 2
    0
      react/features/mobile/watchos/index.js
  43. 225
    0
      react/features/mobile/watchos/middleware.js
  44. 34
    0
      react/features/mobile/watchos/reducer.js

+ 1
- 0
ios/Podfile View File

@@ -51,6 +51,7 @@ target 'JitsiMeet' do
51 51
     :path => '../node_modules/react-native-google-signin'
52 52
   pod 'RNSound', :path => '../node_modules/react-native-sound'
53 53
   pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
54
+  pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
54 55
   pod 'react-native-calendar-events',
55 56
     :path => '../node_modules/react-native-calendar-events'
56 57
 end

+ 7
- 1
ios/Podfile.lock View File

@@ -156,6 +156,8 @@ PODS:
156 156
     - React/Core
157 157
   - RNVectorIcons (6.0.2):
158 158
     - React
159
+  - RNWatch (0.2.0):
160
+    - React
159 161
   - SDWebImage/Core (4.4.6)
160 162
   - SDWebImage/GIF (4.4.6):
161 163
     - FLAnimatedImage (~> 1.0)
@@ -191,6 +193,7 @@ DEPENDENCIES:
191 193
   - RNGoogleSignin (from `../node_modules/react-native-google-signin`)
192 194
   - RNSound (from `../node_modules/react-native-sound`)
193 195
   - RNVectorIcons (from `../node_modules/react-native-vector-icons`)
196
+  - RNWatch (from `../node_modules/react-native-watch-connectivity`)
194 197
   - yoga (from `../node_modules/react-native/ReactCommon/yoga`)
195 198
 
196 199
 SPEC REPOS:
@@ -242,6 +245,8 @@ EXTERNAL SOURCES:
242 245
     :path: "../node_modules/react-native-sound"
243 246
   RNVectorIcons:
244 247
     :path: "../node_modules/react-native-vector-icons"
248
+  RNWatch:
249
+    :path: "../node_modules/react-native-watch-connectivity"
245 250
   yoga:
246 251
     :path: "../node_modules/react-native/ReactCommon/yoga"
247 252
 
@@ -277,9 +282,10 @@ SPEC CHECKSUMS:
277 282
   RNGoogleSignin: 361174d9a3090d295b06257162b560d8efc8a6ed
278 283
   RNSound: e157320f503bdd4f4ee6d8542e948d54f90c3c3a
279 284
   RNVectorIcons: d819334932bcda3332deb3d2c8ea4d069e0b98f9
285
+  RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
280 286
   SDWebImage: 3f3f0c02f09798048c47a5ed0a13f17b063572d8
281 287
   yoga: 2e571f113e8cbeb0eb752aeebc86c1bfe7a8200c
282 288
 
283
-PODFILE CHECKSUM: 4a11c3d66127a9845d4a5b2c7fad49f58a9c7a89
289
+PODFILE CHECKSUM: 8e6caba6dab554c16a3d89d1fa8b69c70c5452d0
284 290
 
285 291
 COCOAPODS: 1.6.1

+ 364
- 0
ios/app/app.xcodeproj/project.pbxproj View File

@@ -11,16 +11,45 @@
11 11
 		0B26BE6F1EC5BC3C00EEFB41 /* JitsiMeet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12 12
 		0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */; };
13 13
 		0B412F211EDEE95300B1A0A6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B412F201EDEE95300B1A0A6 /* Main.storyboard */; };
14
+		0B5418471F7C5D8C00A2DD86 /* MeetingRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */; };
15
+		0B7001701F7C51CC005944F4 /* InCallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B70016F1F7C51CC005944F4 /* InCallController.swift */; };
14 16
 		0BD6B4371EF82A6B00D1F4CD /* WebRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */; };
15 17
 		0BD6B4381EF82A6B00D1F4CD /* WebRTC.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
18
+		0BEA5C291F7B8F73000D0AB4 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */; };
19
+		0BEA5C2B1F7B8F73000D0AB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C2A1F7B8F73000D0AB4 /* Assets.xcassets */; };
20
+		0BEA5C321F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
21
+		0BEA5C371F7B8F73000D0AB4 /* InterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C361F7B8F73000D0AB4 /* InterfaceController.swift */; };
22
+		0BEA5C391F7B8F73000D0AB4 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C381F7B8F73000D0AB4 /* ExtensionDelegate.swift */; };
23
+		0BEA5C3B1F7B8F73000D0AB4 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */; };
24
+		0BEA5C3D1F7B8F73000D0AB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */; };
25
+		0BEA5C411F7B8F73000D0AB4 /* JitsiMeetCompanion.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */; };
16 26
 		13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
17 27
 		13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
18 28
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
19 29
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
20 30
 		695AF3ED6F686F9C5EE40F9A /* libPods-jitsi-meet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 489E8EFE2C720D10F5961AEF /* libPods-jitsi-meet.a */; };
21 31
 		DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */; };
32
+		E588011722789D43008B0561 /* JitsiMeetContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E58801132278944E008B0561 /* JitsiMeetContext.swift */; };
33
+		E5C97B63227A1EB400199214 /* JitsiMeetCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C97B62227A1EB400199214 /* JitsiMeetCommands.swift */; };
22 34
 /* End PBXBuildFile section */
23 35
 
36
+/* Begin PBXContainerItemProxy section */
37
+		0BEA5C331F7B8F73000D0AB4 /* PBXContainerItemProxy */ = {
38
+			isa = PBXContainerItemProxy;
39
+			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
40
+			proxyType = 1;
41
+			remoteGlobalIDString = 0BEA5C301F7B8F73000D0AB4;
42
+			remoteInfo = "JitsiMeetCompanion Extension";
43
+		};
44
+		0BEA5C3F1F7B8F73000D0AB4 /* PBXContainerItemProxy */ = {
45
+			isa = PBXContainerItemProxy;
46
+			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
47
+			proxyType = 1;
48
+			remoteGlobalIDString = 0BEA5C241F7B8F73000D0AB4;
49
+			remoteInfo = JitsiMeetCompanion;
50
+		};
51
+/* End PBXContainerItemProxy section */
52
+
24 53
 /* Begin PBXCopyFilesBuildPhase section */
25 54
 		0B26BE701EC5BC3C00EEFB41 /* Embed Frameworks */ = {
26 55
 			isa = PBXCopyFilesBuildPhase;
@@ -34,6 +63,28 @@
34 63
 			name = "Embed Frameworks";
35 64
 			runOnlyForDeploymentPostprocessing = 0;
36 65
 		};
66
+		0BEA5C471F7B8F73000D0AB4 /* Embed App Extensions */ = {
67
+			isa = PBXCopyFilesBuildPhase;
68
+			buildActionMask = 2147483647;
69
+			dstPath = "";
70
+			dstSubfolderSpec = 13;
71
+			files = (
72
+				0BEA5C321F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex in Embed App Extensions */,
73
+			);
74
+			name = "Embed App Extensions";
75
+			runOnlyForDeploymentPostprocessing = 0;
76
+		};
77
+		0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */ = {
78
+			isa = PBXCopyFilesBuildPhase;
79
+			buildActionMask = 2147483647;
80
+			dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
81
+			dstSubfolderSpec = 16;
82
+			files = (
83
+				0BEA5C411F7B8F73000D0AB4 /* JitsiMeetCompanion.app in Embed Watch Content */,
84
+			);
85
+			name = "Embed Watch Content";
86
+			runOnlyForDeploymentPostprocessing = 0;
87
+		};
37 88
 /* End PBXCopyFilesBuildPhase section */
38 89
 
39 90
 /* Begin PBXFileReference section */
@@ -42,8 +93,20 @@
42 93
 		0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
43 94
 		0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
44 95
 		0B412F201EDEE95300B1A0A6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
96
+		0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingRowController.swift; sourceTree = "<group>"; };
97
+		0B70016F1F7C51CC005944F4 /* InCallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InCallController.swift; sourceTree = "<group>"; };
45 98
 		0BBD021F212EB69D00CCB19F /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
46 99
 		0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = "<group>"; };
100
+		0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JitsiMeetCompanion.app; sourceTree = BUILT_PRODUCTS_DIR; };
101
+		0BEA5C281F7B8F73000D0AB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = "<group>"; };
102
+		0BEA5C2A1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
103
+		0BEA5C2C1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
104
+		0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "JitsiMeetCompanion Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
105
+		0BEA5C361F7B8F73000D0AB4 /* InterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceController.swift; sourceTree = "<group>"; };
106
+		0BEA5C381F7B8F73000D0AB4 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = "<group>"; };
107
+		0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = "<group>"; };
108
+		0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
109
+		0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
47 110
 		13B07F961A680F5B00A75B9A /* jitsi-meet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jitsi-meet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
48 111
 		13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
49 112
 		13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -56,9 +119,18 @@
56 119
 		B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; sourceTree = "<group>"; };
57 120
 		DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRUtilities.m; sourceTree = "<group>"; };
58 121
 		DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRUtilities.h; sourceTree = "<group>"; };
122
+		E58801132278944E008B0561 /* JitsiMeetContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiMeetContext.swift; sourceTree = "<group>"; };
123
+		E5C97B62227A1EB400199214 /* JitsiMeetCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiMeetCommands.swift; sourceTree = "<group>"; };
59 124
 /* End PBXFileReference section */
60 125
 
61 126
 /* Begin PBXFrameworksBuildPhase section */
127
+		0BEA5C2E1F7B8F73000D0AB4 /* Frameworks */ = {
128
+			isa = PBXFrameworksBuildPhase;
129
+			buildActionMask = 2147483647;
130
+			files = (
131
+			);
132
+			runOnlyForDeploymentPostprocessing = 0;
133
+		};
62 134
 		13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
63 135
 			isa = PBXFrameworksBuildPhase;
64 136
 			buildActionMask = 2147483647;
@@ -69,6 +141,13 @@
69 141
 			);
70 142
 			runOnlyForDeploymentPostprocessing = 0;
71 143
 		};
144
+		1F021A8A5B056078665DE530 /* Frameworks */ = {
145
+			isa = PBXFrameworksBuildPhase;
146
+			buildActionMask = 2147483647;
147
+			files = (
148
+			);
149
+			runOnlyForDeploymentPostprocessing = 0;
150
+		};
72 151
 /* End PBXFrameworksBuildPhase section */
73 152
 
74 153
 /* Begin PBXGroup section */
@@ -82,6 +161,34 @@
82 161
 			name = Frameworks;
83 162
 			sourceTree = "<group>";
84 163
 		};
164
+		0BEA5C261F7B8F73000D0AB4 /* Watch app */ = {
165
+			isa = PBXGroup;
166
+			children = (
167
+				0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */,
168
+				0BEA5C2A1F7B8F73000D0AB4 /* Assets.xcassets */,
169
+				0BEA5C2C1F7B8F73000D0AB4 /* Info.plist */,
170
+			);
171
+			name = "Watch app";
172
+			path = watchos/app;
173
+			sourceTree = "<group>";
174
+		};
175
+		0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */ = {
176
+			isa = PBXGroup;
177
+			children = (
178
+				0BEA5C361F7B8F73000D0AB4 /* InterfaceController.swift */,
179
+				0BEA5C381F7B8F73000D0AB4 /* ExtensionDelegate.swift */,
180
+				0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */,
181
+				0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */,
182
+				0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */,
183
+				0B70016F1F7C51CC005944F4 /* InCallController.swift */,
184
+				0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */,
185
+				E58801132278944E008B0561 /* JitsiMeetContext.swift */,
186
+				E5C97B62227A1EB400199214 /* JitsiMeetCommands.swift */,
187
+			);
188
+			name = "WatchKit extension";
189
+			path = watchos/extension;
190
+			sourceTree = "<group>";
191
+		};
85 192
 		13B07FAE1A68108700A75B9A /* src */ = {
86 193
 			isa = PBXGroup;
87 194
 			children = (
@@ -118,6 +225,8 @@
118 225
 				83CBBA001A601CBA00E9B192 /* Products */,
119 226
 				13B07FAE1A68108700A75B9A /* src */,
120 227
 				5E96ADD5E49F3B3822EF9A52 /* Pods */,
228
+				0BEA5C261F7B8F73000D0AB4 /* Watch app */,
229
+				0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
121 230
 			);
122 231
 			indentWidth = 2;
123 232
 			sourceTree = "<group>";
@@ -127,6 +236,8 @@
127 236
 			isa = PBXGroup;
128 237
 			children = (
129 238
 				13B07F961A680F5B00A75B9A /* jitsi-meet.app */,
239
+				0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */,
240
+				0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */,
130 241
 			);
131 242
 			name = Products;
132 243
 			sourceTree = "<group>";
@@ -134,6 +245,41 @@
134 245
 /* End PBXGroup section */
135 246
 
136 247
 /* Begin PBXNativeTarget section */
248
+		0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */ = {
249
+			isa = PBXNativeTarget;
250
+			buildConfigurationList = 0BEA5C481F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion" */;
251
+			buildPhases = (
252
+				0BEA5C231F7B8F73000D0AB4 /* Resources */,
253
+				0BEA5C471F7B8F73000D0AB4 /* Embed App Extensions */,
254
+				1F021A8A5B056078665DE530 /* Frameworks */,
255
+			);
256
+			buildRules = (
257
+			);
258
+			dependencies = (
259
+				0BEA5C341F7B8F73000D0AB4 /* PBXTargetDependency */,
260
+			);
261
+			name = JitsiMeetCompanion;
262
+			productName = JitsiMeetCompanion;
263
+			productReference = 0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */;
264
+			productType = "com.apple.product-type.application.watchapp2";
265
+		};
266
+		0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */ = {
267
+			isa = PBXNativeTarget;
268
+			buildConfigurationList = 0BEA5C461F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion Extension" */;
269
+			buildPhases = (
270
+				0BEA5C2D1F7B8F73000D0AB4 /* Sources */,
271
+				0BEA5C2E1F7B8F73000D0AB4 /* Frameworks */,
272
+				0BEA5C2F1F7B8F73000D0AB4 /* Resources */,
273
+			);
274
+			buildRules = (
275
+			);
276
+			dependencies = (
277
+			);
278
+			name = "JitsiMeetCompanion Extension";
279
+			productName = "JitsiMeetCompanion Extension";
280
+			productReference = 0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */;
281
+			productType = "com.apple.product-type.watchkit2-extension";
282
+		};
137 283
 		13B07F861A680F5B00A75B9A /* jitsi-meet */ = {
138 284
 			isa = PBXNativeTarget;
139 285
 			buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "jitsi-meet" */;
@@ -150,10 +296,12 @@
150 296
 				DEC2069321CBBD6900072F03 /* Setup Fabric */,
151 297
 				DE11877A21EE09640078D059 /* Setup Google reverse URL handler */,
152 298
 				DE4F6D6E22005C0400DE699E /* Setup Dropbox */,
299
+				0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */,
153 300
 			);
154 301
 			buildRules = (
155 302
 			);
156 303
 			dependencies = (
304
+				0BEA5C401F7B8F73000D0AB4 /* PBXTargetDependency */,
157 305
 			);
158 306
 			name = "jitsi-meet";
159 307
 			productName = "Jitsi Meet";
@@ -169,6 +317,16 @@
169 317
 				LastUpgradeCheck = 1020;
170 318
 				ORGANIZATIONNAME = Facebook;
171 319
 				TargetAttributes = {
320
+					0BEA5C241F7B8F73000D0AB4 = {
321
+						CreatedOnToolsVersion = 9.0;
322
+						DevelopmentTeam = FC967L3QRG;
323
+						ProvisioningStyle = Automatic;
324
+					};
325
+					0BEA5C301F7B8F73000D0AB4 = {
326
+						CreatedOnToolsVersion = 9.0;
327
+						DevelopmentTeam = FC967L3QRG;
328
+						ProvisioningStyle = Automatic;
329
+					};
172 330
 					13B07F861A680F5B00A75B9A = {
173 331
 						DevelopmentTeam = FC967L3QRG;
174 332
 						ProvisioningStyle = Automatic;
@@ -197,11 +355,30 @@
197 355
 			projectRoot = "";
198 356
 			targets = (
199 357
 				13B07F861A680F5B00A75B9A /* jitsi-meet */,
358
+				0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */,
359
+				0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */,
200 360
 			);
201 361
 		};
202 362
 /* End PBXProject section */
203 363
 
204 364
 /* Begin PBXResourcesBuildPhase section */
365
+		0BEA5C231F7B8F73000D0AB4 /* Resources */ = {
366
+			isa = PBXResourcesBuildPhase;
367
+			buildActionMask = 2147483647;
368
+			files = (
369
+				0BEA5C2B1F7B8F73000D0AB4 /* Assets.xcassets in Resources */,
370
+				0BEA5C291F7B8F73000D0AB4 /* Interface.storyboard in Resources */,
371
+			);
372
+			runOnlyForDeploymentPostprocessing = 0;
373
+		};
374
+		0BEA5C2F1F7B8F73000D0AB4 /* Resources */ = {
375
+			isa = PBXResourcesBuildPhase;
376
+			buildActionMask = 2147483647;
377
+			files = (
378
+				0BEA5C3D1F7B8F73000D0AB4 /* Assets.xcassets in Resources */,
379
+			);
380
+			runOnlyForDeploymentPostprocessing = 0;
381
+		};
205 382
 		13B07F8E1A680F5B00A75B9A /* Resources */ = {
206 383
 			isa = PBXResourcesBuildPhase;
207 384
 			buildActionMask = 2147483647;
@@ -354,6 +531,20 @@
354 531
 /* End PBXShellScriptBuildPhase section */
355 532
 
356 533
 /* Begin PBXSourcesBuildPhase section */
534
+		0BEA5C2D1F7B8F73000D0AB4 /* Sources */ = {
535
+			isa = PBXSourcesBuildPhase;
536
+			buildActionMask = 2147483647;
537
+			files = (
538
+				0B7001701F7C51CC005944F4 /* InCallController.swift in Sources */,
539
+				E5C97B63227A1EB400199214 /* JitsiMeetCommands.swift in Sources */,
540
+				0B5418471F7C5D8C00A2DD86 /* MeetingRowController.swift in Sources */,
541
+				E588011722789D43008B0561 /* JitsiMeetContext.swift in Sources */,
542
+				0BEA5C391F7B8F73000D0AB4 /* ExtensionDelegate.swift in Sources */,
543
+				0BEA5C371F7B8F73000D0AB4 /* InterfaceController.swift in Sources */,
544
+				0BEA5C3B1F7B8F73000D0AB4 /* ComplicationController.swift in Sources */,
545
+			);
546
+			runOnlyForDeploymentPostprocessing = 0;
547
+		};
357 548
 		13B07F871A680F5B00A75B9A /* Sources */ = {
358 549
 			isa = PBXSourcesBuildPhase;
359 550
 			buildActionMask = 2147483647;
@@ -367,7 +558,28 @@
367 558
 		};
368 559
 /* End PBXSourcesBuildPhase section */
369 560
 
561
+/* Begin PBXTargetDependency section */
562
+		0BEA5C341F7B8F73000D0AB4 /* PBXTargetDependency */ = {
563
+			isa = PBXTargetDependency;
564
+			target = 0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */;
565
+			targetProxy = 0BEA5C331F7B8F73000D0AB4 /* PBXContainerItemProxy */;
566
+		};
567
+		0BEA5C401F7B8F73000D0AB4 /* PBXTargetDependency */ = {
568
+			isa = PBXTargetDependency;
569
+			target = 0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */;
570
+			targetProxy = 0BEA5C3F1F7B8F73000D0AB4 /* PBXContainerItemProxy */;
571
+		};
572
+/* End PBXTargetDependency section */
573
+
370 574
 /* Begin PBXVariantGroup section */
575
+		0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */ = {
576
+			isa = PBXVariantGroup;
577
+			children = (
578
+				0BEA5C281F7B8F73000D0AB4 /* Base */,
579
+			);
580
+			name = Interface.storyboard;
581
+			sourceTree = "<group>";
582
+		};
371 583
 		13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
372 584
 			isa = PBXVariantGroup;
373 585
 			children = (
@@ -379,6 +591,140 @@
379 591
 /* End PBXVariantGroup section */
380 592
 
381 593
 /* Begin XCBuildConfiguration section */
594
+		0BEA5C421F7B8F73000D0AB4 /* Debug */ = {
595
+			isa = XCBuildConfiguration;
596
+			buildSettings = {
597
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
598
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
599
+				CLANG_ANALYZER_NONNULL = YES;
600
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
601
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
602
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
603
+				CLANG_WARN_COMMA = YES;
604
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
605
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
606
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
607
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
608
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
609
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
610
+				CODE_SIGN_STYLE = Automatic;
611
+				DEBUG_INFORMATION_FORMAT = dwarf;
612
+				DEVELOPMENT_TEAM = FC967L3QRG;
613
+				GCC_C_LANGUAGE_STANDARD = gnu11;
614
+				IBSC_MODULE = JitsiMeetCompanion_Extension;
615
+				INFOPLIST_FILE = watchos/app/Info.plist;
616
+				PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit;
617
+				PRODUCT_NAME = "$(TARGET_NAME)";
618
+				SDKROOT = watchos;
619
+				SKIP_INSTALL = YES;
620
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
621
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
622
+				SWIFT_VERSION = 5.0;
623
+				TARGETED_DEVICE_FAMILY = 4;
624
+				WATCHOS_DEPLOYMENT_TARGET = 4.0;
625
+			};
626
+			name = Debug;
627
+		};
628
+		0BEA5C431F7B8F73000D0AB4 /* Release */ = {
629
+			isa = XCBuildConfiguration;
630
+			buildSettings = {
631
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
632
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
633
+				CLANG_ANALYZER_NONNULL = YES;
634
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
635
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
636
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
637
+				CLANG_WARN_COMMA = YES;
638
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
639
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
640
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
641
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
642
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
643
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
644
+				CODE_SIGN_STYLE = Automatic;
645
+				COPY_PHASE_STRIP = NO;
646
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
647
+				DEVELOPMENT_TEAM = FC967L3QRG;
648
+				GCC_C_LANGUAGE_STANDARD = gnu11;
649
+				IBSC_MODULE = JitsiMeetCompanion_Extension;
650
+				INFOPLIST_FILE = watchos/app/Info.plist;
651
+				PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit;
652
+				PRODUCT_NAME = "$(TARGET_NAME)";
653
+				SDKROOT = watchos;
654
+				SKIP_INSTALL = YES;
655
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
656
+				SWIFT_VERSION = 5.0;
657
+				TARGETED_DEVICE_FAMILY = 4;
658
+				WATCHOS_DEPLOYMENT_TARGET = 4.0;
659
+			};
660
+			name = Release;
661
+		};
662
+		0BEA5C441F7B8F73000D0AB4 /* Debug */ = {
663
+			isa = XCBuildConfiguration;
664
+			buildSettings = {
665
+				ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
666
+				CLANG_ANALYZER_NONNULL = YES;
667
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
668
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
669
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
670
+				CLANG_WARN_COMMA = YES;
671
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
672
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
673
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
674
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
675
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
676
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
677
+				CODE_SIGN_STYLE = Automatic;
678
+				DEBUG_INFORMATION_FORMAT = dwarf;
679
+				DEVELOPMENT_TEAM = FC967L3QRG;
680
+				GCC_C_LANGUAGE_STANDARD = gnu11;
681
+				INFOPLIST_FILE = watchos/extension/Info.plist;
682
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
683
+				PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit.extension;
684
+				PRODUCT_NAME = "${TARGET_NAME}";
685
+				SDKROOT = watchos;
686
+				SKIP_INSTALL = YES;
687
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
688
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
689
+				SWIFT_VERSION = 5.0;
690
+				TARGETED_DEVICE_FAMILY = 4;
691
+				WATCHOS_DEPLOYMENT_TARGET = 4.0;
692
+			};
693
+			name = Debug;
694
+		};
695
+		0BEA5C451F7B8F73000D0AB4 /* Release */ = {
696
+			isa = XCBuildConfiguration;
697
+			buildSettings = {
698
+				ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
699
+				CLANG_ANALYZER_NONNULL = YES;
700
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
701
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
702
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
703
+				CLANG_WARN_COMMA = YES;
704
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
705
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
706
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
707
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
708
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
709
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
710
+				CODE_SIGN_STYLE = Automatic;
711
+				COPY_PHASE_STRIP = NO;
712
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
713
+				DEVELOPMENT_TEAM = FC967L3QRG;
714
+				GCC_C_LANGUAGE_STANDARD = gnu11;
715
+				INFOPLIST_FILE = watchos/extension/Info.plist;
716
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
717
+				PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit.extension;
718
+				PRODUCT_NAME = "${TARGET_NAME}";
719
+				SDKROOT = watchos;
720
+				SKIP_INSTALL = YES;
721
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
722
+				SWIFT_VERSION = 5.0;
723
+				TARGETED_DEVICE_FAMILY = 4;
724
+				WATCHOS_DEPLOYMENT_TARGET = 4.0;
725
+			};
726
+			name = Release;
727
+		};
382 728
 		13B07F941A680F5B00A75B9A /* Debug */ = {
383 729
 			isa = XCBuildConfiguration;
384 730
 			baseConfigurationReference = 4670A512A688E2DC34528282 /* Pods-jitsi-meet.debug.xcconfig */;
@@ -566,6 +912,24 @@
566 912
 /* End XCBuildConfiguration section */
567 913
 
568 914
 /* Begin XCConfigurationList section */
915
+		0BEA5C461F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion Extension" */ = {
916
+			isa = XCConfigurationList;
917
+			buildConfigurations = (
918
+				0BEA5C441F7B8F73000D0AB4 /* Debug */,
919
+				0BEA5C451F7B8F73000D0AB4 /* Release */,
920
+			);
921
+			defaultConfigurationIsVisible = 0;
922
+			defaultConfigurationName = Release;
923
+		};
924
+		0BEA5C481F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion" */ = {
925
+			isa = XCConfigurationList;
926
+			buildConfigurations = (
927
+				0BEA5C421F7B8F73000D0AB4 /* Debug */,
928
+				0BEA5C431F7B8F73000D0AB4 /* Release */,
929
+			);
930
+			defaultConfigurationIsVisible = 0;
931
+			defaultConfigurationName = Release;
932
+		};
569 933
 		13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "jitsi-meet" */ = {
570 934
 			isa = XCConfigurationList;
571 935
 			buildConfigurations = (

+ 92
- 0
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Contents.json View File

@@ -0,0 +1,92 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "size" : "24x24",
5
+      "idiom" : "watch",
6
+      "filename" : "Icon-24@2x.png",
7
+      "scale" : "2x",
8
+      "role" : "notificationCenter",
9
+      "subtype" : "38mm"
10
+    },
11
+    {
12
+      "size" : "27.5x27.5",
13
+      "idiom" : "watch",
14
+      "filename" : "Icon-27.5@2x.png",
15
+      "scale" : "2x",
16
+      "role" : "notificationCenter",
17
+      "subtype" : "42mm"
18
+    },
19
+    {
20
+      "size" : "29x29",
21
+      "idiom" : "watch",
22
+      "filename" : "Icon-29@2x.png",
23
+      "role" : "companionSettings",
24
+      "scale" : "2x"
25
+    },
26
+    {
27
+      "size" : "29x29",
28
+      "idiom" : "watch",
29
+      "filename" : "Icon-29@3x.png",
30
+      "role" : "companionSettings",
31
+      "scale" : "3x"
32
+    },
33
+    {
34
+      "size" : "40x40",
35
+      "idiom" : "watch",
36
+      "filename" : "Icon-40@2x.png",
37
+      "scale" : "2x",
38
+      "role" : "appLauncher",
39
+      "subtype" : "38mm"
40
+    },
41
+    {
42
+      "size" : "44x44",
43
+      "idiom" : "watch",
44
+      "filename" : "Icon-88@2x.png",
45
+      "scale" : "2x",
46
+      "role" : "appLauncher",
47
+      "subtype" : "40mm"
48
+    },
49
+    {
50
+      "size" : "50x50",
51
+      "idiom" : "watch",
52
+      "filename" : "Icon-100@2x.png",
53
+      "scale" : "2x",
54
+      "role" : "appLauncher",
55
+      "subtype" : "44mm"
56
+    },
57
+    {
58
+      "size" : "86x86",
59
+      "idiom" : "watch",
60
+      "filename" : "Icon-86@2x.png",
61
+      "scale" : "2x",
62
+      "role" : "quickLook",
63
+      "subtype" : "38mm"
64
+    },
65
+    {
66
+      "size" : "98x98",
67
+      "idiom" : "watch",
68
+      "filename" : "Icon-98@2x.png",
69
+      "scale" : "2x",
70
+      "role" : "quickLook",
71
+      "subtype" : "42mm"
72
+    },
73
+    {
74
+      "size" : "108x108",
75
+      "idiom" : "watch",
76
+      "filename" : "Icon-216@2x.png",
77
+      "scale" : "2x",
78
+      "role" : "quickLook",
79
+      "subtype" : "44mm"
80
+    },
81
+    {
82
+      "size" : "1024x1024",
83
+      "idiom" : "watch-marketing",
84
+      "filename" : "Icon-1024@1x.png",
85
+      "scale" : "1x"
86
+    }
87
+  ],
88
+  "info" : {
89
+    "version" : 1,
90
+    "author" : "xcode"
91
+  }
92
+}

BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-100@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-1024@1x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-216@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-24@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-27.5@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-86@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-88@2x.png View File


BIN
ios/app/watchos/app/Assets.xcassets/AppIcon.appiconset/Icon-98@2x.png View File


+ 6
- 0
ios/app/watchos/app/Assets.xcassets/Contents.json View File

@@ -0,0 +1,6 @@
1
+{
2
+  "info" : {
3
+    "version" : 1,
4
+    "author" : "xcode"
5
+  }
6
+}

+ 21
- 0
ios/app/watchos/app/Assets.xcassets/hangup.imageset/Contents.json View File

@@ -0,0 +1,21 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "idiom" : "universal",
5
+      "scale" : "1x"
6
+    },
7
+    {
8
+      "idiom" : "universal",
9
+      "filename" : "hangup@2x.png",
10
+      "scale" : "2x"
11
+    },
12
+    {
13
+      "idiom" : "universal",
14
+      "scale" : "3x"
15
+    }
16
+  ],
17
+  "info" : {
18
+    "version" : 1,
19
+    "author" : "xcode"
20
+  }
21
+}

BIN
ios/app/watchos/app/Assets.xcassets/hangup.imageset/hangup@2x.png View File


+ 21
- 0
ios/app/watchos/app/Assets.xcassets/mute-off.imageset/Contents.json View File

@@ -0,0 +1,21 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "idiom" : "universal",
5
+      "scale" : "1x"
6
+    },
7
+    {
8
+      "idiom" : "universal",
9
+      "filename" : "mute-off@2x.png",
10
+      "scale" : "2x"
11
+    },
12
+    {
13
+      "idiom" : "universal",
14
+      "scale" : "3x"
15
+    }
16
+  ],
17
+  "info" : {
18
+    "version" : 1,
19
+    "author" : "xcode"
20
+  }
21
+}

BIN
ios/app/watchos/app/Assets.xcassets/mute-off.imageset/mute-off@2x.png View File


+ 21
- 0
ios/app/watchos/app/Assets.xcassets/mute-on.imageset/Contents.json View File

@@ -0,0 +1,21 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "idiom" : "universal",
5
+      "scale" : "1x"
6
+    },
7
+    {
8
+      "idiom" : "universal",
9
+      "filename" : "mute-on@2x.png",
10
+      "scale" : "2x"
11
+    },
12
+    {
13
+      "idiom" : "universal",
14
+      "scale" : "3x"
15
+    }
16
+  ],
17
+  "info" : {
18
+    "version" : 1,
19
+    "author" : "xcode"
20
+  }
21
+}

BIN
ios/app/watchos/app/Assets.xcassets/mute-on.imageset/mute-on@2x.png View File


+ 83
- 0
ios/app/watchos/app/Base.lproj/Interface.storyboard View File

@@ -0,0 +1,83 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="14490.70" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
3
+    <device id="watch38" orientation="portrait">
4
+        <adaptation id="fullscreen"/>
5
+    </device>
6
+    <dependencies>
7
+        <deployment identifier="watchOS"/>
8
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
9
+        <plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="14490.21"/>
10
+    </dependencies>
11
+    <scenes>
12
+        <!--Meetings-->
13
+        <scene sceneID="aou-V4-d1y">
14
+            <objects>
15
+                <controller title="Meetings" id="AgC-eL-Hgc" customClass="InterfaceController" customModule="JitsiMeetCompanion" customModuleProvider="target">
16
+                    <items>
17
+                        <table alignment="left" id="gpO-ql-Xsr">
18
+                            <items>
19
+                                <tableRow identifier="MeetingRowType" id="GGl-av-xeJ" customClass="MeetingRowController" customModule="JitsiMeetCompanion_Extension">
20
+                                    <group key="rootItem" width="1" height="0.0" alignment="left" layout="vertical" id="5XE-gq-qzG">
21
+                                        <items>
22
+                                            <label alignment="left" text="Label" id="Sij-up-N4p"/>
23
+                                            <label alignment="left" text="Label" id="V5K-sm-jEH">
24
+                                                <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
25
+                                                <fontDescription key="font" style="UICTFontTextStyleFootnote"/>
26
+                                            </label>
27
+                                        </items>
28
+                                        <connections>
29
+                                            <segue destination="9RD-qP-1Z0" kind="push" id="Boa-6E-eZs"/>
30
+                                        </connections>
31
+                                    </group>
32
+                                    <connections>
33
+                                        <outlet property="roomLabel" destination="Sij-up-N4p" id="PdS-SO-ylc"/>
34
+                                        <outlet property="rowGroup" destination="5XE-gq-qzG" id="GZN-2c-2Gz"/>
35
+                                        <outlet property="timeLabel" destination="V5K-sm-jEH" id="fWQ-kx-vE4"/>
36
+                                    </connections>
37
+                                </tableRow>
38
+                            </items>
39
+                        </table>
40
+                    </items>
41
+                    <connections>
42
+                        <outlet property="table" destination="gpO-ql-Xsr" id="aVV-iZ-z3l"/>
43
+                    </connections>
44
+                </controller>
45
+            </objects>
46
+            <point key="canvasLocation" x="-99" y="117"/>
47
+        </scene>
48
+        <!--Meetings-->
49
+        <scene sceneID="ns4-Kh-qqU">
50
+            <objects>
51
+                <controller identifier="InCallController" title="Meetings" hidesWhenLoading="NO" id="9RD-qP-1Z0" customClass="InCallController" customModule="JitsiMeetCompanion" customModuleProvider="target">
52
+                    <items>
53
+                        <label alignment="center" text="Label" id="vFt-lL-SNY"/>
54
+                        <timer alignment="center" textAlignment="center" previewedSeconds="0" id="W8S-uZ-MPm">
55
+                            <color key="textColor" red="0.024725984125768763" green="1" blue="0.24241188365329402" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
56
+                            <fontDescription key="font" style="UICTFontTextStyleHeadline"/>
57
+                        </timer>
58
+                        <group alignment="center" verticalAlignment="bottom" spacing="10" id="Hfk-a0-uWj">
59
+                            <items>
60
+                                <button width="60" height="60" alignment="left" verticalAlignment="bottom" backgroundImage="hangup" id="8jF-SI-UHz">
61
+                                    <connections>
62
+                                        <action selector="hangupClicked" destination="9RD-qP-1Z0" id="cXK-lw-tsd"/>
63
+                                    </connections>
64
+                                </button>
65
+                                <button width="60" height="60" alignment="right" verticalAlignment="bottom" backgroundImage="mute-off" id="LmN-FI-aQq">
66
+                                    <connections>
67
+                                        <action selector="muteClicked" destination="9RD-qP-1Z0" id="dJg-kV-cqH"/>
68
+                                    </connections>
69
+                                </button>
70
+                            </items>
71
+                        </group>
72
+                    </items>
73
+                    <connections>
74
+                        <outlet property="mutedButton" destination="LmN-FI-aQq" id="gfi-4T-gdN"/>
75
+                        <outlet property="roomLabel" destination="vFt-lL-SNY" id="cYB-Tf-Efz"/>
76
+                        <outlet property="timer" destination="W8S-uZ-MPm" id="r7T-j1-9VJ"/>
77
+                    </connections>
78
+                </controller>
79
+            </objects>
80
+            <point key="canvasLocation" x="213" y="117"/>
81
+        </scene>
82
+    </scenes>
83
+</document>

+ 33
- 0
ios/app/watchos/app/Info.plist View File

@@ -0,0 +1,33 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
7
+	<key>CFBundleDisplayName</key>
8
+	<string>Jitsi Meet</string>
9
+	<key>CFBundleExecutable</key>
10
+	<string>$(EXECUTABLE_NAME)</string>
11
+	<key>CFBundleIdentifier</key>
12
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+	<key>CFBundleInfoDictionaryVersion</key>
14
+	<string>6.0</string>
15
+	<key>CFBundleName</key>
16
+	<string>$(PRODUCT_NAME)</string>
17
+	<key>CFBundlePackageType</key>
18
+	<string>APPL</string>
19
+	<key>CFBundleShortVersionString</key>
20
+	<string>19.2.0</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+	<key>UISupportedInterfaceOrientations</key>
24
+	<array>
25
+		<string>UIInterfaceOrientationPortrait</string>
26
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
27
+	</array>
28
+	<key>WKCompanionAppBundleIdentifier</key>
29
+	<string>org.jitsi.meet</string>
30
+	<key>WKWatchKitApp</key>
31
+	<true/>
32
+</dict>
33
+</plist>

+ 6
- 0
ios/app/watchos/extension/Assets.xcassets/Contents.json View File

@@ -0,0 +1,6 @@
1
+{
2
+  "info" : {
3
+    "version" : 1,
4
+    "author" : "xcode"
5
+  }
6
+}

+ 21
- 0
ios/app/watchos/extension/Assets.xcassets/jitsi.imageset/Contents.json View File

@@ -0,0 +1,21 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "idiom" : "universal",
5
+      "scale" : "1x"
6
+    },
7
+    {
8
+      "idiom" : "universal",
9
+      "filename" : "jitsi@2x.png",
10
+      "scale" : "2x"
11
+    },
12
+    {
13
+      "idiom" : "universal",
14
+      "scale" : "3x"
15
+    }
16
+  ],
17
+  "info" : {
18
+    "version" : 1,
19
+    "author" : "xcode"
20
+  }
21
+}

BIN
ios/app/watchos/extension/Assets.xcassets/jitsi.imageset/jitsi@2x.png View File


+ 81
- 0
ios/app/watchos/extension/ComplicationController.swift View File

@@ -0,0 +1,81 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+import ClockKit
19
+
20
+
21
+class ComplicationController: NSObject, CLKComplicationDataSource {
22
+
23
+    // MARK: - Timeline Configuration
24
+
25
+    func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void) {
26
+        handler([])
27
+    }
28
+
29
+    func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
30
+        handler(.showOnLockScreen)
31
+    }
32
+
33
+    // MARK: - Timeline Population
34
+
35
+    func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
36
+        // Call the handler with the current timeline entry
37
+        getLocalizableSampleTemplate(for: complication) {template in
38
+            guard let template = template else {
39
+                handler(nil)
40
+                return
41
+            }
42
+            handler(CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template))
43
+        }
44
+    }
45
+
46
+    func getTimelineEntries(for complication: CLKComplication, before date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
47
+        // Call the handler with the timeline entries prior to the given date
48
+        handler(nil)
49
+    }
50
+
51
+    func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
52
+        // Call the handler with the timeline entries after to the given date
53
+        handler(nil)
54
+    }
55
+
56
+    // MARK: - Placeholder Templates
57
+
58
+    func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
59
+        // This method will be called once per supported complication, and the results will be cached
60
+
61
+        let imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "jitsi")!)
62
+        if complication.family == .circularSmall {
63
+            let small = CLKComplicationTemplateCircularSmallRingImage()
64
+            small.imageProvider = imageProvider
65
+            small.ringStyle = .closed
66
+            small.fillFraction = 0
67
+            handler(small)
68
+        } else if complication.family == .utilitarianSmall {
69
+            let utilitarian = CLKComplicationTemplateUtilitarianSmallSquare()
70
+            utilitarian.imageProvider = imageProvider
71
+            handler(utilitarian)
72
+        } else if complication.family == .modularSmall {
73
+            let modular = CLKComplicationTemplateModularSmallRingImage()
74
+            modular.imageProvider = imageProvider
75
+            modular.ringStyle = .closed
76
+            modular.fillFraction = 0
77
+            handler(modular)
78
+        }
79
+    }
80
+
81
+}

+ 103
- 0
ios/app/watchos/extension/ExtensionDelegate.swift View File

@@ -0,0 +1,103 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+import WatchConnectivity
19
+import WatchKit
20
+
21
+class ExtensionDelegate: NSObject, WCSessionDelegate, WKExtensionDelegate {
22
+
23
+    var currentContext : JitsiMeetContext = JitsiMeetContext()
24
+
25
+    static var currentJitsiMeetContext: JitsiMeetContext {
26
+        get {
27
+            return (WKExtension.shared().delegate as! ExtensionDelegate).currentContext
28
+        }
29
+    }
30
+
31
+    func applicationDidFinishLaunching() {
32
+        // Start Watch Connectivity
33
+        if WCSession.isSupported() {
34
+            let session  = WCSession.default
35
+            session.delegate = self
36
+            session.activate()
37
+        }
38
+    }
39
+
40
+    func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
41
+        // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
42
+        for task in backgroundTasks {
43
+            // Use a switch statement to check the task type
44
+            switch task {
45
+            case let backgroundTask as WKApplicationRefreshBackgroundTask:
46
+                // Be sure to complete the background task once you’re done.
47
+                backgroundTask.setTaskCompletedWithSnapshot(false)
48
+            case let snapshotTask as WKSnapshotRefreshBackgroundTask:
49
+                // Snapshot tasks have a unique completion call, make sure to set your expiration date
50
+                snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
51
+            case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
52
+                // Be sure to complete the connectivity task once you’re done.
53
+                connectivityTask.setTaskCompletedWithSnapshot(false)
54
+            case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
55
+                // Be sure to complete the URL session task once you’re done.
56
+                urlSessionTask.setTaskCompletedWithSnapshot(false)
57
+            default:
58
+                // make sure to complete unhandled task types
59
+                task.setTaskCompletedWithSnapshot(false)
60
+            }
61
+        }
62
+    }
63
+
64
+    func session(_ session: WCSession, activationDidCompleteWith
65
+        activationState: WCSessionActivationState, error: Error?) {
66
+        if let error = error {
67
+            print("WATCH Session activation failed with error: \(error.localizedDescription)")
68
+            return
69
+        }
70
+        print("WATCH Session activated with state: \(activationState.rawValue)")
71
+    }
72
+
73
+    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
74
+        DispatchQueue.main.async {
75
+            let newContext = JitsiMeetContext(context: applicationContext)
76
+
77
+            print("WATCH got new context: \(newContext.description)");
78
+
79
+            // Update context on the root controller which displays the recent list
80
+            let controller = WKExtension.shared().rootInterfaceController as! InterfaceController
81
+            controller.updateUI(newContext)
82
+
83
+            // If the current controller is not the in-call controller and we have a
84
+            // conference URL, show the in-call controller
85
+            if let currentController = WKExtension.shared().visibleInterfaceController as? InterfaceController {
86
+                // Go to the in-call controller only if the conference URL has changed, because the user may have
87
+                // clicked the back button
88
+                if newContext.conferenceURL != nil
89
+                        && self.currentContext.conferenceURL != newContext.conferenceURL {
90
+                      currentController.pushController(withName: "InCallController", context: newContext)
91
+                }
92
+            } else if let inCallController = WKExtension.shared().visibleInterfaceController as? InCallController {
93
+                if newContext.conferenceURL == nil {
94
+                      inCallController.popToRootController()
95
+                } else {
96
+                      inCallController.updateUI(newContext)
97
+                }
98
+            }
99
+
100
+            self.currentContext = newContext;
101
+        }
102
+    }
103
+}

+ 109
- 0
ios/app/watchos/extension/InCallController.swift View File

@@ -0,0 +1,109 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+import WatchConnectivity
19
+import WatchKit
20
+import Foundation
21
+
22
+
23
+class InCallController: WKInterfaceController {
24
+    @IBOutlet var mutedButton: WKInterfaceButton!
25
+    @IBOutlet var roomLabel: WKInterfaceLabel!
26
+    @IBOutlet var timer: WKInterfaceTimer!
27
+
28
+    @IBAction func hangupClicked() {
29
+      sendCommand(JitsiMeetCommands.CMD_HANG_UP, message: nil)
30
+    }
31
+
32
+    @IBAction func muteClicked() {
33
+        if var micMuted = ExtensionDelegate.currentJitsiMeetContext.micMuted {
34
+            micMuted = !micMuted;
35
+            sendCommand(
36
+                JitsiMeetCommands.CMD_SET_MUTED,
37
+                message: [
38
+                  "muted": micMuted ? "true" : "false"
39
+                ])
40
+            updateMutedButton(withMuted: micMuted)
41
+        }
42
+    }
43
+
44
+  func sendCommand(_ command: JitsiMeetCommands, message: [String : Any]?) {
45
+        if WCSession.isSupported() {
46
+            let session = WCSession.default
47
+            var data = [String: Any]()
48
+
49
+            if let sessionID = ExtensionDelegate.currentJitsiMeetContext.sessionID {
50
+                if message != nil {
51
+                    message!.forEach { data[$0] = $1 }
52
+                }
53
+              
54
+                data["command"] = command.rawValue;
55
+                data["sessionID"] = sessionID;
56
+              
57
+                session.sendMessage(data, replyHandler: nil, errorHandler: nil)
58
+            }
59
+        }
60
+    }
61
+  
62
+    func updateUI(_ newContext: JitsiMeetContext) {
63
+        var conferenceURL = newContext.conferenceURL
64
+
65
+        if let joinConferenceURL = newContext.joinConferenceURL {
66
+            sendCommand(JitsiMeetCommands.CMD_JOIN_CONFERENCE, message: [ "data" : joinConferenceURL ])
67
+            conferenceURL = joinConferenceURL
68
+        }
69
+
70
+        let newRoomName = conferenceURL != nil ? conferenceURL!.components(separatedBy: "/").last : ""
71
+      
72
+        roomLabel.setText(newRoomName)
73
+      
74
+        if let newTimestamp = newContext.conferenceTimestamp {
75
+            restartTimer(newTimestamp)
76
+        }
77
+        if let newMuted = newContext.micMuted {
78
+            updateMutedButton(withMuted: newMuted)
79
+        }
80
+    }
81
+
82
+    func restartTimer(_ conferenceTimestamp: Int64) {
83
+        if (conferenceTimestamp != 0) {
84
+            let newDate = Date(timeIntervalSince1970: TimeInterval(conferenceTimestamp / 1000))
85
+            timer.setDate(newDate)
86
+            timer.start();
87
+            print("WATCH timer set date to: \(newDate) and start")
88
+        } else {
89
+            print("WATCH timer stop")
90
+            timer.stop();
91
+        }
92
+    }
93
+
94
+    func updateMutedButton(withMuted isMuted: Bool) {
95
+      if isMuted {
96
+          mutedButton.setBackgroundImageNamed("mute-on.png")
97
+      } else {
98
+          mutedButton.setBackgroundImageNamed("mute-off.png")
99
+      }
100
+    }
101
+
102
+    override func awake(withContext context: Any?) {
103
+        super.awake(withContext: context)
104
+
105
+        if let data = context as? JitsiMeetContext {
106
+          updateUI(data)
107
+        }
108
+    }
109
+}

+ 44
- 0
ios/app/watchos/extension/Info.plist View File

@@ -0,0 +1,44 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
7
+	<key>CFBundleDisplayName</key>
8
+	<string>Jitsi Meet Companion Extension</string>
9
+	<key>CFBundleExecutable</key>
10
+	<string>$(EXECUTABLE_NAME)</string>
11
+	<key>CFBundleIdentifier</key>
12
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+	<key>CFBundleInfoDictionaryVersion</key>
14
+	<string>6.0</string>
15
+	<key>CFBundleName</key>
16
+	<string>$(PRODUCT_NAME)</string>
17
+	<key>CFBundlePackageType</key>
18
+	<string>XPC!</string>
19
+	<key>CFBundleShortVersionString</key>
20
+	<string>19.2.0</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>1</string>
23
+	<key>CLKComplicationPrincipalClass</key>
24
+	<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
25
+	<key>CLKComplicationSupportedFamilies</key>
26
+	<array>
27
+		<string>CLKComplicationFamilyModularSmall</string>
28
+		<string>CLKComplicationFamilyUtilitarianSmall</string>
29
+		<string>CLKComplicationFamilyCircularSmall</string>
30
+	</array>
31
+	<key>NSExtension</key>
32
+	<dict>
33
+		<key>NSExtensionAttributes</key>
34
+		<dict>
35
+			<key>WKAppBundleIdentifier</key>
36
+			<string>org.jitsi.meet.watchkit</string>
37
+		</dict>
38
+		<key>NSExtensionPointIdentifier</key>
39
+		<string>com.apple.watchkit</string>
40
+	</dict>
41
+	<key>WKExtensionDelegateClassName</key>
42
+	<string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string>
43
+</dict>
44
+</plist>

+ 80
- 0
ios/app/watchos/extension/InterfaceController.swift View File

@@ -0,0 +1,80 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+import WatchKit
19
+import Foundation
20
+
21
+
22
+class InterfaceController: WKInterfaceController {
23
+
24
+    @IBOutlet var table: WKInterfaceTable!
25
+
26
+    func updateUI(_ newContext:JitsiMeetContext) {
27
+        if let recentURLsArray = newContext.recentURLs {
28
+            updateRecents(withRecents:  recentURLsArray, currentContext: newContext)
29
+        }
30
+    }
31
+
32
+    private func updateRecents(withRecents recents: NSArray, currentContext: JitsiMeetContext) {
33
+        // Updating the # of rows only if it actually changed prevents from blinking the UI
34
+        if (table.numberOfRows != recents.count) {
35
+            table.setNumberOfRows(recents.count, withRowType: "MeetingRowType")
36
+        }
37
+
38
+        for (index, entry) in recents.enumerated() {
39
+            let entryDict = entry as! NSDictionary
40
+            let roomURL = entryDict["conference"] as! NSString
41
+            let timestamp = entryDict["date"] as! NSNumber
42
+
43
+            // Prepare values
44
+            let room = roomURL.components(separatedBy: "/").last
45
+            let date = Date(timeIntervalSince1970: timestamp.doubleValue / 1000)  // timestamp is taken with Date.now() in JS, which uses milliseconds
46
+            let dateFormatter = DateFormatter()
47
+            dateFormatter.timeZone = TimeZone.current
48
+            dateFormatter.locale = NSLocale.current
49
+            dateFormatter.dateFormat = "HH:mm yyyy-MM-dd"
50
+            let strDate = dateFormatter.string(from: date)
51
+
52
+            // Update row controller
53
+            let controller = table.rowController(at: index) as! MeetingRowController
54
+            controller.room = room
55
+            controller.roomUrl = roomURL as String
56
+            controller.roomLabel.setText(room)
57
+            controller.timeLabel.setText(strDate)
58
+
59
+            // Change the background for the active meeting
60
+            if (controller.roomUrl == currentContext.conferenceURL) {
61
+                controller.rowGroup.setBackgroundColor(UIColor(red: 0.125, green: 0.58, blue: 0.98, alpha: 1))
62
+            } else {
63
+                controller.rowGroup.setBackgroundColor(UIColor(red: 0.949, green: 0.956, blue: 1, alpha: 0.14))
64
+            }
65
+        }
66
+    }
67
+
68
+    override func contextForSegue(withIdentifier segueIdentifier: String, in table: WKInterfaceTable, rowIndex: Int) -> Any? {
69
+        let controller = table.rowController(at: rowIndex) as! MeetingRowController
70
+        let currentContext = ExtensionDelegate.currentJitsiMeetContext
71
+      
72
+        // Copy the current context and add the joinConferenceURL to trigger the command when the in-call screen is displayed
73
+        let actionContext = JitsiMeetContext(jmContext: currentContext)
74
+        actionContext.joinConferenceURL = controller.roomUrl
75
+
76
+        print("WATCH contextForSegue: \(actionContext.description)");
77
+
78
+        return actionContext;
79
+    }
80
+}

+ 27
- 0
ios/app/watchos/extension/JitsiMeetCommands.swift View File

@@ -0,0 +1,27 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+// This needs to be in sync with features/mobile/watchos/constants.js
19
+enum JitsiMeetCommands : String {
20
+  typealias RawValue = String
21
+  
22
+  case CMD_HANG_UP = "hangup";
23
+  
24
+  case CMD_JOIN_CONFERENCE = "joinConference";
25
+  
26
+  case CMD_SET_MUTED = "setMuted";
27
+}

+ 71
- 0
ios/app/watchos/extension/JitsiMeetContext.swift View File

@@ -0,0 +1,71 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+import Foundation
19
+
20
+class JitsiMeetContext {
21
+    private var dictionary : [String : Any]
22
+
23
+    var joinConferenceURL : String? = nil;
24
+
25
+    init() {
26
+        dictionary = [:]
27
+    }
28
+  
29
+    init(context: [String : Any]) {
30
+        dictionary = context
31
+    }
32
+  
33
+    init(jmContext: JitsiMeetContext) {
34
+        dictionary = jmContext.dictionary
35
+        joinConferenceURL = jmContext.joinConferenceURL
36
+    }
37
+  
38
+    var conferenceURL : String? {
39
+        get {
40
+            return dictionary["conferenceURL"] as? String
41
+        }
42
+    }
43
+  
44
+    var conferenceTimestamp : Int64? {
45
+        get {
46
+            return dictionary["conferenceTimestamp"] as? Int64;
47
+        }
48
+    }
49
+  
50
+    var sessionID : Int64? {
51
+        get {
52
+            return dictionary["sessionID"] as? Int64;
53
+        }
54
+    }
55
+  
56
+    var recentURLs : NSArray? {
57
+        get {
58
+            return dictionary["recentURLs"] as? NSArray
59
+        }
60
+    }
61
+  
62
+    var micMuted : Bool? {
63
+        get {
64
+            return (dictionary["micMuted"] as? NSNumber)?.boolValue ?? nil;
65
+        }
66
+    }
67
+  
68
+    public var description: String {
69
+        return "JitsiMeetContext[conferenceURL: \(String(describing: conferenceURL)), conferenceTimestamp: \(String(describing:conferenceTimestamp)), sessionID: \(String(describing:sessionID)), recentURLs: \(String(describing:recentURLs)), joinConferenceURL: \(String(describing:joinConferenceURL)) "
70
+    }
71
+}

+ 27
- 0
ios/app/watchos/extension/MeetingRowController.swift View File

@@ -0,0 +1,27 @@
1
+/*
2
+ * Copyright @ 2018-present 8x8, Inc.
3
+ * Copyright @ 2017-2018 Atlassian Pty Ltd
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *     http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+import WatchKit
19
+
20
+class MeetingRowController: NSObject {
21
+  @IBOutlet var roomLabel: WKInterfaceLabel!
22
+  @IBOutlet var timeLabel: WKInterfaceLabel!
23
+  @IBOutlet var rowGroup: WKInterfaceGroup!
24
+
25
+  var room: String!
26
+  var roomUrl: String!
27
+}

+ 5
- 0
package-lock.json View File

@@ -12260,6 +12260,11 @@
12260 12260
         }
12261 12261
       }
12262 12262
     },
12263
+    "react-native-watch-connectivity": {
12264
+      "version": "0.2.0",
12265
+      "resolved": "https://registry.npmjs.org/react-native-watch-connectivity/-/react-native-watch-connectivity-0.2.0.tgz",
12266
+      "integrity": "sha512-l3Quzbb+qa4in2U5RSt/lT0/pHrIpEChT1NnqrVAAXNrjkXjVOsxduaaEDdDhTzNJQEm/PcAcoyrFmgvGOohxw=="
12267
+    },
12263 12268
     "react-native-webrtc": {
12264 12269
       "version": "github:jitsi/react-native-webrtc#659d2fe417b52356b1b706636de97e23bae3e9f5",
12265 12270
       "from": "github:jitsi/react-native-webrtc#659d2fe417b52356b1b706636de97e23bae3e9f5",

+ 1
- 0
package.json View File

@@ -74,6 +74,7 @@
74 74
     "react-native-sound": "0.10.12",
75 75
     "react-native-swipeout": "2.3.6",
76 76
     "react-native-vector-icons": "6.0.2",
77
+    "react-native-watch-connectivity": "0.2.0",
77 78
     "react-native-webrtc": "github:jitsi/react-native-webrtc#659d2fe417b52356b1b706636de97e23bae3e9f5",
78 79
     "react-redux": "5.0.7",
79 80
     "react-transition-group": "2.4.0",

+ 1
- 0
react/features/app/components/App.native.js View File

@@ -22,6 +22,7 @@ import '../../mobile/permissions';
22 22
 import '../../mobile/picture-in-picture';
23 23
 import '../../mobile/proximity';
24 24
 import '../../mobile/wake-lock';
25
+import '../../mobile/watchos';
25 26
 
26 27
 import { AbstractApp } from './AbstractApp';
27 28
 import type { Props as AbstractAppProps } from './AbstractApp';

+ 28
- 0
react/features/mobile/watchos/actionTypes.js View File

@@ -0,0 +1,28 @@
1
+// @flow
2
+
3
+/**
4
+ * See {@link setConferenceTimestamp} for more details.
5
+ * {
6
+ *      type: SET_CONFERENCE_TIMESTAMP,
7
+ *      conferenceTimestamp: number
8
+ * }
9
+ */
10
+export const SET_CONFERENCE_TIMESTAMP = Symbol('WATCH_OS_SET_CONFERENCE_TIMESTAMP');
11
+
12
+/**
13
+ * See {@link setSessionId} action for more details.
14
+ * {
15
+ *     type: SET_SESSION_ID,
16
+ *     sessionID: number
17
+ * }
18
+ */
19
+export const SET_SESSION_ID = Symbol('WATCH_OS_SET_SESSION_ID');
20
+
21
+/**
22
+ * See {@link setWatchReachable} for more details.
23
+ * {
24
+ *     type: SET_WATCH_REACHABLE,
25
+ *     watchReachable: boolean
26
+ * }
27
+ */
28
+export const SET_WATCH_REACHABLE = Symbol('WATCH_OS_SET_WATCH_REACHABLE');

+ 55
- 0
react/features/mobile/watchos/actions.js View File

@@ -0,0 +1,55 @@
1
+// @flow
2
+
3
+import { SET_CONFERENCE_TIMESTAMP, SET_SESSION_ID, SET_WATCH_REACHABLE } from './actionTypes';
4
+
5
+/**
6
+ * Stores a timestamp when the conference is joined, so that the watch counterpart can start counting from when
7
+ * the meeting has really started.
8
+ *
9
+ * @param {number} conferenceTimestamp - A timestamp retrieved with {@code newDate.getTime()}.
10
+ * @returns {{
11
+ *      type: SET_CONFERENCE_TIMESTAMP,
12
+ *      conferenceTimestamp: number
13
+ * }}
14
+ */
15
+export function setConferenceTimestamp(conferenceTimestamp: number) {
16
+    return {
17
+        type: SET_CONFERENCE_TIMESTAMP,
18
+        conferenceTimestamp
19
+    };
20
+}
21
+
22
+/**
23
+ * Updates the session ID which is sent to the Watch app and then used by the app to send commands. Commands from
24
+ * the watch are accepted only if the 'sessionID' passed by the Watch matches the one currently stored in Redux. It is
25
+ * supposed to prevent from processing outdated commands.
26
+ *
27
+ * @returns {{
28
+ *     type: SET_SESSION_ID,
29
+ *     sessionID: number
30
+ * }}
31
+ */
32
+export function setSessionId() {
33
+    return {
34
+        type: SET_SESSION_ID,
35
+        sessionID: new Date().getTime()
36
+    };
37
+}
38
+
39
+/**
40
+ * Updates the reachable status of the watch. It's used to get in sync with the watch counterpart when it gets
41
+ * reconnected, but also to prevent from sending updates if the app is not installed at all (which would fail with
42
+ * an error).
43
+ *
44
+ * @param {boolean} isReachable - Indicates whether the watch is currently reachable or not.
45
+ * @returns {{
46
+ *      type: SET_WATCH_REACHABLE,
47
+ *      watchReachable: boolean
48
+ * }}
49
+ */
50
+export function setWatchReachable(isReachable: boolean) {
51
+    return {
52
+        type: SET_WATCH_REACHABLE,
53
+        watchReachable: isReachable
54
+    };
55
+}

+ 11
- 0
react/features/mobile/watchos/constants.js View File

@@ -0,0 +1,11 @@
1
+// @flow
2
+
3
+// NOTE When changing any of the commands make sure to update JitsiMeetCommands enum in the WatchKit extension code.
4
+
5
+export const CMD_HANG_UP = 'hangup';
6
+
7
+export const CMD_JOIN_CONFERENCE = 'joinConference';
8
+
9
+export const CMD_SET_MUTED = 'setMuted';
10
+
11
+export const MAX_RECENT_URLS = 10;

+ 2
- 0
react/features/mobile/watchos/index.js View File

@@ -0,0 +1,2 @@
1
+import './middleware';
2
+import './reducer';

+ 225
- 0
react/features/mobile/watchos/middleware.js View File

@@ -0,0 +1,225 @@
1
+// @flow
2
+
3
+import { Platform } from 'react-native';
4
+import * as watch from 'react-native-watch-connectivity';
5
+
6
+import { appNavigate } from '../../app';
7
+
8
+import { APP_WILL_MOUNT } from '../../base/app';
9
+import { CONFERENCE_JOINED } from '../../base/conference';
10
+import { getInviteURL, isInviteURLReady } from '../../base/connection';
11
+import { setAudioMuted } from '../../base/media';
12
+import {
13
+    MiddlewareRegistry,
14
+    StateListenerRegistry,
15
+    toState
16
+} from '../../base/redux';
17
+import { toURLString } from '../../base/util';
18
+
19
+import { setConferenceTimestamp, setSessionId, setWatchReachable } from './actions';
20
+import { CMD_HANG_UP, CMD_JOIN_CONFERENCE, CMD_SET_MUTED, MAX_RECENT_URLS } from './constants';
21
+
22
+const logger = require('jitsi-meet-logger').getLogger(__filename);
23
+
24
+const watchOSEnabled = Platform.OS === 'ios';
25
+
26
+// Handles the recent URLs state sent to the watch
27
+watchOSEnabled && StateListenerRegistry.register(
28
+    /* selector */ state => state['features/recent-list'],
29
+    /* listener */ (recentListState, { getState }) => {
30
+        _updateApplicationContext(getState);
31
+    });
32
+
33
+// Handles the mic muted state sent to the watch
34
+watchOSEnabled && StateListenerRegistry.register(
35
+    /* selector */ state => _isAudioMuted(state),
36
+    /* listener */ (isAudioMuted, { getState }) => {
37
+        _updateApplicationContext(getState);
38
+    });
39
+
40
+// Handles the conference URL state sent to the watch
41
+watchOSEnabled && StateListenerRegistry.register(
42
+    /* selector */ state => _getCurrentConferenceUrl(state),
43
+    /* listener */ (currentUrl, { dispatch, getState }) => {
44
+        dispatch(setSessionId());
45
+        _updateApplicationContext(getState);
46
+    });
47
+
48
+/**
49
+ * Middleware that captures conference actions.
50
+ *
51
+ * @param {Store} store - The redux store.
52
+ * @returns {Function}
53
+ */
54
+watchOSEnabled && MiddlewareRegistry.register(store => next => action => {
55
+    switch (action.type) {
56
+    case APP_WILL_MOUNT:
57
+        _appWillMount(store);
58
+        break;
59
+    case CONFERENCE_JOINED:
60
+        store.dispatch(setConferenceTimestamp(new Date().getTime()));
61
+        _updateApplicationContext(store.getState());
62
+        break;
63
+    }
64
+
65
+    return next(action);
66
+});
67
+
68
+/**
69
+ * Registers listeners to the react-native-watch-connectivity lib.
70
+ *
71
+ * @param {Store} store - The redux store.
72
+ * @private
73
+ * @returns {void}
74
+ */
75
+function _appWillMount({ dispatch, getState }) {
76
+    watch.subscribeToWatchReachability((error, reachable) => {
77
+        dispatch(setWatchReachable(reachable));
78
+        _updateApplicationContext(getState);
79
+    });
80
+
81
+    watch.subscribeToMessages((error, message) => {
82
+        if (error) {
83
+            logger.error('watch.subscribeToMessages error:', error);
84
+
85
+            return;
86
+        }
87
+
88
+        const {
89
+            command,
90
+            sessionID
91
+        } = message;
92
+        const currentSessionID = _getSessionId(getState());
93
+
94
+        if (!sessionID || sessionID !== currentSessionID) {
95
+            logger.warn(
96
+                `Ignoring outdated watch command: ${message.command}`
97
+                    + ` sessionID: ${sessionID} current session ID: ${currentSessionID}`);
98
+
99
+            return;
100
+        }
101
+
102
+        switch (command) {
103
+        case CMD_HANG_UP:
104
+            if (typeof _getCurrentConferenceUrl(getState()) !== undefined) {
105
+                dispatch(appNavigate(undefined));
106
+            }
107
+            break;
108
+        case CMD_JOIN_CONFERENCE: {
109
+            const newConferenceURL = message.data;
110
+            const oldConferenceURL = _getCurrentConferenceUrl(getState());
111
+
112
+            if (oldConferenceURL !== newConferenceURL) {
113
+                dispatch(appNavigate(newConferenceURL));
114
+            }
115
+            break;
116
+        }
117
+        case CMD_SET_MUTED:
118
+            dispatch(
119
+                setAudioMuted(
120
+                    message.muted === 'true',
121
+                    /* ensureTrack */ true));
122
+            break;
123
+        }
124
+    });
125
+}
126
+
127
+/**
128
+ * Figures out what's the current conference URL which is supposed to indicate what conference is currently active.
129
+ * When not currently in any conference and not trying to join any then the 'NULL' string value is returned.
130
+ *
131
+ * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
132
+ * @returns {string}
133
+ * @private
134
+ */
135
+function _getCurrentConferenceUrl(stateful) {
136
+    const state = toState(stateful);
137
+    let currentUrl;
138
+
139
+    if (isInviteURLReady(state)) {
140
+        currentUrl = toURLString(getInviteURL(state));
141
+    }
142
+
143
+    // Check if the URL doesn't end with a slash
144
+    if (currentUrl && currentUrl.substr(-1) === '/') {
145
+        currentUrl = undefined;
146
+    }
147
+
148
+    return currentUrl ? currentUrl : undefined;
149
+}
150
+
151
+/**
152
+ * Gets the current Apple Watch session's ID. A new session is started whenever the conference URL has changed. It is
153
+ * used to filter out outdated commands which may arrive very later if the Apple Watch loses the connectivity.
154
+ *
155
+ * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
156
+ * @returns {number}
157
+ * @private
158
+ */
159
+function _getSessionId(stateful) {
160
+    const state = toState(stateful);
161
+
162
+    return state['features/mobile/watchos'].sessionID;
163
+}
164
+
165
+/**
166
+ * Gets the list of recent URLs to be passed over to the Watch app.
167
+ *
168
+ * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
169
+ * @returns {Array<Object>}
170
+ * @private
171
+ */
172
+function _getRecentUrls(stateful) {
173
+    const state = toState(stateful);
174
+    const recentURLs = state['features/recent-list'];
175
+
176
+    // Trim to MAX_RECENT_URLS and reverse the list
177
+    const reversedList = recentURLs.slice(-MAX_RECENT_URLS);
178
+
179
+    reversedList.reverse();
180
+
181
+    return reversedList;
182
+}
183
+
184
+/**
185
+ * Determines the audio muted state to be sent to the apple watch.
186
+ *
187
+ * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
188
+ * @returns {boolean}
189
+ * @private
190
+ */
191
+function _isAudioMuted(stateful) {
192
+    const state = toState(stateful);
193
+    const { audio } = state['features/base/media'];
194
+
195
+    return audio.muted;
196
+}
197
+
198
+/**
199
+ * Sends the context to the watch os app. At the time of this writing it's the entire state of
200
+ * the 'features/mobile/watchos' reducer.
201
+ *
202
+ * @param {Object|Function} stateful - Either the whole Redux state object or the Redux store's {@code getState} method.
203
+ * @private
204
+ * @returns {void}
205
+ */
206
+function _updateApplicationContext(stateful) {
207
+    const state = toState(stateful);
208
+    const { conferenceTimestamp, sessionID, watchReachable } = state['features/mobile/watchos'];
209
+
210
+    if (!watchReachable) {
211
+        return;
212
+    }
213
+
214
+    try {
215
+        watch.updateApplicationContext({
216
+            conferenceTimestamp,
217
+            conferenceURL: _getCurrentConferenceUrl(state),
218
+            micMuted: _isAudioMuted(state),
219
+            recentURLs: _getRecentUrls(state),
220
+            sessionID
221
+        });
222
+    } catch (error) {
223
+        logger.error('Failed to stringify or send the context', error);
224
+    }
225
+}

+ 34
- 0
react/features/mobile/watchos/reducer.js View File

@@ -0,0 +1,34 @@
1
+// @flow
2
+
3
+import { assign, ReducerRegistry } from '../../base/redux';
4
+import { SET_CONFERENCE_TIMESTAMP, SET_SESSION_ID, SET_WATCH_REACHABLE } from './actionTypes';
5
+
6
+const INITIAL_STATE = {
7
+    sessionID: new Date().getTime()
8
+};
9
+
10
+/**
11
+ * Reduces the Redux actions of the feature features/mobile/watchos.
12
+ */
13
+ReducerRegistry.register('features/mobile/watchos', (state = INITIAL_STATE, action) => {
14
+    switch (action.type) {
15
+    case SET_CONFERENCE_TIMESTAMP: {
16
+        return assign(state, {
17
+            conferenceTimestamp: action.conferenceTimestamp
18
+        });
19
+    }
20
+    case SET_SESSION_ID: {
21
+        return assign(state, {
22
+            sessionID: action.sessionID,
23
+            conferenceTimestamp: 0
24
+        });
25
+    }
26
+    case SET_WATCH_REACHABLE: {
27
+        return assign(state, {
28
+            watchReachable: action.watchReachable
29
+        });
30
+    }
31
+    default:
32
+        return state;
33
+    }
34
+});

Loading…
Cancel
Save