Video call improvements

This commit is contained in:
Ali 2020-08-04 23:08:27 +04:00
parent abb6e4a6bf
commit 8134159629
43 changed files with 3722 additions and 3585 deletions

View File

@ -4788,6 +4788,7 @@ Any member of this group will be able to see messages in the channel.";
"ContactList.Context.SendMessage" = "Send Message"; "ContactList.Context.SendMessage" = "Send Message";
"ContactList.Context.StartSecretChat" = "Start Secret Chat"; "ContactList.Context.StartSecretChat" = "Start Secret Chat";
"ContactList.Context.Call" = "Call"; "ContactList.Context.Call" = "Call";
"ContactList.Context.VideoCall" = "Video Call";
"Theme.Context.Apply" = "Apply"; "Theme.Context.Apply" = "Apply";
@ -5332,7 +5333,7 @@ Any member of this group will be able to see messages in the channel.";
"PeerInfo.ButtonMessage" = "Message"; "PeerInfo.ButtonMessage" = "Message";
"PeerInfo.ButtonDiscuss" = "Discuss"; "PeerInfo.ButtonDiscuss" = "Discuss";
"PeerInfo.ButtonCall" = "Call"; "PeerInfo.ButtonCall" = "Call";
"PeerInfo.ButtonVideoCall" = "Video Call"; "PeerInfo.ButtonVideoCall" = "Video";
"PeerInfo.ButtonMute" = "Mute"; "PeerInfo.ButtonMute" = "Mute";
"PeerInfo.ButtonUnmute" = "Unmute"; "PeerInfo.ButtonUnmute" = "Unmute";
"PeerInfo.ButtonMore" = "More"; "PeerInfo.ButtonMore" = "More";

View File

@ -647,6 +647,7 @@ public protocol AccountContext: class {
var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get } var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get }
var currentContentSettings: Atomic<ContentSettings> { get } var currentContentSettings: Atomic<ContentSettings> { get }
var currentAppConfiguration: Atomic<AppConfiguration> { get }
func storeSecureIdPassword(password: String) func storeSecureIdPassword(password: String)
func getStoredSecureIdPassword() -> String? func getStoredSecureIdPassword() -> String?

View File

@ -81,17 +81,20 @@ public final class PresentationCallVideoView {
public let getOrientation: () -> Orientation public let getOrientation: () -> Orientation
public let setOnOrientationUpdated: (((Orientation) -> Void)?) -> Void public let setOnOrientationUpdated: (((Orientation) -> Void)?) -> Void
public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void
public init( public init(
view: UIView, view: UIView,
setOnFirstFrameReceived: @escaping ((() -> Void)?) -> Void, setOnFirstFrameReceived: @escaping ((() -> Void)?) -> Void,
getOrientation: @escaping () -> Orientation, getOrientation: @escaping () -> Orientation,
setOnOrientationUpdated: @escaping (((Orientation) -> Void)?) -> Void setOnOrientationUpdated: @escaping (((Orientation) -> Void)?) -> Void,
setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void
) { ) {
self.view = view self.view = view
self.setOnFirstFrameReceived = setOnFirstFrameReceived self.setOnFirstFrameReceived = setOnFirstFrameReceived
self.getOrientation = getOrientation self.getOrientation = getOrientation
self.setOnOrientationUpdated = setOnOrientationUpdated self.setOnOrientationUpdated = setOnOrientationUpdated
self.setOnIsMirroredUpdated = setOnIsMirroredUpdated
} }
} }
@ -133,5 +136,5 @@ public protocol PresentationCall: class {
public protocol PresentationCallManager: class { public protocol PresentationCallManager: class {
var currentCallSignal: Signal<PresentationCall?, NoError> { get } var currentCallSignal: Signal<PresentationCall?, NoError> { get }
func requestCall(account: Account, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult func requestCall(context: AccountContext, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult
} }

View File

@ -0,0 +1,39 @@
import SyncCore
public struct VideoCallsConfiguration: Equatable {
public enum VideoCallsSupport {
case disabled
case full
case onlyVideo
}
public var videoCallsSupport: VideoCallsSupport
public init(appConfiguration: AppConfiguration) {
var videoCallsSupport: VideoCallsSupport = .full
if let data = appConfiguration.data, let value = data["video_calls_support"] as? String {
switch value {
case "disabled":
videoCallsSupport = .disabled
case "full":
videoCallsSupport = .full
case "only_video":
videoCallsSupport = .onlyVideo
default:
videoCallsSupport = .full
}
}
self.videoCallsSupport = videoCallsSupport
}
}
public extension VideoCallsConfiguration {
var areVideoCallsEnabled: Bool {
switch self.videoCallsSupport {
case .disabled:
return false
case .full, .onlyVideo:
return true
}
}
}

View File

@ -277,7 +277,7 @@ public final class CallListController: ViewController {
return return
} }
let callResult = strongSelf.context.sharedContext.callManager?.requestCall(account: strongSelf.context.account, peerId: peerId, isVideo: isVideo, endCurrentIfAny: false) let callResult = strongSelf.context.sharedContext.callManager?.requestCall(context: strongSelf.context, peerId: peerId, isVideo: isVideo, endCurrentIfAny: false)
if let callResult = callResult { if let callResult = callResult {
if case let .alreadyInProgress(currentPeerId) = callResult { if case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == peerId { if currentPeerId == peerId {
@ -291,7 +291,7 @@ public final class CallListController: ViewController {
if let strongSelf = self, let peer = peer, let current = current { if let strongSelf = self, let peer = peer, let current = current {
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
if let strongSelf = self { if let strongSelf = self {
let _ = strongSelf.context.sharedContext.callManager?.requestCall(account: strongSelf.context.account, peerId: peerId, isVideo: isVideo, endCurrentIfAny: true) let _ = strongSelf.context.sharedContext.callManager?.requestCall(context: strongSelf.context, peerId: peerId, isVideo: isVideo, endCurrentIfAny: true)
began?() began?()
} }
})]), in: .window(.root)) })]), in: .window(.root))

View File

@ -113,15 +113,17 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
} }
var canVideoCall = false var canVideoCall = false
if canCall { if canCall {
if context.sharedContext.immediateExperimentalUISettings.videoCalls { if let cachedUserData = transaction.getPeerCachedData(peerId: peerId) as? CachedUserData {
canVideoCall = true if cachedUserData.videoCallsAvailable {
canVideoCall = true
}
} }
} }
if canCall { if canCall {
items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_Call, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { _, f in items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_Call, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { _, f in
if let contactsController = contactsController { if let contactsController = contactsController {
let callResult = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peerId, isVideo: false, endCurrentIfAny: false) let callResult = context.sharedContext.callManager?.requestCall(context: context, peerId: peerId, isVideo: false, endCurrentIfAny: false)
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == peerId { if currentPeerId == peerId {
context.sharedContext.navigateToCurrentCall() context.sharedContext.navigateToCurrentCall()
@ -133,7 +135,7 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
|> deliverOnMainQueue).start(next: { [weak contactsController] peer, current in |> deliverOnMainQueue).start(next: { [weak contactsController] peer, current in
if let contactsController = contactsController, let peer = peer, let current = current { if let contactsController = contactsController, let peer = peer, let current = current {
contactsController.present(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { contactsController.present(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
let _ = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peerId, isVideo: false, endCurrentIfAny: true) let _ = context.sharedContext.callManager?.requestCall(context: context, peerId: peerId, isVideo: false, endCurrentIfAny: true)
})]), in: .window(.root)) })]), in: .window(.root))
} }
}) })
@ -144,10 +146,9 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
}))) })))
} }
if canVideoCall { if canVideoCall {
//TODO:localize items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_VideoCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { _, f in
items.append(.action(ContextMenuActionItem(text: "Video Call", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { _, f in
if let contactsController = contactsController { if let contactsController = contactsController {
let callResult = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peerId, isVideo: true, endCurrentIfAny: false) let callResult = context.sharedContext.callManager?.requestCall(context: context, peerId: peerId, isVideo: true, endCurrentIfAny: false)
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == peerId { if currentPeerId == peerId {
context.sharedContext.navigateToCurrentCall() context.sharedContext.navigateToCurrentCall()
@ -159,7 +160,7 @@ func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsCo
|> deliverOnMainQueue).start(next: { [weak contactsController] peer, current in |> deliverOnMainQueue).start(next: { [weak contactsController] peer, current in
if let contactsController = contactsController, let peer = peer, let current = current { if let contactsController = contactsController, let peer = peer, let current = current {
contactsController.present(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { contactsController.present(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
let _ = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peerId, isVideo: true, endCurrentIfAny: true) let _ = context.sharedContext.callManager?.requestCall(context: context, peerId: peerId, isVideo: true, endCurrentIfAny: true)
})]), in: .window(.root)) })]), in: .window(.root))
} }
}) })

View File

@ -877,7 +877,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
ActionSheetItemGroup(items: [ ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.UserInfo_TelegramCall, action: { ActionSheetButtonItem(title: presentationData.strings.UserInfo_TelegramCall, action: {
dismissAction() dismissAction()
let callResult = context.sharedContext.callManager?.requestCall(account: context.account, peerId: user.id, isVideo: false, endCurrentIfAny: false) let callResult = context.sharedContext.callManager?.requestCall(context: context, peerId: user.id, isVideo: false, endCurrentIfAny: false)
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == user.id { if currentPeerId == user.id {
context.sharedContext.navigateToCurrentCall() context.sharedContext.navigateToCurrentCall()
@ -888,7 +888,7 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
} |> deliverOnMainQueue).start(next: { peer, current in } |> deliverOnMainQueue).start(next: { peer, current in
if let peer = peer, let current = current { if let peer = peer, let current = current {
presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
let _ = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peer.id, isVideo: false, endCurrentIfAny: true) let _ = context.sharedContext.callManager?.requestCall(context: context, peerId: peer.id, isVideo: false, endCurrentIfAny: true)
})]), nil) })]), nil)
} }
}) })

View File

@ -597,7 +597,7 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat
var callsAvailable = true var callsAvailable = true
if let cachedUserData = cachedPeerData as? CachedUserData { if let cachedUserData = cachedPeerData as? CachedUserData {
callsAvailable = cachedUserData.callsAvailable callsAvailable = cachedUserData.voiceCallsAvailable
} }
entries.append(UserInfoEntry.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: user, presence: view.peerPresences[user.id], cachedData: cachedPeerData, state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), displayCall: user.botInfo == nil && callsAvailable)) entries.append(UserInfoEntry.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: user, presence: view.peerPresences[user.id], cachedData: cachedPeerData, state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: nil), displayCall: user.botInfo == nil && callsAvailable))
@ -873,7 +873,7 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
return return
} }
let callResult = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: false) let callResult = context.sharedContext.callManager?.requestCall(context: context, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: false)
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == peer.id { if currentPeerId == peer.id {
context.sharedContext.navigateToCurrentCall() context.sharedContext.navigateToCurrentCall()
@ -884,7 +884,7 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
} |> deliverOnMainQueue).start(next: { peer, current in } |> deliverOnMainQueue).start(next: { peer, current in
if let peer = peer, let current = current { if let peer = peer, let current = current {
presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
let _ = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: true) let _ = context.sharedContext.callManager?.requestCall(context: context, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: true)
})]), nil) })]), nil)
} }
}) })

View File

@ -72,9 +72,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
case alternativeFolderTabs(Bool) case alternativeFolderTabs(Bool)
case playerEmbedding(Bool) case playerEmbedding(Bool)
case playlistPlayback(Bool) case playlistPlayback(Bool)
case videoCalls(Bool) case enableHighBitrateVideoCalls(Bool)
case videoCallsReference(Bool)
case videoCallsInfo(PresentationTheme, String)
case hostInfo(PresentationTheme, String) case hostInfo(PresentationTheme, String)
case versionInfo(PresentationTheme) case versionInfo(PresentationTheme)
@ -90,7 +88,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return DebugControllerSection.experiments.rawValue return DebugControllerSection.experiments.rawValue
case .clearTips, .reimport, .resetData, .resetDatabase, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .alternativeFolderTabs, .playerEmbedding, .playlistPlayback: case .clearTips, .reimport, .resetData, .resetDatabase, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .alternativeFolderTabs, .playerEmbedding, .playlistPlayback:
return DebugControllerSection.experiments.rawValue return DebugControllerSection.experiments.rawValue
case .videoCalls, .videoCallsReference, .videoCallsInfo: case .enableHighBitrateVideoCalls:
return DebugControllerSection.videoExperiments.rawValue return DebugControllerSection.videoExperiments.rawValue
case .hostInfo, .versionInfo: case .hostInfo, .versionInfo:
return DebugControllerSection.info.rawValue return DebugControllerSection.info.rawValue
@ -149,12 +147,8 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 24 return 24
case .playlistPlayback: case .playlistPlayback:
return 25 return 25
case .videoCalls: case .enableHighBitrateVideoCalls:
return 26 return 26
case .videoCallsReference:
return 27
case .videoCallsInfo:
return 28
case .hostInfo: case .hostInfo:
return 29 return 29
case .versionInfo: case .versionInfo:
@ -576,28 +570,16 @@ private enum DebugControllerEntry: ItemListNodeEntry {
}) })
}).start() }).start()
}) })
case let .videoCalls(value): case let .enableHighBitrateVideoCalls(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Experimental Feature", value: value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: "HD Video Calls", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings
settings.videoCalls = value settings.enableHighBitrateVideoCalls = value
return settings return settings
}) })
}).start() }).start()
}) })
case let .videoCallsReference(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Reference Implementation", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings
settings.videoCallsReference = value
return settings
})
}).start()
})
case let .videoCallsInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .hostInfo(theme, string): case let .hostInfo(theme, string):
return ItemListTextItem(presentationData: presentationData, text: .plain(string), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(string), sectionId: self.section)
case let .versionInfo(theme): case let .versionInfo(theme):
@ -643,11 +625,7 @@ private func debugControllerEntries(presentationData: PresentationData, loggingS
entries.append(.alternativeFolderTabs(experimentalSettings.foldersTabAtBottom)) entries.append(.alternativeFolderTabs(experimentalSettings.foldersTabAtBottom))
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding)) entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback)) entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
entries.append(.videoCalls(experimentalSettings.videoCalls)) entries.append(.enableHighBitrateVideoCalls(experimentalSettings.enableHighBitrateVideoCalls))
if experimentalSettings.videoCalls {
entries.append(.videoCallsReference(experimentalSettings.videoCallsReference))
}
entries.append(.videoCallsInfo(presentationData.theme, "Enables experimental transmission of electromagnetic radiation synchronized with pressure waves. Needs to be enabled on both sides."))
if let backupHostOverride = networkSettings?.backupHostOverride { if let backupHostOverride = networkSettings?.backupHostOverride {
entries.append(.hostInfo(presentationData.theme, "Host: \(backupHostOverride)")) entries.append(.hostInfo(presentationData.theme, "Host: \(backupHostOverride)"))

View File

@ -8,7 +8,8 @@ public final class CachedUserData: CachedPeerData {
public let pinnedMessageId: MessageId? public let pinnedMessageId: MessageId?
public let isBlocked: Bool public let isBlocked: Bool
public let commonGroupCount: Int32 public let commonGroupCount: Int32
public let callsAvailable: Bool public let voiceCallsAvailable: Bool
public let videoCallsAvailable: Bool
public let callsPrivate: Bool public let callsPrivate: Bool
public let canPinMessages: Bool public let canPinMessages: Bool
public let hasScheduledMessages: Bool public let hasScheduledMessages: Bool
@ -24,21 +25,23 @@ public final class CachedUserData: CachedPeerData {
self.pinnedMessageId = nil self.pinnedMessageId = nil
self.isBlocked = false self.isBlocked = false
self.commonGroupCount = 0 self.commonGroupCount = 0
self.callsAvailable = false self.voiceCallsAvailable = false
self.videoCallsAvailable = false
self.callsPrivate = false self.callsPrivate = false
self.canPinMessages = false self.canPinMessages = false
self.hasScheduledMessages = false self.hasScheduledMessages = false
self.messageIds = Set() self.messageIds = Set()
} }
public init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, callsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool) { public init(about: String?, botInfo: BotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool) {
self.about = about self.about = about
self.botInfo = botInfo self.botInfo = botInfo
self.peerStatusSettings = peerStatusSettings self.peerStatusSettings = peerStatusSettings
self.pinnedMessageId = pinnedMessageId self.pinnedMessageId = pinnedMessageId
self.isBlocked = isBlocked self.isBlocked = isBlocked
self.commonGroupCount = commonGroupCount self.commonGroupCount = commonGroupCount
self.callsAvailable = callsAvailable self.voiceCallsAvailable = voiceCallsAvailable
self.videoCallsAvailable = videoCallsAvailable
self.callsPrivate = callsPrivate self.callsPrivate = callsPrivate
self.canPinMessages = canPinMessages self.canPinMessages = canPinMessages
self.hasScheduledMessages = hasScheduledMessages self.hasScheduledMessages = hasScheduledMessages
@ -66,7 +69,8 @@ public final class CachedUserData: CachedPeerData {
} }
self.isBlocked = decoder.decodeInt32ForKey("b", orElse: 0) != 0 self.isBlocked = decoder.decodeInt32ForKey("b", orElse: 0) != 0
self.commonGroupCount = decoder.decodeInt32ForKey("cg", orElse: 0) self.commonGroupCount = decoder.decodeInt32ForKey("cg", orElse: 0)
self.callsAvailable = decoder.decodeInt32ForKey("ca", orElse: 0) != 0 self.voiceCallsAvailable = decoder.decodeInt32ForKey("ca", orElse: 0) != 0
self.videoCallsAvailable = decoder.decodeInt32ForKey("vca", orElse: 0) != 0
self.callsPrivate = decoder.decodeInt32ForKey("cp", orElse: 0) != 0 self.callsPrivate = decoder.decodeInt32ForKey("cp", orElse: 0) != 0
self.canPinMessages = decoder.decodeInt32ForKey("cpm", orElse: 0) != 0 self.canPinMessages = decoder.decodeInt32ForKey("cpm", orElse: 0) != 0
self.hasScheduledMessages = decoder.decodeBoolForKey("hsm", orElse: false) self.hasScheduledMessages = decoder.decodeBoolForKey("hsm", orElse: false)
@ -105,7 +109,8 @@ public final class CachedUserData: CachedPeerData {
} }
encoder.encodeInt32(self.isBlocked ? 1 : 0, forKey: "b") encoder.encodeInt32(self.isBlocked ? 1 : 0, forKey: "b")
encoder.encodeInt32(self.commonGroupCount, forKey: "cg") encoder.encodeInt32(self.commonGroupCount, forKey: "cg")
encoder.encodeInt32(self.callsAvailable ? 1 : 0, forKey: "ca") encoder.encodeInt32(self.voiceCallsAvailable ? 1 : 0, forKey: "ca")
encoder.encodeInt32(self.videoCallsAvailable ? 1 : 0, forKey: "vca")
encoder.encodeInt32(self.callsPrivate ? 1 : 0, forKey: "cp") encoder.encodeInt32(self.callsPrivate ? 1 : 0, forKey: "cp")
encoder.encodeInt32(self.canPinMessages ? 1 : 0, forKey: "cpm") encoder.encodeInt32(self.canPinMessages ? 1 : 0, forKey: "cpm")
encoder.encodeBool(self.hasScheduledMessages, forKey: "hsm") encoder.encodeBool(self.hasScheduledMessages, forKey: "hsm")
@ -123,46 +128,50 @@ public final class CachedUserData: CachedPeerData {
return false return false
} }
return other.about == self.about && other.botInfo == self.botInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.callsAvailable == other.callsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages return other.about == self.about && other.botInfo == self.botInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.voiceCallsAvailable == other.voiceCallsAvailable && self.videoCallsAvailable == other.videoCallsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages
} }
public func withUpdatedAbout(_ about: String?) -> CachedUserData { public func withUpdatedAbout(_ about: String?) -> CachedUserData {
return CachedUserData(about: about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedBotInfo(_ botInfo: BotInfo?) -> CachedUserData { public func withUpdatedBotInfo(_ botInfo: BotInfo?) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedUserData { public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedUserData { public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedIsBlocked(_ isBlocked: Bool) -> CachedUserData { public func withUpdatedIsBlocked(_ isBlocked: Bool) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedCommonGroupCount(_ commonGroupCount: Int32) -> CachedUserData { public func withUpdatedCommonGroupCount(_ commonGroupCount: Int32) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedCallsAvailable(_ callsAvailable: Bool) -> CachedUserData { public func withUpdatedVoiceCallsAvailable(_ voiceCallsAvailable: Bool) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
}
public func withUpdatedVideoCallsAvailable(_ videoCallsAvailable: Bool) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedCallsPrivate(_ callsPrivate: Bool) -> CachedUserData { public func withUpdatedCallsPrivate(_ callsPrivate: Bool) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedCanPinMessages(_ canPinMessages: Bool) -> CachedUserData { public func withUpdatedCanPinMessages(_ canPinMessages: Bool) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages)
} }
public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedUserData { public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedUserData {
return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages) return CachedUserData(about: self.about, botInfo: self.botInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages)
} }
} }

View File

@ -255,7 +255,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[889491791] = { return Api.Update.parse_updateDialogFilters($0) } dict[889491791] = { return Api.Update.parse_updateDialogFilters($0) }
dict[643940105] = { return Api.Update.parse_updatePhoneCallSignalingData($0) } dict[643940105] = { return Api.Update.parse_updatePhoneCallSignalingData($0) }
dict[1708307556] = { return Api.Update.parse_updateChannelParticipant($0) } dict[1708307556] = { return Api.Update.parse_updateChannelParticipant($0) }
dict[1854571743] = { return Api.Update.parse_updateChannelMessageForwards($0) }
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) } dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) } dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) } dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
@ -388,7 +387,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1694474197] = { return Api.messages.Chats.parse_chats($0) } dict[1694474197] = { return Api.messages.Chats.parse_chats($0) }
dict[-1663561404] = { return Api.messages.Chats.parse_chatsSlice($0) } dict[-1663561404] = { return Api.messages.Chats.parse_chatsSlice($0) }
dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) } dict[482797855] = { return Api.InputSingleMedia.parse_inputSingleMedia($0) }
dict[1831138451] = { return Api.MessageViews.parse_messageViews($0) }
dict[218751099] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowContacts($0) } dict[218751099] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowContacts($0) }
dict[407582158] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowAll($0) } dict[407582158] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowAll($0) }
dict[320652927] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowUsers($0) } dict[320652927] = { return Api.InputPrivacyRule.parse_inputPrivacyValueAllowUsers($0) }
@ -600,7 +598,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1820043071] = { return Api.User.parse_user($0) } dict[-1820043071] = { return Api.User.parse_user($0) }
dict[-2082087340] = { return Api.Message.parse_messageEmpty($0) } dict[-2082087340] = { return Api.Message.parse_messageEmpty($0) }
dict[-1642487306] = { return Api.Message.parse_messageService($0) } dict[-1642487306] = { return Api.Message.parse_messageService($0) }
dict[-181507201] = { return Api.Message.parse_message($0) } dict[1160515173] = { return Api.Message.parse_message($0) }
dict[831924812] = { return Api.StatsGroupTopInviter.parse_statsGroupTopInviter($0) } dict[831924812] = { return Api.StatsGroupTopInviter.parse_statsGroupTopInviter($0) }
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) } dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) }
dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) } dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) }
@ -685,7 +683,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[364538944] = { return Api.messages.Dialogs.parse_dialogs($0) } dict[364538944] = { return Api.messages.Dialogs.parse_dialogs($0) }
dict[1910543603] = { return Api.messages.Dialogs.parse_dialogsSlice($0) } dict[1910543603] = { return Api.messages.Dialogs.parse_dialogsSlice($0) }
dict[-253500010] = { return Api.messages.Dialogs.parse_dialogsNotModified($0) } dict[-253500010] = { return Api.messages.Dialogs.parse_dialogsNotModified($0) }
dict[-1986399595] = { return Api.stats.MessageStats.parse_messageStats($0) }
dict[-709641735] = { return Api.EmojiKeyword.parse_emojiKeyword($0) } dict[-709641735] = { return Api.EmojiKeyword.parse_emojiKeyword($0) }
dict[594408994] = { return Api.EmojiKeyword.parse_emojiKeywordDeleted($0) } dict[594408994] = { return Api.EmojiKeyword.parse_emojiKeywordDeleted($0) }
dict[-290921362] = { return Api.upload.CdnFile.parse_cdnFileReuploadNeeded($0) } dict[-290921362] = { return Api.upload.CdnFile.parse_cdnFileReuploadNeeded($0) }
@ -708,6 +705,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) } dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) }
dict[-302170017] = { return Api.messages.AllStickers.parse_allStickers($0) } dict[-302170017] = { return Api.messages.AllStickers.parse_allStickers($0) }
dict[-1655957568] = { return Api.PhoneConnection.parse_phoneConnection($0) } dict[-1655957568] = { return Api.PhoneConnection.parse_phoneConnection($0) }
dict[1667228533] = { return Api.PhoneConnection.parse_phoneConnectionWebrtc($0) }
dict[-206688531] = { return Api.help.UserInfo.parse_userInfoEmpty($0) } dict[-206688531] = { return Api.help.UserInfo.parse_userInfoEmpty($0) }
dict[32192344] = { return Api.help.UserInfo.parse_userInfo($0) } dict[32192344] = { return Api.help.UserInfo.parse_userInfo($0) }
dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) } dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) }
@ -1108,8 +1106,6 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.InputSingleMedia: case let _1 as Api.InputSingleMedia:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.MessageViews:
_1.serialize(buffer, boxed)
case let _1 as Api.InputPrivacyRule: case let _1 as Api.InputPrivacyRule:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.DhConfig: case let _1 as Api.messages.DhConfig:
@ -1370,8 +1366,6 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.messages.Dialogs: case let _1 as Api.messages.Dialogs:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.stats.MessageStats:
_1.serialize(buffer, boxed)
case let _1 as Api.EmojiKeyword: case let _1 as Api.EmojiKeyword:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.upload.CdnFile: case let _1 as Api.upload.CdnFile:

View File

@ -6038,7 +6038,6 @@ public extension Api {
case updateDialogFilters case updateDialogFilters
case updatePhoneCallSignalingData(phoneCallId: Int64, data: Buffer) case updatePhoneCallSignalingData(phoneCallId: Int64, data: Buffer)
case updateChannelParticipant(flags: Int32, channelId: Int32, date: Int32, userId: Int32, prevParticipant: Api.ChannelParticipant?, newParticipant: Api.ChannelParticipant?, qts: Int32) case updateChannelParticipant(flags: Int32, channelId: Int32, date: Int32, userId: Int32, prevParticipant: Api.ChannelParticipant?, newParticipant: Api.ChannelParticipant?, qts: Int32)
case updateChannelMessageForwards(channelId: Int32, id: Int32, forwards: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -6731,14 +6730,6 @@ public extension Api {
if Int(flags) & Int(1 << 1) != 0 {newParticipant!.serialize(buffer, true)} if Int(flags) & Int(1 << 1) != 0 {newParticipant!.serialize(buffer, true)}
serializeInt32(qts, buffer: buffer, boxed: false) serializeInt32(qts, buffer: buffer, boxed: false)
break break
case .updateChannelMessageForwards(let channelId, let id, let forwards):
if boxed {
buffer.appendInt32(1854571743)
}
serializeInt32(channelId, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
serializeInt32(forwards, buffer: buffer, boxed: false)
break
} }
} }
@ -6908,8 +6899,6 @@ public extension Api {
return ("updatePhoneCallSignalingData", [("phoneCallId", phoneCallId), ("data", data)]) return ("updatePhoneCallSignalingData", [("phoneCallId", phoneCallId), ("data", data)])
case .updateChannelParticipant(let flags, let channelId, let date, let userId, let prevParticipant, let newParticipant, let qts): case .updateChannelParticipant(let flags, let channelId, let date, let userId, let prevParticipant, let newParticipant, let qts):
return ("updateChannelParticipant", [("flags", flags), ("channelId", channelId), ("date", date), ("userId", userId), ("prevParticipant", prevParticipant), ("newParticipant", newParticipant), ("qts", qts)]) return ("updateChannelParticipant", [("flags", flags), ("channelId", channelId), ("date", date), ("userId", userId), ("prevParticipant", prevParticipant), ("newParticipant", newParticipant), ("qts", qts)])
case .updateChannelMessageForwards(let channelId, let id, let forwards):
return ("updateChannelMessageForwards", [("channelId", channelId), ("id", id), ("forwards", forwards)])
} }
} }
@ -8288,23 +8277,6 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_updateChannelMessageForwards(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.Update.updateChannelMessageForwards(channelId: _1!, id: _2!, forwards: _3!)
}
else {
return nil
}
}
} }
public enum PopularContact: TypeConstructorDescription { public enum PopularContact: TypeConstructorDescription {
@ -11746,44 +11718,6 @@ public extension Api {
} }
} }
}
public enum MessageViews: TypeConstructorDescription {
case messageViews(views: Int32, forwards: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageViews(let views, let forwards):
if boxed {
buffer.appendInt32(1831138451)
}
serializeInt32(views, buffer: buffer, boxed: false)
serializeInt32(forwards, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageViews(let views, let forwards):
return ("messageViews", [("views", views), ("forwards", forwards)])
}
}
public static func parse_messageViews(_ reader: BufferReader) -> MessageViews? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageViews.messageViews(views: _1!, forwards: _2!)
}
else {
return nil
}
}
} }
public enum InputPrivacyRule: TypeConstructorDescription { public enum InputPrivacyRule: TypeConstructorDescription {
case inputPrivacyValueAllowContacts case inputPrivacyValueAllowContacts
@ -17158,7 +17092,7 @@ public extension Api {
public enum Message: TypeConstructorDescription { public enum Message: TypeConstructorDescription {
case messageEmpty(id: Int32) case messageEmpty(id: Int32)
case messageService(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, replyToMsgId: Int32?, date: Int32, action: Api.MessageAction) case messageService(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, replyToMsgId: Int32?, date: Int32, action: Api.MessageAction)
case message(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, restrictionReason: [Api.RestrictionReason]?) case message(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, restrictionReason: [Api.RestrictionReason]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -17180,9 +17114,9 @@ public extension Api {
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
action.serialize(buffer, true) action.serialize(buffer, true)
break break
case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let editDate, let postAuthor, let groupedId, let restrictionReason): case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId, let restrictionReason):
if boxed { if boxed {
buffer.appendInt32(-181507201) buffer.appendInt32(1160515173)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false)
@ -17201,7 +17135,6 @@ public extension Api {
item.serialize(buffer, true) item.serialize(buffer, true)
}} }}
if Int(flags) & Int(1 << 10) != 0 {serializeInt32(views!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 10) != 0 {serializeInt32(views!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 10) != 0 {serializeInt32(forwards!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 15) != 0 {serializeInt32(editDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 15) != 0 {serializeInt32(editDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 16) != 0 {serializeString(postAuthor!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 16) != 0 {serializeString(postAuthor!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 17) != 0 {serializeInt64(groupedId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 17) != 0 {serializeInt64(groupedId!, buffer: buffer, boxed: false)}
@ -17220,8 +17153,8 @@ public extension Api {
return ("messageEmpty", [("id", id)]) return ("messageEmpty", [("id", id)])
case .messageService(let flags, let id, let fromId, let toId, let replyToMsgId, let date, let action): case .messageService(let flags, let id, let fromId, let toId, let replyToMsgId, let date, let action):
return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("replyToMsgId", replyToMsgId), ("date", date), ("action", action)]) return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("replyToMsgId", replyToMsgId), ("date", date), ("action", action)])
case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let editDate, let postAuthor, let groupedId, let restrictionReason): case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId, let restrictionReason):
return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("forwards", forwards), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId), ("restrictionReason", restrictionReason)]) return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId), ("restrictionReason", restrictionReason)])
} }
} }
@ -17307,16 +17240,14 @@ public extension Api {
var _13: Int32? var _13: Int32?
if Int(_1!) & Int(1 << 10) != 0 {_13 = reader.readInt32() } if Int(_1!) & Int(1 << 10) != 0 {_13 = reader.readInt32() }
var _14: Int32? var _14: Int32?
if Int(_1!) & Int(1 << 10) != 0 {_14 = reader.readInt32() } if Int(_1!) & Int(1 << 15) != 0 {_14 = reader.readInt32() }
var _15: Int32? var _15: String?
if Int(_1!) & Int(1 << 15) != 0 {_15 = reader.readInt32() } if Int(_1!) & Int(1 << 16) != 0 {_15 = parseString(reader) }
var _16: String? var _16: Int64?
if Int(_1!) & Int(1 << 16) != 0 {_16 = parseString(reader) } if Int(_1!) & Int(1 << 17) != 0 {_16 = reader.readInt64() }
var _17: Int64? var _17: [Api.RestrictionReason]?
if Int(_1!) & Int(1 << 17) != 0 {_17 = reader.readInt64() }
var _18: [Api.RestrictionReason]?
if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() { if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() {
_18 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self) _17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
} } } }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
@ -17331,13 +17262,12 @@ public extension Api {
let _c11 = (Int(_1!) & Int(1 << 6) == 0) || _11 != nil let _c11 = (Int(_1!) & Int(1 << 6) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 7) == 0) || _12 != nil let _c12 = (Int(_1!) & Int(1 << 7) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 10) == 0) || _13 != nil let _c13 = (Int(_1!) & Int(1 << 10) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 10) == 0) || _14 != nil let _c14 = (Int(_1!) & Int(1 << 15) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 15) == 0) || _15 != nil let _c15 = (Int(_1!) & Int(1 << 16) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 16) == 0) || _16 != nil let _c16 = (Int(_1!) & Int(1 << 17) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 17) == 0) || _17 != nil let _c17 = (Int(_1!) & Int(1 << 22) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 22) == 0) || _18 != nil if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 {
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 { return Api.Message.message(flags: _1!, id: _2!, fromId: _3, toId: _4!, fwdFrom: _5, viaBotId: _6, replyToMsgId: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, editDate: _14, postAuthor: _15, groupedId: _16, restrictionReason: _17)
return Api.Message.message(flags: _1!, id: _2!, fromId: _3, toId: _4!, fwdFrom: _5, viaBotId: _6, replyToMsgId: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, forwards: _14, editDate: _15, postAuthor: _16, groupedId: _17, restrictionReason: _18)
} }
else { else {
return nil return nil
@ -19911,6 +19841,7 @@ public extension Api {
} }
public enum PhoneConnection: TypeConstructorDescription { public enum PhoneConnection: TypeConstructorDescription {
case phoneConnection(id: Int64, ip: String, ipv6: String, port: Int32, peerTag: Buffer) case phoneConnection(id: Int64, ip: String, ipv6: String, port: Int32, peerTag: Buffer)
case phoneConnectionWebrtc(flags: Int32, id: Int64, ip: String, ipv6: String, port: Int32, username: String, password: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -19924,6 +19855,18 @@ public extension Api {
serializeInt32(port, buffer: buffer, boxed: false) serializeInt32(port, buffer: buffer, boxed: false)
serializeBytes(peerTag, buffer: buffer, boxed: false) serializeBytes(peerTag, buffer: buffer, boxed: false)
break break
case .phoneConnectionWebrtc(let flags, let id, let ip, let ipv6, let port, let username, let password):
if boxed {
buffer.appendInt32(1667228533)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false)
serializeString(ip, buffer: buffer, boxed: false)
serializeString(ipv6, buffer: buffer, boxed: false)
serializeInt32(port, buffer: buffer, boxed: false)
serializeString(username, buffer: buffer, boxed: false)
serializeString(password, buffer: buffer, boxed: false)
break
} }
} }
@ -19931,6 +19874,8 @@ public extension Api {
switch self { switch self {
case .phoneConnection(let id, let ip, let ipv6, let port, let peerTag): case .phoneConnection(let id, let ip, let ipv6, let port, let peerTag):
return ("phoneConnection", [("id", id), ("ip", ip), ("ipv6", ipv6), ("port", port), ("peerTag", peerTag)]) return ("phoneConnection", [("id", id), ("ip", ip), ("ipv6", ipv6), ("port", port), ("peerTag", peerTag)])
case .phoneConnectionWebrtc(let flags, let id, let ip, let ipv6, let port, let username, let password):
return ("phoneConnectionWebrtc", [("flags", flags), ("id", id), ("ip", ip), ("ipv6", ipv6), ("port", port), ("username", username), ("password", password)])
} }
} }
@ -19957,6 +19902,35 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_phoneConnectionWebrtc(_ reader: BufferReader) -> PhoneConnection? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: String?
_3 = parseString(reader)
var _4: String?
_4 = parseString(reader)
var _5: Int32?
_5 = reader.readInt32()
var _6: String?
_6 = parseString(reader)
var _7: String?
_7 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.PhoneConnection.phoneConnectionWebrtc(flags: _1!, id: _2!, ip: _3!, ipv6: _4!, port: _5!, username: _6!, password: _7!)
}
else {
return nil
}
}
} }
public enum AccountDaysTTL: TypeConstructorDescription { public enum AccountDaysTTL: TypeConstructorDescription {

View File

@ -810,42 +810,6 @@ public struct stats {
} }
} }
public enum MessageStats: TypeConstructorDescription {
case messageStats(viewsGraph: Api.StatsGraph)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageStats(let viewsGraph):
if boxed {
buffer.appendInt32(-1986399595)
}
viewsGraph.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageStats(let viewsGraph):
return ("messageStats", [("viewsGraph", viewsGraph)])
}
}
public static func parse_messageStats(_ reader: BufferReader) -> MessageStats? {
var _1: Api.StatsGraph?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
let _c1 = _1 != nil
if _c1 {
return Api.stats.MessageStats.messageStats(viewsGraph: _1!)
}
else {
return nil
}
}
}
} }
} }
public extension Api { public extension Api {

View File

@ -2243,6 +2243,26 @@ public extension Api {
}) })
} }
public static func getMessagesViews(peer: Api.InputPeer, id: [Int32], increment: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) {
let buffer = Buffer()
buffer.appendInt32(-993483427)
peer.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(id.count))
for item in id {
serializeInt32(item, buffer: buffer, boxed: false)
}
increment.serialize(buffer, true)
return (FunctionDescription(name: "messages.getMessagesViews", parameters: [("peer", peer), ("id", id), ("increment", increment)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Int32]? in
let reader = BufferReader(buffer)
var result: [Int32]?
if let _ = reader.readInt32() {
result = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
}
return result
})
}
public static func editChatAdmin(chatId: Int32, userId: Api.InputUser, isAdmin: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func editChatAdmin(chatId: Int32, userId: Api.InputUser, isAdmin: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-1444503762) buffer.appendInt32(-1444503762)
@ -3698,26 +3718,6 @@ public extension Api {
return result return result
}) })
} }
public static func getMessagesViews(peer: Api.InputPeer, id: [Int32], increment: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.MessageViews]>) {
let buffer = Buffer()
buffer.appendInt32(-39035462)
peer.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(id.count))
for item in id {
serializeInt32(item, buffer: buffer, boxed: false)
}
increment.serialize(buffer, true)
return (FunctionDescription(name: "messages.getMessagesViews", parameters: [("peer", peer), ("id", id), ("increment", increment)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.MessageViews]? in
let reader = BufferReader(buffer)
var result: [Api.MessageViews]?
if let _ = reader.readInt32() {
result = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageViews.self)
}
return result
})
}
} }
public struct channels { public struct channels {
public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
@ -4450,41 +4450,6 @@ public extension Api {
return result return result
}) })
} }
public static func getMessagePublicForwards(channel: Api.InputChannel, msgId: Int32, offsetRate: Int32, offsetPeer: Api.InputPeer, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Messages>) {
let buffer = Buffer()
buffer.appendInt32(1445996571)
channel.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(offsetRate, buffer: buffer, boxed: false)
offsetPeer.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stats.getMessagePublicForwards", parameters: [("channel", channel), ("msgId", msgId), ("offsetRate", offsetRate), ("offsetPeer", offsetPeer), ("offsetId", offsetId), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in
let reader = BufferReader(buffer)
var result: Api.messages.Messages?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.Messages
}
return result
})
}
public static func getMessageStats(flags: Int32, channel: Api.InputChannel, msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stats.MessageStats>) {
let buffer = Buffer()
buffer.appendInt32(-1226791947)
serializeInt32(flags, buffer: buffer, boxed: false)
channel.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stats.getMessageStats", parameters: [("flags", flags), ("channel", channel), ("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.MessageStats? in
let reader = BufferReader(buffer)
var result: Api.stats.MessageStats?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.stats.MessageStats
}
return result
})
}
} }
public struct auth { public struct auth {
public static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.auth.CheckedPhone>) { public static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.auth.CheckedPhone>) {

View File

@ -34,11 +34,11 @@ private final class CallVideoNode: ASDisplayNode {
private(set) var isReady: Bool = false private(set) var isReady: Bool = false
private var isReadyTimer: SwiftSignalKit.Timer? private var isReadyTimer: SwiftSignalKit.Timer?
private let isFlippedUpdated: () -> Void private let isFlippedUpdated: (CallVideoNode) -> Void
private(set) var currentOrientation: PresentationCallVideoView.Orientation private(set) var currentOrientation: PresentationCallVideoView.Orientation
init(videoView: PresentationCallVideoView, isReadyUpdated: @escaping () -> Void, orientationUpdated: @escaping () -> Void, isFlippedUpdated: @escaping () -> Void) { init(videoView: PresentationCallVideoView, assumeReadyAfterTimeout: Bool, isReadyUpdated: @escaping () -> Void, orientationUpdated: @escaping () -> Void, isFlippedUpdated: @escaping (CallVideoNode) -> Void) {
self.isReadyUpdated = isReadyUpdated self.isReadyUpdated = isReadyUpdated
self.isFlippedUpdated = isFlippedUpdated self.isFlippedUpdated = isFlippedUpdated
@ -46,46 +46,60 @@ private final class CallVideoNode: ASDisplayNode {
self.videoTransformContainer.clipsToBounds = true self.videoTransformContainer.clipsToBounds = true
self.videoView = videoView self.videoView = videoView
videoView.view.clipsToBounds = true videoView.view.clipsToBounds = true
videoView.view.backgroundColor = .black
self.currentOrientation = videoView.getOrientation() self.currentOrientation = videoView.getOrientation()
super.init() super.init()
self.backgroundColor = .black
self.videoTransformContainer.view.addSubview(self.videoView.view) self.videoTransformContainer.view.addSubview(self.videoView.view)
self.addSubnode(self.videoTransformContainer) self.addSubnode(self.videoTransformContainer)
self.videoView.setOnFirstFrameReceived { [weak self] in self.videoView.setOnFirstFrameReceived { [weak self] in
guard let strongSelf = self else { Queue.mainQueue().async {
return guard let strongSelf = self else {
} return
if !strongSelf.isReady { }
strongSelf.isReady = true if !strongSelf.isReady {
strongSelf.isReadyTimer?.invalidate() strongSelf.isReady = true
strongSelf.isReadyUpdated() strongSelf.isReadyTimer?.invalidate()
strongSelf.isReadyUpdated()
}
} }
} }
self.videoView.setOnOrientationUpdated { [weak self] orientation in self.videoView.setOnOrientationUpdated { [weak self] orientation in
guard let strongSelf = self else { Queue.mainQueue().async {
return guard let strongSelf = self else {
} return
if strongSelf.currentOrientation != orientation { }
strongSelf.currentOrientation = orientation if strongSelf.currentOrientation != orientation {
orientationUpdated() strongSelf.currentOrientation = orientation
orientationUpdated()
}
} }
} }
self.isReadyTimer = SwiftSignalKit.Timer(timeout: 3.0, repeat: false, completion: { [weak self] in self.videoView.setOnIsMirroredUpdated { [weak self] _ in
guard let strongSelf = self else { Queue.mainQueue().async {
return guard let strongSelf = self else {
return
}
strongSelf.isFlippedUpdated(strongSelf)
} }
if !strongSelf.isReady { }
strongSelf.isReady = true
strongSelf.isReadyUpdated() if assumeReadyAfterTimeout {
} self.isReadyTimer = SwiftSignalKit.Timer(timeout: 3.0, repeat: false, completion: { [weak self] in
}, queue: .mainQueue()) guard let strongSelf = self else {
return
}
if !strongSelf.isReady {
strongSelf.isReady = true
strongSelf.isReadyUpdated()
}
}, queue: .mainQueue())
}
self.isReadyTimer?.start() self.isReadyTimer?.start()
} }
@ -201,8 +215,6 @@ private final class CallVideoNode: ASDisplayNode {
if let effectView = self.effectView { if let effectView = self.effectView {
transition.updateCornerRadius(layer: effectView.layer, cornerRadius: self.currentCornerRadius) transition.updateCornerRadius(layer: effectView.layer, cornerRadius: self.currentCornerRadius)
} }
transition.updateCornerRadius(layer: self.layer, cornerRadius: self.currentCornerRadius)
} }
func updateIsBlurred(isBlurred: Bool) { func updateIsBlurred(isBlurred: Bool) {
@ -567,7 +579,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
return return
} }
if let incomingVideoView = incomingVideoView { if let incomingVideoView = incomingVideoView {
let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, isReadyUpdated: { let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, assumeReadyAfterTimeout: false, isReadyUpdated: {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -581,13 +593,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if let (layout, navigationBarHeight) = strongSelf.validLayout { if let (layout, navigationBarHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
} }
}, isFlippedUpdated: { }, isFlippedUpdated: { _ in
guard let strongSelf = self else {
return
}
if let (layout, navigationBarHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
}) })
strongSelf.incomingVideoNodeValue = incomingVideoNode strongSelf.incomingVideoNodeValue = incomingVideoNode
strongSelf.expandedVideoNode = incomingVideoNode strongSelf.expandedVideoNode = incomingVideoNode
@ -637,7 +643,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring)) strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
} }
let outgoingVideoNode = CallVideoNode(videoView: outgoingVideoView, isReadyUpdated: { let outgoingVideoNode = CallVideoNode(videoView: outgoingVideoView, assumeReadyAfterTimeout: true, isReadyUpdated: {
if delayUntilInitialized { if delayUntilInitialized {
Queue.mainQueue().after(0.4, { Queue.mainQueue().after(0.4, {
applyNode() applyNode()
@ -650,13 +656,26 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if let (layout, navigationBarHeight) = strongSelf.validLayout { if let (layout, navigationBarHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
} }
}, isFlippedUpdated: { }, isFlippedUpdated: { videoNode in
guard let strongSelf = self else { guard let _ = self else {
return return
} }
if let (layout, navigationBarHeight) = strongSelf.validLayout { /*if videoNode === strongSelf.minimizedVideoNode, let tempView = videoNode.view.snapshotView(afterScreenUpdates: true) {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) videoNode.view.superview?.insertSubview(tempView, aboveSubview: videoNode.view)
} videoNode.view.frame = videoNode.frame
let transitionOptions: UIView.AnimationOptions = [.transitionFlipFromRight, .showHideTransitionViews]
UIView.transition(with: tempView, duration: 1.0, options: transitionOptions, animations: {
tempView.isHidden = true
}, completion: { [weak tempView] _ in
tempView?.removeFromSuperview()
})
videoNode.view.isHidden = true
UIView.transition(with: videoNode.view, duration: 1.0, options: transitionOptions, animations: {
videoNode.view.isHidden = false
})
}*/
}) })
strongSelf.candidateOutgoingVideoNodeValue = outgoingVideoNode strongSelf.candidateOutgoingVideoNodeValue = outgoingVideoNode

View File

@ -29,7 +29,7 @@ public final class CallKitIntegration {
return self.audioSessionActivePromise.get() return self.audioSessionActivePromise.get()
} }
init?(enableVideoCalls: Bool, startCall: @escaping (Account, UUID, String, Bool) -> Signal<Bool, NoError>, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal<Bool, NoError>, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) { init?(startCall: @escaping (Account, UUID, String, Bool) -> Signal<Bool, NoError>, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal<Bool, NoError>, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) {
if !CallKitIntegration.isAvailable { if !CallKitIntegration.isAvailable {
return nil return nil
} }
@ -40,7 +40,7 @@ public final class CallKitIntegration {
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
if sharedProviderDelegate == nil { if sharedProviderDelegate == nil {
sharedProviderDelegate = CallKitProviderDelegate(enableVideoCalls: enableVideoCalls) sharedProviderDelegate = CallKitProviderDelegate()
} }
(sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged) (sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged)
} else { } else {
@ -112,8 +112,8 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
fileprivate var audioSessionActivePromise: ValuePromise<Bool>? fileprivate var audioSessionActivePromise: ValuePromise<Bool>?
init(enableVideoCalls: Bool) { override init() {
self.provider = CXProvider(configuration: CallKitProviderDelegate.providerConfiguration(enableVideoCalls: enableVideoCalls)) self.provider = CXProvider(configuration: CallKitProviderDelegate.providerConfiguration())
super.init() super.init()
@ -129,7 +129,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
self.audioSessionActivationChanged = audioSessionActivationChanged self.audioSessionActivationChanged = audioSessionActivationChanged
} }
private static func providerConfiguration(enableVideoCalls: Bool) -> CXProviderConfiguration { private static func providerConfiguration() -> CXProviderConfiguration {
let providerConfiguration = CXProviderConfiguration(localizedName: "Telegram") let providerConfiguration = CXProviderConfiguration(localizedName: "Telegram")
providerConfiguration.supportsVideo = false providerConfiguration.supportsVideo = false

View File

@ -169,6 +169,7 @@ public final class PresentationCallImpl: PresentationCall {
public let isOutgoing: Bool public let isOutgoing: Bool
public var isVideo: Bool public var isVideo: Bool
public var isVideoPossible: Bool public var isVideoPossible: Bool
public let enableHighBitrateVideoCalls: Bool
public let peer: Peer? public let peer: Peer?
private let serializedData: String? private let serializedData: String?
@ -257,7 +258,8 @@ public final class PresentationCallImpl: PresentationCall {
currentNetworkType: NetworkType, currentNetworkType: NetworkType,
updatedNetworkType: Signal<NetworkType, NoError>, updatedNetworkType: Signal<NetworkType, NoError>,
startWithVideo: Bool, startWithVideo: Bool,
isVideoPossible: Bool isVideoPossible: Bool,
enableHighBitrateVideoCalls: Bool
) { ) {
self.account = account self.account = account
self.audioSession = audioSession self.audioSession = audioSession
@ -286,6 +288,7 @@ public final class PresentationCallImpl: PresentationCall {
self.isVideoPossible = isVideoPossible self.isVideoPossible = isVideoPossible
self.peer = peer self.peer = peer
self.isVideo = startWithVideo self.isVideo = startWithVideo
self.enableHighBitrateVideoCalls = enableHighBitrateVideoCalls
if self.isVideo { if self.isVideo {
self.videoCapturer = OngoingCallVideoCapturer() self.videoCapturer = OngoingCallVideoCapturer()
self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: .outgoingRequested, remoteVideoState: .active)) self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: .outgoingRequested, remoteVideoState: .active))
@ -569,7 +572,7 @@ public final class PresentationCallImpl: PresentationCall {
if let _ = audioSessionControl, !wasActive || previousControl == nil { if let _ = audioSessionControl, !wasActive || previousControl == nil {
let logName = "\(id.id)_\(id.accessHash)" let logName = "\(id.id)_\(id.accessHash)"
let ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, auxiliaryServers: auxiliaryServers, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: connections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get(), logName: logName) let ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: connections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, enableHighBitrateVideoCalls: self.enableHighBitrateVideoCalls, audioSessionActive: self.audioSessionActive.get(), logName: logName)
self.ongoingContext = ongoingContext self.ongoingContext = ongoingContext
ongoingContext.setIsMuted(self.isMutedValue) ongoingContext.setIsMuted(self.isMutedValue)
@ -811,6 +814,7 @@ public final class PresentationCallImpl: PresentationCall {
if let view = view { if let view = view {
let setOnFirstFrameReceived = view.setOnFirstFrameReceived let setOnFirstFrameReceived = view.setOnFirstFrameReceived
let setOnOrientationUpdated = view.setOnOrientationUpdated let setOnOrientationUpdated = view.setOnOrientationUpdated
let setOnIsMirroredUpdated = view.setOnIsMirroredUpdated
completion(PresentationCallVideoView( completion(PresentationCallVideoView(
view: view.view, view: view.view,
setOnFirstFrameReceived: { f in setOnFirstFrameReceived: { f in
@ -849,6 +853,11 @@ public final class PresentationCallImpl: PresentationCall {
} }
f?(mappedValue) f?(mappedValue)
} }
},
setOnIsMirroredUpdated: { f in
setOnIsMirroredUpdated { value in
f?(value)
}
} }
)) ))
} else { } else {
@ -867,6 +876,7 @@ public final class PresentationCallImpl: PresentationCall {
if let view = view { if let view = view {
let setOnFirstFrameReceived = view.setOnFirstFrameReceived let setOnFirstFrameReceived = view.setOnFirstFrameReceived
let setOnOrientationUpdated = view.setOnOrientationUpdated let setOnOrientationUpdated = view.setOnOrientationUpdated
let setOnIsMirroredUpdated = view.setOnIsMirroredUpdated
completion(PresentationCallVideoView( completion(PresentationCallVideoView(
view: view.view, view: view.view,
setOnFirstFrameReceived: { f in setOnFirstFrameReceived: { f in
@ -905,8 +915,12 @@ public final class PresentationCallImpl: PresentationCall {
} }
f?(mappedValue) f?(mappedValue)
} }
},
setOnIsMirroredUpdated: { f in
setOnIsMirroredUpdated { value in
f?(value)
}
} }
)) ))
} else { } else {
completion(nil) completion(nil)

View File

@ -82,7 +82,6 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
private let accountManager: AccountManager private let accountManager: AccountManager
private let audioSession: ManagedAudioSession private let audioSession: ManagedAudioSession
private let callKitIntegration: CallKitIntegration? private let callKitIntegration: CallKitIntegration?
private var isVideoPossible: Bool
private var currentCallValue: PresentationCallImpl? private var currentCallValue: PresentationCallImpl?
private var currentCall: PresentationCallImpl? { private var currentCall: PresentationCallImpl? {
@ -117,15 +116,14 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
return OngoingCallContext.maxLayer return OngoingCallContext.maxLayer
} }
public static func voipVersions(includeExperimental: Bool, includeReference: Bool) -> [String] { public static func voipVersions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] {
return OngoingCallContext.versions(includeExperimental: includeExperimental, includeReference: includeReference) return OngoingCallContext.versions(includeExperimental: includeExperimental, includeReference: includeReference)
} }
public init(accountManager: AccountManager, enableVideoCalls: Bool, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), isMediaPlaying: @escaping () -> Bool, resumeMediaPlayback: @escaping () -> Void, audioSession: ManagedAudioSession, activeAccounts: Signal<[Account], NoError>) { public init(accountManager: AccountManager, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), isMediaPlaying: @escaping () -> Bool, resumeMediaPlayback: @escaping () -> Void, audioSession: ManagedAudioSession, activeAccounts: Signal<[Account], NoError>) {
self.getDeviceAccessData = getDeviceAccessData self.getDeviceAccessData = getDeviceAccessData
self.accountManager = accountManager self.accountManager = accountManager
self.audioSession = audioSession self.audioSession = audioSession
self.isVideoPossible = enableVideoCalls
self.isMediaPlaying = isMediaPlaying self.isMediaPlaying = isMediaPlaying
self.resumeMediaPlayback = resumeMediaPlayback self.resumeMediaPlayback = resumeMediaPlayback
@ -136,7 +134,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
var setCallMutedImpl: ((UUID, Bool) -> Void)? var setCallMutedImpl: ((UUID, Bool) -> Void)?
var audioSessionActivationChangedImpl: ((Bool) -> Void)? var audioSessionActivationChangedImpl: ((Bool) -> Void)?
self.callKitIntegration = CallKitIntegration(enableVideoCalls: enableVideoCalls, startCall: { account, uuid, handle, isVideo in self.callKitIntegration = CallKitIntegration(startCall: { account, uuid, handle, isVideo in
if let startCallImpl = startCallImpl { if let startCallImpl = startCallImpl {
return startCallImpl(account, uuid, handle, isVideo) return startCallImpl(account, uuid, handle, isVideo)
} else { } else {
@ -214,7 +212,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
startCallImpl = { [weak self] account, uuid, handle, isVideo in startCallImpl = { [weak self] account, uuid, handle, isVideo in
if let strongSelf = self, let userId = Int32(handle) { if let strongSelf = self, let userId = Int32(handle) {
return strongSelf.startCall(account: account, peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), isVideo: isVideo, isVideoPossible: strongSelf.isVideoPossible, internalId: uuid) return strongSelf.startCall(account: account, peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), isVideo: isVideo, internalId: uuid)
|> take(1) |> take(1)
|> map { result -> Bool in |> map { result -> Bool in
return result return result
@ -283,7 +281,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
private func ringingStatesUpdated(_ ringingStates: [(Account, Peer, CallSessionRingingState, Bool, NetworkType)], enableCallKit: Bool) { private func ringingStatesUpdated(_ ringingStates: [(Account, Peer, CallSessionRingingState, Bool, NetworkType)], enableCallKit: Bool) {
if let firstState = ringingStates.first { if let firstState = ringingStates.first {
if self.currentCall == nil { if self.currentCall == nil {
self.currentCallDisposable.set((combineLatest(firstState.0.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings]) |> take(1)) self.currentCallDisposable.set((combineLatest(firstState.0.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> take(1))
|> deliverOnMainQueue).start(next: { [weak self] preferences, sharedData in |> deliverOnMainQueue).start(next: { [weak self] preferences, sharedData in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -292,6 +290,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue
let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default
let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings
let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings ?? .defaultSettings
let appConfiguration = preferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue let appConfiguration = preferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue
let call = PresentationCallImpl( let call = PresentationCallImpl(
@ -313,7 +312,8 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
currentNetworkType: firstState.4, currentNetworkType: firstState.4,
updatedNetworkType: firstState.0.networkType, updatedNetworkType: firstState.0.networkType,
startWithVideo: firstState.2.isVideo, startWithVideo: firstState.2.isVideo,
isVideoPossible: strongSelf.isVideoPossible isVideoPossible: firstState.2.isVideoPossible,
enableHighBitrateVideoCalls: experimentalSettings.enableHighBitrateVideoCalls
) )
strongSelf.updateCurrentCall(call) strongSelf.updateCurrentCall(call)
strongSelf.currentCallPromise.set(.single(call)) strongSelf.currentCallPromise.set(.single(call))
@ -339,8 +339,9 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
} }
} }
public func requestCall(account: Account, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult { public func requestCall(context: AccountContext, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult {
let isVideoPossible = self.isVideoPossible let account = context.account
if let call = self.currentCall, !endCurrentIfAny { if let call = self.currentCall, !endCurrentIfAny {
return .alreadyInProgress(call.peerId) return .alreadyInProgress(call.peerId)
} }
@ -405,7 +406,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let _ = strongSelf.startCall(account: account, peerId: peerId, isVideo: isVideo, isVideoPossible: isVideoPossible).start() let _ = strongSelf.startCall(account: account, peerId: peerId, isVideo: isVideo).start()
} }
if let currentCall = self.currentCall { if let currentCall = self.currentCall {
self.startCallDisposable.set((currentCall.hangUp() self.startCallDisposable.set((currentCall.hangUp()
@ -423,7 +424,6 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
account: Account, account: Account,
peerId: PeerId, peerId: PeerId,
isVideo: Bool, isVideo: Bool,
isVideoPossible: Bool,
internalId: CallSessionInternalId = CallSessionInternalId() internalId: CallSessionInternalId = CallSessionInternalId()
) -> Signal<Bool, NoError> { ) -> Signal<Bool, NoError> {
let (presentationData, present, openSettings) = self.getDeviceAccessData() let (presentationData, present, openSettings) = self.getDeviceAccessData()
@ -459,9 +459,28 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
if !accessEnabled { if !accessEnabled {
return .single(false) return .single(false)
} }
return (combineLatest(queue: .mainQueue(), account.callSessionManager.request(peerId: peerId, isVideo: isVideo, internalId: internalId), networkType |> take(1), account.postbox.peerView(id: peerId) |> map { peerView -> Bool in
let request = account.postbox.transaction { transaction -> VideoCallsConfiguration in
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue
return VideoCallsConfiguration(appConfiguration: appConfiguration)
}
|> mapToSignal { callsConfiguration -> Signal<CallSessionInternalId, NoError> in
let isVideoPossible: Bool
switch callsConfiguration.videoCallsSupport {
case .disabled:
isVideoPossible = isVideo
case .full:
isVideoPossible = true
case .onlyVideo:
isVideoPossible = isVideo
}
return account.callSessionManager.request(peerId: peerId, isVideo: isVideo, enableVideo: isVideoPossible, internalId: internalId)
}
return (combineLatest(queue: .mainQueue(), request, networkType |> take(1), account.postbox.peerView(id: peerId) |> map { peerView -> Bool in
return peerView.peerIsContact return peerView.peerIsContact
} |> take(1), account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings]) |> take(1)) } |> take(1), account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState, PreferencesKeys.appConfiguration]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> take(1))
|> deliverOnMainQueue |> deliverOnMainQueue
|> beforeNext { internalId, currentNetworkType, isContact, preferences, sharedData in |> beforeNext { internalId, currentNetworkType, isContact, preferences, sharedData in
if let strongSelf = self, accessEnabled { if let strongSelf = self, accessEnabled {
@ -474,6 +493,19 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings
let appConfiguration = preferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue let appConfiguration = preferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue
let callsConfiguration = VideoCallsConfiguration(appConfiguration: appConfiguration)
let isVideoPossible: Bool
switch callsConfiguration.videoCallsSupport {
case .disabled:
isVideoPossible = isVideo
case .full:
isVideoPossible = true
case .onlyVideo:
isVideoPossible = isVideo
}
let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings ?? .defaultSettings
let call = PresentationCallImpl( let call = PresentationCallImpl(
account: account, account: account,
audioSession: strongSelf.audioSession, audioSession: strongSelf.audioSession,
@ -496,7 +528,8 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
currentNetworkType: currentNetworkType, currentNetworkType: currentNetworkType,
updatedNetworkType: account.networkType, updatedNetworkType: account.networkType,
startWithVideo: isVideo, startWithVideo: isVideo,
isVideoPossible: isVideoPossible isVideoPossible: isVideoPossible,
enableHighBitrateVideoCalls: experimentalSettings.enableHighBitrateVideoCalls
) )
strongSelf.updateCurrentCall(call) strongSelf.updateCurrentCall(call)
strongSelf.currentCallPromise.set(.single(call)) strongSelf.currentCallPromise.set(.single(call))

View File

@ -1253,8 +1253,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
updatedState.addReadMessagesContents((PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), messages)) updatedState.addReadMessagesContents((PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), messages))
case let .updateChannelMessageViews(channelId, id, views): case let .updateChannelMessageViews(channelId, id, views):
updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: id), count: views) updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: id), count: views)
case let .updateChannelMessageForwards(channelId, id, forwards): /*case let .updateChannelMessageForwards(channelId, id, forwards):
updatedState.addUpdateMessageForwardsCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: id), count: forwards) updatedState.addUpdateMessageForwardsCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: id), count: forwards)*/
case let .updateNewStickerSet(stickerset): case let .updateNewStickerSet(stickerset):
updatedState.addUpdateInstalledStickerPacks(.add(stickerset)) updatedState.addUpdateInstalledStickerPacks(.add(stickerset))
case let .updateStickerSetsOrder(flags, order): case let .updateStickerSetsOrder(flags, order):
@ -1898,8 +1898,8 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat
updatedState.addReadMessagesContents((peer.id, messages)) updatedState.addReadMessagesContents((peer.id, messages))
case let .updateChannelMessageViews(_, id, views): case let .updateChannelMessageViews(_, id, views):
updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views) updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views)
case let .updateChannelMessageForwards(_, id, views): /*case let .updateChannelMessageForwards(_, id, views):
updatedState.addUpdateMessageForwardsCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views) updatedState.addUpdateMessageForwardsCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views)*/
case let .updateChannelWebPage(_, apiWebpage, _, _): case let .updateChannelWebPage(_, apiWebpage, _, _):
switch apiWebpage { switch apiWebpage {
case let .webPageEmpty(id): case let .webPageEmpty(id):

View File

@ -591,7 +591,7 @@ public final class AccountViewTracker {
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.getMessagesViews(peer: inputPeer, id: messageIds.map { $0.id }, increment: .boolTrue)) return account.network.request(Api.functions.messages.getMessagesViews(peer: inputPeer, id: messageIds.map { $0.id }, increment: .boolTrue))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<[Api.MessageViews]?, NoError> in |> `catch` { _ -> Signal<[Int32]?, NoError> in
return .single(nil) return .single(nil)
} }
|> mapToSignal { viewCounts -> Signal<Void, NoError> in |> mapToSignal { viewCounts -> Signal<Void, NoError> in
@ -599,7 +599,20 @@ public final class AccountViewTracker {
return account.postbox.transaction { transaction -> Void in return account.postbox.transaction { transaction -> Void in
for i in 0 ..< messageIds.count { for i in 0 ..< messageIds.count {
if i < viewCounts.count { if i < viewCounts.count {
if case let .messageViews(views, forwards) = viewCounts[i] { let views = viewCounts[i]
do {
transaction.updateMessage(messageIds[i], update: { currentMessage in
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
var attributes = currentMessage.attributes
loop: for j in 0 ..< attributes.count {
if let attribute = attributes[j] as? ViewCountMessageAttribute {
attributes[j] = ViewCountMessageAttribute(count: max(attribute.count, Int(views)))
}
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
}
/*if case let .messageViews(views, forwards) = viewCounts[i] {
transaction.updateMessage(messageIds[i], update: { currentMessage in transaction.updateMessage(messageIds[i], update: { currentMessage in
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init) let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
var attributes = currentMessage.attributes var attributes = currentMessage.attributes
@ -613,7 +626,7 @@ public final class AccountViewTracker {
} }
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
}) })
} }*/
} }
} }
} }

View File

@ -108,10 +108,7 @@ public struct CallSessionRingingState: Equatable {
public let id: CallSessionInternalId public let id: CallSessionInternalId
public let peerId: PeerId public let peerId: PeerId
public let isVideo: Bool public let isVideo: Bool
public let isVideoPossible: Bool
public static func ==(lhs: CallSessionRingingState, rhs: CallSessionRingingState) -> Bool {
return lhs.id == rhs.id && lhs.peerId == rhs.peerId && lhs.isVideo == rhs.isVideo
}
} }
public enum DropCallReason { public enum DropCallReason {
@ -191,18 +188,79 @@ public struct CallSession {
public let state: CallSessionState public let state: CallSessionState
} }
public struct CallSessionConnection { public enum CallSessionConnection: Equatable {
public let id: Int64 public struct Reflector: Equatable {
public let ip: String public let id: Int64
public let ipv6: String public let ip: String
public let port: Int32 public let ipv6: String
public let peerTag: Data public let port: Int32
public let peerTag: Data
public init(
id: Int64,
ip: String,
ipv6: String,
port: Int32,
peerTag: Data
) {
self.id = id
self.ip = ip
self.ipv6 = ipv6
self.port = port
self.peerTag = peerTag
}
}
public struct WebRtcReflector: Equatable {
public let id: Int64
public let hasStun: Bool
public let hasTurn: Bool
public let ip: String
public let ipv6: String
public let port: Int32
public let username: String
public let password: String
public init(
id: Int64,
hasStun: Bool,
hasTurn: Bool,
ip: String,
ipv6: String,
port: Int32,
username: String,
password: String
) {
self.id = id
self.hasStun = hasStun
self.hasTurn = hasTurn
self.ip = ip
self.ipv6 = ipv6
self.port = port
self.username = username
self.password = password
}
}
case reflector(Reflector)
case webRtcReflector(WebRtcReflector)
} }
private func parseConnection(_ apiConnection: Api.PhoneConnection) -> CallSessionConnection { private func parseConnection(_ apiConnection: Api.PhoneConnection) -> CallSessionConnection {
switch apiConnection { switch apiConnection {
case let .phoneConnection(id, ip, ipv6, port, peerTag): case let .phoneConnection(id, ip, ipv6, port, peerTag):
return CallSessionConnection(id: id, ip: ip, ipv6: ipv6, port: port, peerTag: peerTag.makeData()) return .reflector(CallSessionConnection.Reflector(id: id, ip: ip, ipv6: ipv6, port: port, peerTag: peerTag.makeData()))
case let .phoneConnectionWebrtc(flags, id, ip, ipv6, port, username, password):
return .webRtcReflector(CallSessionConnection.WebRtcReflector(
id: id,
hasStun: (flags & (1 << 1)) != 0,
hasTurn: (flags & (1 << 0)) != 0,
ip: ip,
ipv6: ipv6,
port: port,
username: username,
password: password
))
} }
} }
@ -219,6 +277,7 @@ private final class CallSessionContext {
let peerId: PeerId let peerId: PeerId
let isOutgoing: Bool let isOutgoing: Bool
var type: CallSession.CallType var type: CallSession.CallType
let isVideoPossible: Bool
var state: CallSessionInternalState var state: CallSessionInternalState
let subscribers = Bag<(CallSession) -> Void>() let subscribers = Bag<(CallSession) -> Void>()
let signalingSubscribers = Bag<(Data) -> Void>() let signalingSubscribers = Bag<(Data) -> Void>()
@ -235,10 +294,11 @@ private final class CallSessionContext {
} }
} }
init(peerId: PeerId, isOutgoing: Bool, type: CallSession.CallType, state: CallSessionInternalState) { init(peerId: PeerId, isOutgoing: Bool, type: CallSession.CallType, isVideoPossible: Bool, state: CallSessionInternalState) {
self.peerId = peerId self.peerId = peerId
self.isOutgoing = isOutgoing self.isOutgoing = isOutgoing
self.type = type self.type = type
self.isVideoPossible = isVideoPossible
self.state = state self.state = state
} }
@ -247,8 +307,8 @@ private final class CallSessionContext {
} }
} }
private func selectVersionOnAccept(localVersions: [String], remoteVersions: [String]) -> [String]? { private func selectVersionOnAccept(localVersions: [CallSessionManagerImplementationVersion], remoteVersions: [String]) -> [String]? {
let filteredVersions = localVersions.filter(remoteVersions.contains) let filteredVersions = localVersions.map(\.version).filter(remoteVersions.contains)
if filteredVersions.isEmpty { if filteredVersions.isEmpty {
return nil return nil
} else { } else {
@ -256,12 +316,22 @@ private func selectVersionOnAccept(localVersions: [String], remoteVersions: [Str
} }
} }
public struct CallSessionManagerImplementationVersion: Hashable {
public var version: String
public var supportsVideo: Bool
public init(version: String, supportsVideo: Bool) {
self.version = version
self.supportsVideo = supportsVideo
}
}
private final class CallSessionManagerContext { private final class CallSessionManagerContext {
private let queue: Queue private let queue: Queue
private let postbox: Postbox private let postbox: Postbox
private let network: Network private let network: Network
private let maxLayer: Int32 private let maxLayer: Int32
private var versions: [String] private var versions: [CallSessionManagerImplementationVersion]
private let addUpdates: (Api.Updates) -> Void private let addUpdates: (Api.Updates) -> Void
private let ringingSubscribers = Bag<([CallSessionRingingState]) -> Void>() private let ringingSubscribers = Bag<([CallSessionRingingState]) -> Void>()
@ -270,7 +340,7 @@ private final class CallSessionManagerContext {
private let disposables = DisposableSet() private let disposables = DisposableSet()
init(queue: Queue, postbox: Postbox, network: Network, maxLayer: Int32, versions: [String], addUpdates: @escaping (Api.Updates) -> Void) { init(queue: Queue, postbox: Postbox, network: Network, maxLayer: Int32, versions: [CallSessionManagerImplementationVersion], addUpdates: @escaping (Api.Updates) -> Void) {
self.queue = queue self.queue = queue
self.postbox = postbox self.postbox = postbox
self.network = network self.network = network
@ -284,10 +354,32 @@ private final class CallSessionManagerContext {
self.disposables.dispose() self.disposables.dispose()
} }
func updateVersions(versions: [String]) { func updateVersions(versions: [CallSessionManagerImplementationVersion]) {
self.versions = versions.reversed() self.versions = versions.reversed()
} }
func filteredVersions(enableVideo: Bool) -> [String] {
return self.versions.compactMap { version -> String? in
if enableVideo {
return version.version
} else if !version.supportsVideo {
return version.version
} else {
return nil
}
}
}
func videoVersions() -> [String] {
return self.versions.compactMap { version -> String? in
if version.supportsVideo {
return version.version
} else {
return nil
}
}
}
func ringingStates() -> Signal<[CallSessionRingingState], NoError> { func ringingStates() -> Signal<[CallSessionRingingState], NoError> {
let queue = self.queue let queue = self.queue
return Signal { [weak self] subscriber in return Signal { [weak self] subscriber in
@ -366,7 +458,7 @@ private final class CallSessionManagerContext {
var ringingContexts: [CallSessionRingingState] = [] var ringingContexts: [CallSessionRingingState] = []
for (id, context) in self.contexts { for (id, context) in self.contexts {
if case .ringing = context.state { if case .ringing = context.state {
ringingContexts.append(CallSessionRingingState(id: id, peerId: context.peerId, isVideo: context.type == .video)) ringingContexts.append(CallSessionRingingState(id: id, peerId: context.peerId, isVideo: context.type == .video, isVideoPossible: context.isVideoPossible))
} }
} }
return ringingContexts return ringingContexts
@ -398,8 +490,13 @@ private final class CallSessionManagerContext {
let b = Data(bytesNoCopy: bBytes, count: 256, deallocator: .free) let b = Data(bytesNoCopy: bBytes, count: 256, deallocator: .free)
if randomStatus == 0 { if randomStatus == 0 {
var isVideoPossible = self.videoVersions().contains(where: { versions.contains($0) })
#if DEBUG
isVideoPossible = true
#endif
let internalId = CallSessionInternalId() let internalId = CallSessionInternalId()
let context = CallSessionContext(peerId: peerId, isOutgoing: false, type: isVideo ? .video : .audio, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions)) let context = CallSessionContext(peerId: peerId, isOutgoing: false, type: isVideo ? .video : .audio, isVideoPossible: isVideoPossible, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions))
self.contexts[internalId] = context self.contexts[internalId] = context
let queue = self.queue let queue = self.queue
context.acknowledgeIncomingCallDisposable.set(self.network.request(Api.functions.phone.receivedCall(peer: .inputPhoneCall(id: stableId, accessHash: accessHash))).start(error: { [weak self] _ in context.acknowledgeIncomingCallDisposable.set(self.network.request(Api.functions.phone.receivedCall(peer: .inputPhoneCall(id: stableId, accessHash: accessHash))).start(error: { [weak self] _ in
@ -529,11 +626,7 @@ private final class CallSessionManagerContext {
if let context = self.contexts[internalId] { if let context = self.contexts[internalId] {
switch context.state { switch context.state {
case let .ringing(id, accessHash, gAHash, b, remoteVersions): case let .ringing(id, accessHash, gAHash, b, remoteVersions):
guard var acceptVersions = selectVersionOnAccept(localVersions: self.versions, remoteVersions: remoteVersions) else { let acceptVersions = self.versions.map(\.version)
self.drop(internalId: internalId, reason: .disconnect, debugLog: .single(nil))
return
}
acceptVersions = self.versions
context.state = .accepting(id: id, accessHash: accessHash, gAHash: gAHash, b: b, disposable: (acceptCallSession(postbox: self.postbox, network: self.network, stableId: id, accessHash: accessHash, b: b, maxLayer: self.maxLayer, versions: acceptVersions) |> deliverOn(self.queue)).start(next: { [weak self] result in context.state = .accepting(id: id, accessHash: accessHash, gAHash: gAHash, b: b, disposable: (acceptCallSession(postbox: self.postbox, network: self.network, stableId: id, accessHash: accessHash, b: b, maxLayer: self.maxLayer, versions: acceptVersions) |> deliverOn(self.queue)).start(next: { [weak self] result in
if let strongSelf = self, let context = strongSelf.contexts[internalId] { if let strongSelf = self, let context = strongSelf.contexts[internalId] {
if case .accepting = context.state { if case .accepting = context.state {
@ -819,12 +912,12 @@ private final class CallSessionManagerContext {
return (key, keyId, keyVisualHash) return (key, keyId, keyVisualHash)
} }
func request(peerId: PeerId, internalId: CallSessionInternalId, isVideo: Bool) -> CallSessionInternalId? { func request(peerId: PeerId, internalId: CallSessionInternalId, isVideo: Bool, enableVideo: Bool) -> CallSessionInternalId? {
let aBytes = malloc(256)! let aBytes = malloc(256)!
let randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self)) let randomStatus = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self))
let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free) let a = Data(bytesNoCopy: aBytes, count: 256, deallocator: .free)
if randomStatus == 0 { if randomStatus == 0 {
self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, type: isVideo ? .video : .audio, state: .requesting(a: a, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer, versions: self.versions, isVideo: isVideo) |> deliverOn(queue)).start(next: { [weak self] result in self.contexts[internalId] = CallSessionContext(peerId: peerId, isOutgoing: true, type: isVideo ? .video : .audio, isVideoPossible: enableVideo || isVideo, state: .requesting(a: a, disposable: (requestCallSession(postbox: self.postbox, network: self.network, peerId: peerId, a: a, maxLayer: self.maxLayer, versions: self.filteredVersions(enableVideo: enableVideo), isVideo: isVideo) |> deliverOn(queue)).start(next: { [weak self] result in
if let strongSelf = self, let context = strongSelf.contexts[internalId] { if let strongSelf = self, let context = strongSelf.contexts[internalId] {
if case .requesting = context.state { if case .requesting = context.state {
switch result { switch result {
@ -858,7 +951,7 @@ public final class CallSessionManager {
private let queue = Queue() private let queue = Queue()
private var contextRef: Unmanaged<CallSessionManagerContext>? private var contextRef: Unmanaged<CallSessionManagerContext>?
init(postbox: Postbox, network: Network, maxLayer: Int32, versions: [String], addUpdates: @escaping (Api.Updates) -> Void) { init(postbox: Postbox, network: Network, maxLayer: Int32, versions: [CallSessionManagerImplementationVersion], addUpdates: @escaping (Api.Updates) -> Void) {
self.queue.async { self.queue.async {
let context = CallSessionManagerContext(queue: self.queue, postbox: postbox, network: network, maxLayer: maxLayer, versions: versions, addUpdates: addUpdates) let context = CallSessionManagerContext(queue: self.queue, postbox: postbox, network: network, maxLayer: maxLayer, versions: versions, addUpdates: addUpdates)
self.contextRef = Unmanaged.passRetained(context) self.contextRef = Unmanaged.passRetained(context)
@ -917,12 +1010,12 @@ public final class CallSessionManager {
} }
} }
public func request(peerId: PeerId, isVideo: Bool, internalId: CallSessionInternalId = CallSessionInternalId()) -> Signal<CallSessionInternalId, NoError> { public func request(peerId: PeerId, isVideo: Bool, enableVideo: Bool, internalId: CallSessionInternalId = CallSessionInternalId()) -> Signal<CallSessionInternalId, NoError> {
return Signal { [weak self] subscriber in return Signal { [weak self] subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
self?.withContext { context in self?.withContext { context in
if let internalId = context.request(peerId: peerId, internalId: internalId, isVideo: isVideo) { if let internalId = context.request(peerId: peerId, internalId: internalId, isVideo: isVideo, enableVideo: enableVideo) {
subscriber.putNext(internalId) subscriber.putNext(internalId)
subscriber.putCompletion() subscriber.putCompletion()
} }
@ -944,7 +1037,7 @@ public final class CallSessionManager {
} }
} }
public func updateVersions(versions: [String]) { public func updateVersions(versions: [CallSessionManagerImplementationVersion]) {
self.withContext { context in self.withContext { context in
context.updateVersions(versions: versions) context.updateVersions(versions: versions)
} }

View File

@ -39,7 +39,8 @@ public struct MessageStatsContextState: Equatable {
} }
private func requestMessageStats(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId, dark: Bool = false) -> Signal<MessageStats?, NoError> { private func requestMessageStats(postbox: Postbox, network: Network, datacenterId: Int32, messageId: MessageId, dark: Bool = false) -> Signal<MessageStats?, NoError> {
return postbox.transaction { transaction -> (Peer, Message)? in return .single(nil)
/*return postbox.transaction { transaction -> (Peer, Message)? in
if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) { if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) {
return (peer, message) return (peer, message)
} else { } else {
@ -86,7 +87,7 @@ private func requestMessageStats(postbox: Postbox, network: Network, datacenterI
} }
} }
|> retryRequest |> retryRequest
} }*/
} }
private final class MessageStatsContextImpl { private final class MessageStatsContextImpl {

View File

@ -403,12 +403,12 @@ public struct NetworkInitializationArguments {
public let languagesCategory: String public let languagesCategory: String
public let appVersion: String public let appVersion: String
public let voipMaxLayer: Int32 public let voipMaxLayer: Int32
public let voipVersions: [String] public let voipVersions: [CallSessionManagerImplementationVersion]
public let appData: Signal<Data?, NoError> public let appData: Signal<Data?, NoError>
public let autolockDeadine: Signal<Int32?, NoError> public let autolockDeadine: Signal<Int32?, NoError>
public let encryptionProvider: EncryptionProvider public let encryptionProvider: EncryptionProvider
public init(apiId: Int32, apiHash: String, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, voipVersions: [String], appData: Signal<Data?, NoError>, autolockDeadine: Signal<Int32?, NoError>, encryptionProvider: EncryptionProvider) { public init(apiId: Int32, apiHash: String, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, voipVersions: [CallSessionManagerImplementationVersion], appData: Signal<Data?, NoError>, autolockDeadine: Signal<Int32?, NoError>, encryptionProvider: EncryptionProvider) {
self.apiId = apiId self.apiId = apiId
self.apiHash = apiHash self.apiHash = apiHash
self.languagesCategory = languagesCategory self.languagesCategory = languagesCategory

View File

@ -292,7 +292,8 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
} }
} }
case let .publicForwards(messageId, datacenterId): case let .publicForwards(messageId, datacenterId):
remoteSearchResult = account.postbox.transaction { transaction -> (Api.InputChannel?, Int32, MessageIndex?, Api.InputPeer) in remoteSearchResult = .single((nil, nil))
/*remoteSearchResult = account.postbox.transaction { transaction -> (Api.InputChannel?, Int32, MessageIndex?, Api.InputPeer) in
let sourcePeer = transaction.getPeer(messageId.peerId) let sourcePeer = transaction.getPeer(messageId.peerId)
let inputChannel = sourcePeer.flatMap { apiInputChannel($0) } let inputChannel = sourcePeer.flatMap { apiInputChannel($0) }
@ -329,7 +330,7 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
|> `catch` { _ -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in |> `catch` { _ -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in
return .single((nil, nil)) return .single((nil, nil))
} }
} }*/
} }
return remoteSearchResult return remoteSearchResult

View File

@ -136,7 +136,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
switch message { switch message {
case let .message(flags, _, fromId, toId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _, _): case let .message(flags, _, fromId, toId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _):
let peerId: PeerId let peerId: PeerId
switch toId { switch toId {
case let .peerUser(userId): case let .peerUser(userId):
@ -240,7 +240,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? { func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? {
switch message { switch message {
case let .message(flags, _, fromId, toId, _, _, replyToMsgId, _, _, _, _, _, _, _, _, _, _, _): case let .message(flags, _, fromId, toId, _, _, replyToMsgId, _, _, _, _, _, _, _, _, _, _):
if let replyToMsgId = replyToMsgId { if let replyToMsgId = replyToMsgId {
let peerId: PeerId let peerId: PeerId
switch toId { switch toId {
@ -398,7 +398,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
extension StoreMessage { extension StoreMessage {
convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) { convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
switch apiMessage { switch apiMessage {
case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, forwards, editDate, postAuthor, groupingId, restrictionReason): case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, editDate, postAuthor, groupingId, restrictionReason):
let peerId: PeerId let peerId: PeerId
var authorId: PeerId? var authorId: PeerId?
switch toId { switch toId {
@ -521,9 +521,9 @@ extension StoreMessage {
attributes.append(ViewCountMessageAttribute(count: Int(views))) attributes.append(ViewCountMessageAttribute(count: Int(views)))
} }
if let forwards = forwards, namespace != Namespaces.Message.ScheduledCloud { /*if let forwards = forwards, namespace != Namespaces.Message.ScheduledCloud {
attributes.append(ForwardCountMessageAttribute(count: Int(forwards))) attributes.append(ForwardCountMessageAttribute(count: Int(forwards)))
} }*/
if let editDate = editDate { if let editDate = editDate {
attributes.append(EditedMessageAttribute(date: editDate, isHidden: (flags & (1 << 21)) != 0)) attributes.append(EditedMessageAttribute(date: editDate, isHidden: (flags & (1 << 21)) != 0))

View File

@ -193,7 +193,11 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
case let .userFull(userFull): case let .userFull(userFull):
let botInfo = userFull.botInfo.flatMap(BotInfo.init(apiBotInfo:)) let botInfo = userFull.botInfo.flatMap(BotInfo.init(apiBotInfo:))
let isBlocked = (userFull.flags & (1 << 0)) != 0 let isBlocked = (userFull.flags & (1 << 0)) != 0
let callsAvailable = (userFull.flags & (1 << 4)) != 0 let voiceCallsAvailable = (userFull.flags & (1 << 4)) != 0
var videoCallsAvailable = (userFull.flags & (1 << 13)) != 0
#if DEBUG
videoCallsAvailable = true
#endif
let callsPrivate = (userFull.flags & (1 << 5)) != 0 let callsPrivate = (userFull.flags & (1 << 5)) != 0
let canPinMessages = (userFull.flags & (1 << 7)) != 0 let canPinMessages = (userFull.flags & (1 << 7)) != 0
let pinnedMessageId = userFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) let pinnedMessageId = userFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
@ -205,7 +209,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
hasScheduledMessages = true hasScheduledMessages = true
} }
return previous.withUpdatedAbout(userFull.about).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFull.commonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedCallsAvailable(callsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages) return previous.withUpdatedAbout(userFull.about).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFull.commonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
} }
}) })
return true return true

View File

@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
self.putNext(groups) self.putNext(groups)
} }
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyToMsgId, entities): case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyToMsgId, entities):
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: fromId, toId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil) let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: fromId, toId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 { if groups.count != 0 {
@ -75,7 +75,7 @@ class UpdateMessageService: NSObject, MTMessageService {
generatedToId = Api.Peer.peerUser(userId: self.peerId.id) generatedToId = Api.Peer.peerUser(userId: self.peerId.id)
} }
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, toId: generatedToId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil) let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, toId: generatedToId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount) let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil) let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 { if groups.count != 0 {

View File

@ -141,11 +141,18 @@ public final class AccountContextImpl: AccountContext {
return self._contentSettings.get() return self._contentSettings.get()
} }
public var currentAppConfiguration: Atomic<AppConfiguration>
private let _appConfiguration = Promise<AppConfiguration>()
public var appConfiguration: Signal<AppConfiguration, NoError> {
return self._appConfiguration.get()
}
public var watchManager: WatchManager? public var watchManager: WatchManager?
private var storedPassword: (String, CFAbsoluteTime, SwiftSignalKit.Timer)? private var storedPassword: (String, CFAbsoluteTime, SwiftSignalKit.Timer)?
private var limitsConfigurationDisposable: Disposable? private var limitsConfigurationDisposable: Disposable?
private var contentSettingsDisposable: Disposable? private var contentSettingsDisposable: Disposable?
private var appConfigurationDisposable: Disposable?
private let deviceSpecificContactImportContexts: QueueLocalObject<DeviceSpecificContactImportContexts> private let deviceSpecificContactImportContexts: QueueLocalObject<DeviceSpecificContactImportContexts>
private var managedAppSpecificContactsDisposable: Disposable? private var managedAppSpecificContactsDisposable: Disposable?
@ -177,7 +184,7 @@ public final class AccountContextImpl: AccountContext {
} }
#endif #endif
public init(sharedContext: SharedAccountContextImpl, account: Account, /*tonContext: StoredTonContext?, */limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, temp: Bool = false) public init(sharedContext: SharedAccountContextImpl, account: Account, /*tonContext: StoredTonContext?, */limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, appConfiguration: AppConfiguration, temp: Bool = false)
{ {
self.sharedContextImpl = sharedContext self.sharedContextImpl = sharedContext
self.account = account self.account = account
@ -233,6 +240,16 @@ public final class AccountContextImpl: AccountContext {
let _ = currentContentSettings.swap(value) let _ = currentContentSettings.swap(value)
}) })
let updatedAppConfiguration = getAppConfiguration(postbox: account.postbox)
self.currentAppConfiguration = Atomic(value: appConfiguration)
self._appConfiguration.set(.single(appConfiguration) |> then(updatedAppConfiguration))
let currentAppConfiguration = self.currentAppConfiguration
self.appConfigurationDisposable = (self._appConfiguration.get()
|> deliverOnMainQueue).start(next: { value in
let _ = currentAppConfiguration.swap(value)
})
let queue = Queue() let queue = Queue()
self.deviceSpecificContactImportContexts = QueueLocalObject(queue: queue, generate: { self.deviceSpecificContactImportContexts = QueueLocalObject(queue: queue, generate: {
return DeviceSpecificContactImportContexts(queue: queue) return DeviceSpecificContactImportContexts(queue: queue)
@ -248,11 +265,8 @@ public final class AccountContextImpl: AccountContext {
}) })
} }
self.experimentalUISettingsDisposable = (sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.experimentalUISettings]) account.callSessionManager.updateVersions(versions: PresentationCallManagerImpl.voipVersions(includeExperimental: true, includeReference: false).map { version, supportsVideo -> CallSessionManagerImplementationVersion in
|> deliverOnMainQueue).start(next: { sharedData in CallSessionManagerImplementationVersion(version: version, supportsVideo: supportsVideo)
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings {
account.callSessionManager.updateVersions(versions: PresentationCallManagerImpl.voipVersions(includeExperimental: settings.videoCalls, includeReference: settings.videoCallsReference))
}
}) })
} }
@ -260,6 +274,7 @@ public final class AccountContextImpl: AccountContext {
self.limitsConfigurationDisposable?.dispose() self.limitsConfigurationDisposable?.dispose()
self.managedAppSpecificContactsDisposable?.dispose() self.managedAppSpecificContactsDisposable?.dispose()
self.contentSettingsDisposable?.dispose() self.contentSettingsDisposable?.dispose()
self.appConfigurationDisposable?.dispose()
self.experimentalUISettingsDisposable?.dispose() self.experimentalUISettingsDisposable?.dispose()
} }
@ -284,3 +299,17 @@ public final class AccountContextImpl: AccountContext {
} }
} }
} }
func getAppConfiguration(transaction: Transaction) -> AppConfiguration {
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue
return appConfiguration
}
func getAppConfiguration(postbox: Postbox) -> Signal<AppConfiguration, NoError> {
return postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { view -> AppConfiguration in
let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue
return appConfiguration
}
|> distinctUntilChanged
}

View File

@ -401,7 +401,9 @@ final class SharedApplicationContext {
} }
} }
let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManagerImpl.voipMaxLayer, voipVersions: PresentationCallManagerImpl.voipVersions(includeExperimental: false, includeReference: false), appData: self.deviceToken.get() let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManagerImpl.voipMaxLayer, voipVersions: PresentationCallManagerImpl.voipVersions(includeExperimental: true, includeReference: false).map { version, supportsVideo -> CallSessionManagerImplementationVersion in
CallSessionManagerImplementationVersion(version: version, supportsVideo: supportsVideo)
}, appData: self.deviceToken.get()
|> map { token in |> map { token in
let data = buildConfig.bundleData(withAppToken: token, signatureDict: signatureDict) let data = buildConfig.bundleData(withAppToken: token, signatureDict: signatureDict)
if let data = data, let jsonString = String(data: data, encoding: .utf8) { if let data = data, let jsonString = String(data: data, encoding: .utf8) {
@ -990,7 +992,7 @@ final class SharedApplicationContext {
} }
return true return true
}) })
|> mapToSignal { account -> Signal<(Account, LimitsConfiguration, CallListSettings, ContentSettings)?, NoError> in |> mapToSignal { account -> Signal<(Account, LimitsConfiguration, CallListSettings, ContentSettings, AppConfiguration)?, NoError> in
return sharedApplicationContext.sharedContext.accountManager.transaction { transaction -> CallListSettings? in return sharedApplicationContext.sharedContext.accountManager.transaction { transaction -> CallListSettings? in
return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings
} }
@ -1003,12 +1005,13 @@ final class SharedApplicationContext {
} }
return result return result
} }
|> mapToSignal { callListSettings -> Signal<(Account, LimitsConfiguration, CallListSettings, ContentSettings)?, NoError> in |> mapToSignal { callListSettings -> Signal<(Account, LimitsConfiguration, CallListSettings, ContentSettings, AppConfiguration)?, NoError> in
if let account = account { if let account = account {
return account.postbox.transaction { transaction -> (Account, LimitsConfiguration, CallListSettings, ContentSettings)? in return account.postbox.transaction { transaction -> (Account, LimitsConfiguration, CallListSettings, ContentSettings, AppConfiguration)? in
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue
let contentSettings = getContentSettings(transaction: transaction) let contentSettings = getContentSettings(transaction: transaction)
return (account, limitsConfiguration, callListSettings ?? CallListSettings.defaultSettings, contentSettings) let appConfiguration = getAppConfiguration(transaction: transaction)
return (account, limitsConfiguration, callListSettings ?? CallListSettings.defaultSettings, contentSettings, appConfiguration)
} }
} else { } else {
return .single(nil) return .single(nil)
@ -1017,11 +1020,8 @@ final class SharedApplicationContext {
} }
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { accountAndSettings -> AuthorizedApplicationContext? in |> map { accountAndSettings -> AuthorizedApplicationContext? in
return accountAndSettings.flatMap { account, limitsConfiguration, callListSettings, contentSettings in return accountAndSettings.flatMap { account, limitsConfiguration, callListSettings, contentSettings, appConfiguration in
#if ENABLE_WALLET let context = AccountContextImpl(sharedContext: sharedApplicationContext.sharedContext, account: account, limitsConfiguration: limitsConfiguration, contentSettings: contentSettings, appConfiguration: appConfiguration)
let tonContext = StoredTonContext(basePath: account.basePath, postbox: account.postbox, network: account.network, keychain: tonKeychain)
#endif
let context = AccountContextImpl(sharedContext: sharedApplicationContext.sharedContext, account: account/*, tonContext: tonContext*/, limitsConfiguration: limitsConfiguration, contentSettings: contentSettings)
return AuthorizedApplicationContext(sharedApplicationContext: sharedApplicationContext, mainWindow: self.mainWindow, watchManagerArguments: watchManagerArgumentsPromise.get(), context: context, accountManager: sharedApplicationContext.sharedContext.accountManager, showCallsTab: callListSettings.showTab, reinitializedNotificationSettings: { return AuthorizedApplicationContext(sharedApplicationContext: sharedApplicationContext, mainWindow: self.mainWindow, watchManagerArguments: watchManagerArgumentsPromise.get(), context: context, accountManager: sharedApplicationContext.sharedContext.accountManager, showCallsTab: callListSettings.showTab, reinitializedNotificationSettings: {
let _ = (self.context.get() let _ = (self.context.get()
|> take(1) |> take(1)

View File

@ -763,7 +763,7 @@ final class AuthorizedApplicationContext {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let _ = strongSelf.context.sharedContext.callManager?.requestCall(account: strongSelf.context.account, peerId: peerId, isVideo: isVideo, endCurrentIfAny: false) let _ = strongSelf.context.sharedContext.callManager?.requestCall(context: strongSelf.context, peerId: peerId, isVideo: isVideo, endCurrentIfAny: false)
})) }))
} }

View File

@ -1219,7 +1219,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
let callResult = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: false) let callResult = context.sharedContext.callManager?.requestCall(context: context, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: false)
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == peer.id { if currentPeerId == peer.id {
context.sharedContext.navigateToCurrentCall() context.sharedContext.navigateToCurrentCall()
@ -1231,7 +1231,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|> deliverOnMainQueue).start(next: { peer, current in |> deliverOnMainQueue).start(next: { peer, current in
if let peer = peer, let current = current { if let peer = peer, let current = current {
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
let _ = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: true) let _ = context.sharedContext.callManager?.requestCall(context: context, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: true)
})]), in: .window(.root)) })]), in: .window(.root))
} }
}) })
@ -2922,7 +2922,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} else if let cachedData = combinedInitialData.cachedData as? CachedUserData { } else if let cachedData = combinedInitialData.cachedData as? CachedUserData {
peerIsBlocked = cachedData.isBlocked peerIsBlocked = cachedData.isBlocked
callsAvailable = cachedData.callsAvailable callsAvailable = cachedData.voiceCallsAvailable
callsPrivate = cachedData.callsPrivate callsPrivate = cachedData.callsPrivate
pinnedMessageId = cachedData.pinnedMessageId pinnedMessageId = cachedData.pinnedMessageId
} else if let cachedData = combinedInitialData.cachedData as? CachedGroupData { } else if let cachedData = combinedInitialData.cachedData as? CachedGroupData {
@ -3063,7 +3063,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} else if let cachedData = cachedData as? CachedUserData { } else if let cachedData = cachedData as? CachedUserData {
peerIsBlocked = cachedData.isBlocked peerIsBlocked = cachedData.isBlocked
callsAvailable = cachedData.callsAvailable callsAvailable = cachedData.voiceCallsAvailable
callsPrivate = cachedData.callsPrivate callsPrivate = cachedData.callsPrivate
pinnedMessageId = cachedData.pinnedMessageId pinnedMessageId = cachedData.pinnedMessageId
} else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {

View File

@ -911,15 +911,17 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
result.append(.message) result.append(.message)
} }
var callsAvailable = false var callsAvailable = false
var videoCallsAvailable = false
if !user.isDeleted, user.botInfo == nil, !user.flags.contains(.isSupport) { if !user.isDeleted, user.botInfo == nil, !user.flags.contains(.isSupport) {
if let cachedUserData = cachedData as? CachedUserData { if let cachedUserData = cachedData as? CachedUserData {
callsAvailable = cachedUserData.callsAvailable callsAvailable = cachedUserData.voiceCallsAvailable
videoCallsAvailable = cachedUserData.videoCallsAvailable
} }
callsAvailable = true callsAvailable = true
} }
if callsAvailable { if callsAvailable {
result.append(.call) result.append(.call)
if videoCallsEnabled { if videoCallsEnabled && videoCallsAvailable {
result.append(.videoCall) result.append(.videoCall)
} }
} }

View File

@ -2565,7 +2565,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.isAvatarExpanded = avatarInitiallyExpanded self.isAvatarExpanded = avatarInitiallyExpanded
self.isOpenedFromChat = isOpenedFromChat self.isOpenedFromChat = isOpenedFromChat
self.isSettings = isSettings self.isSettings = isSettings
self.videoCallsEnabled = context.sharedContext.immediateExperimentalUISettings.videoCalls self.videoCallsEnabled = VideoCallsConfiguration(appConfiguration: context.currentAppConfiguration.with { $0 }).areVideoCallsEnabled
self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded) self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded)

View File

@ -1422,7 +1422,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
self.isOpenedFromChat = isOpenedFromChat self.isOpenedFromChat = isOpenedFromChat
self.videoCallsEnabled = context.sharedContext.immediateExperimentalUISettings.videoCalls self.videoCallsEnabled = VideoCallsConfiguration(appConfiguration: context.currentAppConfiguration.with { $0 }).areVideoCallsEnabled
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.nearbyPeerDistance = nearbyPeerDistance self.nearbyPeerDistance = nearbyPeerDistance
self.callMessages = callMessages self.callMessages = callMessages
@ -3153,7 +3153,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
return return
} }
let callResult = self.context.sharedContext.callManager?.requestCall(account: self.context.account, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: false) let callResult = self.context.sharedContext.callManager?.requestCall(context: self.context, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: false)
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if currentPeerId == peer.id { if currentPeerId == peer.id {
self.context.sharedContext.navigateToCurrentCall() self.context.sharedContext.navigateToCurrentCall()
@ -3170,7 +3170,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let _ = strongSelf.context.sharedContext.callManager?.requestCall(account: strongSelf.context.account, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: true) let _ = strongSelf.context.sharedContext.callManager?.requestCall(context: strongSelf.context, peerId: peer.id, isVideo: isVideo, endCurrentIfAny: true)
})]), in: .window(.root)) })]), in: .window(.root))
} }
}) })

View File

@ -260,10 +260,11 @@ public class ShareRootControllerImpl {
let applicationInterface = account let applicationInterface = account
|> mapToSignal { sharedContext, account, otherAccounts -> Signal<(AccountContext, PostboxAccessChallengeData, [AccountWithInfo]), ShareAuthorizationError> in |> mapToSignal { sharedContext, account, otherAccounts -> Signal<(AccountContext, PostboxAccessChallengeData, [AccountWithInfo]), ShareAuthorizationError> in
let limitsConfigurationAndContentSettings = account.postbox.transaction { transaction -> (LimitsConfiguration, ContentSettings) in let limitsConfigurationAndContentSettings = account.postbox.transaction { transaction -> (LimitsConfiguration, ContentSettings, AppConfiguration) in
return ( return (
transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue, transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue,
getContentSettings(transaction: transaction) getContentSettings(transaction: transaction),
getAppConfiguration(transaction: transaction)
) )
} }
return combineLatest(sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), limitsConfigurationAndContentSettings, sharedContext.accountManager.accessChallengeData()) return combineLatest(sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), limitsConfigurationAndContentSettings, sharedContext.accountManager.accessChallengeData())
@ -272,7 +273,7 @@ public class ShareRootControllerImpl {
|> castError(ShareAuthorizationError.self) |> castError(ShareAuthorizationError.self)
|> map { sharedData, limitsConfigurationAndContentSettings, data -> (AccountContext, PostboxAccessChallengeData, [AccountWithInfo]) in |> map { sharedData, limitsConfigurationAndContentSettings, data -> (AccountContext, PostboxAccessChallengeData, [AccountWithInfo]) in
updateLegacyLocalization(strings: sharedContext.currentPresentationData.with({ $0 }).strings) updateLegacyLocalization(strings: sharedContext.currentPresentationData.with({ $0 }).strings)
let context = AccountContextImpl(sharedContext: sharedContext, account: account/*, tonContext: nil*/, limitsConfiguration: limitsConfigurationAndContentSettings.0, contentSettings: limitsConfigurationAndContentSettings.1) let context = AccountContextImpl(sharedContext: sharedContext, account: account, limitsConfiguration: limitsConfigurationAndContentSettings.0, contentSettings: limitsConfigurationAndContentSettings.1, appConfiguration: limitsConfigurationAndContentSettings.2)
return (context, data.data, otherAccounts) return (context, data.data, otherAccounts)
} }
} }

View File

@ -574,7 +574,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}) })
if let mainWindow = mainWindow, applicationBindings.isMainApp { if let mainWindow = mainWindow, applicationBindings.isMainApp {
let callManager = PresentationCallManagerImpl(accountManager: self.accountManager, enableVideoCalls: self.immediateExperimentalUISettings.videoCalls, getDeviceAccessData: { let callManager = PresentationCallManagerImpl(accountManager: self.accountManager, getDeviceAccessData: {
return (self.currentPresentationData.with { $0 }, { [weak self] c, a in return (self.currentPresentationData.with { $0 }, { [weak self] c, a in
self?.presentGlobalController(c, a) self?.presentGlobalController(c, a)
}, { }, {
@ -937,7 +937,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
} }
public func makeTempAccountContext(account: Account) -> AccountContext { public func makeTempAccountContext(account: Account) -> AccountContext {
return AccountContextImpl(sharedContext: self, account: account/*, tonContext: nil*/, limitsConfiguration: .defaultValue, contentSettings: .default, temp: true) return AccountContextImpl(sharedContext: self, account: account, limitsConfiguration: .defaultValue, contentSettings: .default, appConfiguration: .defaultValue, temp: true)
} }
public func openChatMessage(_ params: OpenChatMessageParams) -> Bool { public func openChatMessage(_ params: OpenChatMessageParams) -> Bool {

View File

@ -9,8 +9,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
public var chatListPhotos: Bool public var chatListPhotos: Bool
public var knockoutWallpaper: Bool public var knockoutWallpaper: Bool
public var foldersTabAtBottom: Bool public var foldersTabAtBottom: Bool
public var videoCalls: Bool public var enableHighBitrateVideoCalls: Bool
public var videoCallsReference: Bool
public var playerEmbedding: Bool public var playerEmbedding: Bool
public var playlistPlayback: Bool public var playlistPlayback: Bool
@ -22,8 +21,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
chatListPhotos: false, chatListPhotos: false,
knockoutWallpaper: false, knockoutWallpaper: false,
foldersTabAtBottom: false, foldersTabAtBottom: false,
videoCalls: false, enableHighBitrateVideoCalls: false,
videoCallsReference: true,
playerEmbedding: false, playerEmbedding: false,
playlistPlayback: false playlistPlayback: false
) )
@ -36,8 +34,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
chatListPhotos: Bool, chatListPhotos: Bool,
knockoutWallpaper: Bool, knockoutWallpaper: Bool,
foldersTabAtBottom: Bool, foldersTabAtBottom: Bool,
videoCalls: Bool, enableHighBitrateVideoCalls: Bool,
videoCallsReference: Bool,
playerEmbedding: Bool, playerEmbedding: Bool,
playlistPlayback: Bool playlistPlayback: Bool
) { ) {
@ -47,8 +44,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
self.chatListPhotos = chatListPhotos self.chatListPhotos = chatListPhotos
self.knockoutWallpaper = knockoutWallpaper self.knockoutWallpaper = knockoutWallpaper
self.foldersTabAtBottom = foldersTabAtBottom self.foldersTabAtBottom = foldersTabAtBottom
self.videoCalls = videoCalls self.enableHighBitrateVideoCalls = enableHighBitrateVideoCalls
self.videoCallsReference = videoCallsReference
self.playerEmbedding = playerEmbedding self.playerEmbedding = playerEmbedding
self.playlistPlayback = playlistPlayback self.playlistPlayback = playlistPlayback
} }
@ -60,8 +56,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
self.chatListPhotos = decoder.decodeInt32ForKey("chatListPhotos", orElse: 0) != 0 self.chatListPhotos = decoder.decodeInt32ForKey("chatListPhotos", orElse: 0) != 0
self.knockoutWallpaper = decoder.decodeInt32ForKey("knockoutWallpaper", orElse: 0) != 0 self.knockoutWallpaper = decoder.decodeInt32ForKey("knockoutWallpaper", orElse: 0) != 0
self.foldersTabAtBottom = decoder.decodeInt32ForKey("foldersTabAtBottom", orElse: 0) != 0 self.foldersTabAtBottom = decoder.decodeInt32ForKey("foldersTabAtBottom", orElse: 0) != 0
self.videoCalls = decoder.decodeInt32ForKey("videoCalls", orElse: 0) != 0 self.enableHighBitrateVideoCalls = decoder.decodeInt32ForKey("enableHighBitrateVideoCalls", orElse: 0) != 0
self.videoCallsReference = decoder.decodeInt32ForKey("videoCallsReference", orElse: 1) != 0
self.playerEmbedding = decoder.decodeInt32ForKey("playerEmbedding", orElse: 0) != 0 self.playerEmbedding = decoder.decodeInt32ForKey("playerEmbedding", orElse: 0) != 0
self.playlistPlayback = decoder.decodeInt32ForKey("playlistPlayback", orElse: 0) != 0 self.playlistPlayback = decoder.decodeInt32ForKey("playlistPlayback", orElse: 0) != 0
} }
@ -73,8 +68,7 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
encoder.encodeInt32(self.chatListPhotos ? 1 : 0, forKey: "chatListPhotos") encoder.encodeInt32(self.chatListPhotos ? 1 : 0, forKey: "chatListPhotos")
encoder.encodeInt32(self.knockoutWallpaper ? 1 : 0, forKey: "knockoutWallpaper") encoder.encodeInt32(self.knockoutWallpaper ? 1 : 0, forKey: "knockoutWallpaper")
encoder.encodeInt32(self.foldersTabAtBottom ? 1 : 0, forKey: "foldersTabAtBottom") encoder.encodeInt32(self.foldersTabAtBottom ? 1 : 0, forKey: "foldersTabAtBottom")
encoder.encodeInt32(self.videoCalls ? 1 : 0, forKey: "videoCalls") encoder.encodeInt32(self.enableHighBitrateVideoCalls ? 1 : 0, forKey: "enableHighBitrateVideoCalls")
encoder.encodeInt32(self.videoCallsReference ? 1 : 0, forKey: "videoCallsReference")
encoder.encodeInt32(self.playerEmbedding ? 1 : 0, forKey: "playerEmbedding") encoder.encodeInt32(self.playerEmbedding ? 1 : 0, forKey: "playerEmbedding")
encoder.encodeInt32(self.playlistPlayback ? 1 : 0, forKey: "playlistPlayback") encoder.encodeInt32(self.playlistPlayback ? 1 : 0, forKey: "playlistPlayback")
} }

View File

@ -8,20 +8,25 @@ import TelegramUIPreferences
import TgVoip import TgVoip
import TgVoipWebrtc import TgVoipWebrtc
//import TgVoipWebrtcCustom
private func callConnectionDescription(_ connection: CallSessionConnection) -> OngoingCallConnectionDescription { private func callConnectionDescription(_ connection: CallSessionConnection) -> OngoingCallConnectionDescription? {
return OngoingCallConnectionDescription(connectionId: connection.id, ip: connection.ip, ipv6: connection.ipv6, port: connection.port, peerTag: connection.peerTag) switch connection {
case let .reflector(reflector):
return OngoingCallConnectionDescription(connectionId: reflector.id, ip: reflector.ip, ipv6: reflector.ipv6, port: reflector.port, peerTag: reflector.peerTag)
case .webRtcReflector:
return nil
}
} }
private func callConnectionDescriptionWebrtc(_ connection: CallSessionConnection) -> OngoingCallConnectionDescriptionWebrtc { private func callConnectionDescriptionWebrtc(_ connection: CallSessionConnection) -> OngoingCallConnectionDescriptionWebrtc? {
return OngoingCallConnectionDescriptionWebrtc(connectionId: connection.id, ip: connection.ip, ipv6: connection.ipv6, port: connection.port, peerTag: connection.peerTag) switch connection {
case .reflector:
return nil
case let .webRtcReflector(reflector):
return OngoingCallConnectionDescriptionWebrtc(connectionId: reflector.id, hasStun: reflector.hasStun, hasTurn: reflector.hasTurn, ip: reflector.ip.isEmpty ? reflector.ipv6 : reflector.ip, port: reflector.port, username: reflector.username, password: reflector.password)
}
} }
/*private func callConnectionDescriptionWebrtcCustom(_ connection: CallSessionConnection) -> OngoingCallConnectionDescriptionWebrtcCustom {
return OngoingCallConnectionDescriptionWebrtcCustom(connectionId: connection.id, ip: connection.ip, ipv6: connection.ipv6, port: connection.port, peerTag: connection.peerTag)
}*/
private let callLogsLimit = 20 private let callLogsLimit = 20
public func callLogNameForId(id: Int64, account: Account) -> String? { public func callLogNameForId(id: Int64, account: Account) -> String? {
@ -323,6 +328,9 @@ public final class OngoingCallVideoCapturer {
return .rotation0 return .rotation0
}, },
setOnOrientationUpdated: { _ in setOnOrientationUpdated: { _ in
},
setOnIsMirroredUpdated: { [weak view] f in
view?.setOnIsMirroredUpdated(f)
} }
)) ))
} else { } else {
@ -437,17 +445,20 @@ public final class OngoingCallContextPresentationCallVideoView {
public let setOnFirstFrameReceived: ((() -> Void)?) -> Void public let setOnFirstFrameReceived: ((() -> Void)?) -> Void
public let getOrientation: () -> OngoingCallVideoOrientation public let getOrientation: () -> OngoingCallVideoOrientation
public let setOnOrientationUpdated: (((OngoingCallVideoOrientation) -> Void)?) -> Void public let setOnOrientationUpdated: (((OngoingCallVideoOrientation) -> Void)?) -> Void
public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void
public init( public init(
view: UIView, view: UIView,
setOnFirstFrameReceived: @escaping ((() -> Void)?) -> Void, setOnFirstFrameReceived: @escaping ((() -> Void)?) -> Void,
getOrientation: @escaping () -> OngoingCallVideoOrientation, getOrientation: @escaping () -> OngoingCallVideoOrientation,
setOnOrientationUpdated: @escaping (((OngoingCallVideoOrientation) -> Void)?) -> Void setOnOrientationUpdated: @escaping (((OngoingCallVideoOrientation) -> Void)?) -> Void,
setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void
) { ) {
self.view = view self.view = view
self.setOnFirstFrameReceived = setOnFirstFrameReceived self.setOnFirstFrameReceived = setOnFirstFrameReceived
self.getOrientation = getOrientation self.getOrientation = getOrientation
self.setOnOrientationUpdated = setOnOrientationUpdated self.setOnOrientationUpdated = setOnOrientationUpdated
self.setOnIsMirroredUpdated = setOnIsMirroredUpdated
} }
} }
@ -503,15 +514,17 @@ public final class OngoingCallContext {
return OngoingCallThreadLocalContext.maxLayer() return OngoingCallThreadLocalContext.maxLayer()
} }
public static func versions(includeExperimental: Bool, includeReference: Bool) -> [String] { public static func versions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] {
var result: [String] = [OngoingCallThreadLocalContext.version()] var result: [(version: String, supportsVideo: Bool)] = [(OngoingCallThreadLocalContext.version(), false)]
if includeExperimental { if includeExperimental {
result.append(contentsOf: OngoingCallThreadLocalContextWebrtc.versions(withIncludeReference: includeReference)) result.append(contentsOf: OngoingCallThreadLocalContextWebrtc.versions(withIncludeReference: includeReference).map { version -> (version: String, supportsVideo: Bool) in
return (version, true)
})
} }
return result return result
} }
public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, auxiliaryServers: [AuxiliaryServer], initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String) { public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, enableHighBitrateVideoCalls: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String) {
let _ = setupLogs let _ = setupLogs
OngoingCallThreadLocalContext.applyServerConfig(serializedData) OngoingCallThreadLocalContext.applyServerConfig(serializedData)
@ -540,35 +553,33 @@ public final class OngoingCallContext {
break break
} }
} }
var rtcServers: [VoipRtcServerWebrtc] = []
for server in auxiliaryServers {
switch server.connection {
case .stun:
rtcServers.append(VoipRtcServerWebrtc(
host: server.host,
port: Int32(clamping: server.port),
username: "",
password: "",
isTurn: false
))
case let .turn(username, password):
rtcServers.append(VoipRtcServerWebrtc(
host: server.host,
port: Int32(clamping: server.port),
username: username,
password: password,
isTurn: true
))
}
}
let screenSize = UIScreen.main.bounds.size let screenSize = UIScreen.main.bounds.size
let portraitSize = CGSize(width: min(screenSize.width, screenSize.height), height: max(screenSize.width, screenSize.height)) let portraitSize = CGSize(width: min(screenSize.width, screenSize.height), height: max(screenSize.width, screenSize.height))
let preferredAspectRatio = portraitSize.width / portraitSize.height let preferredAspectRatio = portraitSize.width / portraitSize.height
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, rtcServers: rtcServers, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtc(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtc), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in
let unfilteredConnections = [connections.primary] + connections.alternatives
var processedConnections: [CallSessionConnection] = []
var filteredConnections: [OngoingCallConnectionDescriptionWebrtc] = []
for connection in unfilteredConnections {
if processedConnections.contains(connection) {
continue
}
processedConnections.append(connection)
if let mapped = callConnectionDescriptionWebrtc(connection) {
if mapped.ip.isEmpty {
continue
}
filteredConnections.append(mapped)
}
}
let primaryConnection = filteredConnections.first!
let restConnections = Array(filteredConnections[1...])
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: primaryConnection, alternativeConnections: restConnections, maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in
callSessionManager?.sendSignalingData(internalId: internalId, data: data) callSessionManager?.sendSignalingData(internalId: internalId, data: data)
}, videoCapturer: video?.impl, preferredAspectRatio: Float(preferredAspectRatio)) }, videoCapturer: video?.impl, preferredAspectRatio: Float(preferredAspectRatio), enableHighBitrateVideoCalls: enableHighBitrateVideoCalls)
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context)) strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState in context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState in
@ -628,7 +639,7 @@ public final class OngoingCallContext {
break break
} }
} }
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath) let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary)!, alternativeConnections: connections.alternatives.compactMap(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context)) strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { state in context.stateChanged = { state in
@ -775,6 +786,11 @@ public final class OngoingCallContext {
view?.setOnOrientationUpdated { value in view?.setOnOrientationUpdated { value in
f?(OngoingCallVideoOrientation(value)) f?(OngoingCallVideoOrientation(value))
} }
},
setOnIsMirroredUpdated: { [weak view] f in
view?.setOnIsMirroredUpdated { value in
f?(value)
}
} }
)) ))
} else { } else {

View File

@ -13,12 +13,14 @@
@interface OngoingCallConnectionDescriptionWebrtc : NSObject @interface OngoingCallConnectionDescriptionWebrtc : NSObject
@property (nonatomic, readonly) int64_t connectionId; @property (nonatomic, readonly) int64_t connectionId;
@property (nonatomic, readonly) bool hasStun;
@property (nonatomic, readonly) bool hasTurn;
@property (nonatomic, strong, readonly) NSString * _Nonnull ip; @property (nonatomic, strong, readonly) NSString * _Nonnull ip;
@property (nonatomic, strong, readonly) NSString * _Nonnull ipv6;
@property (nonatomic, readonly) int32_t port; @property (nonatomic, readonly) int32_t port;
@property (nonatomic, strong, readonly) NSData * _Nonnull peerTag; @property (nonatomic, strong, readonly) NSString * _Nonnull username;
@property (nonatomic, strong, readonly) NSString * _Nonnull password;
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag; - (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId hasStun:(bool)hasStun hasTurn:(bool)hasTurn ip:(NSString * _Nonnull)ip port:(int32_t)port username:(NSString * _Nonnull)username password:(NSString * _Nonnull)password;
@end @end
@ -81,24 +83,13 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
@end @end
@interface VoipRtcServerWebrtc : NSObject
@property (nonatomic, strong, readonly) NSString * _Nonnull host;
@property (nonatomic, readonly) int32_t port;
@property (nonatomic, strong, readonly) NSString * _Nullable username;
@property (nonatomic, strong, readonly) NSString * _Nullable password;
@property (nonatomic, readonly) bool isTurn;
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password isTurn:(bool)isTurn;
@end
@protocol OngoingCallThreadLocalContextWebrtcVideoView <NSObject> @protocol OngoingCallThreadLocalContextWebrtcVideoView <NSObject>
@property (nonatomic, readonly) OngoingCallVideoOrientationWebrtc orientation; @property (nonatomic, readonly) OngoingCallVideoOrientationWebrtc orientation;
- (void)setOnFirstFrameReceived:(void (^ _Nullable)())onFirstFrameReceived; - (void)setOnFirstFrameReceived:(void (^ _Nullable)())onFirstFrameReceived;
- (void)setOnOrientationUpdated:(void (^ _Nullable)(OngoingCallVideoOrientationWebrtc))onOrientationUpdated; - (void)setOnOrientationUpdated:(void (^ _Nullable)(OngoingCallVideoOrientationWebrtc))onOrientationUpdated;
- (void)setOnIsMirroredUpdated:(void (^ _Nullable)(bool))onIsMirroredUpdated;
@end @end
@ -123,7 +114,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallStateWebrtc, OngoingCallVideoStateWebrtc, OngoingCallRemoteVideoStateWebrtc); @property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallStateWebrtc, OngoingCallVideoStateWebrtc, OngoingCallRemoteVideoStateWebrtc);
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t); @property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy rtcServers:(NSArray<VoipRtcServerWebrtc *> * _Nonnull)rtcServers networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredAspectRatio:(float)preferredAspectRatio; - (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredAspectRatio:(float)preferredAspectRatio enableHighBitrateVideoCalls:(bool)enableHighBitrateVideoCalls;
- (void)beginTermination; - (void)beginTermination;
- (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion; - (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;

View File

@ -22,14 +22,16 @@
@implementation OngoingCallConnectionDescriptionWebrtc @implementation OngoingCallConnectionDescriptionWebrtc
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag { - (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId hasStun:(bool)hasStun hasTurn:(bool)hasTurn ip:(NSString * _Nonnull)ip port:(int32_t)port username:(NSString * _Nonnull)username password:(NSString * _Nonnull)password {
self = [super init]; self = [super init];
if (self != nil) { if (self != nil) {
_connectionId = connectionId; _connectionId = connectionId;
_hasStun = hasStun;
_hasTurn = hasTurn;
_ip = ip; _ip = ip;
_ipv6 = ipv6;
_port = port; _port = port;
_peerTag = peerTag; _username = username;
_password = password;
} }
return self; return self;
} }
@ -74,6 +76,16 @@
} }
} }
- (void)setOnIsMirroredUpdated:(void (^ _Nullable)(bool))onIsMirroredUpdated {
if (onIsMirroredUpdated) {
[self internalSetOnIsMirroredUpdated:^(bool value) {
onIsMirroredUpdated(value);
}];
} else {
[self internalSetOnIsMirroredUpdated:nil];
}
}
@end @end
@interface GLVideoView (VideoViewImpl) <OngoingCallThreadLocalContextWebrtcVideoView, OngoingCallThreadLocalContextWebrtcVideoViewImpl> @interface GLVideoView (VideoViewImpl) <OngoingCallThreadLocalContextWebrtcVideoView, OngoingCallThreadLocalContextWebrtcVideoViewImpl>
@ -102,6 +114,16 @@
} }
} }
- (void)setOnIsMirroredUpdated:(void (^ _Nullable)(bool))onIsMirroredUpdated {
if (onIsMirroredUpdated) {
[self internalSetOnIsMirroredUpdated:^(bool value) {
onIsMirroredUpdated(value);
}];
} else {
[self internalSetOnIsMirroredUpdated:nil];
}
}
@end @end
@implementation OngoingCallThreadLocalContextVideoCapturer @implementation OngoingCallThreadLocalContextVideoCapturer
@ -219,22 +241,6 @@
@end @end
@implementation VoipRtcServerWebrtc
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password isTurn:(bool)isTurn {
self = [super init];
if (self != nil) {
_host = host;
_port = port;
_username = username;
_password = password;
_isTurn = isTurn;
}
return self;
}
@end
static tgcalls::NetworkType callControllerNetworkTypeForType(OngoingCallNetworkTypeWebrtc type) { static tgcalls::NetworkType callControllerNetworkTypeForType(OngoingCallNetworkTypeWebrtc type) {
switch (type) { switch (type) {
case OngoingCallNetworkTypeWifi: case OngoingCallNetworkTypeWifi:
@ -294,7 +300,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
} }
} }
- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy rtcServers:(NSArray<VoipRtcServerWebrtc *> * _Nonnull)rtcServers networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredAspectRatio:(float)preferredAspectRatio { - (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtc * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredAspectRatio:(float)preferredAspectRatio enableHighBitrateVideoCalls:(bool)enableHighBitrateVideoCalls {
self = [super init]; self = [super init];
if (self != nil) { if (self != nil) {
_version = version; _version = version;
@ -334,42 +340,31 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
proxyValue = std::unique_ptr<tgcalls::Proxy>(proxyObject); proxyValue = std::unique_ptr<tgcalls::Proxy>(proxyObject);
} }
std::vector<tgcalls::RtcServer> parsedRtcServers; NSArray<OngoingCallConnectionDescriptionWebrtc *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
for (VoipRtcServerWebrtc *server in rtcServers) {
parsedRtcServers.push_back((tgcalls::RtcServer){
.host = server.host.UTF8String,
.port = (uint16_t)server.port,
.login = server.username.UTF8String,
.password = server.password.UTF8String,
.isTurn = server.isTurn
});
}
/*TgVoipCrypto crypto; std::vector<tgcalls::RtcServer> parsedRtcServers;
crypto.sha1 = &TGCallSha1; for (OngoingCallConnectionDescriptionWebrtc *connection in connections) {
crypto.sha256 = &TGCallSha256; if (connection.hasStun) {
crypto.rand_bytes = &TGCallRandomBytes; parsedRtcServers.push_back((tgcalls::RtcServer){
crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt; .host = connection.ip.UTF8String,
crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt; .port = (uint16_t)connection.port,
crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;*/ .login = "",
.password = "",
.isTurn = false
});
}
if (connection.hasTurn) {
parsedRtcServers.push_back((tgcalls::RtcServer){
.host = connection.ip.UTF8String,
.port = (uint16_t)connection.port,
.login = connection.username.UTF8String,
.password = connection.password.UTF8String,
.isTurn = true
});
}
}
std::vector<tgcalls::Endpoint> endpoints; std::vector<tgcalls::Endpoint> endpoints;
NSArray<OngoingCallConnectionDescriptionWebrtc *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
for (OngoingCallConnectionDescriptionWebrtc *connection in connections) {
unsigned char peerTag[16];
[connection.peerTag getBytes:peerTag length:16];
tgcalls::Endpoint endpoint;
endpoint.endpointId = connection.connectionId;
endpoint.host = {
.ipv4 = std::string(connection.ip.UTF8String),
.ipv6 = std::string(connection.ipv6.UTF8String)
};
endpoint.port = (uint16_t)connection.port;
endpoint.type = tgcalls::EndpointType::UdpRelay;
memcpy(endpoint.peerTag, peerTag, 16);
endpoints.push_back(endpoint);
}
tgcalls::Config config = { tgcalls::Config config = {
.initializationTimeout = _callConnectTimeout, .initializationTimeout = _callConnectTimeout,
@ -382,7 +377,8 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
.enableCallUpgrade = false, .enableCallUpgrade = false,
.logPath = logPath.length == 0 ? "" : std::string(logPath.UTF8String), .logPath = logPath.length == 0 ? "" : std::string(logPath.UTF8String),
.maxApiLayer = [OngoingCallThreadLocalContextWebrtc maxLayer], .maxApiLayer = [OngoingCallThreadLocalContextWebrtc maxLayer],
.preferredAspectRatio = preferredAspectRatio .preferredAspectRatio = preferredAspectRatio,
.enableHighBitrateVideo = enableHighBitrateVideoCalls
}; };
auto encryptionKeyValue = std::make_shared<std::array<uint8_t, 256>>(); auto encryptionKeyValue = std::make_shared<std::array<uint8_t, 256>>();

@ -1 +1 @@
Subproject commit ebe663f05867d81a84f02d10d6bb4dae737162a2 Subproject commit 0806eae4d11e1fdc2f82402f2f49a3a2ff053077