parent
a7252544b0
commit
91cd1af3f9
|
@ -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 */,
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -29,7 +29,6 @@ extern const UIWindowLevel UIWindowLevel_Background;
|
|||
- (void)startCall:(UIViewController *)callViewController;
|
||||
- (void)endCall:(UIViewController *)callViewController;
|
||||
- (void)leaveCallView;
|
||||
- (void)returnToCallView;
|
||||
- (BOOL)hasCall;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue