"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-5186/ios/sdk/src/JitsiMeetView.m" (30 Jul 2021, 7307 Bytes) of package /linux/misc/jitsi-meet-5186.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.

    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      * The unique identifier of this `JitsiMeetView` within the process for the
   37      * purposes of `ExternalAPI`. The name scope was inspired by postis which we
   38      * use on Web for the similar purposes of the iframe-based external API.
   39      */
   40     NSString *externalAPIScope;
   41 
   42     /**
   43      * React Native view where the entire content will be rendered.
   44      */
   45     RNRootView *rootView;
   46 }
   47 
   48 /**
   49  * The `JitsiMeetView`s associated with their `ExternalAPI` scopes (i.e. unique
   50  * identifiers within the process).
   51  */
   52 static NSMapTable<NSString *, JitsiMeetView *> *views;
   53 /**
   54  * This gets called automagically when the program starts.
   55  */
   56 __attribute__((constructor))
   57 static void initializeViewsMap() {
   58     views = [NSMapTable strongToWeakObjectsMapTable];
   59 }
   60 
   61 #pragma mark Initializers
   62 
   63 - (instancetype)init {
   64     self = [super init];
   65     if (self) {
   66         [self initWithXXX];
   67     }
   68 
   69     return self;
   70 }
   71 
   72 - (instancetype)initWithCoder:(NSCoder *)coder {
   73     self = [super initWithCoder:coder];
   74     if (self) {
   75         [self initWithXXX];
   76     }
   77 
   78     return self;
   79 }
   80 
   81 - (instancetype)initWithFrame:(CGRect)frame {
   82     self = [super initWithFrame:frame];
   83     if (self) {
   84         [self initWithXXX];
   85     }
   86 
   87     return self;
   88 }
   89 
   90 /**
   91  * Internal initialization:
   92  *
   93  * - sets the background color
   94  * - initializes the external API scope
   95  */
   96 - (void)initWithXXX {
   97     // Hook this JitsiMeetView into ExternalAPI.
   98     externalAPIScope = [NSUUID UUID].UUIDString;
   99     [views setObject:self forKey:externalAPIScope];
  100 
  101     // Set a background color which is in accord with the JavaScript and Android
  102     // parts of the application and causes less perceived visual flicker than
  103     // the default background color.
  104     self.backgroundColor
  105         = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
  106 }
  107 
  108 #pragma mark API
  109 
  110 - (void)join:(JitsiMeetConferenceOptions *)options {
  111     [self setProps:options == nil ? @{} : [options asProps]];
  112 }
  113 
  114 - (void)leave {
  115     [self setProps:@{}];
  116 }
  117 
  118 - (void)hangUp {
  119     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  120     [externalAPI sendHangUp];
  121 }
  122 
  123 - (void)setAudioMuted:(BOOL)muted {
  124     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  125     [externalAPI sendSetAudioMuted:muted];
  126 }
  127 
  128 - (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
  129     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  130     [externalAPI sendEndpointTextMessage:message :to];
  131 }
  132 
  133 - (void)toggleScreenShare:(BOOL)enabled {
  134     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  135     [externalAPI toggleScreenShare:enabled];
  136 }
  137 
  138 - (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler {
  139     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  140     [externalAPI retrieveParticipantsInfo:completionHandler];
  141 }
  142 
  143 - (void)openChat:(NSString*)to  {
  144     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  145     [externalAPI openChat:to];
  146 }
  147 
  148 - (void)closeChat  {
  149     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  150     [externalAPI closeChat];
  151 }
  152 
  153 - (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
  154     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  155     [externalAPI sendChatMessage:message :to];
  156 }
  157 
  158 - (void)setVideoMuted:(BOOL)muted {
  159     ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
  160     [externalAPI sendSetVideoMuted:muted];
  161 }
  162 
  163 #pragma mark Private methods
  164 
  165 /**
  166  * Passes the given props to the React Native application. The props which we pass
  167  * are a combination of 3 different sources:
  168  *
  169  * - JitsiMeet.defaultConferenceOptions
  170  * - This function's parameters
  171  * - Some extras which are added by this function
  172  */
  173 - (void)setProps:(NSDictionary *_Nonnull)newProps {
  174     NSMutableDictionary *props = mergeProps([[JitsiMeet sharedInstance] getDefaultProps], newProps);
  175 
  176     // Set the PiP flag if it wasn't manually set.
  177     NSMutableDictionary *featureFlags = props[@"flags"];
  178     if (featureFlags[PiPEnabledFeatureFlag] == nil) {
  179         featureFlags[PiPEnabledFeatureFlag]
  180             = [NSNumber numberWithBool:
  181                self.delegate && [self.delegate respondsToSelector:@selector(enterPictureInPicture:)]];
  182     }
  183 
  184     props[@"externalAPIScope"] = externalAPIScope;
  185 
  186     // This method is supposed to be imperative i.e. a second
  187     // invocation with one and the same URL is expected to join the respective
  188     // conference again if the first invocation was followed by leaving the
  189     // conference. However, React and, respectively,
  190     // appProperties/initialProperties are declarative expressions i.e. one and
  191     // the same URL will not trigger an automatic re-render in the JavaScript
  192     // source code. The workaround implemented below introduces imperativeness
  193     // in React Component props by defining a unique value per invocation.
  194     props[@"timestamp"] = @(mach_absolute_time());
  195 
  196     if (rootView) {
  197         // Update props with the new URL.
  198         rootView.appProperties = props;
  199     } else {
  200         RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
  201         rootView
  202             = [[RNRootView alloc] initWithBridge:bridge
  203                                       moduleName:@"App"
  204                                initialProperties:props];
  205         rootView.backgroundColor = self.backgroundColor;
  206 
  207         // Add rootView as a subview which completely covers this one.
  208         [rootView setFrame:[self bounds]];
  209         rootView.autoresizingMask
  210             = UIViewAutoresizingFlexibleWidth
  211                 | UIViewAutoresizingFlexibleHeight;
  212         [self addSubview:rootView];
  213     }
  214 }
  215 
  216 + (BOOL)setPropsInViews:(NSDictionary *_Nonnull)newProps {
  217     BOOL handled = NO;
  218 
  219     if (views) {
  220         for (NSString *externalAPIScope in views) {
  221             JitsiMeetView *view
  222                 = [self viewForExternalAPIScope:externalAPIScope];
  223 
  224             if (view) {
  225                 [view setProps:newProps];
  226                 handled = YES;
  227             }
  228         }
  229     }
  230 
  231     return handled;
  232 }
  233 
  234 + (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope {
  235     return [views objectForKey:externalAPIScope];
  236 }
  237 
  238 @end