diff --git a/CHANGES.rst b/CHANGES.rst index 4eeea8623..bd72b4413 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,8 @@ Changes to be released in next version * MXRoomSummary: Adapt room summary changes on MatrixSDK (#4360). * EncryptionKeyManager: Create keys for room last message data type. * Integrated FLEX for debug builds. - * Add dial pad for PSTN capable servers to menu on homescreen + * VoIP: Add dial pad for PSTN capable servers to menu on homescreen. + * VoIP: Replace call bar with PiP tiles for every type of calls. 🐛 Bugfix * StartChatViewController: Add more helpful message when trying to start DM with a user that does not exist (#224). diff --git a/Riot/Managers/Call/CallPresenter.swift b/Riot/Managers/Call/CallPresenter.swift index e3b4f6e31..4f5ad7e13 100644 --- a/Riot/Managers/Call/CallPresenter.swift +++ b/Riot/Managers/Call/CallPresenter.swift @@ -48,13 +48,11 @@ class CallPresenter: NSObject { updateOnHoldCall() } } - private weak var inBarCallVC: UIViewController? private weak var pipCallVC: UIViewController? /// UI operation queue for various UI operations private var uiOperationQueue: OperationQueue = .main /// Flag to indicate whether the presenter is active. private var isStarted: Bool = false - private var callTimer: Timer? #if canImport(JitsiMeetSDK) private var widgetEventsListener: Any? /// Jitsi calls map. Keys are CallKit call UUIDs, values are corresponding widgets. @@ -121,7 +119,6 @@ class CallPresenter: NSObject { MXLog.debug("[CallPresenter] start") addCallObservers() - startCallTimer() } /// Stop the service @@ -129,22 +126,6 @@ class CallPresenter: NSObject { MXLog.debug("[CallPresenter] stop") removeCallObservers() - stopCallTimer() - } - - /// Method to be called when the call status bar is tapped. - func callStatusBarTapped() { - MXLog.debug("[CallPresenter] callStatusBarTapped") - - if let callVC = (inBarCallVC ?? activeCallVC) as? CallViewController { - dismissCallBar(for: callVC) - presentCallVC(callVC) - return - } - if let jitsiVC = jitsiVC { - dismissCallBar(for: jitsiVC) - presentCallVC(jitsiVC) - } } // MARK - Group Calls @@ -412,17 +393,12 @@ class CallPresenter: NSObject { if let oldCallVC = self.callVCs.values.first, self.presentedCallVC == nil, !self.uiOperationQueue.containsPresentCallVCOperation, - !self.uiOperationQueue.containsPresentCallBarOperation { - // present the call bar after dismissing this one - self.presentCallBar(for: oldCallVC) + !self.uiOperationQueue.containsEnterPiPOperation { + // present the call screen after dismissing this one + self.presentCallVC(oldCallVC) } } - if inBarCallVC == callVC { - // this call currently in the status bar, - // first present it and then dismiss it - presentCallVC(callVC) - } if pipCallVC == callVC { // this call currently in the PiP mode, // first present it by exiting PiP mode and then dismiss it @@ -446,36 +422,6 @@ class CallPresenter: NSObject { } } - // MARK: - Timer - - private func startCallTimer() { - callTimer = Timer.scheduledTimer(timeInterval: 1.0, - target: self, - selector: #selector(callTimerFired(_:)), - userInfo: nil, - repeats: true) - } - - private func stopCallTimer() { - callTimer?.invalidate() - callTimer = nil - } - - @objc private func callTimerFired(_ timer: Timer) { - if let inBarCallVC = inBarCallVC as? CallViewController { - guard let call = inBarCallVC.mxCall else { - return - } - guard call.state != .ended else { - return - } - - updateCallBar() - } else if inBarCallVC as? JitsiViewController != nil { - updateCallBar() - } - } - // MARK: - Observers private func addCallObservers() { @@ -614,14 +560,11 @@ class CallPresenter: NSObject { } case .connected: MXLog.debug("[CallPresenter] callStateChanged: call connected: \(call.callId)") - callTimer?.fire() case .onHold: MXLog.debug("[CallPresenter] callStateChanged: call holded: \(call.callId)") - callTimer?.fire() callHolded(withCallId: call.callId) case .remotelyOnHold: MXLog.debug("[CallPresenter] callStateChanged: call remotely holded: \(call.callId)") - callTimer?.fire() callHolded(withCallId: call.callId) case .ended: MXLog.debug("[CallPresenter] callStateChanged: call ended: \(call.callId)") @@ -716,10 +659,6 @@ class CallPresenter: NSObject { // do not use PiP transitions here, as we really want to present the screen callVC.transitioningDelegate = nil - if let inBarCallVC = inBarCallVC { - dismissCallBar(for: inBarCallVC) - } - if let presentedCallVC = presentedCallVC { dismissCallVC(presentedCallVC) } @@ -781,42 +720,6 @@ class CallPresenter: NSObject { uiOperationQueue.addOperation(operation) } - // MARK: - Call Bar - - private func presentCallBar(for callVC: UIViewController, completion: (() -> Void)? = nil) { - logCallVC(callVC, log: "presentCallBar") - - let activeCallVC = self.activeCallVC - - let operation = CallBarPresentOperation(presenter: self, activeCallVC: activeCallVC, numberOfPausedCalls: numberOfPausedCalls) { [weak self] in - // active calls are more prior to paused ones. - // So, if user taps the bar when we have one active and one paused call, we navigate to the active one. - self?.inBarCallVC = activeCallVC ?? callVC - completion?() - } - uiOperationQueue.addOperation(operation) - } - - private func updateCallBar() { - let activeCallVC = self.activeCallVC - - let operation = CallBarUpdateOperation(presenter: self, activeCallVC: activeCallVC, numberOfPausedCalls: numberOfPausedCalls) - uiOperationQueue.addOperation(operation) - } - - private func dismissCallBar(for callVC: UIViewController, completion: (() -> Void)? = nil) { - logCallVC(callVC, log: "dismissCallBar") - - let operation = CallBarDismissOperation(presenter: self) { [weak self] in - if callVC == self?.inBarCallVC { - self?.inBarCallVC = nil - } - completion?() - } - - uiOperationQueue.addOperation(operation) - } - } // MARK: - MXKCallViewControllerDelegate @@ -834,13 +737,8 @@ extension CallPresenter: MXKCallViewControllerDelegate { // wait for the call state changes, will be handled there return } else { - if callVC.mxCall.isVideoCall { - // go to pip mode here - enterPipCallVC(callVC, completion: completion) - } else { - dismissCallVC(callVC) - self.presentCallBar(for: callVC, completion: completion) - } + // go to pip mode here + enterPipCallVC(callVC, completion: completion) } } @@ -902,8 +800,8 @@ extension OperationQueue { return containsOperation(ofType: CallVCPresentOperation.self) } - var containsPresentCallBarOperation: Bool { - return containsOperation(ofType: CallBarPresentOperation.self) + var containsEnterPiPOperation: Bool { + return containsOperation(ofType: CallVCEnterPipOperation.self) } private func containsOperation(ofType type: Operation.Type) -> Bool { diff --git a/Riot/Managers/Call/CallPresenterDelegate.swift b/Riot/Managers/Call/CallPresenterDelegate.swift index 57ee1c941..9c7f44687 100644 --- a/Riot/Managers/Call/CallPresenterDelegate.swift +++ b/Riot/Managers/Call/CallPresenterDelegate.swift @@ -26,17 +26,6 @@ protocol CallPresenterDelegate: class { dismissCallViewController viewController: UIViewController, completion:(() -> Void)?) - // Call Bar - func callPresenter(_ presenter: CallPresenter, - presentCallBarFor activeCallViewController: UIViewController?, - numberOfPausedCalls: UInt, - completion:(() -> Void)?) - func callPresenter(_ presenter: CallPresenter, - updateCallBarFor activeCallViewController: UIViewController?, - numberOfPausedCalls: UInt) - func callPresenter(_ presenter: CallPresenter, - dismissCallBar completion:(() -> Void)?) - // PiP func callPresenter(_ presenter: CallPresenter, enterPipForCallViewController viewController: UIViewController, diff --git a/Riot/Managers/Call/Operations/CallBarDismissOperation.swift b/Riot/Managers/Call/Operations/CallBarDismissOperation.swift deleted file mode 100644 index 02be105d1..000000000 --- a/Riot/Managers/Call/Operations/CallBarDismissOperation.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright 2020 New Vector 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 - -class CallBarDismissOperation: AsyncOperation { - - private var presenter: CallPresenter - private var completion: (() -> Void)? - - init(presenter: CallPresenter, - completion: (() -> Void)? = nil) { - self.presenter = presenter - self.completion = completion - } - - override func main() { - presenter.delegate?.callPresenter(presenter, dismissCallBar: { - self.finish() - self.completion?() - }) - } - -} diff --git a/Riot/Managers/Call/Operations/CallBarPresentOperation.swift b/Riot/Managers/Call/Operations/CallBarPresentOperation.swift deleted file mode 100644 index 31ec542f1..000000000 --- a/Riot/Managers/Call/Operations/CallBarPresentOperation.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright 2020 New Vector 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 - -class CallBarPresentOperation: AsyncOperation { - - private var presenter: CallPresenter - private var activeCallVC: UIViewController? - private var numberOfPausedCalls: UInt - private var completion: (() -> Void)? - - init(presenter: CallPresenter, - activeCallVC: UIViewController?, - numberOfPausedCalls: UInt, - completion: (() -> Void)? = nil) { - self.presenter = presenter - self.activeCallVC = activeCallVC - self.numberOfPausedCalls = numberOfPausedCalls - self.completion = completion - } - - override func main() { - presenter.delegate?.callPresenter(presenter, presentCallBarFor: activeCallVC, numberOfPausedCalls: numberOfPausedCalls, completion: { - self.finish() - // wait for the next life cycle to detect status bar layout updates - DispatchQueue.main.async { - self.completion?() - } - }) - } - -} diff --git a/Riot/Managers/Call/Operations/CallBarUpdateOperation.swift b/Riot/Managers/Call/Operations/CallBarUpdateOperation.swift deleted file mode 100644 index 23c7a5f5d..000000000 --- a/Riot/Managers/Call/Operations/CallBarUpdateOperation.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2020 New Vector 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 - -class CallBarUpdateOperation: AsyncOperation { - - private var presenter: CallPresenter - private var activeCallVC: UIViewController? - private var numberOfPausedCalls: UInt - - init(presenter: CallPresenter, - activeCallVC: UIViewController?, - numberOfPausedCalls: UInt) { - self.presenter = presenter - self.activeCallVC = activeCallVC - self.numberOfPausedCalls = numberOfPausedCalls - } - - override func main() { - presenter.delegate?.callPresenter(presenter, updateCallBarFor: activeCallVC, numberOfPausedCalls: numberOfPausedCalls) - self.finish() - } - -} diff --git a/Riot/Managers/Call/Operations/CallVCPresentOperation.swift b/Riot/Managers/Call/Operations/CallVCPresentOperation.swift index fae80e51b..ce452d575 100644 --- a/Riot/Managers/Call/Operations/CallVCPresentOperation.swift +++ b/Riot/Managers/Call/Operations/CallVCPresentOperation.swift @@ -31,8 +31,15 @@ class CallVCPresentOperation: AsyncOperation { } override func main() { + if let pipable = callVC as? PictureInPicturable { + pipable.willExitPiP?() + } presenter.delegate?.callPresenter(presenter, presentCallViewController: callVC, completion: { self.finish() + if let pipable = self.callVC as? PictureInPicturable { + pipable.didExitPiP?() + self.callVC.view.isUserInteractionEnabled = true + } self.completion?() }) } diff --git a/Riot/Managers/Call/PiPAnimator.swift b/Riot/Managers/Call/PiPAnimator.swift index 46171be6d..7df05af53 100644 --- a/Riot/Managers/Call/PiPAnimator.swift +++ b/Riot/Managers/Call/PiPAnimator.swift @@ -52,6 +52,10 @@ class PiPAnimator: NSObject { return } + if let pipable = fromVC as? PictureInPicturable { + pipable.willEnterPiP?() + } + fromVC.willMove(toParent: nil) // TODO: find a way to call this at the end of animation context.completeTransition(true) @@ -65,6 +69,7 @@ class PiPAnimator: NSObject { let scale = Constants.pipViewSize.width/pipView.frame.width let transform = CGAffineTransform(scaleX: scale, y: scale) let targetSize = Constants.pipViewSize + pipView.cornerRadius = pipView.cornerRadius / scale let animator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 1) { pipView.transform = transform @@ -75,7 +80,7 @@ class PiPAnimator: NSObject { animator.addCompletion { (position) in if let pipable = fromVC as? PictureInPicturable { - pipable.enterPiP?() + pipable.didEnterPiP?() } fromVC.dismiss(animated: false, completion: nil) } @@ -89,8 +94,16 @@ class PiPAnimator: NSObject { return } - guard let toVC = context.viewController(forKey: .to), - let snapshot = toVC.view.snapshotView(afterScreenUpdates: true) else { + guard let toVC = context.viewController(forKey: .to) else { + context.completeTransition(false) + return + } + + if let pipable = toVC as? PictureInPicturable { + pipable.willExitPiP?() + } + + guard let snapshot = toVC.view.snapshotView(afterScreenUpdates: true) else { context.completeTransition(false) return } @@ -122,7 +135,7 @@ class PiPAnimator: NSObject { snapshot.removeFromSuperview() if let pipable = toVC as? PictureInPicturable { - pipable.exitPiP?() + pipable.didExitPiP?() } context.completeTransition(!context.transitionWasCancelled) diff --git a/Riot/Managers/Call/PictureInPicturable.swift b/Riot/Managers/Call/PictureInPicturable.swift index b8ee9ae05..c37a904e8 100644 --- a/Riot/Managers/Call/PictureInPicturable.swift +++ b/Riot/Managers/Call/PictureInPicturable.swift @@ -18,7 +18,10 @@ import Foundation @objc protocol PictureInPicturable { - @objc optional func enterPiP() - @objc optional func exitPiP() + @objc optional func willEnterPiP() + @objc optional func didEnterPiP() + + @objc optional func willExitPiP() + @objc optional func didExitPiP() } diff --git a/Riot/Modules/Application/LegacyAppDelegate.h b/Riot/Modules/Application/LegacyAppDelegate.h index 076dcb45f..78269f348 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.h +++ b/Riot/Modules/Application/LegacyAppDelegate.h @@ -256,14 +256,6 @@ UINavigationControllerDelegate */ @property (nonatomic, readonly) JitsiViewController *jitsiViewController; -#pragma mark - Call status handling - -/** - Call status window displayed when user goes back to app during a call. - */ -@property (nonatomic, readonly) UIWindow* callStatusBarWindow; -@property (nonatomic, readonly) CallBar* callBar; - #pragma mark - App version management /** diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index e7057271e..f01d3a668 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -87,7 +87,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUniversalLinkDidChangeNotification"; -@interface LegacyAppDelegate () +@interface LegacyAppDelegate () { /** Reachability observer @@ -3164,117 +3164,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni completion:nil]; } - -#pragma mark - Call status handling - -/// Returns a suitable height for call status bar. Considers safe area insets if available and notch status. -- (CGFloat)calculateCallStatusBarHeight -{ - CGFloat result = CALL_STATUS_BAR_HEIGHT; - if (@available(iOS 11.0, *)) - { - if (UIDevice.currentDevice.hasNotch) - { - // this device has a notch (iPhone X +) - result += UIApplication.sharedApplication.keyWindow.safeAreaInsets.top; - } - } - return result; -} - -- (void)displayCallStatusBarWithTitle:(NSString*)title -{ - // Add a call status bar - CGSize topBarSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width, [self calculateCallStatusBarHeight]); - - _callStatusBarWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, topBarSize.width, topBarSize.height)]; - _callStatusBarWindow.windowLevel = UIWindowLevelStatusBar; - - // Create statusBarButton - _callBar = [CallBar instantiate]; - _callBar.frame = _callStatusBarWindow.bounds; - _callBar.title = title; - _callBar.backgroundColor = ThemeService.shared.theme.tintColor; - _callBar.delegate = self; - _callBar.translatesAutoresizingMaskIntoConstraints = NO; - - // Set call bar view as the view of the root view controller - UIViewController *viewController = [[UIViewController alloc] init]; - viewController.view = _callBar; - _callStatusBarWindow.rootViewController = viewController; - - _callStatusBarWindow.hidden = NO; - [self deviceOrientationDidChange]; - - // We need to listen to the device orientation change events to refresh the root controller frame. - // Else the navigation bar position will be wrong. - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deviceOrientationDidChange) - name:UIDeviceOrientationDidChangeNotification - object:nil]; -} - -- (void)updateCallStatusBarWithTitle:(NSString*)title -{ - _callBar.title = title; -} - -- (void)removeCallStatusBar -{ - if (_callStatusBarWindow) - { - // No more need to listen to device orientation changes - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; - - // Hide & destroy it - _callStatusBarWindow.hidden = YES; - [_callBar removeFromSuperview]; - _callBar = nil; - _callStatusBarWindow = nil; - - [self deviceOrientationDidChange]; - } -} - -- (void)deviceOrientationDidChange -{ - UIApplication *app = [UIApplication sharedApplication]; - UIViewController *rootController = app.keyWindow.rootViewController; - - // Refresh the root view controller frame - CGRect rootControllerFrame = [[UIScreen mainScreen] bounds]; - - if (_callStatusBarWindow) - { - CGFloat callStatusBarHeight = [self calculateCallStatusBarHeight]; - - UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation; - CGFloat width; - - if (UIDeviceOrientationIsPortrait(deviceOrientation)) - { - width = MIN(rootControllerFrame.size.width, rootControllerFrame.size.height); - } - else - { - width = MAX(rootControllerFrame.size.width, rootControllerFrame.size.height); - } - - _callStatusBarWindow.frame = CGRectMake(0, 0, width, callStatusBarHeight); - - // Apply the vertical offset due to call status bar - rootControllerFrame.origin.y = callStatusBarHeight; - rootControllerFrame.size.height -= callStatusBarHeight; - } - - rootController.view.frame = rootControllerFrame; - if (rootController.presentedViewController) - { - rootController.presentedViewController.view.frame = rootControllerFrame; - } - [rootController.view setNeedsLayout]; -} - #pragma mark - Status Bar Tap handling - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event @@ -4465,97 +4354,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni } } -- (void)callPresenter:(CallPresenter *)presenter presentCallBarFor:(UIViewController *)activeCallViewController numberOfPausedCalls:(NSUInteger)numberOfPausedCalls completion:(void (^)(void))completion -{ - [self displayCallStatusBarWithTitle:nil]; - [self callPresenter:presenter updateCallBarFor:activeCallViewController numberOfPausedCalls:numberOfPausedCalls]; - - if (completion) - { - completion(); - } -} - -- (void)callPresenter:(CallPresenter *)presenter updateCallBarFor:(UIViewController *)activeCallViewController numberOfPausedCalls:(NSUInteger)numberOfPausedCalls -{ - NSString *btnTitle; - - if (activeCallViewController) - { - NSString *callStatus = @""; - BOOL isGroupCall = NO; - if ([activeCallViewController isKindOfClass:[CallViewController class]]) - { - CallViewController *activeCallVC = (CallViewController *)activeCallViewController; - callStatus = activeCallVC.callStatusLabel.text; - } - else if ([activeCallViewController isKindOfClass:[JitsiViewController class]]) - { - JitsiViewController *jitsiVC = (JitsiViewController *)activeCallViewController; - NSUInteger duration = jitsiVC.callDuration / 1000; - NSUInteger secs = duration % 60; - NSUInteger mins = (duration / 60) % 60; - NSUInteger hours = duration / 3600; - if (hours > 0) - { - callStatus = [NSString stringWithFormat:@"%02tu:%02tu:%02tu", hours, mins, secs]; - } - else - { - callStatus = [NSString stringWithFormat:@"%02tu:%02tu", mins, secs]; - } - isGroupCall = YES; - } - - if (numberOfPausedCalls == 0) - { - // only one active - if (isGroupCall) - { - btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_single_active_group", @"Vector", nil), callStatus]; - } - else - { - btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_single_active", @"Vector", nil), callStatus]; - } - } - else if (numberOfPausedCalls == 1) - { - // one active and one paused - btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_active_and_single_paused", @"Vector", nil), callStatus]; - } - else - { - // one active and multiple paused - btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_active_and_multiple_paused", @"Vector", nil), callStatus, @(numberOfPausedCalls)]; - } - } - else - { - // no active calls - if (numberOfPausedCalls == 1) - { - btnTitle = NSLocalizedStringFromTable(@"callbar_only_single_paused", @"Vector", nil); - } - else - { - btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_multiple_paused", @"Vector", nil), @(numberOfPausedCalls)]; - } - } - - [self updateCallStatusBarWithTitle:btnTitle]; -} - -- (void)callPresenter:(CallPresenter *)presenter dismissCallBar:(void (^)(void))completion -{ - [self removeCallStatusBar]; - - if (completion) - { - completion(); - } -} - - (void)callPresenter:(CallPresenter *)presenter enterPipForCallViewController:(UIViewController *)viewController completion:(void (^)(void))completion { // Check whether the call view controller is actually presented @@ -4582,13 +4380,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [self presentViewController:viewController animated:YES completion:completion]; } -#pragma mark - CallBarDelegate - -- (void)callBarDidTap:(CallBar *)callBar -{ - [_callPresenter callStatusBarTapped]; -} - #pragma mark - Authentication - (BOOL)continueSSOLoginWithToken:(NSString*)loginToken txnId:(NSString*)txnId diff --git a/Riot/Modules/Call/CallViewController.m b/Riot/Modules/Call/CallViewController.m index 631936080..9fc8596e5 100644 --- a/Riot/Modules/Call/CallViewController.m +++ b/Riot/Modules/Call/CallViewController.m @@ -37,8 +37,11 @@ BOOL promptForStunServerFallback; } +@property (nonatomic, weak) IBOutlet UIView *pipViewContainer; + @property (nonatomic, strong) id overriddenTheme; @property (nonatomic, assign) BOOL inPiP; +@property (nonatomic, strong) CallPiPView *pipView; @property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController; @@ -224,6 +227,8 @@ - (void)call:(MXCall *)call stateDidChange:(MXCallState)state reason:(MXEvent *)event { [super call:call stateDidChange:state reason:event]; + + [self configurePiPView]; [self checkStunServerFallbackWithCallState:state]; } @@ -379,6 +384,23 @@ return _overriddenTheme; } +- (CallPiPView *)pipView +{ + if (_pipView == nil) + { + _pipView = [CallPiPView instantiateWithSession:self.mainSession]; + [_pipView updateWithTheme:self.overriddenTheme]; + } + return _pipView; +} + +- (void)setMxCallOnHold:(MXCall *)mxCallOnHold +{ + [super setMxCallOnHold:mxCallOnHold]; + + [self configurePiPView]; +} + - (UIImage*)picturePlaceholder { CGFloat fontSize = floor(self.callerImageViewWidthConstraint.constant * 0.7); @@ -502,11 +524,19 @@ self.callStatusLabel.hidden = YES; self.localPreviewContainerView.hidden = YES; self.localPreviewActivityView.hidden = YES; + + if (self.pipViewContainer.subviews.count == 0) + { + [self.pipViewContainer vc_addSubViewMatchingParent:self.pipView]; + } + [self configurePiPView]; + self.pipViewContainer.hidden = NO; } else { - self.localPreviewContainerView.hidden = NO; - self.callerImageView.hidden = NO; + self.pipViewContainer.hidden = YES; + self.localPreviewContainerView.hidden = !self.mxCall.isVideoCall; + self.callerImageView.hidden = self.mxCall.isVideoCall && self.mxCall.state == MXCallStateConnected; self.callerNameLabel.hidden = NO; self.callStatusLabel.hidden = NO; @@ -644,14 +674,32 @@ [viewController dismissViewControllerAnimated:YES completion:nil]; } +#pragma mark - PiP + +- (void)configurePiPView +{ + if (self.inPiP) + { + [self.pipView configureWithCall:self.mxCall + peer:self.peer + onHoldCall:self.mxCallOnHold + onHoldPeer:self.peerOnHold]; + } +} + #pragma mark - PictureInPicturable -- (void)enterPiP +- (void)didEnterPiP { self.inPiP = YES; } -- (void)exitPiP +- (void)willExitPiP +{ + self.pipViewContainer.hidden = YES; +} + +- (void)didExitPiP { self.inPiP = NO; } diff --git a/Riot/Modules/Call/CallViewController.xib b/Riot/Modules/Call/CallViewController.xib index d5cf47f3c..1f1c991a7 100644 --- a/Riot/Modules/Call/CallViewController.xib +++ b/Riot/Modules/Call/CallViewController.xib @@ -1,9 +1,9 @@ - + - + @@ -35,6 +35,7 @@ + @@ -294,7 +295,7 @@ - + @@ -339,7 +340,7 @@