Commit e26f8b9d authored by Quentin Muret's avatar Quentin Muret Committed by Kateryna Kostiuk

UI / UX: refactor call view

- replace the registered name display by the display name if exist
- bigger hang up button
- change the switch camera button image
- hide the switch audio button for iPad

Audio calls:
- change the background color to white during connecting, ringing and current call state
- change buttons, texts, and status bar color to gray
- change the pulse animation color to ring color
- add a fade-in animation for the duration label and buttons container appearance
- hide the switch camera and mute video buttons
- remove the info and buttons containers backgrounds

Video calls:
- change the background to captured video with white blur effect during connecting,
ringing and pause call state
- change buttons, texts, and status bar color to white
- change the background of the info and buttons containers to transparent blur effect
- add an activity indicator view when loading the video of the interlocutor
- add a fade-in animation for the info and buttons container appearance
- change the time of disappearance of the info and buttons containers to 7 seconds
- add animation for the captured video vignette appearance
- add rounded corners to the captured video vignette

Change-Id: I37b634782e3ea5f5eb2afd1f8f1809924435e445
Reviewed-by: Kateryna Kostiuk<kateryna.kostiuk@savoirfairelinux.com>
parent 1ee99939
github "AliSoftware/Reusable" "4.0.3"
github "ReactiveX/RxSwift" "4.3.0"
github "AliSoftware/Reusable" "4.0.4"
github "ReactiveX/RxSwift" "4.4.0"
github "RxSwiftCommunity/RxDataSources" "3.1.0"
github "RxSwiftCommunity/RxRealm" "0.7.5"
github "RxSwiftCommunity/RxRealm" "0.7.6"
github "SwiftyBeaver/SwiftyBeaver" "1.6.1"
github "ViccAlexander/Chameleon" "2.2.0"
github "andreamazz/AMPopTip" "3.4.0"
github "ashleymills/Reachability.swift" "v4.2.1"
github "andreamazz/AMPopTip" "3.5.0"
github "ashleymills/Reachability.swift" "v4.3.0"
github "gskbyte/GSKStretchyHeaderView" "1.0.4"
github "optonaut/ActiveLabel.swift" "0.9.0"
github "pkluz/PKHUD" "5.1.0"
github "realm/realm-cocoa" "v3.9.0"
github "optonaut/ActiveLabel.swift" "1.0.1"
github "pkluz/PKHUD" "5.2.0"
github "realm/realm-cocoa" "v3.11.1"
github "stephencelis/SQLite.swift" "0.11.5"
......@@ -25,14 +25,19 @@ class ButtonsContainerView: UIView, NibLoadable {
@IBOutlet var containerView: UIView!
@IBOutlet weak var container: UIView!
@IBOutlet weak var stackView: UIStackView!
@IBOutlet weak var backgroundBlurEffect: UIVisualEffectView!
@IBOutlet weak var muteAudioButton: UIButton!
@IBOutlet weak var muteVideoButton: UIButton!
@IBOutlet weak var pauseCallButton: UIButton!
@IBOutlet weak var switchCameraButton: UIButton!
@IBOutlet weak var switchSpeakerButton: UIButton!
@IBOutlet weak var cancelButton: UIButton!
@IBOutlet weak var cancelButtonHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var containerHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var bottomSpaceConstraint: NSLayoutConstraint!
@IBOutlet weak var stackViewWidthConstraint: NSLayoutConstraint!
@IBOutlet weak var stackViewBottomConstraint: NSLayoutConstraint!
let disposeBag = DisposeBag()
var viewModel: ButtonsContainerViewModel? {
......@@ -79,9 +84,8 @@ class ButtonsContainerView: UIView, NibLoadable {
}
func withoutOptions() {
containerHeightConstraint.priority = UILayoutPriority(rawValue: 250.00)
bottomSpaceConstraint.priority = UILayoutPriority(rawValue: 999.00)
self.container.backgroundColor = UIColor.clear
self.backgroundBlurEffect.isHidden = true
muteAudioButton.isHidden = true
muteVideoButton.isHidden = true
pauseCallButton.isHidden = true
......@@ -91,13 +95,17 @@ class ButtonsContainerView: UIView, NibLoadable {
}
func optionsWithSpeaker() {
containerHeightConstraint.priority = UILayoutPriority(rawValue: 999.00)
bottomSpaceConstraint.priority = UILayoutPriority(rawValue: 250.00)
self.container.backgroundColor = UIColor.black.withAlphaComponent(0.3)
self.backgroundBlurEffect.isHidden = false
muteAudioButton.isHidden = false
muteVideoButton.isHidden = false
if self.viewModel?.isAudioOnly ?? false {
self.stackViewWidthConstraint.constant = 200
muteVideoButton.isHidden = true
switchCameraButton.isHidden = true
} else {
muteVideoButton.isHidden = false
switchCameraButton.isHidden = false
}
pauseCallButton.isHidden = false
switchCameraButton.isHidden = false
switchSpeakerButton.isHidden = false
switchSpeakerButton.alpha = 1.00
switchSpeakerButton.isEnabled = true
......@@ -105,16 +113,18 @@ class ButtonsContainerView: UIView, NibLoadable {
}
func optionsWithoutSpeaker() {
containerHeightConstraint.priority = UILayoutPriority(rawValue: 250.00)
bottomSpaceConstraint.priority = UILayoutPriority(rawValue: 999.00)
self.container.backgroundColor = UIColor.black.withAlphaComponent(0.3)
if self.viewModel?.isAudioOnly ?? false {
self.stackViewWidthConstraint.constant = 150
muteVideoButton.isHidden = true
switchCameraButton.isHidden = true
} else {
muteVideoButton.isHidden = false
switchCameraButton.isHidden = false
}
self.backgroundBlurEffect.isHidden = false
muteAudioButton.isHidden = false
muteVideoButton.isHidden = false
pauseCallButton.isHidden = false
switchCameraButton.isHidden = false
switchSpeakerButton.isHidden = false
switchSpeakerButton.alpha = 0.00
switchSpeakerButton.isEnabled = false
switchSpeakerButton.isHidden = true
cancelButton.isHidden = false
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ButtonsContainerView" customModule="Ring" customModuleProvider="target">
<connections>
<outlet property="bottomSpaceConstraint" destination="XhM-wC-j2L" id="Kw3-nW-cVH"/>
<outlet property="backgroundBlurEffect" destination="w5l-pw-1ET" id="YYh-qB-WIL"/>
<outlet property="cancelButton" destination="ZxT-mA-1xU" id="68q-sF-gBC"/>
<outlet property="cancelButtonHeightConstraint" destination="XhM-wC-j2L" id="xcg-V6-2BW"/>
<outlet property="container" destination="a9g-pf-bHy" id="6bw-CB-5qN"/>
<outlet property="containerHeightConstraint" destination="W6T-0D-HwX" id="Pdz-5B-x5j"/>
<outlet property="containerView" destination="iN0-l3-epB" id="mcP-kY-dVO"/>
<outlet property="muteAudioButton" destination="tXL-FB-O0X" id="6Bh-x3-veQ"/>
<outlet property="muteVideoButton" destination="W7F-nH-kda" id="MWK-JU-544"/>
<outlet property="pauseCallButton" destination="MPk-dB-dhR" id="W4G-AB-WFw"/>
<outlet property="stackView" destination="RHx-cL-CV5" id="Iz9-B0-2Rd"/>
<outlet property="stackViewBottomConstraint" destination="deA-Gc-8FZ" id="etU-MD-0Ig"/>
<outlet property="stackViewWidthConstraint" destination="mIk-2g-tbX" id="Wcy-wd-Quy"/>
<outlet property="switchCameraButton" destination="gfb-nb-FyB" id="FTM-2Z-u3u"/>
<outlet property="switchSpeakerButton" destination="0VH-mO-vFE" id="1Gy-a9-FAW"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="205"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a9g-pf-bHy">
<rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="205"/>
<subviews>
<visualEffectView opaque="NO" alpha="0.84999999999999998" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w5l-pw-1ET" userLabel="Background Blur Effect">
<rect key="frame" x="0.0" y="0.0" width="375" height="205"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="JSn-50-Cd9">
<rect key="frame" x="0.0" y="0.0" width="375" height="205"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="calibratedWhite"/>
<blurEffect style="light"/>
</visualEffectView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="RHx-cL-CV5">
<rect key="frame" x="12.5" y="70" width="350" height="50"/>
<rect key="frame" x="12.5" y="5" width="350" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tXL-FB-O0X">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
......@@ -41,6 +54,7 @@
<constraint firstAttribute="width" constant="50" id="sDn-Gs-HlM"/>
<constraint firstAttribute="height" constant="50" id="zo6-Fk-IRh"/>
</constraints>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="audio_running"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
......@@ -51,7 +65,7 @@
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
......@@ -61,6 +75,7 @@
<constraint firstAttribute="height" constant="50" id="Pn1-SS-vPN"/>
<constraint firstAttribute="width" constant="50" id="jCp-ib-ySo"/>
</constraints>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="video_running"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
......@@ -68,7 +83,7 @@
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="25"/>
......@@ -81,6 +96,7 @@
<constraint firstAttribute="width" constant="50" id="oso-jU-2U3"/>
<constraint firstAttribute="height" constant="50" id="qmE-To-ipl"/>
</constraints>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="disable_speakerphone"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
......@@ -91,7 +107,7 @@
<real key="value" value="25"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
......@@ -101,6 +117,7 @@
<constraint firstAttribute="width" constant="50" id="984-Na-56G"/>
<constraint firstAttribute="height" constant="50" id="kIF-vP-ZJP"/>
</constraints>
<color key="tintColor" white="0.0" alpha="0.5" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" image="pause_call"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
......@@ -108,7 +125,7 @@
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="25"/>
......@@ -121,6 +138,7 @@
<constraint firstAttribute="height" constant="50" id="DYV-x7-KoO"/>
<constraint firstAttribute="width" constant="50" id="XYg-b8-pt8"/>
</constraints>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="switch_camera"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
......@@ -128,7 +146,7 @@
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="value" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="25"/>
......@@ -139,14 +157,14 @@
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="gaC-GZ-ftw"/>
<constraint firstAttribute="width" priority="750" constant="350" id="mIk-2g-tbX"/>
<constraint firstAttribute="width" constant="350" id="mIk-2g-tbX"/>
</constraints>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZxT-mA-1xU">
<rect key="frame" x="162" y="10" width="50" height="50"/>
<rect key="frame" x="152.5" y="75" width="70" height="70"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="0vV-4C-odp"/>
<constraint firstAttribute="height" constant="50" id="kls-aA-2zS"/>
<constraint firstAttribute="width" constant="70" id="0vV-4C-odp"/>
<constraint firstAttribute="height" constant="70" id="kls-aA-2zS"/>
</constraints>
<state key="normal" image="stop_call"/>
<userDefinedRuntimeAttributes>
......@@ -158,41 +176,44 @@
<color key="value" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="25"/>
<real key="value" value="35"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="ZxT-mA-1xU" firstAttribute="top" secondItem="a9g-pf-bHy" secondAttribute="top" constant="10" id="0QU-8q-IjM"/>
<constraint firstItem="w5l-pw-1ET" firstAttribute="height" secondItem="a9g-pf-bHy" secondAttribute="height" id="3vF-Mr-YlI"/>
<constraint firstItem="RHx-cL-CV5" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="a9g-pf-bHy" secondAttribute="leading" constant="12.5" id="FwG-sE-gpJ"/>
<constraint firstAttribute="height" priority="999" constant="150" id="W6T-0D-HwX"/>
<constraint firstAttribute="bottom" secondItem="ZxT-mA-1xU" secondAttribute="bottom" priority="250" constant="30" id="XhM-wC-j2L"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="RHx-cL-CV5" secondAttribute="trailing" constant="12.5" id="aud-x3-DAu"/>
<constraint firstItem="w5l-pw-1ET" firstAttribute="centerY" secondItem="a9g-pf-bHy" secondAttribute="centerY" id="Key-mX-9mY"/>
<constraint firstAttribute="height" priority="999" constant="212" id="W6T-0D-HwX"/>
<constraint firstAttribute="bottom" secondItem="ZxT-mA-1xU" secondAttribute="bottom" priority="250" constant="60" id="XhM-wC-j2L"/>
<constraint firstItem="RHx-cL-CV5" firstAttribute="centerX" secondItem="a9g-pf-bHy" secondAttribute="centerX" id="bmE-qo-8aJ"/>
<constraint firstAttribute="bottom" secondItem="RHx-cL-CV5" secondAttribute="bottom" constant="30" id="deA-Gc-8FZ"/>
<constraint firstAttribute="bottom" secondItem="RHx-cL-CV5" secondAttribute="bottom" constant="150" id="deA-Gc-8FZ"/>
<constraint firstItem="w5l-pw-1ET" firstAttribute="centerX" secondItem="a9g-pf-bHy" secondAttribute="centerX" id="eH5-i0-6bS"/>
<constraint firstItem="ZxT-mA-1xU" firstAttribute="centerX" secondItem="a9g-pf-bHy" secondAttribute="centerX" id="eV9-Wr-xF9"/>
<constraint firstItem="w5l-pw-1ET" firstAttribute="width" secondItem="a9g-pf-bHy" secondAttribute="width" id="sXZ-Jz-OmC"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="a9g-pf-bHy" firstAttribute="height" secondItem="iN0-l3-epB" secondAttribute="height" id="Kgd-1N-Hij"/>
<constraint firstItem="a9g-pf-bHy" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="X3f-ZS-P0M"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="a9g-pf-bHy" secondAttribute="bottom" id="svV-zg-XlK"/>
<constraint firstItem="a9g-pf-bHy" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="uv2-qL-KQX"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="33.5" y="94"/>
<point key="canvasLocation" x="32.799999999999997" y="68.815592203898049"/>
</view>
</objects>
<resources>
<image name="audio_running" width="24" height="24"/>
<image name="disable_speakerphone" width="24" height="24"/>
<image name="pause_call" width="24" height="24"/>
<image name="stop_call" width="24" height="24"/>
<image name="switch_camera" width="25" height="25"/>
<image name="video_running" width="24" height="24"/>
<image name="audio_running" width="48" height="48"/>
<image name="disable_speakerphone" width="48" height="48"/>
<image name="pause_call" width="48" height="48"/>
<image name="stop_call" width="48" height="48"/>
<image name="switch_camera" width="50" height="37"/>
<image name="video_running" width="48" height="48"/>
</resources>
</document>
......@@ -31,16 +31,18 @@ class ButtonsContainerViewModel {
let audioService: AudioService
let callID: String
let disposeBag = DisposeBag()
var isAudioOnly: Bool
let avalaibleCallOptions = BehaviorSubject<CallOptions>(value: .none)
lazy var observableCallOptions: Observable<CallOptions> = {
return self.avalaibleCallOptions.asObservable()
}()
init(with callService: CallsService, audioService: AudioService, callID: String) {
init(isAudioOnly: Bool, with callService: CallsService, audioService: AudioService, callID: String) {
self.callService = callService
self.audioService = audioService
self.callID = callID
self.isAudioOnly = isAudioOnly
checkCallOptions()
}
......
......@@ -30,27 +30,36 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
//preview screen
@IBOutlet private weak var profileImageView: UIImageView!
@IBOutlet private weak var nameLabel: UILabel!
@IBOutlet weak var nameLabelYConstraint: NSLayoutConstraint!
@IBOutlet private weak var durationLabel: UILabel!
@IBOutlet private weak var infoBottomLabel: UILabel!
@IBOutlet weak var avatarView: UIView!
@IBOutlet private weak var mainView: UIView!
//video screen
@IBOutlet private weak var callView: UIView!
@IBOutlet private weak var incomingVideo: UIImageView!
@IBOutlet private weak var capturedVideo: UIImageView!
@IBOutlet weak var spinner: UIActivityIndicatorView!
@IBOutlet weak var capturedVideo: UIImageView!
@IBOutlet weak var capturedVideoWidthConstraint: NSLayoutConstraint!
@IBOutlet weak var capturedVideoTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var capturedVideoTopConstraint: NSLayoutConstraint!
@IBOutlet weak var capturedVideoHeightConstraint: NSLayoutConstraint!
@IBOutlet private weak var infoContainer: UIView!
@IBOutlet weak var infoContainerHeightConstraint: NSLayoutConstraint!
@IBOutlet private weak var callProfileImage: UIImageView!
@IBOutlet private weak var audioOnlyImage: UIImageView!
@IBOutlet weak var callProfileImageTopConstraint: NSLayoutConstraint!
@IBOutlet private weak var callNameLabel: UILabel!
@IBOutlet private weak var callInfoTimerLabel: UILabel!
@IBOutlet private weak var infoLabelTopConstraint: NSLayoutConstraint!
@IBOutlet private weak var callButtonsLeftConstraint: NSLayoutConstraint!
@IBOutlet private weak var callButtonsRightConstraint: NSLayoutConstraint!
@IBOutlet weak var callInfoTimerLabelLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var callInfoTimerLabelBottomConstraint: NSLayoutConstraint!
@IBOutlet private weak var infoLabelHeightConstraint: NSLayoutConstraint!
@IBOutlet private weak var callPulse: UIView!
@IBOutlet private weak var buttonsContainer: ButtonsContainerView!
@IBOutlet weak var buttonsContainerHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var backgroundBlurEffectHeightConstraint: NSLayoutConstraint!
var viewModel: CallViewModel!
......@@ -64,22 +73,66 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
override func viewDidLoad() {
super.viewDidLoad()
self.setColorButtons()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(screenTapped))
self.mainView.addGestureRecognizer(tapGestureRecognizer)
self.infoContainer.backgroundColor = UIColor.black.withAlphaComponent(0.3)
self.setUpCallButtons()
self.setupBindings()
let device = UIDevice.modelName
switch device {
case "iPhone X", "iPhone XS", "iPhone XS Max", "iPhone XR" :
//keep the 4:3 format of the captured video on iPhone X and later when display it in full screen
if !self.avatarView.isHidden {
self.capturedVideoWidthConstraint.constant += 200
self.capturedVideoTrailingConstraint.constant = (self.capturedVideoWidthConstraint.constant - UIScreen.main.bounds.width) / 2
self.infoLabelHeightConstraint.constant = 90
}
default :
//On other devices, we don't have notch, so the infoContainerHeightConstraint should be smaller
self.infoContainerHeightConstraint.constant = 204
}
if self.viewModel.isAudioOnly {
// The durationLabel and buttonsContainer alpha is set here to 0, and to 1 (with a duration) when appear on the screen to have a fade in animation
self.durationLabel.alpha = 0
self.buttonsContainer.stackView.alpha = 0
self.showAllInfo()
self.setWhiteAvatarView()
} else {
UIApplication.shared.statusBarStyle = .lightContent
}
UIDevice.current.isProximityMonitoringEnabled = self.viewModel.isAudioOnly
initCallAnimation()
}
func setColorButtons() {
if !(self.viewModel.call?.isAudioOnly ?? false) {
self.buttonsContainer.cancelButton.backgroundColor = UIColor.white
self.buttonsContainer.muteAudioButton.tintColor = UIColor.white
self.buttonsContainer.muteAudioButton.borderColor = UIColor.white
self.buttonsContainer.muteVideoButton.tintColor = UIColor.white
self.buttonsContainer.muteVideoButton.borderColor = UIColor.white
self.buttonsContainer.pauseCallButton.tintColor = UIColor.white
self.buttonsContainer.pauseCallButton.borderColor = UIColor.white
self.buttonsContainer.switchCameraButton.tintColor = UIColor.white
self.buttonsContainer.switchCameraButton.borderColor = UIColor.white
self.buttonsContainer.switchSpeakerButton.tintColor = UIColor.white
self.buttonsContainer.switchSpeakerButton.borderColor = UIColor.white
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIApplication.shared.statusBarStyle = .lightContent
}
func setWhiteAvatarView() {
UIApplication.shared.statusBarStyle = .default
self.callPulse.backgroundColor = UIColor.ringCallPulse
self.avatarView.backgroundColor = UIColor.white
self.nameLabel.textColor = UIColor.ringCallInfos
self.durationLabel.textColor = UIColor.ringCallInfos
self.infoBottomLabel.textColor = UIColor.ringCallInfos
}
func initCallAnimation() {
......@@ -104,6 +157,7 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
func setUpCallButtons() {
self.buttonsContainer.viewModel = self.viewModel.containerViewModel
self.buttonsContainerHeightConstraint.constant = self.buttonsContainer.containerHeightConstraint.constant
//bind actions
self.buttonsContainer.cancelButton.rx.tap
.subscribe(onNext: { [weak self] in
......@@ -201,6 +255,16 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
self.viewModel.callDuration.drive(self.durationLabel.rx.text)
.disposed(by: self.disposeBag)
self.viewModel.callDuration.asObservable().observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
if self?.durationLabel.text == "00:00:00" {
UIView.animate(withDuration: 0.3, animations: {
self?.durationLabel.alpha = 1
self?.buttonsContainer.stackView.alpha = 1
})
}
}).disposed(by: self.disposeBag)
self.viewModel.callDuration.drive(self.callInfoTimerLabel.rx.text)
.disposed(by: self.disposeBag)
......@@ -213,6 +277,7 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] frame in
if let image = frame {
self?.spinner.stopAnimating()
DispatchQueue.main.async {
self?.incomingVideo.image = image
}
......@@ -242,24 +307,26 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
.subscribe(onNext: { show in
if show {
self.showCancelButton()
} else if !self.viewModel.isAudioOnly {
self.hideCancelButton()
} else {
self.buttonsContainer.bottomSpaceConstraint.constant = 30
}
}).disposed(by: self.disposeBag)
if !self.viewModel.isAudioOnly {
self.setupShowCapturedFrame()
}
self.viewModel.videoMuted
.observeOn(MainScheduler.instance)
.bind(to: self.capturedVideo.rx.isHidden)
.disposed(by: self.disposeBag)
self.audioOnlyImage.isHidden = !self.viewModel.isAudioOnly
if !self.viewModel.isAudioOnly {
self.viewModel.callPaused
.observeOn(MainScheduler.instance)
.map({value in return !value })
.bind(to: self.avatarView.rx.isHidden)
.disposed(by: self.disposeBag)
}
self.viewModel.callPaused
.observeOn(MainScheduler.instance)
.bind(to: self.callView.rx.isHidden)
.disposed(by: self.disposeBag)
self.viewModel.callPaused
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [unowned self] show in
......@@ -270,6 +337,37 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
}).disposed(by: self.disposeBag)
}
func setupShowCapturedFrame() {
self.viewModel.showCapturedFrame
.observeOn(MainScheduler.instance)
.subscribe(onNext: { dontShow in
if dontShow {
self.showAllInfo()
DispatchQueue.global(qos: .background).async {
sleep(3)
DispatchQueue.main.async {
self.hideContactInfo()
self.hideCancelButton()
}
}
UIView.animate(withDuration: 0.4, animations: { [unowned self] in
let device = UIDevice.modelName
switch device {
case "iPhone X", "iPhone XS", "iPhone XS Max", "iPhone XR" :
self.capturedVideoTopConstraint.constant = 40
default :
self.capturedVideoTopConstraint.constant = 32
}
self.capturedVideoTrailingConstraint.constant = 10
self.capturedVideoWidthConstraint.constant = -UIScreen.main.bounds.width + 120
self.capturedVideoHeightConstraint.constant = -UIScreen.main.bounds.height + 160
self.capturedVideo.cornerRadius = 10
self.view.layoutIfNeeded()
}, completion: nil)
}
}).disposed(by: self.disposeBag)
}
func removeFromScreen() {
UIDevice.current.isProximityMonitoringEnabled = false
self.dismiss(animated: false)
......@@ -281,13 +379,11 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
func showCancelButton() {
self.buttonsContainer.isHidden = false
self.buttonsContainer.bottomSpaceConstraint.constant = 90
self.view.layoutIfNeeded()
}
func hideCancelButton() {
self.buttonsContainer.isHidden = true
self.buttonsContainer.bottomSpaceConstraint.constant = 30
self.view.layoutIfNeeded()
}
......@@ -296,67 +392,44 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
self.view.layoutIfNeeded()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {