Commit 81a65949 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk

UI/UX: update conference/calls

- hide preview and contact info in conference
- add conference participants widget
- fix button color for audio call
- update contact info when current call changed

Change-Id: I33fdbd5412f00412689f3d389b5f4a23cffb4f0a
parent d090f700
......@@ -166,9 +166,9 @@
0EE1B54E1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE1B54D1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift */; };
0EE1B5501F75AD4700BA98EE /* VCardUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE1B54F1F75AD4700BA98EE /* VCardUtils.swift */; };
0EEFBA3C1F83DA21000EDBAD /* libsecp256k1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */; };
0EF49A9F23828C960064CD98 /* ConferencePendingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF49A9E23828C960064CD98 /* ConferencePendingCallView.swift */; };
0EF49AA123828CBC0064CD98 /* ConferencePendingCallViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF49AA023828CBC0064CD98 /* ConferencePendingCallViewModel.swift */; };
0EF49AA323828CD00064CD98 /* ConferencePendingCallView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EF49AA223828CD00064CD98 /* ConferencePendingCallView.xib */; };
0EF49A9F23828C960064CD98 /* ConferenceParticipantView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF49A9E23828C960064CD98 /* ConferenceParticipantView.swift */; };
0EF49AA123828CBC0064CD98 /* ConferenceParticipantViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF49AA023828CBC0064CD98 /* ConferenceParticipantViewModel.swift */; };
0EF49AA323828CD00064CD98 /* ConferenceParticipantView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EF49AA223828CD00064CD98 /* ConferenceParticipantView.xib */; };
0EF78DE31FD0AE3000FC6966 /* ConversationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF78DE21FD0AE3000FC6966 /* ConversationsManager.swift */; };
1A0C4EDA1F1D4B1B00550433 /* WelcomeViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A0C4ED91F1D4B1B00550433 /* WelcomeViewController.storyboard */; };
1A0C4EDC1F1D4B7E00550433 /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C4EDB1F1D4B7E00550433 /* WelcomeViewController.swift */; };
......@@ -505,9 +505,9 @@
0EE1B54D1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CNContactVCardSerialization+Helpers.swift"; sourceTree = "<group>"; };
0EE1B54F1F75AD4700BA98EE /* VCardUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VCardUtils.swift; sourceTree = "<group>"; };
0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecp256k1.a; path = ../DEPS/arm64/lib/libsecp256k1.a; sourceTree = "<group>"; };
0EF49A9E23828C960064CD98 /* ConferencePendingCallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConferencePendingCallView.swift; sourceTree = "<group>"; };
0EF49AA023828CBC0064CD98 /* ConferencePendingCallViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConferencePendingCallViewModel.swift; sourceTree = "<group>"; };
0EF49AA223828CD00064CD98 /* ConferencePendingCallView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConferencePendingCallView.xib; sourceTree = "<group>"; };
0EF49A9E23828C960064CD98 /* ConferenceParticipantView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConferenceParticipantView.swift; sourceTree = "<group>"; };
0EF49AA023828CBC0064CD98 /* ConferenceParticipantViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConferenceParticipantViewModel.swift; sourceTree = "<group>"; };
0EF49AA223828CD00064CD98 /* ConferenceParticipantView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConferenceParticipantView.xib; sourceTree = "<group>"; };
0EF78DE21FD0AE3000FC6966 /* ConversationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsManager.swift; sourceTree = "<group>"; };
1A0C4ED91F1D4B1B00550433 /* WelcomeViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = WelcomeViewController.storyboard; path = Welcome/WelcomeViewController.storyboard; sourceTree = "<group>"; };
1A0C4EDB1F1D4B7E00550433 /* WelcomeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WelcomeViewController.swift; path = Welcome/WelcomeViewController.swift; sourceTree = "<group>"; };
......@@ -1286,9 +1286,9 @@
0EF49A9D23828C520064CD98 /* views */ = {
isa = PBXGroup;
children = (
0EF49A9E23828C960064CD98 /* ConferencePendingCallView.swift */,
0EF49AA023828CBC0064CD98 /* ConferencePendingCallViewModel.swift */,
0EF49AA223828CD00064CD98 /* ConferencePendingCallView.xib */,
0EF49A9E23828C960064CD98 /* ConferenceParticipantView.swift */,
0EF49AA023828CBC0064CD98 /* ConferenceParticipantViewModel.swift */,
0EF49AA223828CD00064CD98 /* ConferenceParticipantView.xib */,
);
path = views;
sourceTree = "<group>";
......@@ -1858,7 +1858,7 @@
5CE66F751FBF769B00EE9291 /* InitialLoadingViewController.storyboard in Resources */,
1A5DC03E1F35678D0075E8EF /* ContactRequestsViewController.storyboard in Resources */,
446FAF192373424700519C4F /* SendFileViewController.storyboard in Resources */,
0EF49AA323828CD00064CD98 /* ConferencePendingCallView.xib in Resources */,
0EF49AA323828CD00064CD98 /* ConferenceParticipantView.xib in Resources */,
0E72374A20460320006B0C7D /* ProfileHeaderView.xib in Resources */,
4430A66D236CBC5900747177 /* ContactPickerViewController.storyboard in Resources */,
0E96ED75225D06250016C07D /* GeneralSettingsViewController.storyboard in Resources */,
......@@ -2071,7 +2071,7 @@
1A2041821F1E906B00C08435 /* CreateProfileViewModel.swift in Sources */,
1A0C4EE31F1D673600550433 /* InjectionBag.swift in Sources */,
0E3BD4262044778100A50DDF /* ContactViewModel.swift in Sources */,
0EF49A9F23828C960064CD98 /* ConferencePendingCallView.swift in Sources */,
0EF49A9F23828C960064CD98 /* ConferenceParticipantView.swift in Sources */,
564C44641E943E1E000F92B1 /* NameRegistrationAdapterDelegate.swift in Sources */,
0E36979920322D46009A68CA /* BlockListViewController.swift in Sources */,
1A2D18AA1F29131900B2C785 /* ConversationsCoordinator.swift in Sources */,
......@@ -2151,7 +2151,7 @@
564C44601E943C37000F92B1 /* NameRegistrationAdapter.mm in Sources */,
0E35C10C2077DFF000BBA5E3 /* NotificationCell.swift in Sources */,
0E6F5453223C3C7500ECC3CE /* AccountItemView.swift in Sources */,
0EF49AA123828CBC0064CD98 /* ConferencePendingCallViewModel.swift in Sources */,
0EF49AA123828CBC0064CD98 /* ConferenceParticipantViewModel.swift in Sources */,
0E8E9A0520483E1200DA8E8B /* TitleView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
......
......@@ -37,8 +37,6 @@ class ButtonsContainerView: UIView, NibLoadable {
@IBOutlet weak var cancelButton: UIButton!
@IBOutlet weak var switchCameraButton: UIButton!
@IBOutlet weak var acceptCallButton: UIButton!
@IBOutlet weak var addContactButton: UIButton!
@IBOutlet weak var sendMessageButton: UIButton!
//Constraints
@IBOutlet weak var cancelButtonWidthConstraint: NSLayoutConstraint!
......@@ -100,8 +98,6 @@ class ButtonsContainerView: UIView, NibLoadable {
dialpadButton.isHidden = true
switchSpeakerButton.isHidden = true
cancelButton.isHidden = false
addContactButton.isHidden = true
sendMessageButton.isHidden = true
if self.viewModel?.isIncoming ?? false {
acceptCallButton.isHidden = false
cancelButtonBottomConstraint.constant = 60
......@@ -133,9 +129,8 @@ class ButtonsContainerView: UIView, NibLoadable {
switchSpeakerButton.isEnabled = true
switchSpeakerButton.isHidden = false
cancelButton.isHidden = false
addContactButton.isHidden = false
sendMessageButton.isHidden = false
setUpConference()
setButtonsColor()
}
func optionsWithoutSpeaker() {
......@@ -159,16 +154,14 @@ class ButtonsContainerView: UIView, NibLoadable {
self.backgroundBlurEffect.isHidden = false
pauseCallButton.isHidden = false
cancelButton.isHidden = false
addContactButton.isHidden = false
sendMessageButton.isHidden = false
setUpConference()
setButtonsColor()
}
func setUpConference() {
if !(self.viewModel?.isConference ?? false) {
return
}
sendMessageButton.isHidden = true
pauseCallButton.isHidden = true
muteAudioButton.isHidden = true
muteVideoButton.isHidden = true
......@@ -182,4 +175,29 @@ class ButtonsContainerView: UIView, NibLoadable {
self.optionsWithSpeaker()
}
}
func setButtonsColor() {
if self.viewModel?.isAudioOnly ?? false {
pauseCallButton.tintColor = UIColor.gray
pauseCallButton.borderColor = UIColor.gray
muteAudioButton.tintColor = UIColor.gray
muteAudioButton.borderColor = UIColor.gray
dialpadButton.tintColor = UIColor.gray
dialpadButton.borderColor = UIColor.gray
switchSpeakerButton.tintColor = UIColor.gray
switchSpeakerButton.borderColor = UIColor.gray
return
}
pauseCallButton.tintColor = UIColor.white
pauseCallButton.borderColor = UIColor.white
muteAudioButton.tintColor = UIColor.white
muteAudioButton.borderColor = UIColor.white
dialpadButton.tintColor = UIColor.white
dialpadButton.borderColor = UIColor.white
switchSpeakerButton.tintColor = UIColor.white
switchSpeakerButton.borderColor = UIColor.white
muteVideoButton.tintColor = UIColor.white
muteVideoButton.borderColor = UIColor.white
switchCameraButton.tintColor = UIColor.white
}
}
......@@ -11,7 +11,6 @@
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ButtonsContainerView" customModule="Ring" customModuleProvider="target">
<connections>
<outlet property="acceptCallButton" destination="rfz-9h-HoH" id="V6j-8E-g68"/>
<outlet property="addContactButton" destination="XPt-Qw-ege" id="hcj-H8-UyK"/>
<outlet property="backgroundBlurEffect" destination="w5l-pw-1ET" id="YYh-qB-WIL"/>
<outlet property="cancelButton" destination="ZxT-mA-1xU" id="4nk-iI-vPV"/>
<outlet property="cancelButtonBottomConstraint" destination="Ilu-Zu-JqW" id="Yeg-Ca-8pf"/>
......@@ -25,7 +24,6 @@
<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="sendMessageButton" destination="Clm-qc-fSa" id="ahZ-I9-gRG"/>
<outlet property="stackView" destination="RHx-cL-CV5" id="Iz9-B0-2Rd"/>
<outlet property="stackViewWidthConstraint" destination="ZuV-LV-CYZ" id="ita-8Y-fAb"/>
<outlet property="stackViewYConstraint" destination="z8B-uv-Vcb" id="Gaj-8x-yif"/>
......@@ -199,6 +197,7 @@
<constraint firstAttribute="width" constant="70" id="0vV-4C-odp"/>
<constraint firstAttribute="height" constant="70" id="kls-aA-2zS"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" image="stop_call"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
......@@ -232,56 +231,6 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="avx-hr-7CF">
<rect key="frame" x="15" y="10" width="50" height="120"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Clm-qc-fSa">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="0i2-PP-0nV"/>
<constraint firstAttribute="width" constant="50" id="254-56-HSy"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" image="conversation_icon"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="25"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XPt-Qw-ege">
<rect key="frame" x="0.0" y="70" width="50" height="50"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="GM7-dt-aWh"/>
<constraint firstAttribute="height" constant="50" id="jT2-0U-rR3"/>
</constraints>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" image="add_person"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="25"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
</subviews>
<constraints>
<constraint firstAttribute="width" constant="50" id="AKF-a1-POe"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
......@@ -296,7 +245,6 @@
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="450" id="ZfR-cx-MUB"/>
<constraint firstItem="w5l-pw-1ET" firstAttribute="leading" secondItem="a9g-pf-bHy" secondAttribute="leading" id="bbd-5D-5So"/>
<constraint firstItem="RHx-cL-CV5" firstAttribute="centerX" secondItem="a9g-pf-bHy" secondAttribute="centerX" id="bmE-qo-8aJ"/>
<constraint firstItem="RHx-cL-CV5" firstAttribute="top" secondItem="avx-hr-7CF" secondAttribute="bottom" constant="20" id="eJB-M0-m2x"/>
<constraint firstItem="ZxT-mA-1xU" firstAttribute="centerX" secondItem="a9g-pf-bHy" secondAttribute="centerX" id="ls1-Ze-LXF"/>
<constraint firstAttribute="trailing" secondItem="RHx-cL-CV5" secondAttribute="trailing" constant="15" id="pgj-7m-5gr"/>
<constraint firstAttribute="bottom" secondItem="RHx-cL-CV5" secondAttribute="bottom" id="z8B-uv-Vcb"/>
......@@ -305,7 +253,6 @@
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="avx-hr-7CF" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="15" id="9J5-UI-CPG"/>
<constraint firstAttribute="bottom" secondItem="a9g-pf-bHy" secondAttribute="bottom" constant="30" id="YHm-ET-yjX"/>
<constraint firstItem="a9g-pf-bHy" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" priority="750" id="ZI5-4F-WCS"/>
<constraint firstItem="a9g-pf-bHy" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="uv2-qL-KQX"/>
......@@ -316,10 +263,8 @@
</view>
</objects>
<resources>
<image name="add_person" width="24" height="24"/>
<image name="audio_running" width="24" height="24"/>
<image name="call_button" width="29" height="29"/>
<image name="conversation_icon" width="24" height="24"/>
<image name="dialpad" width="37.5" height="37.5"/>
<image name="disable_speakerphone" width="24" height="24"/>
<image name="pause_call" width="24" height="24"/>
......
This diff is collapsed.
......@@ -47,7 +47,9 @@ class CallViewModel: Stateable, ViewModel {
var isHeadsetConnected = false
var isAudioOnly = false
var currentCallVariable: Variable<CallModel> = Variable<CallModel>(CallModel())
lazy var currentCallVariable: Variable<CallModel> = {
Variable<CallModel>(self.call ?? CallModel())
}()
lazy var currentCall: Observable<CallModel> = {
currentCallVariable.asObservable()
}()
......@@ -68,6 +70,7 @@ class CallViewModel: Stateable, ViewModel {
self.callService
.currentCall(callId: call.callId)
.share()
.startWith(call)
.subscribe(onNext: { [weak self] call in
self?.currentCallVariable.value = call
}).disposed(by: self.callDisposeBag)
......@@ -77,8 +80,8 @@ class CallViewModel: Stateable, ViewModel {
}
self.callService.currentConferenceEvent
.asObservable().filter { conference-> Bool in
return conference.calls.contains(call.callId) ||
conference.conferenceID == call.callId
return conference.calls.contains(self.call?.callId ?? "") ||
conference.conferenceID == self.rendererId
}
.subscribe(onNext: { [weak self] conf in
if conf.conferenceID.isEmpty {
......@@ -202,13 +205,17 @@ class CallViewModel: Stateable, ViewModel {
}()
lazy var callDuration: Driver<String> = {
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
let timer = Observable<Int>.interval(1.0, scheduler: MainScheduler.instance)
.takeUntil(currentCall
.filter { call in
call.state == .over
})
.map({ elapsed in
return CallViewModel.formattedDurationFrom(interval: elapsed)
.map({ (elapsed) -> String in
var time = elapsed
if let startTime = self.call?.dateReceived {
time = Int(Date().timeIntervalSince1970 - startTime.timeIntervalSince1970)
}
return CallViewModel.formattedDurationFrom(interval: time)
}).share()
return currentCall.filter({ call in
return call.state == .current
......@@ -427,7 +434,7 @@ class CallViewModel: Stateable, ViewModel {
}
}
}
self.callService.hangUp(callId: rendererId)
self.callService.hangUpCallOrConference(callId: rendererId)
.subscribe(onCompleted: { [weak self] in
// switch to either spk or headset (if connected) for loud ringtone
// incase we were using rcv during the call
......
......@@ -51,6 +51,9 @@ class ContactPickerViewModel: Stateable, ViewModel {
call.callId == self.currentCallId {
return
}
if call.state != .current || call.state != .hold || call.state != .unhold {
return
}
let profile = self.contactsService.getProfile(uri: uriString, accountId: call.accountId)
var contact = Contact(contactUri: uriString,
accountId: call.accountId,
......@@ -88,8 +91,8 @@ class ContactPickerViewModel: Stateable, ViewModel {
if callURIs.contains(contactUri) {
return
}
let profile = self.contactsService.getProfile(uri: contactUri, accountId: currentAccount.id)
var contactToAdd = Contact(contactUri: contactUri,
let profile = self.contactsService.getProfile(uri: contactUri, accountId: currentAccount.id)
var contactToAdd = Contact(contactUri: contactUri,
accountId: currentAccount.id,
registrName: contact.userName ?? "",
presService: self.presenceService,
......
......@@ -22,12 +22,20 @@ import UIKit
import Reusable
import RxSwift
class ConferencePendingCallView: UIView {
protocol ConferenceParticipantViewDelegate: class {
func setConferenceParticipantMenu(menu: UIView?)
}
var inConfViewWidth: CGFloat = 60
var inConfViewHeight: CGFloat = 60
class ConferenceParticipantView: UIView {
@IBOutlet var containerView: UIView!
@IBOutlet var backgroundView: UIView!
@IBOutlet var nameLabel: UILabel!
@IBOutlet var cancelButton: UIButton!
@IBOutlet var avatarView: UIView!
let disposeBag = DisposeBag()
weak var delegate: ConferenceParticipantViewDelegate?
let menuWidth = 80
let menuHight = 40
override init(frame: CGRect) {
super.init(frame: frame)
......@@ -40,39 +48,76 @@ class ConferencePendingCallView: UIView {
}
func commonInit() {
Bundle.main.loadNibNamed("ConferencePendingCallView", owner: self, options: nil)
Bundle.main.loadNibNamed("ConferenceParticipantView", owner: self, options: nil)
addSubview(containerView)
containerView.frame = self.bounds
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showMenu))
self.avatarView.addGestureRecognizer(tapGestureRecognizer)
}
@objc func showMenu() {
let menu = UIView(frame: CGRect(x: 50, y: 50, width: menuWidth, height: menuHight))
let blurView = UIBlurEffect(style: .light)
let background = UIVisualEffectView(effect: blurView)
background.frame = CGRect(x: 0, y: 0, width: menuWidth, height: menuHight)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: menuWidth, height: menuHight))
label.text = L10n.Calls.haghUp
label.textAlignment = .center
let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: menuWidth, height: menuHight))
if #available(iOS 10.0, *) {
label.adjustsFontSizeToFitWidth = true
} else {
label.font = UIFont.systemFont(ofSize: 10)
}
menu.cornerRadius = 10
menu.addSubview(background)
menu.addSubview(label)
menu.addSubview(menuButton)
menuButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.viewModel?.cancelCall()
self?.removeFromSuperview()
self?.delegate?.setConferenceParticipantMenu(menu: nil)
}).disposed(by: self.disposeBag)
let frame = self.convert(menu.frame, to: self.superview)
menu.frame = frame
self.delegate?.setConferenceParticipantMenu(menu: menu)
}
var viewModel: ConferencePendingCallViewModel? {
var viewModel: ConferenceParticipantViewModel? {
didSet {
self.viewModel?.removeView
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] remove in
if remove {
self?.delegate?.setConferenceParticipantMenu(menu: nil)
self?.removeFromSuperview()
}
}).disposed(by: self.disposeBag)
self.cancelButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.viewModel?.cancelCall()
self?.removeFromSuperview()
}).disposed(by: self.disposeBag)
self.viewModel?.displayName.drive(self.nameLabel.rx.text)
.disposed(by: self.disposeBag)
UIView.animate(withDuration: 1,
delay: 0.0,
options: [.curveEaseInOut,
.autoreverse,
.repeat],
animations: { [weak self] in
self?.backgroundView.alpha = 0.1
},
completion: { [weak self] _ in
self?.backgroundView.alpha = 0.7
})
Observable<(Profile?, String?)>
.combineLatest(self.viewModel!
.contactImageData!,
self.viewModel!
.displayName
.asObservable()) { profile, username in
return (profile, username)
}
.observeOn(MainScheduler.instance)
.subscribe({ [weak self] profileData -> Void in
let photoData = NSData(base64Encoded: profileData.element?.0?.photo ?? "", options: NSData.Base64DecodingOptions.ignoreUnknownCharacters) as Data?
let alias = profileData.element?.0?.alias
let nameData = profileData.element?.1
let name = alias != nil ? alias : nameData
guard let displayName = name else {return}
self?.avatarView.subviews.forEach({ view in
view.removeFromSuperview()
})
self?.avatarView.addSubview(
AvatarView(profileImageData: photoData,
username: displayName,
size: 60))
})
.disposed(by: self.disposeBag)
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<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="ConferenceParticipantView" customModule="Ring" customModuleProvider="target">
<connections>
<outlet property="avatarView" destination="OhW-ga-1rG" id="NfZ-6h-UTh"/>
<outlet property="containerView" destination="jRz-xt-uo1" id="FvB-I0-V5E"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="jRz-xt-uo1">
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Vx7-ys-YlT">
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="AUo-fS-HWV"/>
<constraint firstAttribute="height" constant="60" id="rxd-jx-00m"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OhW-ga-1rG">
<rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="Qmg-jy-gJd"/>
<constraint firstAttribute="height" constant="60" id="tp4-YL-ytg"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="35"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<constraints>
<constraint firstItem="OhW-ga-1rG" firstAttribute="top" secondItem="jRz-xt-uo1" secondAttribute="top" id="5hd-Oe-QMl"/>
<constraint firstItem="OhW-ga-1rG" firstAttribute="leading" secondItem="7Zy-Yx-8I5" secondAttribute="leading" id="Otk-kc-m0S"/>
<constraint firstAttribute="trailing" secondItem="Vx7-ys-YlT" secondAttribute="trailing" id="dA9-th-iek"/>
<constraint firstAttribute="bottom" secondItem="Vx7-ys-YlT" secondAttribute="bottom" id="ohO-th-fjC"/>
<constraint firstItem="Vx7-ys-YlT" firstAttribute="leading" secondItem="jRz-xt-uo1" secondAttribute="leading" id="rdm-qH-VtL"/>
<constraint firstItem="Vx7-ys-YlT" firstAttribute="top" secondItem="jRz-xt-uo1" secondAttribute="top" id="vfJ-xv-8Db"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="7Zy-Yx-8I5"/>
<point key="canvasLocation" x="31.884057971014496" y="111.16071428571428"/>
</view>
</objects>
</document>
......@@ -21,19 +21,35 @@
import RxSwift
import RxCocoa
class ConferencePendingCallViewModel {
class ConferenceParticipantViewModel {
let call: CallModel
let callsSercive: CallsService
let profileService: ProfilesService
let accountService: AccountsService
lazy var observableCall = {
self.callsSercive.currentCall(callId: call.callId)
}()
let disposeBag = DisposeBag()
init(with call: CallModel, callsService: CallsService) {
init(with call: CallModel, injectionBag: InjectionBag) {
self.call = call
self.callsSercive = callsService
self.callsSercive = injectionBag.callService
self.profileService = injectionBag.profileService
self.accountService = injectionBag.accountService
}
lazy var contactImageData: Observable<Profile>? = {
guard let account = self.accountService.getAccount(fromAccountId: call.accountId) else {
return nil
}
let type = account.type == AccountType.sip ? URIType.sip : URIType.ring
guard let uriString = JamiURI.init(schema: type,
infoHach: call.participantUri,
account: account).uriString else {return nil}
return self.profileService.getProfile(uri: uriString,
createIfNotexists: true, accountId: account.id)
}()
lazy var displayName: Driver<String> = {
var name = self.call.displayName.isEmpty ? self.call.registeredName : self.call.displayName
name = name.isEmpty ? self.call.paricipantHash() : name
......@@ -42,9 +58,9 @@ class ConferencePendingCallViewModel {
lazy var removeView: Observable<Bool> = {
return self.observableCall
.startWith(call)
.map({ callModel in
return (callModel.state == .over ||
callModel.state == .current ||
callModel.state == .failure ||
callModel.state == .hungup ||
callModel.state == .busy)
......
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<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="ConferencePendingCallView">
<connections>
<outlet property="backgroundView" destination="VgU-qB-aow" id="L6K-W0-IS5"/>
<outlet property="cancelButton" destination="him-Gr-Zhp" id="Loz-zb-iHG"/>
<outlet property="containerView" destination="jRz-xt-uo1" id="FvB-I0-V5E"/>
<outlet property="nameLabel" destination="bxe-Ql-TmR" id="6dX-Nt-q2I"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="jRz-xt-uo1">
<rect key="frame" x="0.0" y="0.0" width="200" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VgU-qB-aow">
<rect key="frame" x="0.0" y="0.0" width="200" height="50"/>
<color key="backgroundColor" red="0.4756349325" green="0.47564673419999998" blue="0.47564041610000002" alpha="0.81878745719178081" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="rI5-7q-UPp"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="10"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="FSg-t4-nuf">
<rect key="frame" x="10" y="10" width="180" height="30"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxe-Ql-TmR">
<rect key="frame" x="0.0" y="0.0" width="130" height="30"/>
<fontDescription key="fontDescription" type="system" pointSize="23"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="him-Gr-Zhp">
<rect key="frame" x="150" y="0.0" width="30" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="Fpz-wr-dra"/>
<constraint firstAttribute="height" constant="30" id="Q1h-u5-k74"/>
</constraints>
<color key="tintColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<inset key="imageEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" image="cross"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="15"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="FSg-t4-nuf" firstAttribute="trailing" secondItem="VgU-qB-aow" secondAttribute="trailing" constant="-10" id="Le6-x0-MbL"/>
<constraint firstItem="FSg-t4-nuf" firstAttribute="leading" secondItem="VgU-qB-aow" secondAttribute="leading" constant="10" id="O1Q-QD-pL4"/>
<constraint firstItem="VgU-qB-aow" firstAttribute="top" secondItem="jRz-xt-uo1" secondAttribute="top" id="RoD-J7-6XK"/>
<constraint firstItem="VgU-qB-aow" firstAttribute="leading" secondItem="jRz-xt-uo1" secondAttribute="leading" id="Uya-Rn-Cnc"/>
<constraint firstItem="FSg-t4-nuf" firstAttribute="top" secondItem="jRz-xt-uo1" secondAttribute="top" constant="10" id="gKc-2N-HyM"/>
<constraint firstAttribute="bottom" secondItem="FSg-t4-nuf" secondAttribute="bottom" constant="10" id="i32-zh-y0d"/>
<constraint firstAttribute="trailing" secondItem="VgU-qB-aow" secondAttribute="trailing" id="sBW-jm-bI3"/>
<constraint firstAttribute="bottom" secondItem="VgU-qB-aow" secondAttribute="bottom" id="zS3-L2-Q0s"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="7Zy-Yx-8I5"/>
<point key="canvasLocation" x="31.884057971014496" y="111.49553571428571"/>
</view>
</objects>
<resources>
<image name="cross" width="40" height="40"/>
</resources>
</document>
......@@ -41,6 +41,7 @@ internal enum Asset {
internal static let downloadIcon = ImageAsset(name: "download_icon")
internal static let enableSpeakerphone = ImageAsset(name: "enable_speakerphone")
internal static