diff --git a/ios/app/src/Info.plist b/ios/app/src/Info.plist
index ae7f21e1c..39d6437c9 100644
--- a/ios/app/src/Info.plist
+++ b/ios/app/src/Info.plist
@@ -55,14 +55,14 @@
- NSCalendarsUsageDescription
- Displays the user's meetings in the app.
+ NSCalendarsUsageDescription
+ See your scheduled conferences in the app.
NSCameraUsageDescription
Participate in conferences with video.
NSLocationWhenInUseUsageDescription
NSMicrophoneUsageDescription
- Participate in conferences with audio.
+ Participate in conferences with voice.
UIBackgroundModes
audio
diff --git a/ios/example-pip-app/PiPApp.xcodeproj/project.pbxproj b/ios/example-pip-app/example-pip-app.xcodeproj/project.pbxproj
similarity index 95%
rename from ios/example-pip-app/PiPApp.xcodeproj/project.pbxproj
rename to ios/example-pip-app/example-pip-app.xcodeproj/project.pbxproj
index 162437c52..dfca5f413 100644
--- a/ios/example-pip-app/PiPApp.xcodeproj/project.pbxproj
+++ b/ios/example-pip-app/example-pip-app.xcodeproj/project.pbxproj
@@ -35,7 +35,7 @@
/* Begin PBXFileReference section */
C6A34247204DF18000E062DD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = ""; };
- C6F99C37204DE6BE0001F710 /* PiPApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PiPApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ C6F99C37204DE6BE0001F710 /* example-pip-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example-pip-app.app; sourceTree = BUILT_PRODUCTS_DIR; };
C6F99C3A204DE6BE0001F710 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
C6F99C3C204DE6BE0001F710 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
C6F99C3F204DE6BE0001F710 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
@@ -70,7 +70,7 @@
C6F99C38204DE6BE0001F710 /* Products */ = {
isa = PBXGroup;
children = (
- C6F99C37204DE6BE0001F710 /* PiPApp.app */,
+ C6F99C37204DE6BE0001F710 /* example-pip-app.app */,
);
name = Products;
sourceTree = "";
@@ -100,9 +100,9 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- C6F99C36204DE6BE0001F710 /* PiPApp */ = {
+ C6F99C36204DE6BE0001F710 /* example-pip-app */ = {
isa = PBXNativeTarget;
- buildConfigurationList = C6F99C49204DE6BE0001F710 /* Build configuration list for PBXNativeTarget "PiPApp" */;
+ buildConfigurationList = C6F99C49204DE6BE0001F710 /* Build configuration list for PBXNativeTarget "example-pip-app" */;
buildPhases = (
C6A3424A204DF91D00E062DD /* Run Adjust ATS for loading JS bundle */,
C6F99C62204DEFFE0001F710 /* Run React Packager */,
@@ -116,9 +116,9 @@
);
dependencies = (
);
- name = PiPApp;
- productName = ExampleAppUsingJitsiWithPiP;
- productReference = C6F99C37204DE6BE0001F710 /* PiPApp.app */;
+ name = example-pip-app;
+ productName = example-pip-app;
+ productReference = C6F99C37204DE6BE0001F710 /* example-pip-app.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
@@ -142,7 +142,7 @@
};
};
};
- buildConfigurationList = C6F99C32204DE6BE0001F710 /* Build configuration list for PBXProject "PiPApp" */;
+ buildConfigurationList = C6F99C32204DE6BE0001F710 /* Build configuration list for PBXProject "example-pip-app" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
@@ -155,7 +155,7 @@
projectDirPath = "";
projectRoot = "";
targets = (
- C6F99C36204DE6BE0001F710 /* PiPApp */,
+ C6F99C36204DE6BE0001F710 /* example-pip-app */,
);
};
/* End PBXProject section */
@@ -366,7 +366,7 @@
INFOPLIST_FILE = src/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.jitsi.PiPApp;
+ PRODUCT_BUNDLE_IDENTIFIER = com.jitsi.example-pip-app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -382,7 +382,7 @@
INFOPLIST_FILE = src/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.jitsi.PiPApp;
+ PRODUCT_BUNDLE_IDENTIFIER = com.jitsi.example-pip-app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -392,7 +392,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- C6F99C32204DE6BE0001F710 /* Build configuration list for PBXProject "PiPApp" */ = {
+ C6F99C32204DE6BE0001F710 /* Build configuration list for PBXProject "example-pip-app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C6F99C47204DE6BE0001F710 /* Debug */,
@@ -401,7 +401,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- C6F99C49204DE6BE0001F710 /* Build configuration list for PBXNativeTarget "PiPApp" */ = {
+ C6F99C49204DE6BE0001F710 /* Build configuration list for PBXNativeTarget "example-pip-app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C6F99C4A204DE6BE0001F710 /* Debug */,
diff --git a/ios/example-pip-app/src/AppDelegate.swift b/ios/example-pip-app/src/AppDelegate.swift
index 1f935761c..96bb81ec6 100644
--- a/ios/example-pip-app/src/AppDelegate.swift
+++ b/ios/example-pip-app/src/AppDelegate.swift
@@ -1,10 +1,18 @@
-//
-// AppDelegate.swift
-// ExampleAppUsingJitsiWithPiP
-//
-// Created by Daniel Ornelas on 3/5/18.
-// Copyright © 2018 Atlassian Inc. All rights reserved.
-//
+/*
+ * Copyright @ 2017-present Atlassian Pty Ltd
+ *
+ * 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 JitsiMeet
@@ -30,6 +38,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return JitsiMeetView.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
}
-
}
-
diff --git a/ios/example-pip-app/src/Base.lproj/Main.storyboard b/ios/example-pip-app/src/Base.lproj/Main.storyboard
index 35ee2b87b..fc16ccefb 100644
--- a/ios/example-pip-app/src/Base.lproj/Main.storyboard
+++ b/ios/example-pip-app/src/Base.lproj/Main.storyboard
@@ -13,17 +13,17 @@
-
+
diff --git a/ios/example-pip-app/src/ViewController.swift b/ios/example-pip-app/src/ViewController.swift
index 64a4723ee..981285b5d 100644
--- a/ios/example-pip-app/src/ViewController.swift
+++ b/ios/example-pip-app/src/ViewController.swift
@@ -1,10 +1,18 @@
-//
-// ViewController.swift
-// ExampleAppUsingJitsiWithPiP
-//
-// Created by Daniel Ornelas on 3/5/18.
-// Copyright © 2018 Atlassian Inc. All rights reserved.
-//
+/*
+ * Copyright @ 2017-present Atlassian Pty Ltd
+ *
+ * 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
import JitsiMeet
@@ -13,7 +21,7 @@ class ViewController: UIViewController {
@IBOutlet weak var videoButton: UIButton?
- private var jitsiMeetManager: JitsiMeetManager?
+ private var jitsiMeetCoordinator: JitsiMeetPresentationCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
@@ -21,12 +29,11 @@ class ViewController: UIViewController {
// MARK: - Actions
- @IBAction func startMeeting(sender: Any?) {
- //let url = URL(string: "")
- self.jitsiMeetManager = JitsiMeetManager()
- jitsiMeetManager?.welcomeScreenEnabled = true
- jitsiMeetManager?.load(withUrl: nil)
+ @IBAction func openJitsiMeet(sender: Any?) {
+ let jitsiMeetCoordinator = JitsiMeetPresentationCoordinator()
+ self.jitsiMeetCoordinator = jitsiMeetCoordinator
+ jitsiMeetCoordinator.jitsiMeetView().welcomePageEnabled = true
+ jitsiMeetCoordinator.jitsiMeetView().load(nil)
+ jitsiMeetCoordinator.show()
}
-
}
-
diff --git a/ios/jitsi-meet.xcworkspace/contents.xcworkspacedata b/ios/jitsi-meet.xcworkspace/contents.xcworkspacedata
index ed0af25d3..bdcb0765e 100644
--- a/ios/jitsi-meet.xcworkspace/contents.xcworkspacedata
+++ b/ios/jitsi-meet.xcworkspace/contents.xcworkspacedata
@@ -2,7 +2,7 @@
+ location = "group:example-pip-app/example-pip-app.xcodeproj">
diff --git a/ios/sdk/sdk.xcodeproj/project.pbxproj b/ios/sdk/sdk.xcodeproj/project.pbxproj
index b3759bcd9..5e7da94bd 100644
--- a/ios/sdk/sdk.xcodeproj/project.pbxproj
+++ b/ios/sdk/sdk.xcodeproj/project.pbxproj
@@ -30,7 +30,7 @@
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; };
C6A3425F204EF76800E062DD /* PiPWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425C204EF76800E062DD /* PiPWindow.swift */; };
- C6A34260204EF76800E062DD /* JitsiMeetManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425D204EF76800E062DD /* JitsiMeetManager.swift */; };
+ C6A34260204EF76800E062DD /* JitsiMeetPresentationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425D204EF76800E062DD /* JitsiMeetPresentationCoordinator.swift */; };
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
C6A3426D204F1C3300E062DD /* JitsiMeetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3426C204F1C3300E062DD /* JitsiMeetViewController.swift */; };
C6F99C15204DB63E0001F710 /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */; };
@@ -62,10 +62,10 @@
0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
98E09B5C73D9036B4ED252FC /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = ""; };
9C77CA3CC919B081F1A52982 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = ""; };
- C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-resize@2x.png"; sourceTree = ""; };
- C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "image-resize@3x.png"; sourceTree = ""; };
+ C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = ""; };
+ C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@3x.png"; path = "src/picture-in-picture/image-resize@3x.png"; sourceTree = ""; };
C6A3425C204EF76800E062DD /* PiPWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PiPWindow.swift; sourceTree = ""; };
- C6A3425D204EF76800E062DD /* JitsiMeetManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JitsiMeetManager.swift; sourceTree = ""; };
+ C6A3425D204EF76800E062DD /* JitsiMeetPresentationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JitsiMeetPresentationCoordinator.swift; sourceTree = ""; };
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = ""; };
C6A3426C204F1C3300E062DD /* JitsiMeetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiMeetViewController.swift; sourceTree = ""; };
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = ""; };
@@ -119,7 +119,7 @@
0BD906E71EC0C00300C8C18E /* src */ = {
isa = PBXGroup;
children = (
- C6A3426B204F127900E062DD /* JitsiMeetManager */,
+ C6A3426B204F127900E062DD /* picture-in-picture */,
0BCA495C1EC4B6C600B793EE /* AudioMode.m */,
0BB9AD7C1F60356D001C08DB /* AppInfo.m */,
0BB9AD7A1F5EC8F4001C08DB /* CallKit.m */,
@@ -161,23 +161,15 @@
name = Pods;
sourceTree = "";
};
- C6245F5A2052043F0040BE68 /* PiPWindow */ = {
+ C6A3426B204F127900E062DD /* picture-in-picture */ = {
isa = PBXGroup;
children = (
C6A3425E204EF76800E062DD /* DragGestureController.swift */,
+ C6A3425D204EF76800E062DD /* JitsiMeetPresentationCoordinator.swift */,
+ C6A3426C204F1C3300E062DD /* JitsiMeetViewController.swift */,
C6A3425C204EF76800E062DD /* PiPWindow.swift */,
);
- path = PiPWindow;
- sourceTree = "";
- };
- C6A3426B204F127900E062DD /* JitsiMeetManager */ = {
- isa = PBXGroup;
- children = (
- C6245F5A2052043F0040BE68 /* PiPWindow */,
- C6A3425D204EF76800E062DD /* JitsiMeetManager.swift */,
- C6A3426C204F1C3300E062DD /* JitsiMeetViewController.swift */,
- );
- path = JitsiMeetManager;
+ path = "picture-in-picture";
sourceTree = "";
};
/* End PBXGroup section */
@@ -345,7 +337,7 @@
buildActionMask = 2147483647;
files = (
0BB9AD7B1F5EC8F4001C08DB /* CallKit.m in Sources */,
- C6A34260204EF76800E062DD /* JitsiMeetManager.swift in Sources */,
+ C6A34260204EF76800E062DD /* JitsiMeetPresentationCoordinator.swift in Sources */,
0BB9AD7D1F60356D001C08DB /* AppInfo.m in Sources */,
0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */,
0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */,
diff --git a/ios/sdk/src/JitsiMeetManager/JitsiMeetManager.swift b/ios/sdk/src/JitsiMeetManager/JitsiMeetManager.swift
deleted file mode 100644
index abd24b918..000000000
--- a/ios/sdk/src/JitsiMeetManager/JitsiMeetManager.swift
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright © 2018 Jitsi. All rights reserved.
-
-import Foundation
-
-/// Creates and coordinates the presentation of JitsiMeetViewController inside of an external window
-/// which can be resized and dragged with custom PiP mode
-open class JitsiMeetManager: NSObject {
-
- /// Defines if welcome screen should be on
- public var welcomeScreenEnabled: Bool = false {
- didSet {
- meetViewController?.jitsiMeetView.welcomePageEnabled = welcomeScreenEnabled
- }
- }
-
- private(set) var meetViewController: JitsiMeetViewController?
- private(set) var meetWindow: PiPWindow?
-
- override public init() {
- super.init()
- self.meetViewController = makeMeetViewController()
- self.meetWindow = makeMeetWindow()
- }
-
- public init(meetViewController: JitsiMeetViewController? = nil, meetWindow: PiPWindow? = nil) {
- super.init()
- self.meetViewController = meetViewController ?? makeMeetViewController()
- self.meetWindow = meetWindow ?? makeMeetWindow()
- }
-
- /// Presents and loads a jitsi meet view
- ///
- /// - Parameter url: The url of the presentation
- public func load(withUrl url: URL?) {
- meetWindow?.show()
- meetViewController?.jitsiMeetView.load(url)
- }
-
- /// Presents and loads a jitsi meet view with configuration
- ///
- /// - Parameter urlObject: A dictionary of keys to be used for configuration
- public func load(withUrlObject urlObject: [AnyHashable : Any]?) {
- meetWindow?.show()
- meetViewController?.jitsiMeetView.loadURLObject(urlObject)
- }
-
- deinit {
- cleanUp()
- }
-
- // MARK: - helpers
-
- fileprivate func cleanUp() {
- // TODO: more clean up work on this
-
- meetWindow?.isHidden = true
- meetWindow?.stopDragGesture()
- }
-
- private func makeMeetViewController() -> JitsiMeetViewController {
- let vc = JitsiMeetViewController()
- vc.jitsiMeetView.welcomePageEnabled = self.welcomeScreenEnabled
- vc.jitsiMeetView.pictureInPictureEnabled = true
- vc.delegate = self
- return vc
- }
-
- private func makeMeetWindow() -> PiPWindow {
- let window = PiPWindow(frame: UIScreen.main.bounds)
- window.backgroundColor = .clear
- window.windowLevel = UIWindowLevelStatusBar + 100
- window.rootViewController = self.meetViewController
- return window
- }
-}
-
-extension JitsiMeetManager: JitsiMeetViewControllerDelegate {
-
- open func performPresentationUpdate(to: JitsiMeetPresentationUpdate) {
- guard let meetWindow = self.meetWindow else { return }
-
- switch to {
- case .enterPiP:
- meetWindow.goToPiP()
- case .traitChange:
- // resize to full screen if rotation happens
- if meetWindow.isInPiP {
- meetWindow.goToFullScreen()
- }
- }
- }
-
- open func meetingStarted() {
- // do something
- }
-
- open func meetingEnded(wasFailure: Bool) {
- cleanUp()
- }
-}
-
diff --git a/ios/sdk/src/JitsiMeetManager/PiPWindow/DragGestureController.swift b/ios/sdk/src/picture-in-picture/DragGestureController.swift
similarity index 73%
rename from ios/sdk/src/JitsiMeetManager/PiPWindow/DragGestureController.swift
rename to ios/sdk/src/picture-in-picture/DragGestureController.swift
index 92f3b1b34..bf0017b0f 100644
--- a/ios/sdk/src/JitsiMeetManager/PiPWindow/DragGestureController.swift
+++ b/ios/sdk/src/picture-in-picture/DragGestureController.swift
@@ -1,4 +1,18 @@
-// Copyright © 2018 Jitsi. All rights reserved.
+/*
+ * Copyright @ 2017-present Atlassian Pty Ltd
+ *
+ * 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.
+ */
final class DragGestureController {
@@ -7,7 +21,8 @@ final class DragGestureController {
private var frameBeforeDragging: CGRect = CGRect.zero
private weak var view: UIView?
private lazy var panGesture: UIPanGestureRecognizer = {
- return UIPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
+ return UIPanGestureRecognizer(target: self,
+ action: #selector(handlePan(gesture:)))
}()
func startDragListener(inView view: UIView) {
@@ -47,7 +62,8 @@ final class DragGestureController {
let distanceMagnitude = magnitude(vector: distance)
let velocityMagnitude = magnitude(vector: velocity)
let animationDuration = 0.5
- let initialSpringVelocity = velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
+ let initialSpringVelocity =
+ velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
frame.origin = CGPoint(x: finalPos.x, y: finalPos.y)
@@ -91,8 +107,14 @@ final class DragGestureController {
goUp = location.y < bounds.midY
}
- let finalPosX: CGFloat = goLeft ? adjustedBounds.origin.x : bounds.size.width - insets.right - currentSize.width
- let finalPosY: CGFloat = goUp ? adjustedBounds.origin.y : bounds.size.height - insets.bottom - currentSize.height
+ let finalPosX: CGFloat =
+ goLeft
+ ? adjustedBounds.origin.x
+ : bounds.size.width - insets.right - currentSize.width
+ let finalPosY: CGFloat =
+ goUp
+ ? adjustedBounds.origin.y
+ : bounds.size.height - insets.bottom - currentSize.height
return CGPoint(x: finalPosX, y: finalPosY)
}
@@ -101,4 +123,3 @@ final class DragGestureController {
return sqrt(pow(vector.x, 2) + pow(vector.y, 2))
}
}
-
diff --git a/ios/sdk/src/picture-in-picture/JitsiMeetPresentationCoordinator.swift b/ios/sdk/src/picture-in-picture/JitsiMeetPresentationCoordinator.swift
new file mode 100644
index 000000000..404bf4c01
--- /dev/null
+++ b/ios/sdk/src/picture-in-picture/JitsiMeetPresentationCoordinator.swift
@@ -0,0 +1,97 @@
+/*
+ * Copyright @ 2017-present Atlassian Pty Ltd
+ *
+ * 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 Foundation
+
+/// Coordinates the presentation of JitsiMeetViewController inside of
+/// an external window that can be resized and dragged with custom PiP mode
+open class JitsiMeetPresentationCoordinator: NSObject {
+
+ fileprivate let meetViewController: JitsiMeetViewController
+ fileprivate let meetWindow: PiPWindow
+
+ public init(meetViewController: JitsiMeetViewController? = nil,
+ meetWindow: PiPWindow? = nil) {
+ self.meetViewController = meetViewController ?? JitsiMeetViewController()
+ self.meetWindow = meetWindow ?? PiPWindow(frame: UIScreen.main.bounds)
+
+ super.init()
+
+ configureMeetWindow()
+ configureMeetViewController()
+ }
+
+ public func jitsiMeetView() -> JitsiMeetView {
+ return meetViewController.jitsiMeetView
+ }
+
+ public func show() {
+ meetWindow.show()
+ }
+
+ public func hide() {
+ meetWindow.hide()
+ }
+
+ deinit {
+ cleanUp()
+ }
+
+ // MARK: - helpers
+
+ fileprivate func cleanUp() {
+ // TODO: more clean up work on this
+
+ meetWindow.isHidden = true
+ meetWindow.stopDragGesture()
+ }
+
+ private func configureMeetViewController() {
+ meetViewController.jitsiMeetView.pictureInPictureEnabled = true
+ meetViewController.delegate = self
+ }
+
+ private func configureMeetWindow() {
+ meetWindow.backgroundColor = .clear
+ meetWindow.windowLevel = UIWindowLevelStatusBar + 100
+ meetWindow.rootViewController = self.meetViewController
+ }
+}
+
+extension JitsiMeetPresentationCoordinator: JitsiMeetViewControllerDelegate {
+
+ open func performPresentationUpdate(to: JitsiMeetPresentationUpdate) {
+ switch to {
+ case .enterPictureInPicture:
+ meetWindow.enterPictureInPicture()
+ case .traitChange:
+ // resize to full screen if rotation happens
+ if meetWindow.isInPiP {
+ meetWindow.exitPictureInPicture()
+ }
+ }
+ }
+
+ open func conferenceStarted() {
+ if meetWindow.isHidden {
+ meetWindow.show()
+ }
+ }
+
+ open func conferenceEnded(didFail: Bool) {
+ cleanUp()
+ }
+}
diff --git a/ios/sdk/src/JitsiMeetManager/JitsiMeetViewController.swift b/ios/sdk/src/picture-in-picture/JitsiMeetViewController.swift
similarity index 63%
rename from ios/sdk/src/JitsiMeetManager/JitsiMeetViewController.swift
rename to ios/sdk/src/picture-in-picture/JitsiMeetViewController.swift
index a9f471a39..c9232e428 100644
--- a/ios/sdk/src/JitsiMeetManager/JitsiMeetViewController.swift
+++ b/ios/sdk/src/picture-in-picture/JitsiMeetViewController.swift
@@ -1,21 +1,42 @@
-// Copyright © 2018 Jitsi. All rights reserved.
+/*
+ * Copyright @ 2017-present Atlassian Pty Ltd
+ *
+ * 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.
+ */
public enum JitsiMeetPresentationUpdate {
+ /// The conference wants to enter Picture-in-Picture
+ case enterPictureInPicture
+
/// A system traitCollectionChange (usually screen rotation)
case traitChange
- /// Meeting wants to enter PiP mode
- case enterPiP
}
public protocol JitsiMeetViewControllerDelegate: class {
- /// Notifies a change of the meeting presentation style.
+ /// Notifies a change of the conference presentation style.
///
/// - Parameter to: The presentation state that will be changed to
func performPresentationUpdate(to: JitsiMeetPresentationUpdate)
- func meetingStarted()
- func meetingEnded(wasFailure: Bool)
+
+ /// The conference started
+ func conferenceStarted()
+
+ /// The conference ended
+ ///
+ /// - Parameter didFail: The reason of ending the conference
+ func conferenceEnded(didFail: Bool)
}
/// Wrapper ViewController of a JitsiMeetView
@@ -52,7 +73,7 @@ extension JitsiMeetViewController: JitsiMeetViewDelegate {
open func conferenceJoined(_ data: [AnyHashable : Any]!) {
DispatchQueue.main.async {
- self.delegate?.meetingStarted()
+ self.delegate?.conferenceStarted()
}
}
@@ -62,13 +83,13 @@ extension JitsiMeetViewController: JitsiMeetViewDelegate {
open func conferenceLeft(_ data: [AnyHashable : Any]!) {
DispatchQueue.main.async {
- self.delegate?.meetingEnded(wasFailure: true)
+ self.delegate?.conferenceEnded(didFail: true)
}
}
open func conferenceFailed(_ data: [AnyHashable : Any]!) {
DispatchQueue.main.async {
- self.delegate?.meetingEnded(wasFailure: true)
+ self.delegate?.conferenceEnded(didFail: true)
}
}
@@ -78,7 +99,7 @@ extension JitsiMeetViewController: JitsiMeetViewDelegate {
open func enterPicture(inPicture data: [AnyHashable : Any]!) {
DispatchQueue.main.async {
- self.delegate?.performPresentationUpdate(to: .enterPiP)
+ self.delegate?.performPresentationUpdate(to: .enterPictureInPicture)
}
}
}
diff --git a/ios/sdk/src/JitsiMeetManager/PiPWindow/PiPWindow.swift b/ios/sdk/src/picture-in-picture/PiPWindow.swift
similarity index 65%
rename from ios/sdk/src/JitsiMeetManager/PiPWindow/PiPWindow.swift
rename to ios/sdk/src/picture-in-picture/PiPWindow.swift
index 424859267..1d9f8a02e 100644
--- a/ios/sdk/src/JitsiMeetManager/PiPWindow/PiPWindow.swift
+++ b/ios/sdk/src/picture-in-picture/PiPWindow.swift
@@ -1,11 +1,28 @@
-// Copyright © 2018 Jitsi. All rights reserved.
+/*
+ * Copyright @ 2017-present Atlassian Pty Ltd
+ *
+ * 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.
+ */
/// A window that allows its root view controller to be presented
/// in full screen or in a custom Picture in Picture mode
open class PiPWindow: UIWindow {
/// Limits the boundries of root view position on screen when minimized
- public var dragBoundInsets: UIEdgeInsets = UIEdgeInsets(top: 25, left: 5, bottom: 5, right: 5) {
+ public var dragBoundInsets: UIEdgeInsets = UIEdgeInsets(top: 25,
+ left: 5,
+ bottom: 5,
+ right: 5) {
didSet {
dragController.insets = dragBoundInsets
}
@@ -24,7 +41,8 @@ open class PiPWindow: UIWindow {
private var exitPiPButton: UIButton?
/// Help out to bubble up the gesture detection outside of the rootVC frame
- open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
+ open override func point(inside point: CGPoint,
+ with event: UIEvent?) -> Bool {
guard let vc = rootViewController else {
return super.point(inside: point, with: event)
}
@@ -36,35 +54,24 @@ open class PiPWindow: UIWindow {
if self.isHidden || self.alpha < 1 {
self.isHidden = false
self.alpha = 0
-
- UIView.animate(
- withDuration: 0.1,
- delay: 0,
- options: .beginFromCurrentState,
- animations: {
- self.alpha = 1
- },
- completion: nil)
+ animateTransition {
+ self.alpha = 1
+ }
}
}
/// animate out the window
open func hide() {
if !self.isHidden || self.alpha > 0 {
- UIView.animate(
- withDuration: 0.1,
- delay: 0,
- options: .beginFromCurrentState,
- animations: {
- self.alpha = 0
- self.isHidden = true
- },
- completion: nil)
+ animateTransition {
+ self.alpha = 0
+ self.isHidden = true
+ }
}
}
/// Resize the root view to PiP mode
- open func goToPiP() {
+ open func enterPictureInPicture() {
guard let view = rootViewController?.view else { return }
isInPiP = true
animateRootViewChange()
@@ -72,13 +79,15 @@ open class PiPWindow: UIWindow {
dragController.insets = dragBoundInsets
// add single tap gesture recognition for displaying exit PiP UI
- let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(toggleExitPiP))
+ let exitSelector = #selector(toggleExitPiP)
+ let tapGestureRecognizer = UITapGestureRecognizer(target: self,
+ action: exitSelector)
self.tapGestureRecognizer = tapGestureRecognizer
view.addGestureRecognizer(tapGestureRecognizer)
}
/// Resize the root view to full screen
- open func goToFullScreen() {
+ open func exitPictureInPicture() {
isInPiP = false
animateRootViewChange()
dragController.stopDragListener()
@@ -88,7 +97,8 @@ open class PiPWindow: UIWindow {
exitPiPButton = nil
// remove gesture
- tapGestureRecognizer?.removeTarget(self, action: #selector(toggleExitPiP))
+ let exitSelector = #selector(toggleExitPiP)
+ tapGestureRecognizer?.removeTarget(self, action: exitSelector)
tapGestureRecognizer = nil
}
@@ -98,8 +108,11 @@ open class PiPWindow: UIWindow {
}
/// Customize the presentation of exit pip button
- open func configureExitPiPButton(target: Any, action: Selector) -> UIButton {
- let buttonImage = UIImage.init(named: "image-resize", in: Bundle(for: type(of: self)), compatibleWith: nil)
+ open func configureExitPiPButton(target: Any,
+ action: Selector) -> UIButton {
+ let buttonImage = UIImage.init(named: "image-resize",
+ in: Bundle(for: type(of: self)),
+ compatibleWith: nil)
let button = UIButton(type: .custom)
let size: CGSize = CGSize(width: 44, height: 44)
button.setImage(buttonImage, for: .normal)
@@ -143,7 +156,9 @@ open class PiPWindow: UIWindow {
if exitPiPButton == nil {
// show button
- let button = configureExitPiPButton(target: self, action: #selector(exitPiP))
+ let exitSelector = #selector(exitPictureInPicture)
+ let button = configureExitPiPButton(target: self,
+ action: exitSelector)
view.addSubview(button)
exitPiPButton = button
@@ -152,10 +167,19 @@ open class PiPWindow: UIWindow {
exitPiPButton?.removeFromSuperview()
exitPiPButton = nil
}
-
}
@objc private func exitPiP() {
- goToFullScreen()
+ exitPictureInPicture()
+ }
+
+ // MARK: - Animation transition
+
+ private func animateTransition(animations: @escaping () -> Void) {
+ UIView.animate(withDuration: 0.1,
+ delay: 0,
+ options: .beginFromCurrentState,
+ animations: animations,
+ completion: nil)
}
}
diff --git a/ios/sdk/image-resize@2x.png b/ios/sdk/src/picture-in-picture/image-resize@2x.png
similarity index 100%
rename from ios/sdk/image-resize@2x.png
rename to ios/sdk/src/picture-in-picture/image-resize@2x.png
diff --git a/ios/sdk/image-resize@3x.png b/ios/sdk/src/picture-in-picture/image-resize@3x.png
similarity index 100%
rename from ios/sdk/image-resize@3x.png
rename to ios/sdk/src/picture-in-picture/image-resize@3x.png