Extract ReturnToCallViewController

// FREEBIE
This commit is contained in:
Michael Kirk 2018-05-16 10:02:08 -04:00 committed by Matthew Chen
parent a7252544b0
commit 91cd1af3f9
4 changed files with 94 additions and 109 deletions

View File

@ -352,6 +352,7 @@
459B775C207BA46C0071D0AB /* OWSQuotedReplyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */; };
459B775D207BA4810071D0AB /* OWSQuotedReplyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */; settings = {ATTRIBUTES = (Public, ); }; };
45A2F005204473A3002E978A /* NewMessage.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45A2F004204473A3002E978A /* NewMessage.aifc */; };
45A60E7320AC674100FB1ABF /* ReturnToCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A60E7220AC674100FB1ABF /* ReturnToCallViewController.swift */; };
45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */; };
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; };
45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; };
@ -998,6 +999,7 @@
459B7759207BA3A80071D0AB /* OWSQuotedReplyModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWSQuotedReplyModel.h; sourceTree = "<group>"; };
459B775A207BA3A80071D0AB /* OWSQuotedReplyModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OWSQuotedReplyModel.m; sourceTree = "<group>"; };
45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Signal/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; };
45A60E7220AC674100FB1ABF /* ReturnToCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReturnToCallViewController.swift; sourceTree = "<group>"; };
45A663C41F92EC760027B59E /* GroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupTableViewCell.swift; sourceTree = "<group>"; };
45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = "<group>"; };
45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = "<group>"; };
@ -1686,6 +1688,7 @@
340FC897204DAC8D007AEB0F /* ThreadSettings */,
34D1F0BE1F8EC1760066283D /* Utils */,
452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */,
45A60E7220AC674100FB1ABF /* ReturnToCallViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
@ -3331,6 +3334,7 @@
340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */,
4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */,
340FC8B0204DAC8D007AEB0F /* AddToBlockListViewController.m in Sources */,
45A60E7320AC674100FB1ABF /* ReturnToCallViewController.swift in Sources */,
340FC8B3204DAC8D007AEB0F /* AppSettingsViewController.m in Sources */,
346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */,
45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */,

View File

@ -0,0 +1,70 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc
public protocol ReturnToCallViewControllerDelegate: class {
func returnToCallWasTapped(_ viewController: ReturnToCallViewController)
}
@objc
public class ReturnToCallViewController: UIViewController {
public weak var delegate: ReturnToCallViewControllerDelegate?
let returnToCallLabel = UILabel()
public func startAnimating() {
self.returnToCallLabel.layer.removeAllAnimations()
self.returnToCallLabel.alpha = 1
UIView.animate(withDuration: 1,
delay: 0,
options: [.repeat, .autoreverse],
animations: { self.returnToCallLabel.alpha = 0 },
completion: { _ in self.returnToCallLabel.alpha = 1 })
}
public func stopAnimating() {
self.returnToCallLabel.layer.removeAllAnimations()
}
override public func loadView() {
self.view = UIView()
// This is the color of the iOS "return to call" banner.
view.backgroundColor = UIColor(rgbHex: 0x4cd964)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapView))
view.addGestureRecognizer(tapGesture)
view.addSubview(returnToCallLabel)
// System UI doesn't use dynamic type for status bar; neither do we.
returnToCallLabel.font = UIFont.ows_regularFont(withSize: 14)
returnToCallLabel.text = NSLocalizedString("CALL_WINDOW_RETURN_TO_CALL", comment: "Label for the 'return to call' banner.")
returnToCallLabel.textColor = .white
returnToCallLabel.autoPinEdge(toSuperviewEdge: .bottom, withInset: 2)
returnToCallLabel.setCompressionResistanceHigh()
returnToCallLabel.setContentHuggingHigh()
returnToCallLabel.autoHCenterInSuperview()
}
@objc
public func didTapView(gestureRecognizer: UITapGestureRecognizer) {
self.delegate?.returnToCallWasTapped(self)
}
override public func viewWillLayoutSubviews() {
Logger.debug("\(self.logTag) in \(#function)")
super.viewWillLayoutSubviews()
}
override public func viewDidLayoutSubviews() {
Logger.debug("\(self.logTag) in \(#function)")
super.viewDidLayoutSubviews()
}
}

View File

@ -29,7 +29,6 @@ extern const UIWindowLevel UIWindowLevel_Background;
- (void)startCall:(UIViewController *)callViewController;
- (void)endCall:(UIViewController *)callViewController;
- (void)leaveCallView;
- (void)returnToCallView;
- (BOOL)hasCall;
@end

View File

@ -10,6 +10,8 @@
NS_ASSUME_NONNULL_BEGIN
const CGFloat OWSWindowManagerCallScreenHeight = 40;
// Behind everything, especially the root window.
const UIWindowLevel UIWindowLevel_Background = -1.f;
@ -50,14 +52,14 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
#pragma mark -
@interface OWSWindowManager ()
@interface OWSWindowManager () <ReturnToCallViewControllerDelegate>
// UIWindowLevelNormal
@property (nonatomic) UIWindow *rootWindow;
// UIWindowLevel_ReturnToCall
@property (nonatomic) UIWindow *returnToCallWindow;
@property (nonatomic) UILabel *returnToCallLabel;
@property (nonatomic) ReturnToCallViewController *returnToCallViewController;
// UIWindowLevel_CallView
@property (nonatomic) UIWindow *callViewWindow;
@ -117,8 +119,6 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
self.returnToCallWindow = [self createReturnToCallWindow:rootWindow];
self.callViewWindow = [self createCallViewWindow:rootWindow];
[self updateReturnToCallWindowLayout];
[self ensureWindowState];
}
@ -128,80 +128,22 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
OWSAssert(rootWindow);
// "Return to call" should remain at the top of the screen.
CGRect windowFrame = rootWindow.bounds;
// Use zero height until updateReturnToCallWindowLayout.
windowFrame.size.height = 0;
CGRect windowFrame = UIScreen.mainScreen.bounds;
windowFrame.size.height = OWSWindowManagerCallScreenHeight;
UIWindow *window = [[UIWindow alloc] initWithFrame:windowFrame];
window.hidden = YES;
window.windowLevel = UIWindowLevel_ReturnToCall();
window.opaque = YES;
// This is the color of the iOS "return to call" banner.
// TODO: What's the right color to use here?
UIColor *backgroundColor = [UIColor colorWithRGBHex:0x4cd964];
window.backgroundColor = backgroundColor;
UIViewController *viewController = [OWSWindowRootViewController new];
viewController.view.backgroundColor = backgroundColor;
UIView *rootView = viewController.view;
rootView.userInteractionEnabled = YES;
[rootView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(returnToCallWasTapped:)]];
rootView.layoutMargins = UIEdgeInsetsZero;
UILabel *label = [UILabel new];
label.text = NSLocalizedString(@"CALL_WINDOW_RETURN_TO_CALL", @"Label for the 'return to call' banner.");
label.textColor = [UIColor whiteColor];
// System UI doesn't use dynamic type; neither do we.
label.font = [UIFont ows_regularFontWithSize:14.f];
[rootView addSubview:label];
[label autoPinBottomToSuperviewMargin];
[label setCompressionResistanceHigh];
[label setContentHuggingHigh];
[label autoHCenterInSuperview];
// TODO animate...
// returnToCallLabel uses manual layout.
//
// TODO: Is there a better way to do this?
label.translatesAutoresizingMaskIntoConstraints = NO;
self.returnToCallLabel = label;
ReturnToCallViewController *viewController = [ReturnToCallViewController new];
self.returnToCallViewController = viewController;
viewController.delegate = self;
window.rootViewController = viewController;
return window;
}
- (void)updateReturnToCallWindowLayout
{
OWSAssertIsOnMainThread();
CGRect statusBarFrame = UIApplication.sharedApplication.statusBarFrame;
CGFloat statusBarHeight = statusBarFrame.size.height;
CGRect windowFrame = self.rootWindow.bounds;
windowFrame.size.height = statusBarHeight + 20.f;
self.returnToCallWindow.frame = windowFrame;
self.returnToCallWindow.rootViewController.view.frame = windowFrame;
[self.returnToCallLabel sizeToFit];
CGRect labelFrame = self.returnToCallLabel.frame;
labelFrame.origin.x = floor(windowFrame.size.width - labelFrame.size.width);
self.returnToCallLabel.frame = labelFrame;
UIView *rootView = self.returnToCallWindow.rootViewController.view;
[rootView setNeedsLayout];
[rootView layoutIfNeeded];
for (UIView *subview in rootView.subviews) {
[subview setNeedsLayout];
[subview layoutIfNeeded];
}
}
- (UIWindow *)createCallViewWindow:(UIWindow *)rootWindow
{
OWSAssertIsOnMainThread();
@ -251,8 +193,6 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
[self.callNavigationController pushViewController:callViewController animated:NO];
self.isCallViewActive = YES;
[self updateReturnToCallWindowLayout];
[self ensureWindowState];
}
@ -286,7 +226,7 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
[self ensureWindowState];
}
- (void)returnToCallView
- (void)showCallView
{
OWSAssertIsOnMainThread();
OWSAssert(self.callViewController);
@ -358,18 +298,12 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
DDLogInfo(@"%@ showing root window.", self.logTag);
}
static CGRect defaultFrame;
static CGRect frameWithActiveCall;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultFrame = self.rootWindow.frame;
CGFloat callBannerHeight = self.returnToCallWindow.frame.size.height;
frameWithActiveCall
= CGRectMake(0, callBannerHeight, defaultFrame.size.width, defaultFrame.size.height - callBannerHeight);
});
CGRect defaultFrame = [UIScreen mainScreen].bounds;
if (isActiveCall) {
CGRect frameWithActiveCall = CGRectMake(0,
OWSWindowManagerCallScreenHeight,
defaultFrame.size.width,
defaultFrame.size.height - OWSWindowManagerCallScreenHeight);
self.rootWindow.frame = frameWithActiveCall;
} else {
self.rootWindow.frame = defaultFrame;
@ -396,26 +330,8 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
{
OWSAssertIsOnMainThread();
if (self.returnToCallWindow.hidden) {
DDLogInfo(@"%@ showing 'return to call' window.", self.logTag);
[self.returnToCallLabel.layer removeAllAnimations];
self.returnToCallLabel.alpha = 1.f;
[UIView animateWithDuration:1.f
delay:0.f
options:(UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse
| UIViewAnimationOptionBeginFromCurrentState)
animations:^{
self.returnToCallLabel.alpha = 0.f;
}
completion:^(BOOL finished) {
self.returnToCallLabel.alpha = 1.f;
}];
}
self.returnToCallWindow.hidden = NO;
[self updateReturnToCallWindowLayout];
[self.returnToCallViewController startAnimating];
}
- (void)ensureReturnToCallWindowHidden
@ -427,7 +343,7 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
}
self.returnToCallWindow.hidden = YES;
[self.returnToCallLabel.layer removeAllAnimations];
[self.returnToCallViewController stopAnimating];
}
- (void)ensureCallViewWindowShown
@ -478,15 +394,11 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
self.screenBlockingWindow.windowLevel = UIWindowLevel_Background;
}
#pragma mark - Events
#pragma mark - ReturnToCallViewControllerDelegate
- (void)returnToCallWasTapped:(UIGestureRecognizer *)sender
- (void)returnToCallWasTapped:(ReturnToCallViewController *)viewController
{
if (sender.state != UIGestureRecognizerStateRecognized) {
return;
}
[self returnToCallView];
[self showCallView];
}
@end