mirror of https://github.com/jitsi/jitsi-meet
pull/11767/head
jitsi-meet_7486
parent
6df2e4009c
commit
ddab27e292
@ -0,0 +1,30 @@ |
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
#import <UIKit/UIKit.h> |
||||
#import "JitsiMeetViewDelegate.h" |
||||
|
||||
NS_ASSUME_NONNULL_BEGIN |
||||
|
||||
@interface JitsiMeetRenderingView : UIView |
||||
|
||||
@property (nonatomic, assign) BOOL isPiPEnabled; |
||||
|
||||
- (void)setProps:(NSDictionary *_Nonnull)newProps; |
||||
|
||||
@end |
||||
|
||||
NS_ASSUME_NONNULL_END |
@ -0,0 +1,103 @@ |
||||
/* |
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
#include <mach/mach_time.h> |
||||
|
||||
#import "JitsiMeetRenderingView.h" |
||||
#import "ReactUtils.h" |
||||
#import "RNRootView.h" |
||||
#import "JitsiMeet+Private.h" |
||||
|
||||
/** |
||||
* Backwards compatibility: turn the boolean prop into a feature flag. |
||||
*/ |
||||
static NSString *const PiPEnabledFeatureFlag = @"pip.enabled"; |
||||
|
||||
@interface JitsiMeetRenderingView () |
||||
|
||||
/** |
||||
* The unique identifier of this `JitsiMeetView` within the process for the |
||||
* purposes of `ExternalAPI`. The name scope was inspired by postis which we |
||||
* use on Web for the similar purposes of the iframe-based external API. |
||||
*/ |
||||
@property (nonatomic, strong) NSString *externalAPIScope; |
||||
|
||||
@end |
||||
|
||||
@implementation JitsiMeetRenderingView { |
||||
/** |
||||
* React Native view where the entire content will be rendered. |
||||
*/ |
||||
RNRootView *rootView; |
||||
} |
||||
|
||||
- (instancetype)init { |
||||
self = [super init]; |
||||
if (self) { |
||||
// Hook this JitsiMeetView into ExternalAPI. |
||||
self.externalAPIScope = [NSUUID UUID].UUIDString; |
||||
} |
||||
|
||||
return self; |
||||
} |
||||
|
||||
/** |
||||
* Passes the given props to the React Native application. The props which we pass |
||||
* are a combination of 3 different sources: |
||||
* |
||||
* - JitsiMeet.defaultConferenceOptions |
||||
* - This function's parameters |
||||
* - Some extras which are added by this function |
||||
*/ |
||||
- (void)setProps:(NSDictionary *_Nonnull)newProps { |
||||
NSMutableDictionary *props = mergeProps([[JitsiMeet sharedInstance] getDefaultProps], newProps); |
||||
|
||||
// Set the PiP flag if it wasn't manually set. |
||||
NSMutableDictionary *featureFlags = props[@"flags"]; |
||||
// TODO: temporary implementation |
||||
if (featureFlags[PiPEnabledFeatureFlag] == nil) { |
||||
featureFlags[PiPEnabledFeatureFlag] = @(self.isPiPEnabled); |
||||
} |
||||
|
||||
props[@"externalAPIScope"] = self.externalAPIScope; |
||||
|
||||
// This method is supposed to be imperative i.e. a second |
||||
// invocation with one and the same URL is expected to join the respective |
||||
// conference again if the first invocation was followed by leaving the |
||||
// conference. However, React and, respectively, |
||||
// appProperties/initialProperties are declarative expressions i.e. one and |
||||
// the same URL will not trigger an automatic re-render in the JavaScript |
||||
// source code. The workaround implemented below introduces imperativeness |
||||
// in React Component props by defining a unique value per invocation. |
||||
props[@"timestamp"] = @(mach_absolute_time()); |
||||
|
||||
if (rootView) { |
||||
// Update props with the new URL. |
||||
rootView.appProperties = props; |
||||
} else { |
||||
RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge]; |
||||
rootView = [[RNRootView alloc] initWithBridge:bridge |
||||
moduleName:@"App" |
||||
initialProperties:props]; |
||||
rootView.backgroundColor = self.backgroundColor; |
||||
|
||||
// Add rootView as a subview which completely covers this one. |
||||
[rootView setFrame:[self bounds]]; |
||||
rootView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; |
||||
[self addSubview:rootView]; |
||||
} |
||||
} |
||||
|
||||
@end |
@ -0,0 +1,25 @@ |
||||
/* |
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
#import "JitsiMeetView+Private.h" |
||||
|
||||
@implementation JitsiMeetView (Private) |
||||
|
||||
+ (void)updateProps:(NSDictionary *_Nonnull)newProps { |
||||
[[NSNotificationCenter defaultCenter] postNotificationName:updateViewPropsNotificationName object:nil userInfo:@{@"props": newProps}]; |
||||
} |
||||
|
||||
@end |
@ -0,0 +1,38 @@ |
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
#import <UIKit/UIKit.h> |
||||
#import "JitsiMeetConferenceOptions.h" |
||||
|
||||
NS_ASSUME_NONNULL_BEGIN |
||||
|
||||
@interface JitsiMeetViewController : UIViewController |
||||
|
||||
- (void)join:(JitsiMeetConferenceOptions *)options withPiP:(BOOL)enablePiP; |
||||
- (void)leave; |
||||
- (void)hangUp; |
||||
- (void)setAudioMuted:(BOOL)muted; |
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to; |
||||
- (void)toggleScreenShare:(BOOL)enabled; |
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler; |
||||
- (void)openChat:(NSString*)to; |
||||
- (void)closeChat; |
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to; |
||||
- (void)setVideoMuted:(BOOL)muted; |
||||
|
||||
@end |
||||
|
||||
NS_ASSUME_NONNULL_END |
@ -0,0 +1,127 @@ |
||||
/* |
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
#import "JitsiMeetViewController.h" |
||||
#import "JitsiMeet+Private.h" |
||||
#import "JitsiMeetConferenceOptions+Private.h" |
||||
#import "JitsiMeetRenderingView.h" |
||||
#import "JitsiMeetView+Private.h" |
||||
|
||||
@interface JitsiMeetViewController () |
||||
|
||||
@property (strong, nonatomic) JitsiMeetRenderingView *view; |
||||
|
||||
@end |
||||
|
||||
@implementation JitsiMeetViewController |
||||
|
||||
@dynamic view; |
||||
|
||||
- (instancetype)init { |
||||
self = [super init]; |
||||
if (self) { |
||||
[self registerObservers]; |
||||
} |
||||
|
||||
return self; |
||||
} |
||||
|
||||
- (void)dealloc { |
||||
[[NSNotificationCenter defaultCenter] removeObserver:self]; |
||||
} |
||||
|
||||
- (void)loadView { |
||||
[super loadView]; |
||||
|
||||
self.view = [[JitsiMeetRenderingView alloc] init]; |
||||
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; |
||||
} |
||||
|
||||
- (void)viewDidLoad { |
||||
[super viewDidLoad]; |
||||
|
||||
// Set a background color which is in accord with the JavaScript and Android |
||||
// parts of the application and causes less perceived visual flicker than |
||||
// the default background color. |
||||
self.view.backgroundColor = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1]; |
||||
} |
||||
|
||||
- (void)join:(JitsiMeetConferenceOptions *)options withPiP:(BOOL)enablePiP { |
||||
self.view.isPiPEnabled = enablePiP; |
||||
[self.view setProps:options == nil ? @{} : [options asProps]]; |
||||
} |
||||
|
||||
- (void)leave { |
||||
[self.view setProps:@{}]; |
||||
} |
||||
|
||||
- (void)hangUp { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI sendHangUp]; |
||||
} |
||||
|
||||
- (void)setAudioMuted:(BOOL)muted { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI sendSetAudioMuted:muted]; |
||||
} |
||||
|
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI sendEndpointTextMessage:message :to]; |
||||
} |
||||
|
||||
- (void)toggleScreenShare:(BOOL)enabled { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI toggleScreenShare:enabled]; |
||||
} |
||||
|
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI retrieveParticipantsInfo:completionHandler]; |
||||
} |
||||
|
||||
- (void)openChat:(NSString*)to { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI openChat:to]; |
||||
} |
||||
|
||||
- (void)closeChat { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI closeChat]; |
||||
} |
||||
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI sendChatMessage:message :to]; |
||||
} |
||||
|
||||
- (void)setVideoMuted:(BOOL)muted { |
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; |
||||
[externalAPI sendSetVideoMuted:muted]; |
||||
} |
||||
|
||||
#pragma mark Private |
||||
|
||||
- (void)registerObservers { |
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUpdateViewPropsNotification:) name:updateViewPropsNotificationName object:nil]; |
||||
} |
||||
|
||||
- (void)handleUpdateViewPropsNotification:(NSNotification *)notification { |
||||
NSDictionary *props = [notification.userInfo objectForKey:@"props"]; |
||||
[self.view setProps:props]; |
||||
} |
||||
|
||||
@end |
Loading…
Reference in new issue