"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