From f3bc4673ef88c70e9909d52197438b2cca048ee1 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 5 Aug 2021 14:57:32 +1000 Subject: [PATCH] Resolve more errors --- Session.xcodeproj/project.pbxproj | 4 + .../Individual/IndividualCallService.swift | 2 +- .../Group/GroupCallNotificationView.swift | 4 + .../Group/GroupCallViewController.swift | 10 + .../ReturnToCallViewController.swift | 219 ++++++++++++++++++ .../Calls/Utilities/TSAccountManager.swift | 2 +- SessionUtilitiesKit/General/AppContext.h | 2 + .../General/UIDevice+featureSupport.swift | 17 ++ 8 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 Session/Calls/UserInterface/ReturnToCallViewController.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index e9711ba71..c117293ba 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -281,6 +281,7 @@ B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; }; B893550126BB9FB3008A7A3A /* ConversationSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893550026BB9FB3008A7A3A /* ConversationSplitViewController.swift */; }; B893550326BBA26F008A7A3A /* CallKitIdStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893550226BBA26F008A7A3A /* CallKitIdStore.swift */; }; + B893550526BBA52E008A7A3A /* ReturnToCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893550426BBA52E008A7A3A /* ReturnToCallViewController.swift */; }; B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; }; B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */; }; B8AE75A425A6C6A6001A84D2 /* Data+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */; }; @@ -1293,6 +1294,7 @@ B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = ""; }; B893550026BB9FB3008A7A3A /* ConversationSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSplitViewController.swift; sourceTree = ""; }; B893550226BBA26F008A7A3A /* CallKitIdStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallKitIdStore.swift; sourceTree = ""; }; + B893550426BBA52E008A7A3A /* ReturnToCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReturnToCallViewController.swift; sourceTree = ""; }; B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = ""; }; B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = ""; }; B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Trimming.swift"; sourceTree = ""; }; @@ -2238,6 +2240,7 @@ B82A0C1426B7B45200C1BCE3 /* RemoteVideoView.h */, B82A0C0F26B7B45200C1BCE3 /* RemoteVideoView.m */, B893550026BB9FB3008A7A3A /* ConversationSplitViewController.swift */, + B893550426BBA52E008A7A3A /* ReturnToCallViewController.swift */, ); path = UserInterface; sourceTree = ""; @@ -5103,6 +5106,7 @@ B82A0C2226B7B45200C1BCE3 /* GroupCallSwipeToastView.swift in Sources */, B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */, B8544E3323D50E4900299F14 /* SNAppearance.swift in Sources */, + B893550526BBA52E008A7A3A /* ReturnToCallViewController.swift in Sources */, 4C586926224FAB83003FD070 /* AVAudioSession+OWS.m in Sources */, C331FFF42558FF0300070591 /* PNOptionView.swift in Sources */, B82A0C2F26B7B45200C1BCE3 /* CallUIAdapter.swift in Sources */, diff --git a/Session/Calls/Individual/IndividualCallService.swift b/Session/Calls/Individual/IndividualCallService.swift index f029822ef..a8c1a18ee 100644 --- a/Session/Calls/Individual/IndividualCallService.swift +++ b/Session/Calls/Individual/IndividualCallService.swift @@ -1165,7 +1165,7 @@ import SessionMessagingKit private func getIceServers() -> Promise<[RTCIceServer]> { return firstly { - accountManager.getTurnServerInfo() + AppEnvironment.shared.accountManager.getTurnServerInfo() }.map(on: .global()) { turnServerInfo -> [RTCIceServer] in Logger.debug("got turn server urls: \(turnServerInfo.urls)") diff --git a/Session/Calls/UserInterface/Group/GroupCallNotificationView.swift b/Session/Calls/UserInterface/Group/GroupCallNotificationView.swift index 0616ec9be..83dc8db1d 100644 --- a/Session/Calls/UserInterface/Group/GroupCallNotificationView.swift +++ b/Session/Calls/UserInterface/Group/GroupCallNotificationView.swift @@ -234,6 +234,9 @@ private class BannerView: UIView { avatarView.autoVCenterInSuperview() avatarView.autoMatch(.height, to: .width, of: avatarView) + // TODO: Implement + + /* if address.isLocalAddress, let avatarImage = profileManager.localProfileAvatarImage() { avatarView.image = avatarImage @@ -243,6 +246,7 @@ private class BannerView: UIView { localUserDisplayMode: .asUser) avatarView.image = avatar } + */ } let label = UILabel() diff --git a/Session/Calls/UserInterface/Group/GroupCallViewController.swift b/Session/Calls/UserInterface/Group/GroupCallViewController.swift index 8334104f7..816661b61 100644 --- a/Session/Calls/UserInterface/Group/GroupCallViewController.swift +++ b/Session/Calls/UserInterface/Group/GroupCallViewController.swift @@ -351,15 +351,25 @@ class GroupCallViewController: UIViewController { if isAnyRemoteDeviceScreenSharing { if !isAutoScrollingToScreenShare { didUserEverSwipeToScreenShare = true + + // TODO: Implement + + /* SDSDatabaseStorage.shared.asyncWrite { writeTx in Self.keyValueStore.setBool(true, key: Self.didUserSwipeToScreenShareKey, transaction: writeTx) } + */ } } else { didUserEverSwipeToSpeakerView = true + + // TODO: Implement + + /* SDSDatabaseStorage.shared.asyncWrite { writeTx in Self.keyValueStore.setBool(true, key: Self.didUserSwipeToSpeakerViewKey, transaction: writeTx) } + */ } } else if swipeToastView.isHidden { diff --git a/Session/Calls/UserInterface/ReturnToCallViewController.swift b/Session/Calls/UserInterface/ReturnToCallViewController.swift new file mode 100644 index 000000000..2a55d09d4 --- /dev/null +++ b/Session/Calls/UserInterface/ReturnToCallViewController.swift @@ -0,0 +1,219 @@ +// +// Copyright (c) 2021 Open Whisper Systems. All rights reserved. +// + +import Foundation + +@objc +public protocol CallViewControllerWindowReference: AnyObject { + var localVideoViewReference: UIView { get } + var remoteVideoViewReference: UIView { get } + var remoteVideoAddress: String { get } + var view: UIView! { get } + + func returnFromPip(pipWindow: UIWindow) +} + +@objc +public class ReturnToCallViewController: UIViewController { + + @objc + public static var pipSize: CGSize { + let nineBySixteen = CGSize(width: 90, height: 160) + let fourByThree = CGSize(width: 272, height: 204) + let threeByFour = CGSize(width: 204, height: 272) + + if UIDevice.current.isIPad && UIDevice.current.isFullScreen { + if CurrentAppContext().frame.size.width > CurrentAppContext().frame.size.height { + return fourByThree + } else { + return threeByFour + } + } else { + return nineBySixteen + } + } + + /* + private weak var callViewController: CallViewControllerWindowReference? + + @objc + public func displayForCallViewController(_ callViewController: CallViewControllerWindowReference) { + guard callViewController !== self.callViewController else { return } + + guard let callViewSnapshot = callViewController.view.snapshotView(afterScreenUpdates: false) else { + return owsFailDebug("failed to snapshot call view") + } + + self.callViewController = callViewController + + view.addSubview(callViewController.remoteVideoViewReference) + callViewController.remoteVideoViewReference.autoPinEdgesToSuperviewEdges() + + view.addSubview(callViewController.localVideoViewReference) + callViewController.localVideoViewReference.layer.cornerRadius = 6 + updateLocalVideoFrame() + + let profileImage = databaseStorage.read { transaction -> UIImage? in + avatarView.configure(address: callViewController.remoteVideoAddress, transaction: transaction) + + return self.profileManagerImpl.profileAvatar(for: callViewController.remoteVideoAddress, + transaction: transaction) + } + + backgroundAvatarView.image = profileImage + + animatePipPresentation(snapshot: callViewSnapshot) + } + + @objc + public func resignCall() { + callViewController?.localVideoViewReference.removeFromSuperview() + callViewController?.remoteVideoViewReference.removeFromSuperview() + callViewController = nil + } + + private lazy var avatarView = ConversationAvatarView(diameterPoints: 60, + localUserDisplayMode: .asUser) + private lazy var backgroundAvatarView = UIImageView() + private lazy var blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + + override public func loadView() { + view = UIView() + + view.backgroundColor = .black + view.clipsToBounds = true + view.layer.cornerRadius = 8 + + backgroundAvatarView.contentMode = .scaleAspectFill + view.addSubview(backgroundAvatarView) + backgroundAvatarView.autoPinEdgesToSuperviewEdges() + + view.addSubview(blurView) + blurView.autoPinEdgesToSuperviewEdges() + + view.addSubview(avatarView) + avatarView.autoCenterInSuperview() + + view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap))) + view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan))) + } + + public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + coordinator.animate(alongsideTransition: { [weak self] _ in + self?.updatePipLayout() + }, completion: nil) + } + + public override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + updatePipLayout() + } + + // MARK: - + + private func updateLocalVideoFrame() { + let localVideoSize = CGSizeScale(Self.pipSize, 0.3) + callViewController?.localVideoViewReference.frame = CGRect( + origin: CGPoint( + x: Self.pipSize.width - 6 - localVideoSize.width, + y: Self.pipSize.height - 6 - localVideoSize.height + ), + size: localVideoSize + ) + } + + private var isAnimating = false + private func animatePipPresentation(snapshot: UIView) { + guard let window = view.window else { return owsFailDebug("missing window") } + + isAnimating = true + + let previousOrigin = window.frame.origin + window.frame = OWSWindowManager.shared.rootWindow.bounds + + view.addSubview(snapshot) + snapshot.autoPinEdgesToSuperviewEdges() + + window.layoutIfNeeded() + + UIView.animate(withDuration: 0.2, animations: { + snapshot.alpha = 0 + window.frame = CGRect( + origin: previousOrigin, + size: Self.pipSize + ).pinnedToVerticalEdge(of: self.pipBoundingRect) + window.layoutIfNeeded() + }) { _ in + snapshot.removeFromSuperview() + self.isAnimating = false + } + } + + private var pipBoundingRect: CGRect { + let padding: CGFloat = 4 + var rect = CurrentAppContext().frame + + let safeAreaInsets = OWSWindowManager.shared.rootWindow.safeAreaInsets + + let leftInset = safeAreaInsets.left + padding + let rightInset = safeAreaInsets.right + padding + rect.origin.x += leftInset + rect.size.width -= leftInset + rightInset + + let topInset = safeAreaInsets.top + padding + let bottomInset = safeAreaInsets.bottom + padding + rect.origin.y += topInset + rect.size.height -= topInset + bottomInset + + return rect + } + + private func updatePipLayout() { + guard !isAnimating else { return } + guard let window = view.window else { return owsFailDebug("missing window") } + let newFrame = CGRect( + origin: window.frame.origin, + size: Self.pipSize + ).pinnedToVerticalEdge(of: pipBoundingRect) + UIView.animate(withDuration: 0.25) { + self.updateLocalVideoFrame() + window.frame = newFrame + } + } + + @objc func handlePan(sender: UIPanGestureRecognizer) { + guard let window = view.window else { return owsFailDebug("missing window") } + + switch sender.state { + case .began, .changed: + let translation = sender.translation(in: window) + sender.setTranslation(.zero, in: window) + + window.frame.origin.y += translation.y + window.frame.origin.x += translation.x + case .ended, .cancelled, .failed: + window.animateDecelerationToVerticalEdge( + withDuration: 0.35, + velocity: sender.velocity(in: window), + boundingRect: pipBoundingRect + ) + default: + break + } + } + + @objc + private func handleTap(sender: UITapGestureRecognizer) { + OWSWindowManager.shared.returnToCallView() + } + + // MARK: Orientation + + public override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return UIDevice.current.isIPad ? .all : .portrait + } + + */ +} diff --git a/Session/Calls/Utilities/TSAccountManager.swift b/Session/Calls/Utilities/TSAccountManager.swift index 46b7ce4b5..3432055f2 100644 --- a/Session/Calls/Utilities/TSAccountManager.swift +++ b/Session/Calls/Utilities/TSAccountManager.swift @@ -4,7 +4,7 @@ import PromiseKit -extension TSAccountManager { +extension AccountManager { func getTurnServerInfo() -> Promise { let request = TSRequest(url: URL(string: "v1/accounts/turn")!, method: "GET", parameters: [:]) diff --git a/SessionUtilitiesKit/General/AppContext.h b/SessionUtilitiesKit/General/AppContext.h index 50305e99e..7610324a3 100755 --- a/SessionUtilitiesKit/General/AppContext.h +++ b/SessionUtilitiesKit/General/AppContext.h @@ -45,6 +45,8 @@ NSString *NSStringForUIApplicationState(UIApplicationState value); @property (atomic, nullable) UIWindow *mainWindow; +@property (nonatomic, readonly) CGRect frame; + // Unlike UIApplication.applicationState, this is thread-safe. // It contains the "last known" application state. // diff --git a/SessionUtilitiesKit/General/UIDevice+featureSupport.swift b/SessionUtilitiesKit/General/UIDevice+featureSupport.swift index 20d723e13..2995708df 100644 --- a/SessionUtilitiesKit/General/UIDevice+featureSupport.swift +++ b/SessionUtilitiesKit/General/UIDevice+featureSupport.swift @@ -66,4 +66,21 @@ public extension UIDevice { // https://stackoverflow.com/questions/20987249/how-do-i-programmatically-set-device-orientation-in-ios7 UINavigationController.attemptRotationToDeviceOrientation() } + + var isFullScreen: Bool { + let windowSize = CurrentAppContext().frame.size + let screenSize = UIScreen.main.bounds.size + return windowSize.largerAxis == screenSize.largerAxis && windowSize.smallerAxis == screenSize.smallerAxis + } +} + +extension CGSize { + + var largerAxis: CGFloat { + Swift.max(width, height) + } + + var smallerAxis: CGFloat { + min(width, height) + } }