element-ios/Riot/Modules/Call/PiP/CallPiPView.swift

181 lines
7.4 KiB
Swift

//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import UIKit
import Reusable
@objcMembers
class CallPiPView: UIView {
private enum Constants {
static let viewWidth: CGFloat = 90
static let smallDotWidth: CGFloat = 8
static let bigDotWidth: CGFloat = 10
static let spaceBetweenDots: CGFloat = 4
static let placeholderFontScale: CGFloat = 0.7
}
@IBOutlet private weak var bgView: UIView!
@IBOutlet private weak var bgImageView: MXKImageView!
@IBOutlet private weak var stackView: UIStackView!
@IBOutlet private weak var mainCallAvatarImageView: MXKImageView! {
didSet {
mainCallAvatarImageView.clipsToBounds = true
mainCallAvatarImageView.layer.cornerRadius = mainCallAvatarImageView.bounds.width/2
}
}
@IBOutlet private weak var mainCallPauseIcon: UIImageView!
@IBOutlet private weak var onHoldCallView: UIView!
@IBOutlet private weak var onHoldCallAvatarImageView: MXKImageView! {
didSet {
onHoldCallAvatarImageView.clipsToBounds = true
onHoldCallAvatarImageView.layer.cornerRadius = onHoldCallAvatarImageView.bounds.width/2
}
}
@IBOutlet private weak var onHoldCallEffectView: UIVisualEffectView! {
didSet {
onHoldCallEffectView.clipsToBounds = true
onHoldCallEffectView.layer.cornerRadius = onHoldCallEffectView.bounds.width/2
}
}
@IBOutlet private weak var connectingView: DotsView! {
didSet {
connectingView.dotMinWidth = self.bounds.width * Constants.smallDotWidth/Constants.viewWidth
connectingView.dotMaxWidth = self.bounds.width * Constants.bigDotWidth/Constants.viewWidth
connectingView.interSpaceMargin = self.bounds.width * Constants.spaceBetweenDots/Constants.viewWidth
}
}
private var theme: Theme = ThemeService.shared().theme
private var session: MXSession!
static func instantiate(withSession session: MXSession) -> CallPiPView {
let view = self.loadFromNib()
view.session = session
return view
}
func configure(withCall mainCall: MXCall,
peer: MXUser?,
onHoldCall: MXCall?,
onHoldPeer: MXUser?) {
switch mainCall.state {
case .fledgling, .waitLocalMedia, .createOffer, .inviteSent, .ringing, .createAnswer, .connecting:
stackView.isHidden = true
connectingView.isHidden = false
mainCallPauseIcon.isHidden = true
default:
connectingView.isHidden = true
if mainCall.isVideoCall {
bgView.isHidden = true
stackView.isHidden = true
} else {
bgView.isHidden = false
stackView.isHidden = false
}
mainCallPauseIcon.isHidden = !mainCall.isOnHold
onHoldCallView.isHidden = onHoldCall == nil
}
let bgPlaceholder = placeholderImage(forPeer: peer,
call: mainCall,
imageView: bgImageView)
let mainCallPlaceholder = placeholderImage(forPeer: peer,
call: mainCall,
imageView: mainCallAvatarImageView)
bgImageView.contentMode = .scaleAspectFill
mainCallAvatarImageView.contentMode = .scaleAspectFill
onHoldCallAvatarImageView.contentMode = .scaleAspectFill
if let avatarUrl = peer?.avatarUrl {
bgImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
bgImageView.enableInMemoryCache = true
bgImageView.setImageURI(avatarUrl,
withType: nil,
andImageOrientation: .up,
previewImage: bgPlaceholder,
mediaManager: session.mediaManager)
mainCallAvatarImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
mainCallAvatarImageView.enableInMemoryCache = true
mainCallAvatarImageView.setImageURI(avatarUrl,
withType: nil,
andImageOrientation: .up,
previewImage: mainCallPlaceholder,
mediaManager: session.mediaManager)
} else {
bgImageView.image = bgPlaceholder
mainCallAvatarImageView.image = mainCallPlaceholder
}
let onHoldCallPlaceholder = placeholderImage(forPeer: onHoldPeer,
call: onHoldCall,
imageView: onHoldCallAvatarImageView)
if let avatarUrl = onHoldPeer?.avatarUrl {
onHoldCallAvatarImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
onHoldCallAvatarImageView.enableInMemoryCache = true
onHoldCallAvatarImageView.setImageURI(avatarUrl,
withType: nil,
andImageOrientation: .up,
previewImage: onHoldCallPlaceholder,
mediaManager: session.mediaManager)
} else {
onHoldCallAvatarImageView.image = onHoldCallPlaceholder
}
}
private func placeholderImage(forPeer peer: MXUser?,
call: MXCall?,
imageView: MXKImageView) -> UIImage? {
let fontSize = imageView.bounds.width * Constants.placeholderFontScale
if let peer = peer {
return AvatarGenerator.generateAvatar(forMatrixItem: peer.userId,
withDisplayName: peer.displayname,
size: imageView.bounds.width,
andFontSize: fontSize)
} else if let room = call?.room {
return AvatarGenerator.generateAvatar(forMatrixItem: room.roomId,
withDisplayName: room.summary.displayName,
size: imageView.bounds.width,
andFontSize: fontSize)
}
return MXKTools.paint(Asset.Images.placeholder.image,
with: theme.tintColor)
}
}
extension CallPiPView: NibReusable {}
extension CallPiPView: Themable {
func update(theme: Theme) {
self.theme = theme
}
}