From 0e87cbe7a53e8d9c04b8291ef8a73bae9aafd168 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 16 May 2018 12:02:15 -0400 Subject: [PATCH] WIP navbar resize -[ ] CallScreen -[x] functional button -[ ] needs design -[ ] disable other contact call buttons while in call -[ ] iOS11 -[x] resize nav content -[ ] background showing at top of all vc's -[] iPhoneX -[x] use differently sized banner for now -[] mimic X system design -[ ] iOS10 -[x] resize nav content -[ ] animation glitch while push/pop -[ ] iOS9 // FREEBIE --- Signal.xcodeproj/project.pbxproj | 6 - Signal/src/UIDevice+featureSupport.swift | 21 ++- .../ViewControllers/CallViewController.swift | 19 ++- Signal/src/util/OWSWindowManager.h | 2 + Signal/src/util/OWSWindowManager.m | 29 ++++- Signal/src/util/UIDevice+TSHardwareVersion.h | 25 ---- Signal/src/util/UIDevice+TSHardwareVersion.m | 28 ---- Signal/src/views/SignalNavigationBar.swift | 120 ++++++++++-------- 8 files changed, 128 insertions(+), 122 deletions(-) delete mode 100644 Signal/src/util/UIDevice+TSHardwareVersion.h delete mode 100644 Signal/src/util/UIDevice+TSHardwareVersion.m diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 0cb6fc3e7..c1233a017 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -489,7 +489,6 @@ FC5CDF3A1A3393DD00B47253 /* warning_white@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FC5CDF381A3393DD00B47253 /* warning_white@2x.png */; }; FC9120411A39EFB70074545C /* qr@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FC91203F1A39EFB70074545C /* qr@2x.png */; }; FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; }; - FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = FCC81A971A44558300DFEC7D /* UIDevice+TSHardwareVersion.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1190,8 +1189,6 @@ FC5CDF381A3393DD00B47253 /* warning_white@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "warning_white@2x.png"; sourceTree = ""; }; FC91203F1A39EFB70074545C /* qr@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "qr@2x.png"; sourceTree = ""; }; FCB11D8B1A129A76002F93FB /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; - FCC81A961A44558300DFEC7D /* UIDevice+TSHardwareVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+TSHardwareVersion.h"; sourceTree = ""; }; - FCC81A971A44558300DFEC7D /* UIDevice+TSHardwareVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+TSHardwareVersion.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2122,8 +2119,6 @@ 450DF2041E0D74AC003D14BE /* Platform.swift */, 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, FCFA64B11A24F29E0007FB87 /* UI Categories */, - FCC81A961A44558300DFEC7D /* UIDevice+TSHardwareVersion.h */, - FCC81A971A44558300DFEC7D /* UIDevice+TSHardwareVersion.m */, ); path = util; sourceTree = ""; @@ -3314,7 +3309,6 @@ 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */, 34DBF004206BD5A500025978 /* OWSBubbleView.m in Sources */, 34E88D262098C5AE00A608F4 /* ContactViewController.swift in Sources */, - FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */, 76EB054018170B33006006FC /* AppDelegate.m in Sources */, 34D1F0831F8678AA0066283D /* ConversationInputTextView.m in Sources */, 340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */, diff --git a/Signal/src/UIDevice+featureSupport.swift b/Signal/src/UIDevice+featureSupport.swift index 67c30fe90..eca3e0f54 100644 --- a/Signal/src/UIDevice+featureSupport.swift +++ b/Signal/src/UIDevice+featureSupport.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // import Foundation @@ -8,4 +8,23 @@ extension UIDevice { var supportsCallKit: Bool { return ProcessInfo().isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0)) } + + var isIPhoneX: Bool { + switch UIScreen.main.nativeBounds.height { + case 1136: + // iPhone 5 or 5S or 5C + return false + case 1334: + // iPhone 6/6S/7/8 + return false + case 1920, 2208: + // iPhone 6+/6S+/7+/8+// + return false + case 2436: + return true + default: + owsFail("\(logTag) in \(#function) unknown device format") + return false + } + } } diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index 27d5ae73a..5c29886c7 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -43,6 +43,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, var contactAvatarContainerView: UIView! var callStatusLabel: UILabel! var callDurationTimer: Timer? + var leaveCallViewButton: UIButton! // MARK: - Ongoing Call Controls @@ -254,6 +255,14 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, } func createContactViews() { + + leaveCallViewButton = UIButton() + let backButtonImage = self.view.isRTL() ? #imageLiteral(resourceName: "NavBarBackRTL") : #imageLiteral(resourceName: "NavBarBack") + leaveCallViewButton.setImage(backButtonImage, for: .normal) + leaveCallViewButton.autoSetDimensions(to: CGSize(width: 40, height: 40)) + leaveCallViewButton.addTarget(self, action: #selector(didTapLeaveCall(sender:)), for: .touchUpInside) + self.view.addSubview(leaveCallViewButton) + contactNameLabel = MarqueeLabel() // marquee config @@ -500,7 +509,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, remoteVideoView.autoPinEdgesToSuperviewEdges() - contactNameLabel.autoPinEdge(toSuperviewEdge: .top, withInset: topMargin) + leaveCallViewButton.autoPinEdge(toSuperviewMargin: .left) + leaveCallViewButton.autoPinEdge(toSuperviewEdge: .top, withInset: topMargin) + + contactNameLabel.autoPinEdge(.top, to: .bottom, of: leaveCallViewButton, withOffset: 8) contactNameLabel.autoPinLeadingToSuperviewMargin() contactNameLabel.setContentHuggingVerticalHigh() contactNameLabel.setCompressionResistanceHigh() @@ -814,8 +826,6 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, Logger.info("\(TAG) called \(#function)") muteButton.isSelected = !muteButton.isSelected - self.didTapLeaveCall() - callUIAdapter.setIsMuted(call: call, isMuted: muteButton.isSelected) } @@ -918,8 +928,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, preferences.setIsCallKitPrivacyEnabled(preferences.isCallKitPrivacyEnabled()) } -// func didTapLeaveCall(sender: UIGestureRecognizer) { - func didTapLeaveCall() { + func didTapLeaveCall(sender: UIButton) { OWSWindowManager.shared().leaveCallView() } diff --git a/Signal/src/util/OWSWindowManager.h b/Signal/src/util/OWSWindowManager.h index 6877c6514..7122f27df 100644 --- a/Signal/src/util/OWSWindowManager.h +++ b/Signal/src/util/OWSWindowManager.h @@ -12,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - +extern NSString *const OWSWindowManagerCallDidChangeNotification; + extern const UIWindowLevel UIWindowLevel_Background; @interface OWSWindowManager : NSObject diff --git a/Signal/src/util/OWSWindowManager.m b/Signal/src/util/OWSWindowManager.m index dc7456d19..ae42b87b0 100644 --- a/Signal/src/util/OWSWindowManager.m +++ b/Signal/src/util/OWSWindowManager.m @@ -10,7 +10,23 @@ NS_ASSUME_NONNULL_BEGIN -const CGFloat OWSWindowManagerCallScreenHeight = 40; +NSString *const OWSWindowManagerCallDidChangeNotification = @"OWSWindowManagerCallDidChangeNotification"; +// NSString *const OWSWindowManagerWillShowReturnToCallWindowNotification = +// @"OWSWindowManagerWillShowReturnToCallWindowNotification"; NSString *const +// OWSWindowManagerWillHideReturnToCallWindowNotification = @"OWSWindowManagerWillHideReturnToCallWindowNotification"; + + +const CGFloat OWSWindowManagerCallScreenHeight(void); +const CGFloat OWSWindowManagerCallScreenHeight(void) +{ + if ([UIDevice currentDevice].isIPhoneX) { + // TODO - rather than a bigger banner, we should stick with iPhoneX + // design changes, which only apply a green circle around the clock UI. + return 60; + } else { + return 40; + } +} // Behind everything, especially the root window. const UIWindowLevel UIWindowLevel_Background = -1.f; @@ -129,7 +145,7 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void) // "Return to call" should remain at the top of the screen. CGRect windowFrame = UIScreen.mainScreen.bounds; - windowFrame.size.height = OWSWindowManagerCallScreenHeight; + windowFrame.size.height = OWSWindowManagerCallScreenHeight(); UIWindow *window = [[UIWindow alloc] initWithFrame:windowFrame]; window.hidden = YES; window.windowLevel = UIWindowLevel_ReturnToCall(); @@ -188,6 +204,9 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void) OWSAssert(!self.callViewController); self.callViewController = callViewController; + // TODO move to setter? + [NSNotificationCenter.defaultCenter postNotificationName:OWSWindowManagerCallDidChangeNotification object:nil]; + // Attach callViewController to window. [self.callNavigationController popToRootViewControllerAnimated:NO]; [self.callNavigationController pushViewController:callViewController animated:NO]; @@ -210,6 +229,8 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void) // Dettach callViewController from window. [self.callNavigationController popToRootViewControllerAnimated:NO]; self.callViewController = nil; + [NSNotificationCenter.defaultCenter postNotificationName:OWSWindowManagerCallDidChangeNotification object:nil]; + self.shouldShowCallView = NO; [self ensureWindowState]; @@ -301,9 +322,9 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void) CGRect defaultFrame = [UIScreen mainScreen].bounds; if (isActiveCall) { CGRect frameWithActiveCall = CGRectMake(0, - OWSWindowManagerCallScreenHeight, + OWSWindowManagerCallScreenHeight(), defaultFrame.size.width, - defaultFrame.size.height - OWSWindowManagerCallScreenHeight); + defaultFrame.size.height - OWSWindowManagerCallScreenHeight()); self.rootWindow.frame = frameWithActiveCall; } else { self.rootWindow.frame = defaultFrame; diff --git a/Signal/src/util/UIDevice+TSHardwareVersion.h b/Signal/src/util/UIDevice+TSHardwareVersion.h deleted file mode 100644 index 1424c1992..000000000 --- a/Signal/src/util/UIDevice+TSHardwareVersion.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// UIDevice+TSHardwareVersion.h -// Signal -// -// Created by Dylan Bourgeois on 19/12/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. -// -// Original Source : -// Erica Sadun, http://ericasadun.com -// iPhone Developer's Cookbook, 6.x Edition -// BSD License, Use at your own risk -// -// - -#import - - -@interface UIDevice (TSHardwareVersion) - -/* - * Returns true if device is iPhone 6 or 6+ - */ -- (BOOL)isiPhoneVersionSixOrMore; - -@end diff --git a/Signal/src/util/UIDevice+TSHardwareVersion.m b/Signal/src/util/UIDevice+TSHardwareVersion.m deleted file mode 100644 index fa87f631a..000000000 --- a/Signal/src/util/UIDevice+TSHardwareVersion.m +++ /dev/null @@ -1,28 +0,0 @@ -// -// UIDevice+TSHardwareVersion.m -// Signal -// -// Created by Dylan Bourgeois on 19/12/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. -// -// Original Source : -// Erica Sadun, http://ericasadun.com -// iPhone Developer's Cookbook, 6.x Edition -// BSD License, Use at your own risk -// -// - -#include -#import "UIDevice+TSHardwareVersion.h" - -@implementation UIDevice (TSHardwareVersion) - -// Look for phone-type devices with a width greater than or equal to the width -// of the original iPhone 6. Hopefully, this is somewhat future proof -- (BOOL)isiPhoneVersionSixOrMore { - return - self.userInterfaceIdiom == UIUserInterfaceIdiomPhone && - ([[UIScreen mainScreen] scale] * [[UIScreen mainScreen] bounds].size.width) >= 750; -} - -@end diff --git a/Signal/src/views/SignalNavigationBar.swift b/Signal/src/views/SignalNavigationBar.swift index 5f4fc04ec..dbeed4801 100644 --- a/Signal/src/views/SignalNavigationBar.swift +++ b/Signal/src/views/SignalNavigationBar.swift @@ -7,60 +7,74 @@ import UIKit @objc class SignalNavigationBar: UINavigationBar { -// var isCallActive: Bool = false { -// didSet { -// guard oldValue != isCallActive else { -// return -// } -// -// if isCallActive { -// self.addSubview(callBanner) -//// callBanner.autoPinEdge(toSuperviewEdge: .top) -// callBanner.autoPinEdge(toSuperviewEdge: .leading) -// callBanner.autoPinEdge(toSuperviewEdge: .trailing) -// } else { -// callBanner.removeFromSuperview() -// } -// } -// } -// -// let callBanner: UIView -// let callLabel: UILabel -// let callBannerHeight: CGFloat = 40 -// -// override init(frame: CGRect) { -// callBanner = UIView() -// callBanner.backgroundColor = .green -// callBanner.autoSetDimension(.height, toSize: callBannerHeight) -// -// callLabel = UILabel() -// callLabel.text = "Return to your call..." -// callLabel.textColor = .white -// -// callBanner.addSubview(callLabel) -// callLabel.autoPinBottomToSuperviewMargin() -// callLabel.autoHCenterInSuperview() -// callLabel.setCompressionResistanceHigh() -// callLabel.setContentHuggingHigh() -// -// super.init(frame: frame) -// -// let debugTap = UITapGestureRecognizer(target: self, action: #selector(didTap)) -// self.addGestureRecognizer(debugTap) -// } -// -// @objc -// func didTap(sender: UITapGestureRecognizer) { -// Logger.debug("\(self.logTag) in \(#function)") -// self.isCallActive = !self.isCallActive -// } -// -// - override func sizeThatFits(_ size: CGSize) -> CGSize { - if OWSWindowManager.shared().hasCall() { - return CGSize(width: UIScreen.main.bounds.width, height: 30) + + // TODO - get a more precise value + // TODO - test with other heights, e.g. w/ hotspot, w/ call in other app + let navbarHeight: CGFloat = 44 + + override init(frame: CGRect) { + super.init(frame: frame) + + // TODO better place to observe? + NotificationCenter.default.addObserver(forName: .OWSWindowManagerCallDidChange, object: nil, queue: nil) { _ in + Logger.debug("\(self.logTag) in \(#function) OWSWindowManagerCallDidChange") + + self.callDidChange() + } + } + + private func callDidChange() { + if #available(iOS 11, *) { + self.layoutSubviews() } else { - return super.sizeThatFits(size) + self.sizeToFit() + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + // pre iOS11, sizeThatFits is repeatedly called to size the navbar, which is pretty straight forward + // as of iOS11, this is not true and we have to do things in layoutSubviews. + // FIXME: pre-iOS11, though the size is right, there's a glitch on the titleView while push/popping items. + let result: CGSize = { + if OWSWindowManager.shared().hasCall() { + // status bar height gets re-added + return CGSize(width: UIScreen.main.bounds.width, height: navbarHeight - UIApplication.shared.statusBarFrame.size.height) + } else { + return super.sizeThatFits(size) + } + }() + + Logger.debug("\(self.logTag) in \(#function): \(result)") + + return result + } + + override func layoutSubviews() { + Logger.debug("\(self.logTag) in \(#function)") + + guard #available(iOS 11.0, *), OWSWindowManager.shared().hasCall() else { + super.layoutSubviews() + return + } + +// let rect = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: self.navbarHeightWithoutStatusBar) +// self.frame = CGRect(x: 0, y: 20, width: UI Screen.main.bounds.width, height: ios11NavbarHeight) + self.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: navbarHeight) + self.bounds = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: navbarHeight) + + super.layoutSubviews() + + for subview in self.subviews { + let stringFromClass = NSStringFromClass(subview.classForCoder) + if stringFromClass.contains("BarBackground") { + subview.frame = self.bounds + } else if stringFromClass.contains("BarContentView") { + subview.frame = self.bounds + } } } }