Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. #include <mach/mach_time.h>
  18. #import <React/RCTRootView.h>
  19. #import "JitsiMeet+Private.h"
  20. #import "JitsiMeetConferenceOptions+Private.h"
  21. #import "JitsiMeetView+Private.h"
  22. #import "ReactUtils.h"
  23. @implementation JitsiMeetView {
  24. /**
  25. * The unique identifier of this `JitsiMeetView` within the process for the
  26. * purposes of `ExternalAPI`. The name scope was inspired by postis which we
  27. * use on Web for the similar purposes of the iframe-based external API.
  28. */
  29. NSString *externalAPIScope;
  30. RCTRootView *rootView;
  31. }
  32. /**
  33. * The `JitsiMeetView`s associated with their `ExternalAPI` scopes (i.e. unique
  34. * identifiers within the process).
  35. */
  36. static NSMapTable<NSString *, JitsiMeetView *> *views;
  37. /**
  38. * This gets called automagically when the program starts.
  39. */
  40. __attribute__((constructor))
  41. static void initializeViewsMap() {
  42. views = [NSMapTable strongToWeakObjectsMapTable];
  43. }
  44. #pragma mark Initializers
  45. - (instancetype)init {
  46. self = [super init];
  47. if (self) {
  48. [self initWithXXX];
  49. }
  50. return self;
  51. }
  52. - (instancetype)initWithCoder:(NSCoder *)coder {
  53. self = [super initWithCoder:coder];
  54. if (self) {
  55. [self initWithXXX];
  56. }
  57. return self;
  58. }
  59. - (instancetype)initWithFrame:(CGRect)frame {
  60. self = [super initWithFrame:frame];
  61. if (self) {
  62. [self initWithXXX];
  63. }
  64. return self;
  65. }
  66. /**
  67. * Internal initialization:
  68. *
  69. * - sets the background color
  70. * - initializes the external API scope
  71. */
  72. - (void)initWithXXX {
  73. // Hook this JitsiMeetView into ExternalAPI.
  74. externalAPIScope = [NSUUID UUID].UUIDString;
  75. [views setObject:self forKey:externalAPIScope];
  76. // Set a background color which is in accord with the JavaScript and Android
  77. // parts of the application and causes less perceived visual flicker than
  78. // the default background color.
  79. self.backgroundColor
  80. = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
  81. }
  82. #pragma mark API
  83. - (void)join:(JitsiMeetConferenceOptions *)options {
  84. [self setProps:options == nil ? @{} : [options asProps]];
  85. }
  86. - (void)leave {
  87. [self setProps:@{}];
  88. }
  89. #pragma mark Private methods
  90. /**
  91. * Passes the given props to the React Native application. The props which we pass
  92. * are a combination of 3 different sources:
  93. *
  94. * - JitsiMeet.defaultConferenceOptions
  95. * - This function's parameters
  96. * - Some extras which are added by this function
  97. */
  98. - (void)setProps:(NSDictionary *_Nonnull)newProps {
  99. NSMutableDictionary *props = mergeProps([[JitsiMeet sharedInstance] getDefaultProps], newProps);
  100. props[@"externalAPIScope"] = externalAPIScope;
  101. // TODO: put this in some 'flags' field
  102. props[@"pictureInPictureEnabled"]
  103. = @(self.delegate && [self.delegate respondsToSelector:@selector(enterPictureInPicture:)]);
  104. // This method is supposed to be imperative i.e. a second
  105. // invocation with one and the same URL is expected to join the respective
  106. // conference again if the first invocation was followed by leaving the
  107. // conference. However, React and, respectively,
  108. // appProperties/initialProperties are declarative expressions i.e. one and
  109. // the same URL will not trigger an automatic re-render in the JavaScript
  110. // source code. The workaround implemented bellow introduces imperativeness
  111. // in React Component props by defining a unique value per invocation.
  112. props[@"timestamp"] = @(mach_absolute_time());
  113. if (rootView) {
  114. // Update props with the new URL.
  115. rootView.appProperties = props;
  116. } else {
  117. RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
  118. rootView
  119. = [[RCTRootView alloc] initWithBridge:bridge
  120. moduleName:@"App"
  121. initialProperties:props];
  122. rootView.backgroundColor = self.backgroundColor;
  123. // Add rootView as a subview which completely covers this one.
  124. [rootView setFrame:[self bounds]];
  125. rootView.autoresizingMask
  126. = UIViewAutoresizingFlexibleWidth
  127. | UIViewAutoresizingFlexibleHeight;
  128. [self addSubview:rootView];
  129. }
  130. }
  131. + (BOOL)setPropsInViews:(NSDictionary *_Nonnull)newProps {
  132. BOOL handled = NO;
  133. if (views) {
  134. for (NSString *externalAPIScope in views) {
  135. JitsiMeetView *view
  136. = [self viewForExternalAPIScope:externalAPIScope];
  137. if (view) {
  138. [view setProps:newProps];
  139. handled = YES;
  140. }
  141. }
  142. }
  143. return handled;
  144. }
  145. + (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope {
  146. return [views objectForKey:externalAPIScope];
  147. }
  148. @end