diff --git a/Classes/ChatConversationCreateView.m b/Classes/ChatConversationCreateView.m index 0398feaeb..4a9ea2617 100644 --- a/Classes/ChatConversationCreateView.m +++ b/Classes/ChatConversationCreateView.m @@ -209,7 +209,7 @@ static UICompositeViewDescription *compositeDescription = nil; [_tableController.contactsGroup removeAllObjects]; if (_isForVoipConference) { if (_isForOngoingVoipConference) { - [PhoneMainView.instance changeCurrentView:VIEW(ActiveCallOrConferenceView).compositeViewDescription]; + [PhoneMainView.instance changeCurrentView:VIEW(ConferenceCallView).compositeViewDescription]; [ControlsViewModelBridge showParticipants]; } else { [PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription]; @@ -225,7 +225,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (IBAction)onNextClick:(id)sender { if (_isForVoipConference) { if (_isForOngoingVoipConference) { - [PhoneMainView.instance changeCurrentView:VIEW(ActiveCallOrConferenceView).compositeViewDescription]; + [PhoneMainView.instance changeCurrentView:VIEW(ConferenceCallView).compositeViewDescription]; [ConferenceViewModelBridge updateParticipantsListWithAddresses:_tableController.contactsGroup]; } else { [PhoneMainView.instance changeCurrentView:VIEW(ConferenceSchedulingSummaryView).compositeViewDescription]; diff --git a/Classes/DialerView.m b/Classes/DialerView.m index 88593f6b7..500c00ead 100644 --- a/Classes/DialerView.m +++ b/Classes/DialerView.m @@ -399,7 +399,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (IBAction)onBackClick:(id)event { - [PhoneMainView.instance popToView:ActiveCallOrConferenceView.compositeViewDescription]; + [PhoneMainView.instance popToView:[CallsViewModelBridge callViewToDisplay]]; } - (IBAction)onAddressChange:(id)sender { diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 44e5e5ce6..f594ea452 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -138,7 +138,6 @@ if ((floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)) { if ([LinphoneManager.instance lpConfigBoolForKey:@"autoanswer_notif_preference"]) { linphone_call_accept(call); - [PhoneMainView.instance changeCurrentView:ActiveCallOrConferenceView.compositeViewDescription]; } else { [PhoneMainView.instance displayIncomingCall:call]; } @@ -344,8 +343,9 @@ return NO; } - [PhoneMainView.instance.mainViewController getCachedController:ActiveCallOrConferenceView.compositeViewDescription.name]; // This will create the single instance of the ActiveCallOrConferenceView including listeneres - + [PhoneMainView.instance.mainViewController getCachedController:SingleCallView.compositeViewDescription.name]; // This will create the single instance of the SingleCallView including listeneres + [PhoneMainView.instance.mainViewController getCachedController:ConferenceCallView.compositeViewDescription.name]; // This will create the single instance of the ConferenceCallView including listeneres + [CallsViewModelBridge setupCallsViewNavigation]; return YES; } @@ -630,7 +630,6 @@ } } else if ([response.notification.request.content.categoryIdentifier isEqual:@"video_request"]) { if (!call) return; - [PhoneMainView.instance changeCurrentView:ActiveCallOrConferenceView.compositeViewDescription]; NSTimer *videoDismissTimer = nil; UIConfirmationDialog *sheet = [UIConfirmationDialog ShowWithMessage:response.notification.request.content.body cancelMessage:nil diff --git a/Classes/LinphoneUI/UIBackToCallButton.m b/Classes/LinphoneUI/UIBackToCallButton.m index df44ff54f..9e45b2aa9 100644 --- a/Classes/LinphoneUI/UIBackToCallButton.m +++ b/Classes/LinphoneUI/UIBackToCallButton.m @@ -48,7 +48,7 @@ } - (IBAction)onBackToCallClick:(id)sender { - [PhoneMainView.instance popToView:ActiveCallOrConferenceView.compositeViewDescription]; + [PhoneMainView.instance popToView:[CallsViewModelBridge callViewToDisplay]]; } @end diff --git a/Classes/LinphoneUI/UICompositeView.m b/Classes/LinphoneUI/UICompositeView.m index 62010fb00..e370ed159 100644 --- a/Classes/LinphoneUI/UICompositeView.m +++ b/Classes/LinphoneUI/UICompositeView.m @@ -316,7 +316,7 @@ bool remove = true; /*ImagePickerView can be used as popover and we do NOT want to free it*/; - if ([key isEqualToString:ImagePickerView.compositeViewDescription.name] || [key isEqualToString:ActiveCallOrConferenceView.compositeViewDescription.name]) { + if ([key isEqualToString:ImagePickerView.compositeViewDescription.name] || [key isEqualToString:SingleCallView.compositeViewDescription.name] || [key isEqualToString:ConferenceCallView.compositeViewDescription.name]) { remove = false; } else if (exclude != nil) { for (UICompositeViewDescription *description in exclude) { diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index ce35f4432..854d72c36 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -385,7 +385,7 @@ static RootViewManager *rootViewManagerInstance = nil; } break; } - case LinphoneCallPausedByRemote: + case LinphoneCallPausedByRemote:break; case LinphoneCallConnected: { if (![LinphoneManager.instance isCTCallCenterExist]) { /*only register CT call center CB for connected call*/ @@ -417,6 +417,7 @@ static RootViewManager *rootViewManagerInstance = nil; } case LinphoneCallUpdating: break; + } if (state == LinphoneCallEnd || state == LinphoneCallError || floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) [self updateApplicationBadgeNumber]; diff --git a/Classes/Swift/Conference/Views/ConferenceWaitingRoomFragment.swift b/Classes/Swift/Conference/Views/ConferenceWaitingRoomFragment.swift index dfb537d00..fd1a8f10c 100644 --- a/Classes/Swift/Conference/Views/ConferenceWaitingRoomFragment.swift +++ b/Classes/Swift/Conference/Views/ConferenceWaitingRoomFragment.swift @@ -142,7 +142,7 @@ import linphonesw self.layoutPicker?.isHidden = joining == true if (joining == true) { self.view.addSubview(self.conferenceJoinSpinner) - self.conferenceJoinSpinner.square(IncomingOutgoingCommonView.spinner_size).center().done() + self.conferenceJoinSpinner.square(AbstractIncomingOutgoingCallView.spinner_size).center().done() self.conferenceJoinSpinner.startRotation() self.controlsView.isHidden = true } else { diff --git a/Classes/Swift/Voip/ViewModels/CallsViewModel.swift b/Classes/Swift/Voip/ViewModels/CallsViewModel.swift index 734b4fd93..85cb96a13 100644 --- a/Classes/Swift/Voip/ViewModels/CallsViewModel.swift +++ b/Classes/Swift/Voip/ViewModels/CallsViewModel.swift @@ -72,13 +72,14 @@ class CallsViewModel { call.answerVideoUpdateRequest(accept: false) } } - }else if (state == Call.State.Connected) { + } else if (state == Call.State.Connected) { self.callConnectedEvent.value = call } else if (state == Call.State.StreamsRunning) { self.callUpdateEvent.value = call } self.updateInactiveCallsCount() self.callsData.notifyValue() + self.currentCallData.notifyValue() }, onMessageReceived : { (core: Core, room: ChatRoom, message: ChatMessage) -> Void in @@ -203,6 +204,32 @@ class CallsViewModel { ControlsViewModel.shared.updateMicState() //updateUnreadChatCount() } - - +} + +@objc class CallsViewModelBridge : NSObject { + @objc static func callViewToDisplay() -> UICompositeViewDescription? { + if let call = CallsViewModel.shared.currentCallData.value??.call { + if (call.conference != nil) { + return ConferenceCallView.compositeDescription + } else { + return SingleCallView.compositeDescription + } + } else { + return DialerView.compositeViewDescription() + } + } + @objc static func setupCallsViewNavigation() { + CallsViewModel.shared.currentCallData.readCurrentAndObserve { currentCallData in + guard currentCallData != nil && currentCallData??.call != nil && currentCallData??.isOutgoing.value != true && currentCallData??.isIncoming.value != true else { + PhoneMainView.instance().popView(SingleCallView.compositeDescription) + PhoneMainView.instance().popView(ConferenceCallView.compositeDescription) + return + } + if (currentCallData??.call.conference != nil) { + PhoneMainView.instance().changeCurrentView(ConferenceCallView.compositeDescription) + } else { + PhoneMainView.instance().changeCurrentView(SingleCallView.compositeDescription) + } + } + } } diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/AbstractCallView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/AbstractCallView.swift new file mode 100644 index 000000000..48d1368bd --- /dev/null +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/AbstractCallView.swift @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +import UIKit +import linphonesw + + +@objc class AbstractCallView: UIViewController { + + let extraButtonsView = VoipExtraButtonsView() + var numpadView : NumpadView? = nil + var currentCallStatsVew : CallStatsView? = nil + var shadingMask = UIView() + var videoAcceptDialog : VoipDialog? = nil + var dismissableView : DismissableView? = nil + + var audioRoutesView : AudioRoutesView? = nil + let fullScreenMutableContainerView = UIView() + let controlsView = ControlsView(showVideo: true, controlsViewModel: ControlsViewModel.shared) + + override func viewDidLoad() { + super.viewDidLoad() + + UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in + self.view.backgroundColor = VoipTheme.voipBackgroundColor.get() + } + + // Hangup + let hangup = CallControlButton(width: 65, imageInset:AbstractIncomingOutgoingCallView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { + ControlsViewModel.shared.hangUp() + }) + view.addSubview(hangup) + hangup.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() + + + // Controls + view.addSubview(controlsView) + controlsView.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() + + // Container view + fullScreenMutableContainerView.backgroundColor = .clear + self.view.addSubview(fullScreenMutableContainerView) + fullScreenMutableContainerView.alignParentLeft(withMargin: SharedLayoutConstants.content_inset).alignParentRight(withMargin: SharedLayoutConstants.content_inset).matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() + + + // Calls List + ControlsViewModel.shared.goToCallsListEvent.observe { (_) in + self.dismissableView = CallsListView() + self.view.addSubview(self.dismissableView!) + self.dismissableView?.matchParentDimmensions().done() + } + + // Goto chat + ControlsViewModel.shared.goToChatEvent.observe { (_) in + self.goToChat() + } + + + // Shading mask, everything before will be shaded upon displaying of the mask + shadingMask.backgroundColor = VoipTheme.voip_translucent_popup_background + shadingMask.isHidden = true + self.view.addSubview(shadingMask) + shadingMask.matchParentDimmensions().done() + + // Extra Buttons + let showextraButtons = CallControlButton(imageInset:AbstractIncomingOutgoingCallView.answer_decline_inset, buttonTheme: VoipTheme.call_more, onClickAction: { + self.showModalSubview(view: self.extraButtonsView) + ControlsViewModel.shared.audioRoutesSelected.value = false + }) + view.addSubview(showextraButtons) + showextraButtons.alignParentRight(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() + + let boucingCounter = BouncingCounter(inButton:showextraButtons) + view.addSubview(boucingCounter) + boucingCounter.dataSource = CallsViewModel.shared.chatAndCallsCount + + view.addSubview(extraButtonsView) + extraButtonsView.matchParentSideBorders(insetedByDx: SharedLayoutConstants.content_inset).alignParentBottom(withMargin:SharedLayoutConstants.bottom_margin_notch_clearance).done() + ControlsViewModel.shared.hideExtraButtons.readCurrentAndObserve { (_) in + self.hideModalSubview(view: self.extraButtonsView) + } + shadingMask.onClick { + if (!self.extraButtonsView.isHidden) { + self.hideModalSubview(view: self.extraButtonsView) + } + ControlsViewModel.shared.audioRoutesSelected.value = false + } + + // Numpad + ControlsViewModel.shared.numpadVisible.readCurrentAndObserve { (visible) in + if (visible == true && CallsViewModel.shared.currentCallData.value != nil ) { + self.numpadView?.removeFromSuperview() + self.shadingMask.isHidden = false + self.numpadView = NumpadView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop: 0.0, above:self.controlsView, onDismissAction: { + ControlsViewModel.shared.numpadVisible.value = false + }) + } else { + self.numpadView?.removeFromSuperview() + self.shadingMask.isHidden = true + } + + } + + // Call stats + ControlsViewModel.shared.callStatsVisible.readCurrentAndObserve { (visible) in + if (visible == true && CallsViewModel.shared.currentCallData.value != nil ) { + self.currentCallStatsVew?.removeFromSuperview() + self.shadingMask.isHidden = false + self.currentCallStatsVew = CallStatsView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:0.0, above:self.controlsView, onDismissAction: { + ControlsViewModel.shared.callStatsVisible.value = false + }) + } else { + self.currentCallStatsVew?.removeFromSuperview() + self.shadingMask.isHidden = true + } + } + + // Audio Routes + audioRoutesView = AudioRoutesView() + view.addSubview(audioRoutesView!) + audioRoutesView!.alignBottomWith(otherView: controlsView).done() + ControlsViewModel.shared.audioRoutesSelected.readCurrentAndObserve { (audioRoutesSelected) in + self.audioRoutesView!.isHidden = audioRoutesSelected != true + } + audioRoutesView!.alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(true) + extraButtonsView.refresh() + ControlsViewModel.shared.callStatsVisible.notifyValue() + ControlsViewModel.shared.audioRoutesSelected.value = false + } + + override func viewWillDisappear(_ animated: Bool) { + dismissableView?.removeFromSuperview() + dismissableView = nil + + ControlsViewModel.shared.numpadVisible.value = false + ControlsViewModel.shared.callStatsVisible.value = false + ControlsViewModel.shared.fullScreenMode.value = false + super.viewWillDisappear(animated) + } + + func showModalSubview(view:UIView) { + view.isHidden = false + shadingMask.isHidden = false + } + func hideModalSubview(view:UIView) { + view.isHidden = true + shadingMask.isHidden = true + } + + func goToChat() { + /*guard + let chatRoom = CallsViewModel.shared.currentCallData.value??.chatRoom + else { + Log.w("[Call] Failed to find existing chat room associated to call") + return + }*/ + PhoneMainView.instance().changeCurrentView(ChatsListView.compositeViewDescription()) + + } + + func layoutRotatableElements() { + let leftMargin = UIDevice.current.orientation == .landscapeLeft && UIDevice.hasNotch() ? UIApplication.shared.keyWindow!.safeAreaInsets.left : SharedLayoutConstants.content_inset + let rightMargin = UIDevice.current.orientation == .landscapeRight && UIDevice.hasNotch() ? UIApplication.shared.keyWindow!.safeAreaInsets.right : SharedLayoutConstants.content_inset + fullScreenMutableContainerView.updateAlignParentLeft(withMargin: leftMargin).updateAlignParentRight(withMargin: rightMargin).done() + controlsView.updateAlignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() + } + + override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { + super.didRotate(from: fromInterfaceOrientation) + self.layoutRotatableElements() + } + + +} diff --git a/Classes/Swift/Voip/Views/Fragments/IncomingOuntgoingCommonView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/AbstractIncomingOutgoingCallView.swift similarity index 79% rename from Classes/Swift/Voip/Views/Fragments/IncomingOuntgoingCommonView.swift rename to Classes/Swift/Voip/Views/CompositeViewControllers/AbstractIncomingOutgoingCallView.swift index 4ceb0020f..ccf5f120c 100644 --- a/Classes/Swift/Voip/Views/Fragments/IncomingOuntgoingCommonView.swift +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/AbstractIncomingOutgoingCallView.swift @@ -22,7 +22,7 @@ import UIKit import Foundation import linphonesw -@objc class IncomingOutgoingCommonView: UIViewController { // Shared between IncomingCallView and OutgoingCallVIew (all upper part except control buttons) +@objc class AbstractIncomingOutgoingCallView: UIViewController { // Shared between IncomingCallView and OutgoingCallVIew (all upper part except control buttons) // Layout constants static let spinner_size = 50 @@ -58,22 +58,22 @@ import linphonesw view.backgroundColor = VoipTheme.voipBackgroundColor.get() view.addSubview(spinner) - spinner.square(IncomingOutgoingCommonView.spinner_size).matchParentSideBorders().alignParentTop(withMargin:IncomingOutgoingCommonView.spinner_margin_top + UIDevice.notchHeight()).done() + spinner.square(AbstractIncomingOutgoingCallView.spinner_size).matchParentSideBorders().alignParentTop(withMargin:AbstractIncomingOutgoingCallView.spinner_margin_top + UIDevice.notchHeight()).done() let callType = StyledLabel(VoipTheme.call_header_title,forCallType) view.addSubview(callType) - callType.matchParentSideBorders().alignUnder(view:spinner,withMargin:IncomingOutgoingCommonView.call_type_margin_top).done() + callType.matchParentSideBorders().alignUnder(view:spinner,withMargin:AbstractIncomingOutgoingCallView.call_type_margin_top).done() self.view.addSubview(duration) - duration.matchParentSideBorders().alignUnder(view:callType,withMargin:IncomingOutgoingCommonView.duration_margin_top).done() + duration.matchParentSideBorders().alignUnder(view:callType,withMargin:AbstractIncomingOutgoingCallView.duration_margin_top).done() // Center : Avatar + Display name + SIP Address let centerSection = UIView() centerSection.addSubview(avatar) centerSection.addSubview(displayName) - displayName.height(IncomingOutgoingCommonView.display_name_height).matchParentSideBorders().alignUnder(view:avatar,withMargin:IncomingOutgoingCommonView.display_name_margin_top).done() + displayName.height(AbstractIncomingOutgoingCallView.display_name_height).matchParentSideBorders().alignUnder(view:avatar,withMargin:AbstractIncomingOutgoingCallView.display_name_margin_top).done() centerSection.addSubview(sipAddress) - sipAddress.height(IncomingOutgoingCommonView.sip_address_height).matchParentSideBorders().alignUnder(view:displayName,withMargin:IncomingOutgoingCommonView.sip_address_margin_top).done() + sipAddress.height(AbstractIncomingOutgoingCallView.sip_address_height).matchParentSideBorders().alignUnder(view:displayName,withMargin:AbstractIncomingOutgoingCallView.sip_address_margin_top).done() self.view.addSubview(centerSection) centerSection.matchParentSideBorders().center().done() diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift deleted file mode 100644 index cd37da76e..000000000 --- a/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2010-2020 Belledonne Communications SARL. - * - * This file is part of linphone-iphone - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -import UIKit -import linphonesw - - -@objc class ActiveCallOrConferenceView: UIViewController, UICompositeViewDelegate { // Replaces CallView - - // Layout constants - static let content_inset = 12.0 - - var callPausedByRemoteView : PausedCallOrConferenceView? = nil - var callPausedByLocalView : PausedCallOrConferenceView? = nil - - var conferencePausedView : PausedCallOrConferenceView? = nil - - var currentCallView : ActiveCallView? = nil - var conferenceGridView: VoipConferenceGridView? = nil - var conferenceActiveSpeakerView: VoipConferenceActiveSpeakerView? = nil - var conferenceAudioOnlyView: VoipConferenceAudioOnlyView? = nil - - let conferenceJoinSpinner = RotatingSpinner() - - - let extraButtonsView = VoipExtraButtonsView() - var numpadView : NumpadView? = nil - var currentCallStatsVew : CallStatsView? = nil - var shadingMask = UIView() - var videoAcceptDialog : VoipDialog? = nil - var dismissableView : DismissableView? = nil - @objc var participantsListView : ParticipantsListView? = nil - - var audioRoutesView : AudioRoutesView? = nil - let fullScreenMutableContainerView = UIView() - let controlsView = ControlsView(showVideo: true, controlsViewModel: ControlsViewModel.shared) - - static let compositeDescription = UICompositeViewDescription(ActiveCallOrConferenceView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: nil, fullscreen: false, isLeftFragment: false,fragmentWith: nil) - static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription } - func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription } - - override func viewDidLoad() { - super.viewDidLoad() - - UIDeviceBridge.displayModeSwitched.readCurrentAndObserve { _ in - self.view.backgroundColor = VoipTheme.voipBackgroundColor.get() - } - - // Hangup - let hangup = CallControlButton(width: 65, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { - ControlsViewModel.shared.hangUp() - }) - view.addSubview(hangup) - hangup.alignParentLeft(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - - // Controls - view.addSubview(controlsView) - controlsView.alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() - - // Container view - fullScreenMutableContainerView.backgroundColor = .clear - self.view.addSubview(fullScreenMutableContainerView) - fullScreenMutableContainerView.alignParentLeft(withMargin: ActiveCallOrConferenceView.content_inset).alignParentRight(withMargin: ActiveCallOrConferenceView.content_inset).matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - // Current (Single) Call (VoipCallView) - currentCallView = ActiveCallView() - currentCallView!.isHidden = true - fullScreenMutableContainerView.addSubview(currentCallView!) - CallsViewModel.shared.currentCallData.readCurrentAndObserve { (currentCallData) in - self.updateNavigation() - let isConferenceCall = currentCallData??.call.conference != nil - self.currentCallView!.isHidden = isConferenceCall - if (!isConferenceCall) { - self.currentCallView!.callData = currentCallData != nil ? currentCallData! : nil - } - currentCallData??.isRemotelyPaused.readCurrentAndObserve { remotelyPaused in - self.callPausedByRemoteView?.isHidden = remotelyPaused != true || isConferenceCall - } - currentCallData??.isPaused.readCurrentAndObserve { locallyPaused in - self.callPausedByLocalView?.isHidden = locallyPaused != true || isConferenceCall - } - if (currentCallData == nil) { - self.callPausedByRemoteView?.isHidden = true - self.callPausedByLocalView?.isHidden = true - - } else { - currentCallData??.isIncoming.readCurrentAndObserve { _ in self.updateNavigation() } - currentCallData??.isOutgoing.readCurrentAndObserve { _ in self.updateNavigation() } - } - self.extraButtonsView.isHidden = true - self.conferencePausedView?.isHidden = currentCallData??.call.conference == nil || ConferenceViewModel.shared.isConferenceLocallyPaused.value != true - - if (isConferenceCall) { - self.conferenceGridView?.isHidden = true - self.conferenceActiveSpeakerView?.isHidden = true - self.conferenceAudioOnlyView?.isHidden = true - } - - } - - currentCallView!.matchParentDimmensions().done() - - // Paused by remote (Call) - callPausedByRemoteView = PausedCallOrConferenceView(iconName: "voip_conference_paused_big",titleText: VoipTexts.call_remotely_paused_title,subTitleText: nil) - view.addSubview(callPausedByRemoteView!) - callPausedByRemoteView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - callPausedByRemoteView?.isHidden = true - - // Paused by local (Call) - callPausedByLocalView = PausedCallOrConferenceView(iconName: "voip_conference_play_big",titleText: VoipTexts.call_locally_paused_title,subTitleText: VoipTexts.call_locally_paused_subtitle, onClickAction: { - CallsViewModel.shared.currentCallData.value??.togglePause() - }) - view.addSubview(callPausedByLocalView!) - callPausedByLocalView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - callPausedByLocalView?.isHidden = true - - - // Conference paused - conferencePausedView = PausedCallOrConferenceView(iconName: "voip_conference_play_big",titleText: VoipTexts.conference_paused_title,subTitleText: VoipTexts.conference_paused_subtitle, onClickAction: { - ConferenceViewModel.shared.togglePlayPause() - }) - view.addSubview(conferencePausedView!) - conferencePausedView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - conferencePausedView?.isHidden = true - - // Conference grid - conferenceGridView = VoipConferenceGridView() - fullScreenMutableContainerView.addSubview(conferenceGridView!) - conferenceGridView?.matchParentDimmensions().done() - conferenceGridView?.isHidden = true - ConferenceViewModel.shared.conferenceExists.readCurrentAndObserve { (exists) in - self.updateNavigation() - let activeCallIsConference = CallsViewModel.shared.currentCallData.value??.call.conference != nil - if (activeCallIsConference) { - self.currentCallView!.isHidden = true - self.extraButtonsView.isHidden = true - self.conferencePausedView?.isHidden = ConferenceViewModel.shared.isConferenceLocallyPaused.value != true - self.displaySelectedConferenceLayout() - } else { - self.conferenceGridView?.isHidden = true - self.conferenceActiveSpeakerView?.isHidden = true - self.conferenceActiveSpeakerView?.isHidden = true - self.conferencePausedView?.isHidden = true - } - } - - ConferenceViewModel.shared.conferenceCreationPending.readCurrentAndObserve { isCreationPending in - if (isCreationPending == true) { - self.fullScreenMutableContainerView.addSubview(self.conferenceJoinSpinner) - self.conferenceJoinSpinner.square(IncomingOutgoingCommonView.spinner_size).center().done() - self.conferenceJoinSpinner.startRotation() - } else { - self.conferenceJoinSpinner.removeFromSuperview() - self.conferenceJoinSpinner.stopRotation() - } - } - - // Conference active speaker - conferenceActiveSpeakerView = VoipConferenceActiveSpeakerView() - fullScreenMutableContainerView.addSubview(conferenceActiveSpeakerView!) - conferenceActiveSpeakerView?.matchParentDimmensions().done() - conferenceActiveSpeakerView?.isHidden = true - - - // Conference audio only - conferenceAudioOnlyView = VoipConferenceAudioOnlyView() - fullScreenMutableContainerView.addSubview(conferenceAudioOnlyView!) - conferenceAudioOnlyView?.matchParentDimmensions().done() - conferenceAudioOnlyView?.isHidden = true - - ConferenceViewModel.shared.conferenceDisplayMode.readCurrentAndObserve { (conferenceMode) in - if (ConferenceViewModel.shared.conferenceExists.value == true) { - self.displaySelectedConferenceLayout() - } - } - ConferenceViewModel.shared.isConferenceLocallyPaused.readCurrentAndObserve { (paused) in - self.conferencePausedView?.isHidden = paused != true - } - - - // Calls List - ControlsViewModel.shared.goToCallsListEvent.observe { (_) in - self.dismissableView = CallsListView() - self.view.addSubview(self.dismissableView!) - self.dismissableView?.matchParentDimmensions().done() - } - - // Conference Participants List - ControlsViewModel.shared.goToConferenceParticipantsListEvent.observe { (_) in - self.participantsListView = ParticipantsListView() - self.view.addSubview(self.participantsListView!) - self.participantsListView?.matchParentDimmensions().done() - } - - // Goto chat - ControlsViewModel.shared.goToChatEvent.observe { (_) in - self.goToChat() - } - - // Conference mode selection - ControlsViewModel.shared.goToConferenceLayoutSettings.observe { (_) in - self.dismissableView = VoipConferenceDisplayModeSelectionView() - self.view.addSubview(self.dismissableView!) - self.dismissableView?.matchParentDimmensions().done() - } - - // Shading mask, everything before will be shaded upon displaying of the mask - shadingMask.backgroundColor = VoipTheme.voip_translucent_popup_background - shadingMask.isHidden = true - self.view.addSubview(shadingMask) - shadingMask.matchParentDimmensions().done() - - // Extra Buttons - let showextraButtons = CallControlButton(imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_more, onClickAction: { - self.showModalSubview(view: self.extraButtonsView) - ControlsViewModel.shared.audioRoutesSelected.value = false - }) - view.addSubview(showextraButtons) - showextraButtons.alignParentRight(withMargin:SharedLayoutConstants.margin_call_view_side_controls_buttons).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() - - let boucingCounter = BouncingCounter(inButton:showextraButtons) - view.addSubview(boucingCounter) - boucingCounter.dataSource = CallsViewModel.shared.chatAndCallsCount - - view.addSubview(extraButtonsView) - extraButtonsView.matchParentSideBorders(insetedByDx: ActiveCallOrConferenceView.content_inset).alignParentBottom(withMargin:SharedLayoutConstants.bottom_margin_notch_clearance).done() - ControlsViewModel.shared.hideExtraButtons.readCurrentAndObserve { (_) in - self.hideModalSubview(view: self.extraButtonsView) - } - shadingMask.onClick { - if (!self.extraButtonsView.isHidden) { - self.hideModalSubview(view: self.extraButtonsView) - } - ControlsViewModel.shared.audioRoutesSelected.value = false - } - - // Numpad - ControlsViewModel.shared.numpadVisible.readCurrentAndObserve { (visible) in - if (visible == true && CallsViewModel.shared.currentCallData.value != nil ) { - self.numpadView?.removeFromSuperview() - self.shadingMask.isHidden = false - self.numpadView = NumpadView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:self.currentCallView?.centerSection.frame.origin.y ?? 0.0, above:self.controlsView, onDismissAction: { - ControlsViewModel.shared.numpadVisible.value = false - }) - } else { - self.numpadView?.removeFromSuperview() - self.shadingMask.isHidden = true - } - - } - - // Call stats - ControlsViewModel.shared.callStatsVisible.readCurrentAndObserve { (visible) in - if (visible == true && CallsViewModel.shared.currentCallData.value != nil ) { - self.currentCallStatsVew?.removeFromSuperview() - self.shadingMask.isHidden = false - self.currentCallStatsVew = CallStatsView(superView: self.view,callData: CallsViewModel.shared.currentCallData.value!!,marginTop:self.currentCallView?.centerSection.frame.origin.y ?? 0.0, above:self.controlsView, onDismissAction: { - ControlsViewModel.shared.callStatsVisible.value = false - }) - } else { - self.currentCallStatsVew?.removeFromSuperview() - self.shadingMask.isHidden = true - } - } - - // Video activation dialog request - CallsViewModel.shared.callUpdateEvent.observe { (call) in - let core = Core.get() - if (call?.state == .StreamsRunning) { - self.videoAcceptDialog?.removeFromSuperview() - self.videoAcceptDialog = nil - } else if (call?.state == .UpdatedByRemote) { - if (core.videoCaptureEnabled || core.videoDisplayEnabled) { - if (call?.currentParams?.videoEnabled != call?.remoteParams?.videoEnabled) { - let accept = ButtonAttributes(text:VoipTexts.dialog_accept, action: {call?.answerVideoUpdateRequest(accept: true)}, isDestructive:false) - let cancel = ButtonAttributes(text:VoipTexts.dialog_decline, action: {call?.answerVideoUpdateRequest(accept: false)}, isDestructive:true) - self.videoAcceptDialog = VoipDialog(message:VoipTexts.call_video_update_requested_dialog, givenButtons: [cancel,accept]) - self.videoAcceptDialog?.show() - } - } else { - Log.w("[Call] Video display & capture are disabled, don't show video dialog") - } - } - } - - // Audio Routes - audioRoutesView = AudioRoutesView() - view.addSubview(audioRoutesView!) - audioRoutesView!.alignBottomWith(otherView: controlsView).done() - ControlsViewModel.shared.audioRoutesSelected.readCurrentAndObserve { (audioRoutesSelected) in - self.audioRoutesView!.isHidden = audioRoutesSelected != true - } - audioRoutesView!.alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() - - // First/Last to join conference : - - ConferenceViewModel.shared.allParticipantsLeftEvent.observe { (allLeft) in - if (allLeft == true) { - VoipDialog.toast(message: VoipTexts.conference_last_user) - } - } - ConferenceViewModel.shared.firstToJoinEvent.observe { (first) in - if (first == true) { - VoipDialog.toast(message: VoipTexts.conference_first_to_join) - } - } - - } // viewDidLoad - - func displaySelectedConferenceLayout() { - let conferenceMode = ConferenceViewModel.shared.conferenceDisplayMode.value - self.conferenceGridView!.isHidden = conferenceMode != .Grid - self.conferenceActiveSpeakerView!.isHidden = conferenceMode != .ActiveSpeaker - self.conferenceAudioOnlyView!.isHidden = conferenceMode != .AudioOnly - if (conferenceMode == .Grid) { - self.conferenceGridView?.conferenceViewModel = ConferenceViewModel.shared - } - if (conferenceMode == .AudioOnly) { - self.conferenceAudioOnlyView?.conferenceViewModel = ConferenceViewModel.shared - } - if (conferenceMode == .ActiveSpeaker) { - self.conferenceActiveSpeakerView?.conferenceViewModel = ConferenceViewModel.shared - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(true) - extraButtonsView.refresh() - ControlsViewModel.shared.callStatsVisible.notifyValue() - CallsViewModel.shared.currentCallData.notifyValue() - ConferenceViewModel.shared.conferenceExists.notifyValue() - ControlsViewModel.shared.audioRoutesSelected.value = false - ControlsViewModel.shared.fullScreenMode.value = true - } - - override func viewWillDisappear(_ animated: Bool) { - dismissableView?.removeFromSuperview() - dismissableView = nil - - participantsListView?.removeFromSuperview() - participantsListView = nil - - ControlsViewModel.shared.numpadVisible.value = false - ControlsViewModel.shared.callStatsVisible.value = false - ControlsViewModel.shared.fullScreenMode.value = false - super.viewWillDisappear(animated) - } - - func showModalSubview(view:UIView) { - view.isHidden = false - shadingMask.isHidden = false - } - func hideModalSubview(view:UIView) { - view.isHidden = true - shadingMask.isHidden = true - } - - func updateNavigation() { - if (Core.get().callsNb == 0) { - PhoneMainView.instance().popView(self.compositeViewDescription()) - } else { - if let data = CallsViewModel.shared.currentCallData.value { - if (data?.isOutgoing.value == true || data?.isIncoming.value == true) { - PhoneMainView.instance().popView(self.compositeViewDescription()) - } else { - if (data!.isInRemoteConference.value == true) { - PhoneMainView.instance().pop(toView: self.compositeViewDescription()) - } else { - PhoneMainView.instance().changeCurrentView(self.compositeViewDescription()) - } - } - } else { - PhoneMainView.instance().changeCurrentView(self.compositeViewDescription()) - } - } - } - - func goToChat() { - /*guard - let chatRoom = CallsViewModel.shared.currentCallData.value??.chatRoom - else { - Log.w("[Call] Failed to find existing chat room associated to call") - return - }*/ - PhoneMainView.instance().changeCurrentView(ChatsListView.compositeViewDescription()) - - } - - - func layoutRotatableElements() { - let leftMargin = UIDevice.current.orientation == .landscapeLeft && UIDevice.hasNotch() ? UIApplication.shared.keyWindow!.safeAreaInsets.left : ActiveCallOrConferenceView.content_inset - let rightMargin = UIDevice.current.orientation == .landscapeRight && UIDevice.hasNotch() ? UIApplication.shared.keyWindow!.safeAreaInsets.right : ActiveCallOrConferenceView.content_inset - fullScreenMutableContainerView.updateAlignParentLeft(withMargin: leftMargin).updateAlignParentRight(withMargin: rightMargin).done() - controlsView.updateAlignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).centerX().done() - } - - override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { - super.didRotate(from: fromInterfaceOrientation) - self.layoutRotatableElements() - self.conferenceActiveSpeakerView?.layoutRotatableElements() - self.currentCallView?.layoutRotatableElements() - } - - -} diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/ConferenceCallView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/ConferenceCallView.swift new file mode 100644 index 000000000..4b39128cb --- /dev/null +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/ConferenceCallView.swift @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +import UIKit +import linphonesw + + +@objc class ConferenceCallView: AbstractCallView, UICompositeViewDelegate { + + var conferencePausedView : PausedCallOrConferenceView? = nil + var conferenceGridView: VoipConferenceGridView? = nil + var conferenceActiveSpeakerView: VoipConferenceActiveSpeakerView? = nil + var conferenceAudioOnlyView: VoipConferenceAudioOnlyView? = nil + let conferenceJoinSpinner = RotatingSpinner() + @objc var participantsListView : ParticipantsListView? = nil + + static let compositeDescription = UICompositeViewDescription(ConferenceCallView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: nil, fullscreen: false, isLeftFragment: false,fragmentWith: nil) + static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription } + func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription } + + override func viewDidLoad() { + super.viewDidLoad() + + // Conference paused + conferencePausedView = PausedCallOrConferenceView(iconName: "voip_conference_play_big",titleText: VoipTexts.conference_paused_title,subTitleText: VoipTexts.conference_paused_subtitle, onClickAction: { + ConferenceViewModel.shared.togglePlayPause() + }) + view.addSubview(conferencePausedView!) + conferencePausedView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() + conferencePausedView?.isHidden = true + + // Conference grid + conferenceGridView = VoipConferenceGridView() + fullScreenMutableContainerView.addSubview(conferenceGridView!) + conferenceGridView?.matchParentDimmensions().done() + conferenceGridView?.isHidden = true + ConferenceViewModel.shared.conferenceExists.readCurrentAndObserve { (exists) in + if (exists == true) { + self.extraButtonsView.isHidden = true + self.conferencePausedView?.isHidden = ConferenceViewModel.shared.isConferenceLocallyPaused.value != true + self.displaySelectedConferenceLayout() + } else { + self.conferenceGridView?.isHidden = true + self.conferenceActiveSpeakerView?.isHidden = true + self.conferenceActiveSpeakerView?.isHidden = true + self.conferencePausedView?.isHidden = true + } + } + + ConferenceViewModel.shared.conferenceCreationPending.readCurrentAndObserve { isCreationPending in + if (isCreationPending == true) { + self.fullScreenMutableContainerView.addSubview(self.conferenceJoinSpinner) + self.conferenceJoinSpinner.square(AbstractIncomingOutgoingCallView.spinner_size).center().done() + self.conferenceJoinSpinner.startRotation() + } else { + self.conferenceJoinSpinner.removeFromSuperview() + self.conferenceJoinSpinner.stopRotation() + } + } + + // Conference active speaker + conferenceActiveSpeakerView = VoipConferenceActiveSpeakerView() + fullScreenMutableContainerView.addSubview(conferenceActiveSpeakerView!) + conferenceActiveSpeakerView?.matchParentDimmensions().done() + conferenceActiveSpeakerView?.isHidden = true + + // Conference audio only + conferenceAudioOnlyView = VoipConferenceAudioOnlyView() + fullScreenMutableContainerView.addSubview(conferenceAudioOnlyView!) + conferenceAudioOnlyView?.matchParentDimmensions().done() + conferenceAudioOnlyView?.isHidden = true + + ConferenceViewModel.shared.conferenceDisplayMode.readCurrentAndObserve { (conferenceMode) in + if (ConferenceViewModel.shared.conferenceExists.value == true) { + self.displaySelectedConferenceLayout() + } + } + ConferenceViewModel.shared.isConferenceLocallyPaused.readCurrentAndObserve { (paused) in + self.conferencePausedView?.isHidden = paused != true + } + + // Conference Participants List + ControlsViewModel.shared.goToConferenceParticipantsListEvent.observe { (_) in + self.participantsListView = ParticipantsListView() + self.view.addSubview(self.participantsListView!) + self.participantsListView?.matchParentDimmensions().done() + } + + // Conference mode selection + ControlsViewModel.shared.goToConferenceLayoutSettings.observe { (_) in + self.dismissableView = VoipConferenceDisplayModeSelectionView() + self.view.addSubview(self.dismissableView!) + self.dismissableView?.matchParentDimmensions().done() + } + + // First/Last to join conference : + ConferenceViewModel.shared.allParticipantsLeftEvent.observe { (allLeft) in + if (allLeft == true) { + VoipDialog.toast(message: VoipTexts.conference_last_user) + } + } + ConferenceViewModel.shared.firstToJoinEvent.observe { (first) in + if (first == true) { + VoipDialog.toast(message: VoipTexts.conference_first_to_join) + } + } + } + + func displaySelectedConferenceLayout() { + let conferenceMode = ConferenceViewModel.shared.conferenceDisplayMode.value + self.conferenceGridView!.isHidden = conferenceMode != .Grid + self.conferenceActiveSpeakerView!.isHidden = conferenceMode != .ActiveSpeaker + self.conferenceAudioOnlyView!.isHidden = conferenceMode != .AudioOnly + if (conferenceMode == .Grid) { + self.conferenceGridView?.conferenceViewModel = ConferenceViewModel.shared + } + if (conferenceMode == .AudioOnly) { + self.conferenceAudioOnlyView?.conferenceViewModel = ConferenceViewModel.shared + } + if (conferenceMode == .ActiveSpeaker) { + self.conferenceActiveSpeakerView?.conferenceViewModel = ConferenceViewModel.shared + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(true) + ConferenceViewModel.shared.conferenceExists.notifyValue() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + participantsListView?.removeFromSuperview() + participantsListView = nil + } + + override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { + super.didRotate(from: fromInterfaceOrientation) + self.conferenceActiveSpeakerView?.layoutRotatableElements() + } + + +} diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/IncomingCallView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/IncomingCallView.swift index e1a7693bc..ef9b4af3a 100644 --- a/Classes/Swift/Voip/Views/CompositeViewControllers/IncomingCallView.swift +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/IncomingCallView.swift @@ -22,7 +22,7 @@ import UIKit import Foundation import linphonesw -@objc class IncomingCallView: IncomingOutgoingCommonView, UICompositeViewDelegate { +@objc class IncomingCallView: AbstractIncomingOutgoingCallView, UICompositeViewDelegate { // Layout constants let buttons_distance_from_center_x = 38 @@ -38,14 +38,14 @@ import linphonesw super.viewDidLoad(forCallType: VoipTexts.call_incoming_title) // Accept - let accept = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_accept, onClickAction: { + let accept = CallControlButton(width: CallControlButton.hungup_width, imageInset:AbstractIncomingOutgoingCallView.answer_decline_inset, buttonTheme: VoipTheme.call_accept, onClickAction: { self.callData.map { CallManager.instance().acceptCall(call: $0.call.getCobject, hasVideo: false)} }) view.addSubview(accept) accept.centerX(withDx: buttons_distance_from_center_x).alignParentBottom(withMargin:SharedLayoutConstants.buttons_bottom_margin).done() // Decline - let decline = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { + let decline = CallControlButton(width: CallControlButton.hungup_width, imageInset:AbstractIncomingOutgoingCallView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { self.callData.map { CallManager.instance().terminateCall(call: $0.call.getCobject)} }) view.addSubview(decline) diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/OutgoingCallView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/OutgoingCallView.swift index 7823d6643..f900e58b4 100644 --- a/Classes/Swift/Voip/Views/CompositeViewControllers/OutgoingCallView.swift +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/OutgoingCallView.swift @@ -22,7 +22,7 @@ import UIKit import Foundation import linphonesw -@objc class OutgoingCallView: IncomingOutgoingCommonView, UICompositeViewDelegate { +@objc class OutgoingCallView: AbstractIncomingOutgoingCallView, UICompositeViewDelegate { // Layout constants let numpad_icon_padding = 10.0 @@ -40,7 +40,7 @@ import linphonesw super.viewDidLoad(forCallType: VoipTexts.call_outgoing_title) // Cancel - let cancelCall = CallControlButton(width: CallControlButton.hungup_width, imageInset:IncomingOutgoingCommonView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { + let cancelCall = CallControlButton(width: CallControlButton.hungup_width, imageInset:AbstractIncomingOutgoingCallView.answer_decline_inset, buttonTheme: VoipTheme.call_terminate, onClickAction: { self.callData.map { CallManager.instance().terminateCall(call: $0.call.getCobject)} }) view.addSubview(cancelCall) diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/SingleCallView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/SingleCallView.swift new file mode 100644 index 000000000..bfa606c9a --- /dev/null +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/SingleCallView.swift @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +import UIKit +import linphonesw + + +@objc class SingleCallView: AbstractCallView, UICompositeViewDelegate { + + var callPausedByRemoteView : PausedCallOrConferenceView? = nil + var callPausedByLocalView : PausedCallOrConferenceView? = nil + var currentCallView : ActiveCallView? = nil + + static let compositeDescription = UICompositeViewDescription(SingleCallView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: nil, fullscreen: false, isLeftFragment: false,fragmentWith: nil) + static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription } + func compositeViewDescription() -> UICompositeViewDescription! { return type(of: self).compositeDescription } + + override func viewDidLoad() { + super.viewDidLoad() + + // Current (Single) Call (VoipCallView) + currentCallView = ActiveCallView() + fullScreenMutableContainerView.addSubview(currentCallView!) + CallsViewModel.shared.currentCallData.readCurrentAndObserve { (currentCallData) in + self.currentCallView!.callData = currentCallData != nil ? currentCallData! : nil + currentCallData??.isRemotelyPaused.readCurrentAndObserve { remotelyPaused in + self.callPausedByRemoteView?.isHidden = remotelyPaused != true + } + currentCallData??.isPaused.readCurrentAndObserve { locallyPaused in + self.callPausedByLocalView?.isHidden = locallyPaused != true + } + if (currentCallData == nil) { + self.callPausedByRemoteView?.isHidden = true + self.callPausedByLocalView?.isHidden = true + + } + self.extraButtonsView.isHidden = true + } + + currentCallView!.matchParentDimmensions().done() + + // Paused by remote (Call) + callPausedByRemoteView = PausedCallOrConferenceView(iconName: "voip_conference_paused_big",titleText: VoipTexts.call_remotely_paused_title,subTitleText: nil) + view.addSubview(callPausedByRemoteView!) + callPausedByRemoteView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() + callPausedByRemoteView?.isHidden = true + + // Paused by local (Call) + callPausedByLocalView = PausedCallOrConferenceView(iconName: "voip_conference_play_big",titleText: VoipTexts.call_locally_paused_title,subTitleText: VoipTexts.call_locally_paused_subtitle, onClickAction: { + CallsViewModel.shared.currentCallData.value??.togglePause() + }) + view.addSubview(callPausedByLocalView!) + callPausedByLocalView?.matchParentSideBorders().matchParentHeight().alignAbove(view:controlsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).done() + callPausedByLocalView?.isHidden = true + + // Video activation dialog request + CallsViewModel.shared.callUpdateEvent.observe { (call) in + let core = Core.get() + if (call?.state == .StreamsRunning) { + self.videoAcceptDialog?.removeFromSuperview() + self.videoAcceptDialog = nil + } else if (call?.state == .UpdatedByRemote) { + if (core.videoCaptureEnabled || core.videoDisplayEnabled) { + if (call?.currentParams?.videoEnabled != call?.remoteParams?.videoEnabled) { + let accept = ButtonAttributes(text:VoipTexts.dialog_accept, action: {call?.answerVideoUpdateRequest(accept: true)}, isDestructive:false) + let cancel = ButtonAttributes(text:VoipTexts.dialog_decline, action: {call?.answerVideoUpdateRequest(accept: false)}, isDestructive:true) + self.videoAcceptDialog = VoipDialog(message:VoipTexts.call_video_update_requested_dialog, givenButtons: [cancel,accept]) + self.videoAcceptDialog?.show() + } + } else { + Log.w("[Call] Video display & capture are disabled, don't show video dialog") + } + } + } + } + + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(true) + CallsViewModel.shared.currentCallData.notifyValue() + } + + override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { + super.didRotate(from: fromInterfaceOrientation) + self.currentCallView?.layoutRotatableElements() + } + +} diff --git a/Classes/Swift/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift b/Classes/Swift/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift index 21119b6bf..6ecf4bdf9 100644 --- a/Classes/Swift/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift +++ b/Classes/Swift/Voip/Views/Fragments/Conference/VoipConferenceActiveSpeakerView.swift @@ -301,7 +301,7 @@ class VoipConferenceActiveSpeakerView: UIView, UICollectionViewDataSource, UICol muted.alignParentLeft(withMargin: switch_camera_button_margins).alignParentTop(withMargin:switch_camera_button_margins).done() activeSpeakerView.addSubview(conferenceJoinSpinner) - conferenceJoinSpinner.square(IncomingOutgoingCommonView.spinner_size).center().done() + conferenceJoinSpinner.square(AbstractIncomingOutgoingCallView.spinner_size).center().done() switchCamera.alignParentTop(withMargin: switch_camera_button_margins).alignParentRight(withMargin: switch_camera_button_margins).square(switch_camera_button_size).done() @@ -411,12 +411,12 @@ class VoipConferenceActiveSpeakerView: UIView, UICollectionViewDataSource, UICol activeSpeakerAvatar.square(Avatar.diameter_for_call_views_land).center().done() meGrid.alignParentRight(withMargin: ActiveCallView.center_view_margin_top).height(grid_height).width(grid_height).alignParentBottom(withMargin: ActiveCallView.center_view_margin_top).done() } else { - activeSpeakerView.alignParentTop().alignParentBottom().alignParentLeft().toLeftOf(grid,withRightMargin: ActiveCallOrConferenceView.content_inset).done() + activeSpeakerView.alignParentTop().alignParentBottom().alignParentLeft().toLeftOf(grid,withRightMargin: SharedLayoutConstants.content_inset).done() if (UIDevice.current.orientation == .landscapeLeft) { // work around some constraints issues with Notch on the left. bounceGrids() } - meGrid.width(grid_height).height(grid_height).toRightOf(activeSpeakerView,withLeftMargin: ActiveCallOrConferenceView.content_inset).alignParentBottom().alignParentRight().done() - grid.width(grid_height).toRightOf(activeSpeakerView,withLeftMargin: ActiveCallOrConferenceView.content_inset).alignParentTop().alignAbove(view: meGrid, withMargin: ActiveCallOrConferenceView.content_inset).alignParentRight().done() + meGrid.width(grid_height).height(grid_height).toRightOf(activeSpeakerView,withLeftMargin: SharedLayoutConstants.content_inset).alignParentBottom().alignParentRight().done() + grid.width(grid_height).toRightOf(activeSpeakerView,withLeftMargin: SharedLayoutConstants.content_inset).alignParentTop().alignAbove(view: meGrid, withMargin: SharedLayoutConstants.content_inset).alignParentRight().done() layout.scrollDirection = .vertical activeSpeakerAvatar.square(Avatar.diameter_for_call_views_land).center().done() } @@ -432,7 +432,7 @@ class VoipConferenceActiveSpeakerView: UIView, UICollectionViewDataSource, UICol activeSpeakerAvatar.square(Avatar.diameter_for_call_views).center().done() activeSpeakerView.matchParentSideBorders().alignParentTop().done() meGrid.alignParentLeft().height(grid_height).width(grid_height).alignParentBottom().alignUnder(view: activeSpeakerView, withMargin:ActiveCallView.center_view_margin_top).done() - grid.toRightOf(meGrid,withLeftMargin: ActiveCallOrConferenceView.content_inset).height(grid_height).alignParentRight().alignParentBottom().alignUnder(view: activeSpeakerView, withMargin:ActiveCallView.center_view_margin_top).done() + grid.toRightOf(meGrid,withLeftMargin: SharedLayoutConstants.content_inset).height(grid_height).alignParentRight().alignParentBottom().alignUnder(view: activeSpeakerView, withMargin:ActiveCallView.center_view_margin_top).done() layout.scrollDirection = .horizontal } } diff --git a/Classes/Swift/Voip/Views/SharedLayoutConstants.swift b/Classes/Swift/Voip/Views/SharedLayoutConstants.swift index 5eb92c3e8..ccb45a9e0 100644 --- a/Classes/Swift/Voip/Views/SharedLayoutConstants.swift +++ b/Classes/Swift/Voip/Views/SharedLayoutConstants.swift @@ -26,5 +26,5 @@ class SharedLayoutConstants { } static let margin_call_view_side_controls_buttons = 12 static let bottom_margin_notch_clearance = UIDevice.hasNotch() ? 30.0 : 0.0 - + static let content_inset = 12.0 } diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 1b2529cb3..e18506a07 100644 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -728,7 +728,7 @@ C63F724A285A24B10066163B /* VoipConferenceActiveSpeakerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71E4285A24B10066163B /* VoipConferenceActiveSpeakerView.swift */; }; C63F724B285A24B10066163B /* VoipConferenceDisplayModeSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71E5285A24B10066163B /* VoipConferenceDisplayModeSelectionView.swift */; }; C63F724C285A24B10066163B /* ActiveCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71E7285A24B10066163B /* ActiveCallView.swift */; }; - C63F724D285A24B10066163B /* IncomingOuntgoingCommonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71E8285A24B10066163B /* IncomingOuntgoingCommonView.swift */; }; + C63F724D285A24B10066163B /* AbstractIncomingOutgoingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71E8285A24B10066163B /* AbstractIncomingOutgoingCallView.swift */; }; C63F724E285A24B10066163B /* PausedCallOrConferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71E9285A24B10066163B /* PausedCallOrConferenceView.swift */; }; C63F724F285A24B10066163B /* LocalVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71EA285A24B10066163B /* LocalVideoView.swift */; }; C63F7250285A24B10066163B /* CallStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71EB285A24B10066163B /* CallStatsView.swift */; }; @@ -742,7 +742,6 @@ C63F7258285A24B10066163B /* ControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71F4285A24B10066163B /* ControlsView.swift */; }; C63F7259285A24B10066163B /* RemotelyRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71F5285A24B10066163B /* RemotelyRecording.swift */; }; C63F725A285A24B10066163B /* OutgoingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71F7285A24B10066163B /* OutgoingCallView.swift */; }; - C63F725B285A24B10066163B /* ActiveCallOrConferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71F8285A24B10066163B /* ActiveCallOrConferenceView.swift */; }; C63F725C285A24B10066163B /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71F9285A24B10066163B /* IncomingCallView.swift */; }; C63F725D285A24B10066163B /* SharedLayoutConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71FA285A24B10066163B /* SharedLayoutConstants.swift */; }; C63F725E285A24B10066163B /* VoipDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C63F71FB285A24B10066163B /* VoipDialog.swift */; }; @@ -838,6 +837,9 @@ C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */; }; C64A85502667B67A00252AD2 /* EphemeralSettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */; }; C64A85522667B74100252AD2 /* ephemeral_messages_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C64A85512667B74100252AD2 /* ephemeral_messages_default.png */; }; + C6548820292D32FA00BF646B /* SingleCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C654881E292D32FA00BF646B /* SingleCallView.swift */; }; + C6548821292D32FA00BF646B /* ConferenceCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C654881F292D32FA00BF646B /* ConferenceCallView.swift */; }; + C6548823292D369500BF646B /* AbstractCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6548822292D369500BF646B /* AbstractCallView.swift */; }; C66B03BB26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C66B03BD26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib */; }; C66B040A26EFDA55009B5EDC /* reply_cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = C66B040926EFDA54009B5EDC /* reply_cancel.png */; }; C66B040E26F095D1009B5EDC /* cancel_forward.png in Resources */ = {isa = PBXBuildFile; fileRef = C66B040D26F095CE009B5EDC /* cancel_forward.png */; }; @@ -1900,7 +1902,7 @@ C63F71E4285A24B10066163B /* VoipConferenceActiveSpeakerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipConferenceActiveSpeakerView.swift; sourceTree = ""; }; C63F71E5285A24B10066163B /* VoipConferenceDisplayModeSelectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipConferenceDisplayModeSelectionView.swift; sourceTree = ""; }; C63F71E7285A24B10066163B /* ActiveCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveCallView.swift; sourceTree = ""; }; - C63F71E8285A24B10066163B /* IncomingOuntgoingCommonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncomingOuntgoingCommonView.swift; sourceTree = ""; }; + C63F71E8285A24B10066163B /* AbstractIncomingOutgoingCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractIncomingOutgoingCallView.swift; sourceTree = ""; }; C63F71E9285A24B10066163B /* PausedCallOrConferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PausedCallOrConferenceView.swift; sourceTree = ""; }; C63F71EA285A24B10066163B /* LocalVideoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalVideoView.swift; sourceTree = ""; }; C63F71EB285A24B10066163B /* CallStatsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallStatsView.swift; sourceTree = ""; }; @@ -1914,7 +1916,6 @@ C63F71F4285A24B10066163B /* ControlsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlsView.swift; sourceTree = ""; }; C63F71F5285A24B10066163B /* RemotelyRecording.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemotelyRecording.swift; sourceTree = ""; }; C63F71F7285A24B10066163B /* OutgoingCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingCallView.swift; sourceTree = ""; }; - C63F71F8285A24B10066163B /* ActiveCallOrConferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActiveCallOrConferenceView.swift; sourceTree = ""; }; C63F71F9285A24B10066163B /* IncomingCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncomingCallView.swift; sourceTree = ""; }; C63F71FA285A24B10066163B /* SharedLayoutConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedLayoutConstants.swift; sourceTree = ""; }; C63F71FB285A24B10066163B /* VoipDialog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoipDialog.swift; sourceTree = ""; }; @@ -2009,6 +2010,9 @@ C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EphemeralSettingsView.m; sourceTree = ""; }; C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EphemeralSettingsView.xib; sourceTree = ""; }; C64A85512667B74100252AD2 /* ephemeral_messages_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ephemeral_messages_default.png; sourceTree = ""; }; + C654881E292D32FA00BF646B /* SingleCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleCallView.swift; sourceTree = ""; }; + C654881F292D32FA00BF646B /* ConferenceCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConferenceCallView.swift; sourceTree = ""; }; + C6548822292D369500BF646B /* AbstractCallView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractCallView.swift; sourceTree = ""; }; C66B03BC26E8EB1A009B5EDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatReplyBubbleView.xib; sourceTree = ""; }; C66B03C126E8EB82009B5EDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/UIChatReplyBubbleView.strings; sourceTree = ""; }; C66B03C326E8EB87009B5EDC /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UIChatReplyBubbleView.strings; sourceTree = ""; }; @@ -3530,7 +3534,6 @@ C63F71DC285A24B10066163B /* AudioRoutesView.swift */, C63F71DD285A24B10066163B /* Conference */, C63F71E6285A24B10066163B /* ActiveCall */, - C63F71E8285A24B10066163B /* IncomingOuntgoingCommonView.swift */, C63F71E9285A24B10066163B /* PausedCallOrConferenceView.swift */, C63F71EA285A24B10066163B /* LocalVideoView.swift */, C63F71EB285A24B10066163B /* CallStatsView.swift */, @@ -3590,8 +3593,11 @@ C63F71F6285A24B10066163B /* CompositeViewControllers */ = { isa = PBXGroup; children = ( + C63F71E8285A24B10066163B /* AbstractIncomingOutgoingCallView.swift */, + C6548822292D369500BF646B /* AbstractCallView.swift */, + C654881F292D32FA00BF646B /* ConferenceCallView.swift */, + C654881E292D32FA00BF646B /* SingleCallView.swift */, C63F71F7285A24B10066163B /* OutgoingCallView.swift */, - C63F71F8285A24B10066163B /* ActiveCallOrConferenceView.swift */, C63F71F9285A24B10066163B /* IncomingCallView.swift */, ); path = CompositeViewControllers; @@ -4932,8 +4938,8 @@ 63B8D6A21BCBF43100C12B09 /* UIChatCreateCell.m in Sources */, 636BC9971B5F921B00C754CE /* UIIconButton.m in Sources */, C63F7263285A24B10066163B /* FormButton.swift in Sources */, - C63F725B285A24B10066163B /* ActiveCallOrConferenceView.swift in Sources */, C63F7215285A24B10066163B /* ConferenceWaitingRoomFragment.swift in Sources */, + C6548820292D32FA00BF646B /* SingleCallView.swift in Sources */, 63423C0A1C4501D000D9A050 /* Contact.m in Sources */, C63F7262285A24B10066163B /* RotatingSpinner.swift in Sources */, 340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */, @@ -4994,6 +5000,7 @@ 63B81A0D1B57DA33009604A6 /* TPKeyboardAvoidingCollectionView.m in Sources */, C63F726D285A24B10066163B /* ProviderDelegate.swift in Sources */, C63F7266285A24B10066163B /* UICallTimer.swift in Sources */, + C6548821292D32FA00BF646B /* ConferenceCallView.swift in Sources */, C63F726C285A24B10066163B /* StyledTextView.swift in Sources */, 570742611D5A09B8004B9C84 /* ShopView.m in Sources */, D37DC6C11594AE1800B2A5EB /* LinphoneCoreSettingsStore.m in Sources */, @@ -5053,6 +5060,7 @@ C63F721F285A24B10066163B /* BackNextNavigationView.swift in Sources */, D3807FC315C28940005BE9BC /* DCRoundSwitchOutlineLayer.m in Sources */, C63F723D285A24B10066163B /* TextStyle.swift in Sources */, + C6548823292D369500BF646B /* AbstractCallView.swift in Sources */, C63F7229285A24B10066163B /* UIButtonExtensions.swift in Sources */, C63F722B285A24B10066163B /* UIDeviceExtensions.swift in Sources */, C63F724B285A24B10066163B /* VoipConferenceDisplayModeSelectionView.swift in Sources */, @@ -5105,7 +5113,7 @@ 637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */, D378AB2A15DCDB4A0098505D /* ImagePickerView.m in Sources */, 22405F001601C19200B92522 /* ImageView.m in Sources */, - C63F724D285A24B10066163B /* IncomingOuntgoingCommonView.swift in Sources */, + C63F724D285A24B10066163B /* AbstractIncomingOutgoingCallView.swift in Sources */, D37EE162160377D7003608A6 /* DTActionSheet.m in Sources */, D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */, C63F7246285A24B10066163B /* VoipGridParticipantCell.swift in Sources */,