Bulk video conference adjustements

This commit is contained in:
Christophe Deschamps 2022-02-01 10:10:33 +01:00
parent 69a885df4f
commit a2112ba9f0
21 changed files with 107 additions and 49 deletions

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}
}
}

View file

@ -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>()

View file

@ -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([])

View file

@ -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()

View file

@ -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()

View 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())
}
}
}

View file

@ -42,10 +42,6 @@ extension Core {
return
}
}
let inConference = conference != nil && conference!.isIn
if !inConference, let call = currentCall {
try?call.update(params: nil)
}*/
*/
}
}

View file

@ -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: "/")

View file

@ -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?

View file

@ -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())

View file

@ -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 ? (

View file

@ -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)
}

View file

@ -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())
}
}
}

View file

@ -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() {

View file

@ -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
}

View file

@ -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)
}

View file

@ -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

View file

@ -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;

View file

@ -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()