mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Bulk video conference adjustements
This commit is contained in:
parent
69a885df4f
commit
a2112ba9f0
21 changed files with 107 additions and 49 deletions
|
|
@ -1344,7 +1344,7 @@ void on_chat_room_chat_message_received(LinphoneChatRoom *cr, const LinphoneEven
|
|||
if ((linphone_core_get_max_size_for_auto_download_incoming_files(LC) > -1) && linphone_chat_message_get_file_transfer_information(chat))
|
||||
hasFile = TRUE;
|
||||
|
||||
if (!linphone_chat_message_is_file_transfer(chat) && !linphone_chat_message_is_text(chat) && !hasFile) /*probably an imdn*/
|
||||
if (!linphone_chat_message_is_file_transfer(chat) && !linphone_chat_message_is_text(chat) && !hasFile && ![ICSBubbleView isConferenceInvitationMessageWithCmessage:chat]) /*probably an imdn*/
|
||||
return;
|
||||
|
||||
const LinphoneAddress *from = linphone_chat_message_get_from_address(chat);
|
||||
|
|
|
|||
|
|
@ -862,7 +862,7 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, LinphoneAut
|
|||
if ((linphone_core_get_max_size_for_auto_download_incoming_files(LC) > -1) && linphone_chat_message_get_file_transfer_information(msg))
|
||||
hasFile = TRUE;
|
||||
|
||||
if (!linphone_chat_message_is_file_transfer(msg) && !linphone_chat_message_is_text(msg) && !hasFile)
|
||||
if (!linphone_chat_message_is_file_transfer(msg) && !linphone_chat_message_is_text(msg) && !hasFile && ![ICSBubbleView isConferenceInvitationMessageWithCmessage:msg])
|
||||
return;
|
||||
|
||||
if (hasFile) {
|
||||
|
|
|
|||
|
|
@ -54,10 +54,6 @@ INIT_WITH_COMMON_CF {
|
|||
if (newCamId) {
|
||||
LOGI(@"Switching from [%s] to [%s]", currentCamId, newCamId);
|
||||
linphone_core_set_video_device(LC, newCamId);
|
||||
LinphoneCall *call = linphone_core_get_current_call(LC);
|
||||
if (call != NULL) {
|
||||
linphone_core_update_call(LC, call, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import linphonesw
|
|||
|
||||
class ConferenceSchedulingViewModel {
|
||||
|
||||
let core = Core.get()
|
||||
var core : Core { get { Core.get() } }
|
||||
static let shared = ConferenceSchedulingViewModel()
|
||||
|
||||
let subject = MutableLiveData<String>()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import linphonesw
|
|||
|
||||
class ScheduledConferencesViewModel {
|
||||
|
||||
let core = Core.get()
|
||||
var core : Core { get { Core.get() } }
|
||||
static let shared = ScheduledConferencesViewModel()
|
||||
|
||||
var conferences : MutableLiveData<[ScheduledConferenceData]> = MutableLiveData([])
|
||||
|
|
|
|||
|
|
@ -46,11 +46,10 @@ import linphonesw
|
|||
contentView.addSubview(subjectLabel)
|
||||
subjectLabel.alignParentLeft(withMargin: form_margin).alignParentTop().done()
|
||||
|
||||
let subjectInput = StyledTextView(VoipTheme.conference_scheduling_font, placeHolder:VoipTexts.conference_schedule_subject_hint, liveValue: viewModel.subject)
|
||||
let subjectInput = StyledTextView(VoipTheme.conference_scheduling_font, placeHolder:VoipTexts.conference_schedule_subject_hint, liveValue: viewModel.subject,maxLines:1)
|
||||
contentView.addSubview(subjectInput)
|
||||
subjectInput.alignUnder(view: subjectLabel,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).height(form_input_height).done()
|
||||
|
||||
|
||||
let schedulingStack = UIStackView()
|
||||
schedulingStack.axis = .vertical
|
||||
schedulingStack.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ import linphonesw
|
|||
// localVideo view
|
||||
localVideo.layer.cornerRadius = center_view_corner_radius
|
||||
localVideo.clipsToBounds = true
|
||||
localVideo.contentMode = .scaleAspectFit
|
||||
localVideo.backgroundColor = .black
|
||||
self.view.addSubview(localVideo)
|
||||
localVideo.matchParentSideBorders(insetedByDx: content_inset).alignAbove(view:buttonsView,withMargin:SharedLayoutConstants.buttons_bottom_margin).alignUnder(view: subject,withMargin: common_margin).done()
|
||||
|
|
|
|||
35
Classes/Swift/Extensions/IOS/UITextViewExtensions.swift
Normal file
35
Classes/Swift/Extensions/IOS/UITextViewExtensions.swift
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linhome
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AVFoundation
|
||||
|
||||
extension UITextView {
|
||||
var numberOfCurrentlyDisplayedLines: Int {
|
||||
return text.components(separatedBy: "\n").count
|
||||
}
|
||||
func removeTextUntilSatisfying(maxNumberOfLines: Int) {
|
||||
while numberOfCurrentlyDisplayedLines > (maxNumberOfLines) {
|
||||
text = String(text.dropLast())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,10 +42,6 @@ extension Core {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
let inConference = conference != nil && conference!.isIn
|
||||
if !inConference, let call = currentCall {
|
||||
try?call.update(params: nil)
|
||||
}*/
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import linphonesw
|
|||
|
||||
@objc class AudioRouteUtils : NSObject {
|
||||
|
||||
static let core = Core.get()
|
||||
|
||||
static var core : Core { get { Core.get() } }
|
||||
|
||||
static private func applyAudioRouteChange( call: Call?, types: [AudioDeviceType], output: Bool = true) {
|
||||
let typesNames = types.map { String(describing: $0) }.joined(separator: "/")
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ class CallsViewModel {
|
|||
let callConnectedEvent = MutableLiveData<Call>()
|
||||
let callUpdateEvent = MutableLiveData<Call>()
|
||||
let noMoreCallEvent = MutableLiveData(false)
|
||||
let core = Core.get()
|
||||
|
||||
var core : Core { get { Core.get() } }
|
||||
|
||||
static let shared = CallsViewModel()
|
||||
|
||||
private var coreDelegate : CoreDelegateStub?
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ConferenceParticipantDeviceData {
|
|||
let videoEnabled = MutableLiveData<Bool>()
|
||||
let activeSpeaker = MutableLiveData<Bool>()
|
||||
let isInConference = MutableLiveData<Bool>()
|
||||
let core = Core.get()
|
||||
var core : Core { get { Core.get() } }
|
||||
|
||||
private var participantDeviceDelegate : ParticipantDeviceDelegate?
|
||||
|
||||
|
|
@ -45,28 +45,43 @@ class ConferenceParticipantDeviceData {
|
|||
}, onConferenceLeft: { (participantDevice) in
|
||||
Log.i("[Conference Participant Device] Participant \(participantDevice) has left the conference")
|
||||
self.isInConference.value = false
|
||||
}, onAudioDirectionChanged: { (participantDevice, direction) in
|
||||
Log.i("[Conference Participant Device] Participant \(participantDevice) audio stream direction changed: \(direction)")
|
||||
}, onVideoDirectionChanged: { (participantDevice, direction) in
|
||||
}, onStreamCapabilityChanged: { (participantDevice, direction, streamType) in
|
||||
Log.i("[Conference Participant Device] Participant \(participantDevice) video stream direction changed: \(direction)")
|
||||
self.videoEnabled.value = direction == MediaDirection.SendOnly || direction == MediaDirection.SendRecv
|
||||
}, onTextDirectionChanged: { (participantDevice, direction) in
|
||||
Log.i("[Conference Participant Device] Participant \(participantDevice) text stream direction changed: \(direction)")
|
||||
})
|
||||
if (streamType == StreamType.Video) {
|
||||
Log.i("[Conference Participant Device] Participant [\(participantDevice.address?.asStringUriOnly())] video capability changed to \(direction)")
|
||||
}
|
||||
}, onStreamAvailabilityChanged: { (participantDevice, available, streamType) in
|
||||
if (streamType == StreamType.Video) {
|
||||
Log.i("[Conference Participant Device] Participant [\(participantDevice.address?.asStringUriOnly())] video availability changed to \(available)")
|
||||
self.videoEnabled.value = available
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
participantDevice.addDelegate(delegate: participantDeviceDelegate!)
|
||||
activeSpeaker.value = false
|
||||
|
||||
// TODO: What happens if we have disabled video locally?
|
||||
videoEnabled.value = participantDevice.videoDirection == MediaDirection.SendOnly || participantDevice.videoDirection == MediaDirection.SendRecv
|
||||
isInConference.value = participantDevice.isInConference
|
||||
|
||||
videoEnabled.value = participantDevice.getStreamAvailability(streamType: .Video)
|
||||
|
||||
isInConference.value = participantDevice.isInConference
|
||||
let videoCapability = participantDevice.getStreamCapability(streamType: .Video)
|
||||
Log.i("[Conference Participant Device] Participant [\(participantDevice.address?.asStringUriOnly())], is in conf? \(isInConference.value), is video enabled? \(videoEnabled.value) \(videoCapability)")
|
||||
}
|
||||
|
||||
func destroy() {
|
||||
clearObservers()
|
||||
participantDevice.removeDelegate(delegate: participantDeviceDelegate!)
|
||||
}
|
||||
|
||||
func clearObservers() {
|
||||
isInConference.clearObservers()
|
||||
videoEnabled.clearObservers()
|
||||
activeSpeaker.clearObservers()
|
||||
}
|
||||
|
||||
func switchCamera() {
|
||||
Core.get().toggleCamera()
|
||||
}
|
||||
|
|
@ -76,12 +91,10 @@ class ConferenceParticipantDeviceData {
|
|||
}
|
||||
|
||||
func setVideoView(view:UIView) {
|
||||
if (!isMe && participantDevice.videoDirection != MediaDirection.SendRecv) {
|
||||
Log.e("[Conference Participant Device] Participant \(participantDevice) device video direction is \(participantDevice.videoDirection), don't set video window!")
|
||||
return
|
||||
}
|
||||
Log.i("[Conference Participant Device] Setting textureView \(view) for participant \(participantDevice)")
|
||||
if (isMe) { // TODO: remove
|
||||
if (isMe) {
|
||||
core.usePreviewWindow(yesno: false)
|
||||
view.contentMode = .scaleAspectFit
|
||||
core.nativePreviewWindow = view
|
||||
} else {
|
||||
participantDevice.nativeVideoWindowId = UnsafeMutableRawPointer(Unmanaged.passRetained(view).toOpaque())
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import AVFoundation
|
|||
|
||||
class ConferenceViewModel {
|
||||
|
||||
let core = Core.get()
|
||||
var core : Core { get { Core.get() } }
|
||||
static let shared = ConferenceViewModel()
|
||||
|
||||
let conferenceExists = MutableLiveData<Bool>()
|
||||
|
|
@ -81,7 +81,7 @@ class ConferenceViewModel {
|
|||
coreDelegate = CoreDelegateStub(
|
||||
onConferenceStateChanged: { (core, conference, state) in
|
||||
Log.i("[Conference] \(conference) Conference state changed: \(state)")
|
||||
self.isVideoConference.value = conference.currentParams?.isVideoEnabled == true
|
||||
self.isVideoConference.value = conference.currentParams?.videoEnabled == true
|
||||
|
||||
if (state == Conference.State.Instantiated) {
|
||||
self.initConference(conference)
|
||||
|
|
@ -135,7 +135,7 @@ class ConferenceViewModel {
|
|||
|
||||
isConferenceLocallyPaused.value = !conference.isIn
|
||||
self.isMeAdmin.value = conference.me?.isAdmin == true
|
||||
isVideoConference.value = conference.currentParams?.isVideoEnabled == true
|
||||
isVideoConference.value = conference.currentParams?.videoEnabled == true
|
||||
|
||||
self.subject.value = conference.subject.isEmpty ? (
|
||||
conference.me?.isFocus == true ? (
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import AVFoundation
|
|||
|
||||
|
||||
class ControlsViewModel {
|
||||
let core = Core.get()
|
||||
|
||||
var core : Core { get { Core.get() } }
|
||||
|
||||
let isSpeakerSelected = MutableLiveData<Bool>()
|
||||
let isMicrophoneMuted = MutableLiveData<Bool>()
|
||||
let isMuteMicrophoneEnabled = MutableLiveData<Bool>()
|
||||
|
|
@ -138,7 +138,7 @@ class ControlsViewModel {
|
|||
func toggleVideo() {
|
||||
if let conference = core.conference, conference.isIn {
|
||||
if let params = try?core.createConferenceParams() {
|
||||
let videoEnabled = conference.currentParams?.isVideoEnabled == true
|
||||
let videoEnabled = conference.currentParams?.videoEnabled == true
|
||||
params.videoEnabled = !videoEnabled
|
||||
_ = conference.updateParams(params: params)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,5 +89,13 @@ extension UITextView {
|
|||
let fontSizeMultiplier: Float = (UIDevice.ipad() ? 1.25 : UIDevice.is5SorSEGen1() ? 0.9 : 1.0)
|
||||
font = UIFont.init(name: style.font, size: CGFloat(style.size*fontSizeMultiplier))
|
||||
}
|
||||
var numberOfCurrentlyDisplayedLines: Int {
|
||||
return text.components(separatedBy: "\n").count
|
||||
}
|
||||
func removeTextUntilSatisfying(maxNumberOfLines: Int) {
|
||||
while numberOfCurrentlyDisplayedLines > (maxNumberOfLines) {
|
||||
text = String(text.dropLast())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ class VoipGridParticipantCell: UICollectionViewCell {
|
|||
}
|
||||
self.switchCamera.isHidden = videoEnabled != true || !data.isSwitchCameraAvailable()
|
||||
}
|
||||
if (data.participantDevice.address == nil) {
|
||||
avatar.isHidden = true
|
||||
}
|
||||
self.displayName.text = ""
|
||||
data.participantDevice.address.map {
|
||||
avatar.fillFromAddress(address: $0)
|
||||
if let displayName = $0.addressBookEnhancedDisplayName() {
|
||||
|
|
|
|||
|
|
@ -24,15 +24,19 @@ class StyledTextView: UITextView, UITextViewDelegate {
|
|||
var placeholder:String?
|
||||
var style:TextStyle?
|
||||
var liveValue: MutableLiveData<String>? = nil
|
||||
var maxLines:Int
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
maxLines = 0
|
||||
super.init(coder: coder)
|
||||
}
|
||||
|
||||
init (_ style:TextStyle, placeHolder:String? = nil, liveValue: MutableLiveData<String>, readOnly:Bool = false) {
|
||||
init (_ style:TextStyle, placeHolder:String? = nil, liveValue: MutableLiveData<String>, readOnly:Bool = false, maxLines:Int = 999) {
|
||||
self.maxLines = maxLines
|
||||
self.style = style
|
||||
self.liveValue = liveValue
|
||||
super.init(frame:.zero, textContainer: nil)
|
||||
textContainer.maximumNumberOfLines = maxLines
|
||||
applyStyle(style)
|
||||
setFormInputBackground(readOnly:readOnly)
|
||||
placeHolder.map {
|
||||
|
|
@ -43,6 +47,7 @@ class StyledTextView: UITextView, UITextViewDelegate {
|
|||
self.text = value
|
||||
if (value == nil || value?.count == 0) {
|
||||
self.showPlaceHolder()
|
||||
self.resignFirstResponder()
|
||||
}
|
||||
}
|
||||
if (readOnly) {
|
||||
|
|
@ -71,6 +76,7 @@ class StyledTextView: UITextView, UITextViewDelegate {
|
|||
}
|
||||
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
textView.removeTextUntilSatisfying(maxNumberOfLines: self.maxLines)
|
||||
liveValue?.value = textView.text
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ class StyledValuePicker: UIView {
|
|||
|
||||
formattedLabel.isUserInteractionEnabled = false
|
||||
formattedLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get()
|
||||
formattedLabel.text = " "+options[liveIndex.value!]
|
||||
|
||||
liveIndex.value.map { formattedLabel.text = " "+options[$0] }
|
||||
|
||||
if (readOnly) {
|
||||
formattedLabel.textColor = formattedLabel.textColor.withAlphaComponent(0.5)
|
||||
}
|
||||
|
|
|
|||
2
Podfile
2
Podfile
|
|
@ -5,7 +5,7 @@ source "https://github.com/CocoaPods/Specs.git"
|
|||
|
||||
def all_pods
|
||||
if ENV['PODFILE_PATH'].nil?
|
||||
pod 'linphone-sdk', '~> 5.1.0-alpha.75+d4a0bd2'
|
||||
pod 'linphone-sdk', '~> 5.2.0-alpha.125+0f20296'
|
||||
else
|
||||
pod 'linphone-sdk', :path => ENV['PODFILE_PATH'] # local sdk
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5642,7 +5642,7 @@
|
|||
"-DENABLE_QRCODE=TRUE",
|
||||
"-DENABLE_SMS_INVITE=TRUE",
|
||||
"$(inherited)",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.94+f4cb5df\\\"",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.125+0f20296\\\"",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
|
||||
|
|
@ -5769,7 +5769,7 @@
|
|||
"-DENABLE_QRCODE=TRUE",
|
||||
"-DENABLE_SMS_INVITE=TRUE",
|
||||
"$(inherited)",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.94+f4cb5df\\\"",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.125+0f20296\\\"",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
|
||||
|
|
@ -5895,7 +5895,7 @@
|
|||
"-DENABLE_QRCODE=TRUE",
|
||||
"-DENABLE_SMS_INVITE=TRUE",
|
||||
"$(inherited)",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.94+f4cb5df\\\"",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.125+0f20296\\\"",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
|
||||
|
|
@ -6020,7 +6020,7 @@
|
|||
"-DENABLE_QRCODE=TRUE",
|
||||
"-DENABLE_SMS_INVITE=TRUE",
|
||||
"$(inherited)",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.94+f4cb5df\\\"",
|
||||
"-DLINPHONE_SDK_VERSION=\\\"5.2.0-alpha.125+0f20296\\\"",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||
}
|
||||
|
||||
func parseMessage(message: PushNotificationMessage) -> MsgData? {
|
||||
let content = message.isText ? message.textContent : "🗻"
|
||||
let content = message.isIcalendar ? NSLocalizedString("You are invited to a conference", comment: "") : message.isText ? message.textContent : "🗻"
|
||||
let fromAddr = message.fromAddr?.username
|
||||
let callId = message.callId
|
||||
let localUri = message.localAddr?.asStringUriOnly()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue