"Fossies" - the Fresh Open Source Software Archive 
Member "jitsi-meet-7542/ios/sdk/src/JitsiMeetView.m" (21 Sep 2023, 7855 Bytes) of package /linux/misc/jitsi-meet-7542.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Matlab source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the last
Fossies "Diffs" side-by-side code changes report for "JitsiMeetView.m":
jitsi-meet_8719_vs_jitsi-meet_8922.
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 #include <mach/mach_time.h>
19
20 #import "ExternalAPI.h"
21 #import "JitsiMeet+Private.h"
22 #import "JitsiMeetConferenceOptions+Private.h"
23 #import "JitsiMeetView+Private.h"
24 #import "ReactUtils.h"
25 #import "RNRootView.h"
26
27
28 /**
29 * Backwards compatibility: turn the boolean prop into a feature flag.
30 */
31 static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
32
33
34 @implementation JitsiMeetView {
35 /**
36 * React Native view where the entire content will be rendered.
37 */
38 RNRootView *rootView;
39 }
40
41 #pragma mark Initializers
42
43 - (instancetype)initWithCoder:(NSCoder *)coder {
44 self = [super initWithCoder:coder];
45 if (self) {
46 [self doInitialize];
47 }
48
49 return self;
50 }
51
52 - (instancetype)initWithFrame:(CGRect)frame {
53 self = [super initWithFrame:frame];
54 if (self) {
55 [self doInitialize];
56 }
57
58 return self;
59 }
60
61 /**
62 * Internal initialization:
63 *
64 * - sets the background color
65 * - registers necessary observers
66 */
67 - (void)doInitialize {
68 // Set a background color which is in accord with the JavaScript and Android
69 // parts of the application and causes less perceived visual flicker than
70 // the default background color.
71 self.backgroundColor
72 = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
73
74 [self registerObservers];
75 }
76
77 - (void)dealloc {
78 [[NSNotificationCenter defaultCenter] removeObserver:self];
79 }
80
81 #pragma mark API
82
83 - (void)join:(JitsiMeetConferenceOptions *)options {
84 [self setProps:options == nil ? @{} : [options asProps]];
85 }
86
87 - (void)leave {
88 [self setProps:@{}];
89 }
90
91 - (void)hangUp {
92 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
93 [externalAPI sendHangUp];
94 }
95
96 - (void)setAudioMuted:(BOOL)muted {
97 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
98 [externalAPI sendSetAudioMuted:muted];
99 }
100
101 - (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
102 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
103 [externalAPI sendEndpointTextMessage:message :to];
104 }
105
106 - (void)toggleScreenShare:(BOOL)enabled {
107 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
108 [externalAPI toggleScreenShare:enabled];
109 }
110
111 - (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler {
112 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
113 [externalAPI retrieveParticipantsInfo:completionHandler];
114 }
115
116 - (void)openChat:(NSString*)to {
117 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
118 [externalAPI openChat:to];
119 }
120
121 - (void)closeChat {
122 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
123 [externalAPI closeChat];
124 }
125
126 - (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
127 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
128 [externalAPI sendChatMessage:message :to];
129 }
130
131 - (void)setVideoMuted:(BOOL)muted {
132 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
133 [externalAPI sendSetVideoMuted:muted];
134 }
135
136 - (void)setClosedCaptionsEnabled:(BOOL)enabled {
137 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
138 [externalAPI sendSetClosedCaptionsEnabled:enabled];
139 }
140
141 - (void)toggleCamera {
142 ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
143 [externalAPI toggleCamera];
144 }
145
146 #pragma mark Private methods
147
148 - (void)registerObservers {
149 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUpdateViewPropsNotification:) name:updateViewPropsNotificationName object:nil];
150 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSendEventNotification:) name:sendEventNotificationName object:nil];
151 }
152
153 - (void)handleUpdateViewPropsNotification:(NSNotification *)notification {
154 NSDictionary *props = [notification.userInfo objectForKey:@"props"];
155 [self setProps:props];
156 }
157
158 - (void)handleSendEventNotification:(NSNotification *)notification {
159 NSString *eventName = notification.userInfo[@"name"];
160 NSString *eventData = notification.userInfo[@"data"];
161
162 SEL sel = NSSelectorFromString([self methodNameFromEventName:eventName]);
163 if (sel && [self.delegate respondsToSelector:sel]) {
164 [self.delegate performSelector:sel withObject:eventData];
165 }
166 }
167
168 /**
169 * Converts a specific event name i.e. redux action type description to a
170 * method name.
171 *
172 * @param eventName The event name to convert to a method name.
173 * @return A method name constructed from the specified `eventName`.
174 */
175 - (NSString *)methodNameFromEventName:(NSString *)eventName {
176 NSMutableString *methodName
177 = [NSMutableString stringWithCapacity:eventName.length];
178
179 for (NSString *c in [eventName componentsSeparatedByString:@"_"]) {
180 if (c.length) {
181 [methodName appendString:
182 methodName.length ? c.capitalizedString : c.lowercaseString];
183 }
184 }
185 [methodName appendString:@":"];
186
187 return methodName;
188 }
189
190 /**
191 * Passes the given props to the React Native application. The props which we pass
192 * are a combination of 3 different sources:
193 *
194 * - JitsiMeet.defaultConferenceOptions
195 * - This function's parameters
196 * - Some extras which are added by this function
197 */
198 - (void)setProps:(NSDictionary *_Nonnull)newProps {
199 NSMutableDictionary *props = mergeProps([[JitsiMeet sharedInstance] getDefaultProps], newProps);
200
201 // Set the PiP flag if it wasn't manually set.
202 NSMutableDictionary *featureFlags = props[@"flags"];
203 if (featureFlags[PiPEnabledFeatureFlag] == nil) {
204 featureFlags[PiPEnabledFeatureFlag]
205 = [NSNumber numberWithBool:
206 self.delegate && [self.delegate respondsToSelector:@selector(enterPictureInPicture:)]];
207 }
208
209 // This method is supposed to be imperative i.e. a second
210 // invocation with one and the same URL is expected to join the respective
211 // conference again if the first invocation was followed by leaving the
212 // conference. However, React and, respectively,
213 // appProperties/initialProperties are declarative expressions i.e. one and
214 // the same URL will not trigger an automatic re-render in the JavaScript
215 // source code. The workaround implemented below introduces imperativeness
216 // in React Component props by defining a unique value per invocation.
217 props[@"timestamp"] = @(mach_absolute_time());
218
219 if (rootView) {
220 // Update props with the new URL.
221 rootView.appProperties = props;
222 } else {
223 RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
224 rootView
225 = [[RNRootView alloc] initWithBridge:bridge
226 moduleName:@"App"
227 initialProperties:props];
228 rootView.backgroundColor = self.backgroundColor;
229
230 // Add rootView as a subview which completely covers this one.
231 [rootView setFrame:[self bounds]];
232 rootView.autoresizingMask
233 = UIViewAutoresizingFlexibleWidth
234 | UIViewAutoresizingFlexibleHeight;
235 [self addSubview:rootView];
236 }
237 }
238
239 @end