Files

341 lines
9.4 KiB
Swift

//
// File 2.swift
//
//
// Created by Mikhail Filimonov on 08.02.2024.
//
import Foundation
import TelegramCore
import Localization
import Postbox
import QuartzCore
import CoreFoundation
public extension PeerCallSessionTerminationReason {
var recall: Bool {
let recall:Bool
switch self {
case .ended(let reason):
switch reason {
case .busy:
recall = true
default:
recall = false
}
case .error(let reason):
switch reason {
case .disconnected:
recall = true
default:
recall = false
}
}
return recall
}
}
private extension EnginePeer {
var compactDisplayTitle: String {
switch self {
case let .user(user):
if let firstName = user.firstName, !firstName.isEmpty {
return firstName
} else if let lastName = user.lastName, !lastName.isEmpty {
return lastName
} else if let _ = user.phone {
return ""
} else {
return "Deleted Account"
}
case let .legacyGroup(group):
return group.title
case let .channel(channel):
return channel.title
case .secretChat:
return ""
}
}
}
public enum PeerCallSessionError: Equatable {
case generic
case privacyRestricted
case notSupportedByPeer(isVideo: Bool)
case serverProvided(text: String)
case disconnected
}
public enum PeerCallSessionEndedType : Equatable {
case hungUp
case busy
case missed
}
public enum PeerCallSessionTerminationReason: Equatable {
case ended(PeerCallSessionEndedType)
case error(PeerCallSessionError)
}
enum PeerCallStatusValue: Equatable {
case text(String, Int32?)
case timer(Double, Int32?)
var hasTimer: Bool {
switch self {
case .timer:
return true
default:
return false
}
}
}
public struct ExternalPeerCallState: Equatable {
public enum State: Equatable {
case waiting
case ringing
case requesting(ringing: Bool)
case connecting
case active(startTime: Double, reception: Int32?, emoji: String)
case reconnecting(startTime: Double, reception: Int32?, emoji: String)
case terminating
case terminated(PeerCallSessionTerminationReason?)
}
public enum VideoState: Equatable {
case notAvailable
case inactive(Bool)
case active(Bool)
case paused(Bool)
}
public enum RemoteAudioState: Equatable {
case active
case muted
}
public enum RemoteBatteryLevel: Equatable {
case normal
case low
}
public enum RemoteVideoState: Equatable {
case inactive
case active
case paused
}
public var state: State
public var videoState: VideoState
public var remoteVideoState: RemoteVideoState
public var isMuted: Bool
public var isOutgoingVideoPaused: Bool
public var remoteAspectRatio: Float
public var remoteAudioState: RemoteAudioState
public var remoteBatteryLevel: RemoteBatteryLevel
public var isScreenCapture: Bool
public var canBeRemoved: Bool
public init(state: State, videoState: VideoState, remoteVideoState: RemoteVideoState, isMuted: Bool, isOutgoingVideoPaused: Bool, remoteAspectRatio: Float, remoteAudioState: RemoteAudioState, remoteBatteryLevel: RemoteBatteryLevel, isScreenCapture: Bool, canBeRemoved: Bool) {
self.state = state
self.videoState = videoState
self.remoteVideoState = remoteVideoState
self.isMuted = isMuted
self.isOutgoingVideoPaused = isOutgoingVideoPaused
self.remoteAspectRatio = remoteAspectRatio
self.remoteAudioState = remoteAudioState
self.remoteBatteryLevel = remoteBatteryLevel
self.isScreenCapture = isScreenCapture
self.canBeRemoved = canBeRemoved
}
}
extension ExternalPeerCallState.State {
func statusText(_ accountPeer: EnginePeer?, _ videoState: ExternalPeerCallState.VideoState) -> PeerCallStatusValue {
let statusValue: PeerCallStatusValue
switch self {
case .waiting, .connecting:
statusValue = .text(L10n.callStatusConnecting, nil)
case let .requesting(ringing):
if ringing {
statusValue = .text(L10n.callStatusRinging, nil)
} else {
statusValue = .text(L10n.callStatusRequesting, nil)
}
case .terminating:
statusValue = .text(L10n.callStatusEnded, nil)
case let .terminated(reason):
if let reason = reason {
switch reason {
case let .ended(type):
switch type {
case .busy:
statusValue = .text(L10n.callStatusBusy, nil)
case .hungUp, .missed:
statusValue = .text(L10n.callStatusEnded, nil)
}
case .error:
statusValue = .text(L10n.callStatusFailed, nil)
}
} else {
statusValue = .text(L10n.callStatusEnded, nil)
}
case .ringing:
if let accountPeer = accountPeer {
statusValue = .text(L10n.callStatusCallingAccount(accountPeer.addressName ?? accountPeer.compactDisplayTitle), nil)
} else {
statusValue = .text(L10n.callStatusCalling, nil)
}
case .active(let timestamp, let reception, _), .reconnecting(let timestamp, let reception, _):
if case .reconnecting = self {
statusValue = .text(L10n.callStatusConnecting, reception)
} else {
statusValue = .timer(timestamp, reception)
}
}
return statusValue
}
}
enum SmallVideoSource : Equatable {
case incoming
case outgoing
}
public struct PeerCallState : Equatable {
public enum SecretKeyViewState : Equatable {
case revealed
case concealed
var rev: SecretKeyViewState {
switch self {
case .concealed:
return .revealed
case .revealed:
return .concealed
}
}
}
public var peer: EnginePeer?
public var accountPeer: EnginePeer?
public var secretKeyViewState: SecretKeyViewState = .concealed
var actions: [PeerCallAction] = []
var smallVideo: SmallVideoSource = .outgoing
var statusTooltip: String? = nil
var mouseInside: Bool = true
public var externalState: ExternalPeerCallState = .init(state: .connecting, videoState: .notAvailable, remoteVideoState: .inactive, isMuted: false, isOutgoingVideoPaused: true, remoteAspectRatio: 1.0, remoteAudioState: .active, remoteBatteryLevel: .low, isScreenCapture: false, canBeRemoved: false)
var status: PeerCallStatusValue {
if self.externalState.canBeRemoved {
return .text(L10n.callStatusEnded, nil)
}
return self.externalState.state.statusText(accountPeer, externalState.videoState)
}
var isActive: Bool {
if externalState.canBeRemoved {
return false
}
switch externalState.state {
case .active, .reconnecting, .connecting, .requesting:
return true
default:
return false
}
}
var title: String? {
if let peer = peer?._asPeer() as? TelegramUser {
return [peer.firstName, peer.lastName].compactMap { $0 }.joined(separator: " ")
}
return nil
}
var compactTitle: String {
if let peer = peer?._asPeer() as? TelegramUser {
return peer.firstName ?? peer.lastName ?? ""
}
return ""
}
var reception: Int32? {
switch externalState.state {
case let .active(_, reception, _):
return reception
case let .reconnecting(_, reception, _):
return reception
default:
return nil
}
}
var seconds: Int32 {
switch externalState.state {
case let .active(referenceTime, _, _):
return Int32(CFAbsoluteTimeGetCurrent() - referenceTime)
case let .reconnecting(referenceTime, _, _):
return Int32(CFAbsoluteTimeGetCurrent() - referenceTime)
default:
return 0
}
}
var secretKey: String? {
switch self.externalState.state {
case .active(_, _, let emoji):
return emoji
case .reconnecting(_, _, let emoji):
return emoji
default:
return nil
}
}
var stateIndex: Int {
switch externalState.state {
case .waiting:
return 0
case .ringing:
return 0
case .requesting:
return 0
case .connecting:
if seconds > 2 {
return 2
} else {
return 1
}
case let .active(_, reception, _):
if let reception = reception, reception < 2, seconds > 2 {
return 2
}
return 1
case .reconnecting:
return 2
case .terminating:
return 0
case .terminated:
return 0
}
}
}