mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' into beta
This commit is contained in:
commit
975a03a1b6
@ -5962,7 +5962,7 @@ Sorry for the inconvenience.";
|
|||||||
"VoiceChat.InvitedPeerText" = "You invited %@ to the voice chat";
|
"VoiceChat.InvitedPeerText" = "You invited %@ to the voice chat";
|
||||||
"VoiceChat.RemovedPeerText" = "You removed %@ from this group";
|
"VoiceChat.RemovedPeerText" = "You removed %@ from this group";
|
||||||
|
|
||||||
"Notification.VoiceChatStarted" = "Voice chat started";
|
"Notification.VoiceChatStarted" = "%1$@ started a voice chat";
|
||||||
"Notification.VoiceChatEnded" = "Voice chat ended (%@)";
|
"Notification.VoiceChatEnded" = "Voice chat ended (%@)";
|
||||||
|
|
||||||
"VoiceChat.Panel.TapToJoin" = "Tap to join";
|
"VoiceChat.Panel.TapToJoin" = "Tap to join";
|
||||||
|
@ -474,6 +474,8 @@ public protocol ChatController: ViewController {
|
|||||||
func updatePresentationMode(_ mode: ChatControllerPresentationMode)
|
func updatePresentationMode(_ mode: ChatControllerPresentationMode)
|
||||||
func beginMessageSearch(_ query: String)
|
func beginMessageSearch(_ query: String)
|
||||||
func displayPromoAnnouncement(text: String)
|
func displayPromoAnnouncement(text: String)
|
||||||
|
|
||||||
|
var isSendButtonVisible: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol ChatMessagePreviewItemNode: class {
|
public protocol ChatMessagePreviewItemNode: class {
|
||||||
|
@ -19,7 +19,8 @@ typedef enum {
|
|||||||
TGCameraControllerPassportIdIntent,
|
TGCameraControllerPassportIdIntent,
|
||||||
TGCameraControllerPassportMultipleIntent,
|
TGCameraControllerPassportMultipleIntent,
|
||||||
TGCameraControllerAvatarIntent,
|
TGCameraControllerAvatarIntent,
|
||||||
TGCameraControllerSignupAvatarIntent
|
TGCameraControllerSignupAvatarIntent,
|
||||||
|
TGCameraControllerGenericPhotoOnlyIntent
|
||||||
} TGCameraControllerIntent;
|
} TGCameraControllerIntent;
|
||||||
|
|
||||||
@interface TGCameraControllerWindow : TGOverlayControllerWindow
|
@interface TGCameraControllerWindow : TGOverlayControllerWindow
|
||||||
|
@ -1250,7 +1250,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
bool hasCamera = !self.inhibitMultipleCapture && ((_intent == TGCameraControllerGenericIntent && !_shortcut) || (_intent == TGCameraControllerPassportMultipleIntent));
|
bool hasCamera = !self.inhibitMultipleCapture && (((_intent == TGCameraControllerGenericIntent || _intent == TGCameraControllerGenericPhotoOnlyIntent) && !_shortcut) || (_intent == TGCameraControllerPassportMultipleIntent));
|
||||||
TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithContext:windowContext items:galleryItems focusItem:focusItem selectionContext:_items.count > 1 ? selectionContext : nil editingContext:editingContext hasCaptions:self.allowCaptions allowCaptionEntities:self.allowCaptionEntities hasTimer:self.hasTimer onlyCrop:_intent == TGCameraControllerPassportIntent || _intent == TGCameraControllerPassportIdIntent || _intent == TGCameraControllerPassportMultipleIntent inhibitDocumentCaptions:self.inhibitDocumentCaptions hasSelectionPanel:true hasCamera:hasCamera recipientName:self.recipientName];
|
TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithContext:windowContext items:galleryItems focusItem:focusItem selectionContext:_items.count > 1 ? selectionContext : nil editingContext:editingContext hasCaptions:self.allowCaptions allowCaptionEntities:self.allowCaptionEntities hasTimer:self.hasTimer onlyCrop:_intent == TGCameraControllerPassportIntent || _intent == TGCameraControllerPassportIdIntent || _intent == TGCameraControllerPassportMultipleIntent inhibitDocumentCaptions:self.inhibitDocumentCaptions hasSelectionPanel:true hasCamera:hasCamera recipientName:self.recipientName];
|
||||||
model.inhibitMute = self.inhibitMute;
|
model.inhibitMute = self.inhibitMute;
|
||||||
model.controller = galleryController;
|
model.controller = galleryController;
|
||||||
|
@ -55,6 +55,8 @@ public final class CachedGroupData: CachedPeerData {
|
|||||||
public let messageIds: Set<MessageId>
|
public let messageIds: Set<MessageId>
|
||||||
public let associatedHistoryMessageId: MessageId? = nil
|
public let associatedHistoryMessageId: MessageId? = nil
|
||||||
|
|
||||||
|
public let activeCall: CachedChannelData.ActiveCall?
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
self.participants = nil
|
self.participants = nil
|
||||||
self.exportedInvitation = nil
|
self.exportedInvitation = nil
|
||||||
@ -68,9 +70,11 @@ public final class CachedGroupData: CachedPeerData {
|
|||||||
self.hasScheduledMessages = false
|
self.hasScheduledMessages = false
|
||||||
self.invitedBy = nil
|
self.invitedBy = nil
|
||||||
self.photo = nil
|
self.photo = nil
|
||||||
|
|
||||||
|
self.activeCall = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(participants: CachedGroupParticipants?, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, about: String?, flags: CachedGroupFlags, hasScheduledMessages: Bool, invitedBy: PeerId?, photo: TelegramMediaImage?) {
|
public init(participants: CachedGroupParticipants?, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, about: String?, flags: CachedGroupFlags, hasScheduledMessages: Bool, invitedBy: PeerId?, photo: TelegramMediaImage?, activeCall: CachedChannelData.ActiveCall?) {
|
||||||
self.participants = participants
|
self.participants = participants
|
||||||
self.exportedInvitation = exportedInvitation
|
self.exportedInvitation = exportedInvitation
|
||||||
self.botInfos = botInfos
|
self.botInfos = botInfos
|
||||||
@ -81,6 +85,7 @@ public final class CachedGroupData: CachedPeerData {
|
|||||||
self.hasScheduledMessages = hasScheduledMessages
|
self.hasScheduledMessages = hasScheduledMessages
|
||||||
self.invitedBy = invitedBy
|
self.invitedBy = invitedBy
|
||||||
self.photo = photo
|
self.photo = photo
|
||||||
|
self.activeCall = activeCall
|
||||||
|
|
||||||
var messageIds = Set<MessageId>()
|
var messageIds = Set<MessageId>()
|
||||||
if let pinnedMessageId = self.pinnedMessageId {
|
if let pinnedMessageId = self.pinnedMessageId {
|
||||||
@ -132,6 +137,12 @@ public final class CachedGroupData: CachedPeerData {
|
|||||||
self.photo = nil
|
self.photo = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let activeCall = decoder.decodeObjectForKey("activeCall", decoder: { CachedChannelData.ActiveCall(decoder: $0) }) as? CachedChannelData.ActiveCall {
|
||||||
|
self.activeCall = activeCall
|
||||||
|
} else {
|
||||||
|
self.activeCall = nil
|
||||||
|
}
|
||||||
|
|
||||||
var messageIds = Set<MessageId>()
|
var messageIds = Set<MessageId>()
|
||||||
if let pinnedMessageId = self.pinnedMessageId {
|
if let pinnedMessageId = self.pinnedMessageId {
|
||||||
messageIds.insert(pinnedMessageId)
|
messageIds.insert(pinnedMessageId)
|
||||||
@ -196,6 +207,12 @@ public final class CachedGroupData: CachedPeerData {
|
|||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "ph")
|
encoder.encodeNil(forKey: "ph")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let activeCall = self.activeCall {
|
||||||
|
encoder.encodeObject(activeCall, forKey: "activeCall")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "activeCall")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isEqual(to: CachedPeerData) -> Bool {
|
public func isEqual(to: CachedPeerData) -> Bool {
|
||||||
@ -203,46 +220,54 @@ public final class CachedGroupData: CachedPeerData {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.activeCall != other.activeCall {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return self.participants == other.participants && self.exportedInvitation == other.exportedInvitation && self.botInfos == other.botInfos && self.peerStatusSettings == other.peerStatusSettings && self.pinnedMessageId == other.pinnedMessageId && self.about == other.about && self.flags == other.flags && self.hasScheduledMessages == other.hasScheduledMessages && self.invitedBy == other.invitedBy
|
return self.participants == other.participants && self.exportedInvitation == other.exportedInvitation && self.botInfos == other.botInfos && self.peerStatusSettings == other.peerStatusSettings && self.pinnedMessageId == other.pinnedMessageId && self.about == other.about && self.flags == other.flags && self.hasScheduledMessages == other.hasScheduledMessages && self.invitedBy == other.invitedBy
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedParticipants(_ participants: CachedGroupParticipants?) -> CachedGroupData {
|
public func withUpdatedParticipants(_ participants: CachedGroupParticipants?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedGroupData {
|
public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedGroupData {
|
public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedGroupData {
|
public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedGroupData {
|
public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedAbout(_ about: String?) -> CachedGroupData {
|
public func withUpdatedAbout(_ about: String?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedFlags(_ flags: CachedGroupFlags) -> CachedGroupData {
|
public func withUpdatedFlags(_ flags: CachedGroupFlags) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedGroupData {
|
public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedInvitedBy(_ invitedBy: PeerId?) -> CachedGroupData {
|
public func withUpdatedInvitedBy(_ invitedBy: PeerId?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: invitedBy, photo: self.photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: invitedBy, photo: self.photo, activeCall: self.activeCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedPhoto(_ photo: TelegramMediaImage?) -> CachedGroupData {
|
public func withUpdatedPhoto(_ photo: TelegramMediaImage?) -> CachedGroupData {
|
||||||
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: photo)
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: photo, activeCall: self.activeCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func withUpdatedActiveCall(_ activeCall: CachedChannelData.ActiveCall?) -> CachedGroupData {
|
||||||
|
return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: activeCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||||
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
dict[1210199983] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
||||||
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) }
|
||||||
dict[461151667] = { return Api.ChatFull.parse_chatFull($0) }
|
|
||||||
dict[-281384243] = { return Api.ChatFull.parse_channelFull($0) }
|
dict[-281384243] = { return Api.ChatFull.parse_channelFull($0) }
|
||||||
|
dict[231260545] = { return Api.ChatFull.parse_chatFull($0) }
|
||||||
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
dict[-1159937629] = { return Api.PollResults.parse_pollResults($0) }
|
||||||
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) }
|
||||||
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
|
dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) }
|
||||||
@ -266,8 +266,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-13975905] = { return Api.Update.parse_updateChannelUserTyping($0) }
|
dict[-13975905] = { return Api.Update.parse_updateChannelUserTyping($0) }
|
||||||
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
|
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
|
||||||
dict[-2054649973] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
|
dict[-2054649973] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
|
||||||
|
dict[321954198] = { return Api.Update.parse_updateChat($0) }
|
||||||
dict[-219423922] = { return Api.Update.parse_updateGroupCallParticipants($0) }
|
dict[-219423922] = { return Api.Update.parse_updateGroupCallParticipants($0) }
|
||||||
dict[1462009966] = { return Api.Update.parse_updateGroupCall($0) }
|
dict[-1537295973] = { return Api.Update.parse_updateGroupCall($0) }
|
||||||
dict[1059076315] = { return Api.Update.parse_updateBotInlineQuery($0) }
|
dict[1059076315] = { return Api.Update.parse_updateBotInlineQuery($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) }
|
||||||
@ -346,7 +347,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1494368259] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaContact($0) }
|
dict[-1494368259] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaContact($0) }
|
||||||
dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
dict[-1768777083] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
||||||
dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) }
|
dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) }
|
||||||
dict[-290164953] = { return Api.StickerSet.parse_stickerSet($0) }
|
dict[1088567208] = { return Api.StickerSet.parse_stickerSet($0) }
|
||||||
dict[354925740] = { return Api.SecureSecretSettings.parse_secureSecretSettings($0) }
|
dict[354925740] = { return Api.SecureSecretSettings.parse_secureSecretSettings($0) }
|
||||||
dict[539045032] = { return Api.photos.Photo.parse_photo($0) }
|
dict[539045032] = { return Api.photos.Photo.parse_photo($0) }
|
||||||
dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) }
|
dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) }
|
||||||
|
@ -2052,30 +2052,11 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
public enum ChatFull: TypeConstructorDescription {
|
public enum ChatFull: TypeConstructorDescription {
|
||||||
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?)
|
|
||||||
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
|
case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32, call: Api.InputGroupCall?)
|
||||||
|
case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?, call: Api.InputGroupCall?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(461151667)
|
|
||||||
}
|
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(id, buffer: buffer, boxed: false)
|
|
||||||
serializeString(about, buffer: buffer, boxed: false)
|
|
||||||
participants.serialize(buffer, true)
|
|
||||||
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
|
|
||||||
notifySettings.serialize(buffer, true)
|
|
||||||
exportedInvite.serialize(buffer, true)
|
|
||||||
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(botInfo!.count))
|
|
||||||
for item in botInfo! {
|
|
||||||
item.serialize(buffer, true)
|
|
||||||
}}
|
|
||||||
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
|
|
||||||
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
|
|
||||||
break
|
|
||||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-281384243)
|
buffer.appendInt32(-281384243)
|
||||||
@ -2113,66 +2094,38 @@ public extension Api {
|
|||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 21) != 0 {call!.serialize(buffer, true)}
|
||||||
break
|
break
|
||||||
|
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(231260545)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
|
serializeString(about, buffer: buffer, boxed: false)
|
||||||
|
participants.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 2) != 0 {chatPhoto!.serialize(buffer, true)}
|
||||||
|
notifySettings.serialize(buffer, true)
|
||||||
|
exportedInvite.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(botInfo!.count))
|
||||||
|
for item in botInfo! {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}}
|
||||||
|
if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)}
|
||||||
|
if Int(flags) & Int(1 << 12) != 0 {call!.serialize(buffer, true)}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId):
|
|
||||||
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId)])
|
|
||||||
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts, let call):
|
||||||
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("call", call)])
|
return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts), ("call", call)])
|
||||||
|
case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId, let call):
|
||||||
|
return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId), ("call", call)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func parse_chatFull(_ reader: BufferReader) -> ChatFull? {
|
|
||||||
var _1: Int32?
|
|
||||||
_1 = reader.readInt32()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
var _3: String?
|
|
||||||
_3 = parseString(reader)
|
|
||||||
var _4: Api.ChatParticipants?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_4 = Api.parse(reader, signature: signature) as? Api.ChatParticipants
|
|
||||||
}
|
|
||||||
var _5: Api.Photo?
|
|
||||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
|
||||||
_5 = Api.parse(reader, signature: signature) as? Api.Photo
|
|
||||||
} }
|
|
||||||
var _6: Api.PeerNotifySettings?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
|
||||||
}
|
|
||||||
var _7: Api.ExportedChatInvite?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
|
|
||||||
}
|
|
||||||
var _8: [Api.BotInfo]?
|
|
||||||
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
|
||||||
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
|
|
||||||
} }
|
|
||||||
var _9: Int32?
|
|
||||||
if Int(_1!) & Int(1 << 6) != 0 {_9 = reader.readInt32() }
|
|
||||||
var _10: Int32?
|
|
||||||
if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() }
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
let _c4 = _4 != nil
|
|
||||||
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
|
||||||
let _c6 = _6 != nil
|
|
||||||
let _c7 = _7 != nil
|
|
||||||
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
|
||||||
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
|
||||||
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
|
||||||
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7!, botInfo: _8, pinnedMsgId: _9, folderId: _10)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_channelFull(_ reader: BufferReader) -> ChatFull? {
|
public static func parse_channelFull(_ reader: BufferReader) -> ChatFull? {
|
||||||
var _1: Int32?
|
var _1: Int32?
|
||||||
_1 = reader.readInt32()
|
_1 = reader.readInt32()
|
||||||
@ -2279,6 +2232,59 @@ public extension Api {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static func parse_chatFull(_ reader: BufferReader) -> ChatFull? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
var _3: String?
|
||||||
|
_3 = parseString(reader)
|
||||||
|
var _4: Api.ChatParticipants?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_4 = Api.parse(reader, signature: signature) as? Api.ChatParticipants
|
||||||
|
}
|
||||||
|
var _5: Api.Photo?
|
||||||
|
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_5 = Api.parse(reader, signature: signature) as? Api.Photo
|
||||||
|
} }
|
||||||
|
var _6: Api.PeerNotifySettings?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_6 = Api.parse(reader, signature: signature) as? Api.PeerNotifySettings
|
||||||
|
}
|
||||||
|
var _7: Api.ExportedChatInvite?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_7 = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
|
||||||
|
}
|
||||||
|
var _8: [Api.BotInfo]?
|
||||||
|
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
||||||
|
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotInfo.self)
|
||||||
|
} }
|
||||||
|
var _9: Int32?
|
||||||
|
if Int(_1!) & Int(1 << 6) != 0 {_9 = reader.readInt32() }
|
||||||
|
var _10: Int32?
|
||||||
|
if Int(_1!) & Int(1 << 11) != 0 {_10 = reader.readInt32() }
|
||||||
|
var _11: Api.InputGroupCall?
|
||||||
|
if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_11 = Api.parse(reader, signature: signature) as? Api.InputGroupCall
|
||||||
|
} }
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
let _c4 = _4 != nil
|
||||||
|
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
|
||||||
|
let _c6 = _6 != nil
|
||||||
|
let _c7 = _7 != nil
|
||||||
|
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
|
||||||
|
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
||||||
|
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
||||||
|
let _c11 = (Int(_1!) & Int(1 << 12) == 0) || _11 != nil
|
||||||
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||||
|
return Api.ChatFull.chatFull(flags: _1!, id: _2!, about: _3!, participants: _4!, chatPhoto: _5, notifySettings: _6!, exportedInvite: _7!, botInfo: _8, pinnedMsgId: _9, folderId: _10, call: _11)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public enum PollResults: TypeConstructorDescription {
|
public enum PollResults: TypeConstructorDescription {
|
||||||
@ -6418,8 +6424,9 @@ public extension Api {
|
|||||||
case updateChannelUserTyping(flags: Int32, channelId: Int32, topMsgId: Int32?, userId: Int32, action: Api.SendMessageAction)
|
case updateChannelUserTyping(flags: Int32, channelId: Int32, topMsgId: Int32?, userId: Int32, action: Api.SendMessageAction)
|
||||||
case updatePinnedMessages(flags: Int32, peer: Api.Peer, messages: [Int32], pts: Int32, ptsCount: Int32)
|
case updatePinnedMessages(flags: Int32, peer: Api.Peer, messages: [Int32], pts: Int32, ptsCount: Int32)
|
||||||
case updatePinnedChannelMessages(flags: Int32, channelId: Int32, messages: [Int32], pts: Int32, ptsCount: Int32)
|
case updatePinnedChannelMessages(flags: Int32, channelId: Int32, messages: [Int32], pts: Int32, ptsCount: Int32)
|
||||||
|
case updateChat(chatId: Int32)
|
||||||
case updateGroupCallParticipants(call: Api.InputGroupCall, participants: [Api.GroupCallParticipant], version: Int32)
|
case updateGroupCallParticipants(call: Api.InputGroupCall, participants: [Api.GroupCallParticipant], version: Int32)
|
||||||
case updateGroupCall(channelId: Int32, call: Api.GroupCall)
|
case updateGroupCall(chatId: Int32, call: Api.GroupCall)
|
||||||
case updateBotInlineQuery(flags: Int32, queryId: Int64, userId: Int32, query: String, geo: Api.GeoPoint?, peerType: Api.InlineQueryPeerType?, offset: String)
|
case updateBotInlineQuery(flags: Int32, queryId: Int64, userId: Int32, query: String, geo: Api.GeoPoint?, peerType: Api.InlineQueryPeerType?, offset: String)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
@ -7145,6 +7152,12 @@ public extension Api {
|
|||||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
|
case .updateChat(let chatId):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(321954198)
|
||||||
|
}
|
||||||
|
serializeInt32(chatId, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
case .updateGroupCallParticipants(let call, let participants, let version):
|
case .updateGroupCallParticipants(let call, let participants, let version):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-219423922)
|
buffer.appendInt32(-219423922)
|
||||||
@ -7157,11 +7170,11 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
serializeInt32(version, buffer: buffer, boxed: false)
|
serializeInt32(version, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
case .updateGroupCall(let channelId, let call):
|
case .updateGroupCall(let chatId, let call):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1462009966)
|
buffer.appendInt32(-1537295973)
|
||||||
}
|
}
|
||||||
serializeInt32(channelId, buffer: buffer, boxed: false)
|
serializeInt32(chatId, buffer: buffer, boxed: false)
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
break
|
break
|
||||||
case .updateBotInlineQuery(let flags, let queryId, let userId, let query, let geo, let peerType, let offset):
|
case .updateBotInlineQuery(let flags, let queryId, let userId, let query, let geo, let peerType, let offset):
|
||||||
@ -7349,10 +7362,12 @@ public extension Api {
|
|||||||
return ("updatePinnedMessages", [("flags", flags), ("peer", peer), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
return ("updatePinnedMessages", [("flags", flags), ("peer", peer), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
||||||
case .updatePinnedChannelMessages(let flags, let channelId, let messages, let pts, let ptsCount):
|
case .updatePinnedChannelMessages(let flags, let channelId, let messages, let pts, let ptsCount):
|
||||||
return ("updatePinnedChannelMessages", [("flags", flags), ("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
return ("updatePinnedChannelMessages", [("flags", flags), ("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
||||||
|
case .updateChat(let chatId):
|
||||||
|
return ("updateChat", [("chatId", chatId)])
|
||||||
case .updateGroupCallParticipants(let call, let participants, let version):
|
case .updateGroupCallParticipants(let call, let participants, let version):
|
||||||
return ("updateGroupCallParticipants", [("call", call), ("participants", participants), ("version", version)])
|
return ("updateGroupCallParticipants", [("call", call), ("participants", participants), ("version", version)])
|
||||||
case .updateGroupCall(let channelId, let call):
|
case .updateGroupCall(let chatId, let call):
|
||||||
return ("updateGroupCall", [("channelId", channelId), ("call", call)])
|
return ("updateGroupCall", [("chatId", chatId), ("call", call)])
|
||||||
case .updateBotInlineQuery(let flags, let queryId, let userId, let query, let geo, let peerType, let offset):
|
case .updateBotInlineQuery(let flags, let queryId, let userId, let query, let geo, let peerType, let offset):
|
||||||
return ("updateBotInlineQuery", [("flags", flags), ("queryId", queryId), ("userId", userId), ("query", query), ("geo", geo), ("peerType", peerType), ("offset", offset)])
|
return ("updateBotInlineQuery", [("flags", flags), ("queryId", queryId), ("userId", userId), ("query", query), ("geo", geo), ("peerType", peerType), ("offset", offset)])
|
||||||
}
|
}
|
||||||
@ -8799,6 +8814,17 @@ public extension Api {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static func parse_updateChat(_ reader: BufferReader) -> Update? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
if _c1 {
|
||||||
|
return Api.Update.updateChat(chatId: _1!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
public static func parse_updateGroupCallParticipants(_ reader: BufferReader) -> Update? {
|
public static func parse_updateGroupCallParticipants(_ reader: BufferReader) -> Update? {
|
||||||
var _1: Api.InputGroupCall?
|
var _1: Api.InputGroupCall?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
@ -8830,7 +8856,7 @@ public extension Api {
|
|||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
if _c1 && _c2 {
|
if _c1 && _c2 {
|
||||||
return Api.Update.updateGroupCall(channelId: _1!, call: _2!)
|
return Api.Update.updateGroupCall(chatId: _1!, call: _2!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -10990,13 +11016,13 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
public enum StickerSet: TypeConstructorDescription {
|
public enum StickerSet: TypeConstructorDescription {
|
||||||
case stickerSet(flags: Int32, installedDate: Int32?, id: Int64, accessHash: Int64, title: String, shortName: String, thumb: Api.PhotoSize?, thumbDcId: Int32?, count: Int32, hash: Int32)
|
case stickerSet(flags: Int32, installedDate: Int32?, id: Int64, accessHash: Int64, title: String, shortName: String, thumbs: [Api.PhotoSize]?, thumbDcId: Int32?, count: Int32, hash: Int32)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .stickerSet(let flags, let installedDate, let id, let accessHash, let title, let shortName, let thumb, let thumbDcId, let count, let hash):
|
case .stickerSet(let flags, let installedDate, let id, let accessHash, let title, let shortName, let thumbs, let thumbDcId, let count, let hash):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-290164953)
|
buffer.appendInt32(1088567208)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(installedDate!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(installedDate!, buffer: buffer, boxed: false)}
|
||||||
@ -11004,7 +11030,11 @@ public extension Api {
|
|||||||
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
serializeInt64(accessHash, buffer: buffer, boxed: false)
|
||||||
serializeString(title, buffer: buffer, boxed: false)
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
serializeString(shortName, buffer: buffer, boxed: false)
|
serializeString(shortName, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 4) != 0 {thumb!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(thumbs!.count))
|
||||||
|
for item in thumbs! {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}}
|
||||||
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(thumbDcId!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(thumbDcId!, buffer: buffer, boxed: false)}
|
||||||
serializeInt32(count, buffer: buffer, boxed: false)
|
serializeInt32(count, buffer: buffer, boxed: false)
|
||||||
serializeInt32(hash, buffer: buffer, boxed: false)
|
serializeInt32(hash, buffer: buffer, boxed: false)
|
||||||
@ -11014,8 +11044,8 @@ public extension Api {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .stickerSet(let flags, let installedDate, let id, let accessHash, let title, let shortName, let thumb, let thumbDcId, let count, let hash):
|
case .stickerSet(let flags, let installedDate, let id, let accessHash, let title, let shortName, let thumbs, let thumbDcId, let count, let hash):
|
||||||
return ("stickerSet", [("flags", flags), ("installedDate", installedDate), ("id", id), ("accessHash", accessHash), ("title", title), ("shortName", shortName), ("thumb", thumb), ("thumbDcId", thumbDcId), ("count", count), ("hash", hash)])
|
return ("stickerSet", [("flags", flags), ("installedDate", installedDate), ("id", id), ("accessHash", accessHash), ("title", title), ("shortName", shortName), ("thumbs", thumbs), ("thumbDcId", thumbDcId), ("count", count), ("hash", hash)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11032,9 +11062,9 @@ public extension Api {
|
|||||||
_5 = parseString(reader)
|
_5 = parseString(reader)
|
||||||
var _6: String?
|
var _6: String?
|
||||||
_6 = parseString(reader)
|
_6 = parseString(reader)
|
||||||
var _7: Api.PhotoSize?
|
var _7: [Api.PhotoSize]?
|
||||||
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
|
if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() {
|
||||||
_7 = Api.parse(reader, signature: signature) as? Api.PhotoSize
|
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PhotoSize.self)
|
||||||
} }
|
} }
|
||||||
var _8: Int32?
|
var _8: Int32?
|
||||||
if Int(_1!) & Int(1 << 4) != 0 {_8 = reader.readInt32() }
|
if Int(_1!) & Int(1 << 4) != 0 {_8 = reader.readInt32() }
|
||||||
@ -11053,7 +11083,7 @@ public extension Api {
|
|||||||
let _c9 = _9 != nil
|
let _c9 = _9 != nil
|
||||||
let _c10 = _10 != nil
|
let _c10 = _10 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
||||||
return Api.StickerSet.stickerSet(flags: _1!, installedDate: _2, id: _3!, accessHash: _4!, title: _5!, shortName: _6!, thumb: _7, thumbDcId: _8, count: _9!, hash: _10!)
|
return Api.StickerSet.stickerSet(flags: _1!, installedDate: _2, id: _3!, accessHash: _4!, title: _5!, shortName: _6!, thumbs: _7, thumbDcId: _8, count: _9!, hash: _10!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -7241,12 +7241,12 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func createGroupCall(channel: Api.InputChannel, randomId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
public static func createGroupCall(peer: Api.InputPeer, randomId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-467076606)
|
buffer.appendInt32(-1120031776)
|
||||||
channel.serialize(buffer, true)
|
peer.serialize(buffer, true)
|
||||||
serializeInt32(randomId, buffer: buffer, boxed: false)
|
serializeInt32(randomId, buffer: buffer, boxed: false)
|
||||||
return (FunctionDescription(name: "phone.createGroupCall", parameters: [("channel", channel), ("randomId", randomId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
return (FunctionDescription(name: "phone.createGroupCall", parameters: [("peer", peer), ("randomId", randomId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.Updates?
|
var result: Api.Updates?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
@ -280,10 +280,13 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
|||||||
if case let .peer(peerId) = groupCallPanelSource {
|
if case let .peer(peerId) = groupCallPanelSource {
|
||||||
availableGroupCall = context.account.viewTracker.peerView(peerId)
|
availableGroupCall = context.account.viewTracker.peerView(peerId)
|
||||||
|> map { peerView -> CachedChannelData.ActiveCall? in
|
|> map { peerView -> CachedChannelData.ActiveCall? in
|
||||||
guard let cachedData = peerView.cachedData as? CachedChannelData else {
|
if let cachedData = peerView.cachedData as? CachedChannelData {
|
||||||
|
return cachedData.activeCall
|
||||||
|
} else if let cachedData = peerView.cachedData as? CachedGroupData {
|
||||||
|
return cachedData.activeCall
|
||||||
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return cachedData.activeCall
|
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|> mapToSignal { activeCall -> Signal<GroupCallPanelData?, NoError> in
|
|> mapToSignal { activeCall -> Signal<GroupCallPanelData?, NoError> in
|
||||||
|
@ -37,6 +37,7 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
case speaker
|
case speaker
|
||||||
case airpods
|
case airpods
|
||||||
case airpodsPro
|
case airpodsPro
|
||||||
|
case headphones
|
||||||
case accept
|
case accept
|
||||||
case end
|
case end
|
||||||
}
|
}
|
||||||
@ -221,6 +222,8 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallAirpodsButton"), color: imageColor)
|
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallAirpodsButton"), color: imageColor)
|
||||||
case .airpodsPro:
|
case .airpodsPro:
|
||||||
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallAirpodsProButton"), color: imageColor)
|
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallAirpodsProButton"), color: imageColor)
|
||||||
|
case .headphones:
|
||||||
|
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallHeadphonesButton"), color: imageColor)
|
||||||
case .accept:
|
case .accept:
|
||||||
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallAcceptButton"), color: imageColor)
|
image = generateTintedImage(image: UIImage(bundleImageName: "Call/CallAcceptButton"), color: imageColor)
|
||||||
case .end:
|
case .end:
|
||||||
|
@ -51,6 +51,7 @@ private enum ButtonDescription: Equatable {
|
|||||||
case bluetooth
|
case bluetooth
|
||||||
case airpods
|
case airpods
|
||||||
case airpodsPro
|
case airpodsPro
|
||||||
|
case headphones
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EndType {
|
enum EndType {
|
||||||
@ -205,7 +206,7 @@ final class CallControllerButtonsNode: ASDisplayNode {
|
|||||||
case .speaker:
|
case .speaker:
|
||||||
soundOutput = .speaker
|
soundOutput = .speaker
|
||||||
case .headphones:
|
case .headphones:
|
||||||
soundOutput = .bluetooth
|
soundOutput = .headphones
|
||||||
case let .bluetooth(type):
|
case let .bluetooth(type):
|
||||||
switch type {
|
switch type {
|
||||||
case .generic:
|
case .generic:
|
||||||
@ -296,7 +297,7 @@ final class CallControllerButtonsNode: ASDisplayNode {
|
|||||||
case .speaker:
|
case .speaker:
|
||||||
soundOutput = .speaker
|
soundOutput = .speaker
|
||||||
case .headphones:
|
case .headphones:
|
||||||
soundOutput = .builtin
|
soundOutput = .headphones
|
||||||
case let .bluetooth(type):
|
case let .bluetooth(type):
|
||||||
switch type {
|
switch type {
|
||||||
case .generic:
|
case .generic:
|
||||||
@ -467,6 +468,9 @@ final class CallControllerButtonsNode: ASDisplayNode {
|
|||||||
case .airpodsPro:
|
case .airpodsPro:
|
||||||
image = .airpodsPro
|
image = .airpodsPro
|
||||||
title = strings.Call_Audio
|
title = strings.Call_Audio
|
||||||
|
case .headphones:
|
||||||
|
image = .headphones
|
||||||
|
title = strings.Call_Audio
|
||||||
}
|
}
|
||||||
buttonContent = CallControllerButtonItemNode.Content(
|
buttonContent = CallControllerButtonItemNode.Content(
|
||||||
appearance: .blurred(isFilled: isFilled),
|
appearance: .blurred(isFilled: isFilled),
|
||||||
|
@ -296,7 +296,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
|||||||
membersText = self.strings.VoiceChat_Panel_Members(Int32(data.participantCount))
|
membersText = self.strings.VoiceChat_Panel_Members(Int32(data.participantCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.avatarsContent = self.avatarsContext.update(peers: data.topParticipants.map { $0.peer }.filter { $0.id != self.context.account.peerId }, animated: false)
|
self.avatarsContent = self.avatarsContext.update(peers: data.topParticipants.map { $0.peer }, animated: false)
|
||||||
|
|
||||||
self.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: self.theme.chat.inputPanel.secondaryTextColor)
|
self.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: self.theme.chat.inputPanel.secondaryTextColor)
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
|||||||
|
|
||||||
strongSelf.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor)
|
strongSelf.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: strongSelf.theme.chat.inputPanel.secondaryTextColor)
|
||||||
|
|
||||||
strongSelf.avatarsContent = strongSelf.avatarsContext.update(peers: summaryState.topParticipants.map { $0.peer }.filter { $0.id != strongSelf.context.account.peerId }, animated: false)
|
strongSelf.avatarsContent = strongSelf.avatarsContext.update(peers: summaryState.topParticipants.map { $0.peer }, animated: false)
|
||||||
|
|
||||||
if let (size, leftInset, rightInset) = strongSelf.validLayout {
|
if let (size, leftInset, rightInset) = strongSelf.validLayout {
|
||||||
strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||||
@ -400,7 +400,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
|||||||
|
|
||||||
self.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: self.theme.chat.inputPanel.secondaryTextColor)
|
self.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: self.theme.chat.inputPanel.secondaryTextColor)
|
||||||
|
|
||||||
self.avatarsContent = self.avatarsContext.update(peers: data.topParticipants.map { $0.peer }.filter { $0.id != self.context.account.peerId }, animated: false)
|
self.avatarsContent = self.avatarsContext.update(peers: data.topParticipants.map { $0.peer }, animated: false)
|
||||||
|
|
||||||
updateAudioLevels = true
|
updateAudioLevels = true
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,8 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
public var hasActiveGroupCall: Bool {
|
public var hasActiveCall: Bool {
|
||||||
return self.currentGroupCall != nil
|
return self.currentCall != nil || self.currentGroupCall != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private let currentCallPromise = Promise<PresentationCall?>(nil)
|
private let currentCallPromise = Promise<PresentationCall?>(nil)
|
||||||
|
@ -20,8 +20,8 @@ private let areaSize = CGSize(width: 440.0, height: 440.0)
|
|||||||
private let blobSize = CGSize(width: 244.0, height: 244.0)
|
private let blobSize = CGSize(width: 244.0, height: 244.0)
|
||||||
|
|
||||||
final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
||||||
enum State {
|
enum State: Equatable {
|
||||||
enum ActiveState {
|
enum ActiveState: Equatable {
|
||||||
case cantSpeak
|
case cantSpeak
|
||||||
case muted
|
case muted
|
||||||
case on
|
case on
|
||||||
@ -31,6 +31,14 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
|||||||
case active(state: ActiveState)
|
case active(state: ActiveState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stateValue: State {
|
||||||
|
return self.currentParams?.state ?? .connecting
|
||||||
|
}
|
||||||
|
var statePromise = ValuePromise<State>()
|
||||||
|
var state: Signal<State, NoError> {
|
||||||
|
return self.statePromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
private let containerNode: ASDisplayNode
|
private let containerNode: ASDisplayNode
|
||||||
private let backgroundNode: VoiceChatActionButtonBackgroundNode
|
private let backgroundNode: VoiceChatActionButtonBackgroundNode
|
||||||
private let iconNode: VoiceChatMicrophoneNode
|
private let iconNode: VoiceChatMicrophoneNode
|
||||||
@ -167,7 +175,7 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
|||||||
let subtitleSize = self.subtitleLabel.updateLayout(CGSize(width: size.width, height: .greatestFiniteMagnitude))
|
let subtitleSize = self.subtitleLabel.updateLayout(CGSize(width: size.width, height: .greatestFiniteMagnitude))
|
||||||
let totalHeight = titleSize.height + subtitleSize.height + 1.0
|
let totalHeight = titleSize.height + subtitleSize.height + 1.0
|
||||||
|
|
||||||
self.titleLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: floor(size.height - totalHeight / 2.0) - 110.0), size: titleSize)
|
self.titleLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: floor(size.height - totalHeight / 2.0) - 112.0), size: titleSize)
|
||||||
self.subtitleLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - subtitleSize.width) / 2.0), y: self.titleLabel.frame.maxY + 1.0), size: subtitleSize)
|
self.subtitleLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - subtitleSize.width) / 2.0), y: self.titleLabel.frame.maxY + 1.0), size: subtitleSize)
|
||||||
|
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
@ -209,7 +217,7 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func applyIconParams() {
|
private func applyIconParams() {
|
||||||
guard let (size, _, state, _, small, title, subtitle, snap) = self.currentParams else {
|
guard let (_, _, state, _, _, _, _, snap) = self.currentParams else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,6 +258,8 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
|||||||
let previousState = previous?.state
|
let previousState = previous?.state
|
||||||
self.currentParams = (size, buttonSize, state, dark, small, title, subtitle, previous?.snap ?? false)
|
self.currentParams = (size, buttonSize, state, dark, small, title, subtitle, previous?.snap ?? false)
|
||||||
|
|
||||||
|
self.statePromise.set(state)
|
||||||
|
|
||||||
var backgroundState: VoiceChatActionButtonBackgroundNode.State
|
var backgroundState: VoiceChatActionButtonBackgroundNode.State
|
||||||
switch state {
|
switch state {
|
||||||
case let .active(state):
|
case let .active(state):
|
||||||
@ -392,6 +402,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var state: State
|
private var state: State
|
||||||
private var hasState = false
|
private var hasState = false
|
||||||
|
|
||||||
private var transition: State?
|
private var transition: State?
|
||||||
|
|
||||||
var audioLevel: CGFloat = 0.0 {
|
var audioLevel: CGFloat = 0.0 {
|
||||||
|
@ -106,7 +106,7 @@ private final class VoiceChatControllerTitleNode: ASDisplayNode {
|
|||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: UIColor(rgb: 0xffffff))
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: UIColor(rgb: 0xffffff))
|
||||||
self.infoNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(13.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.5))
|
self.infoNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(13.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.5))
|
||||||
|
|
||||||
let constrainedSize = CGSize(width: size.width - 80.0, height: size.height)
|
let constrainedSize = CGSize(width: size.width - 120.0, height: size.height)
|
||||||
let titleSize = self.titleNode.measure(constrainedSize)
|
let titleSize = self.titleNode.measure(constrainedSize)
|
||||||
let infoSize = self.infoNode.measure(constrainedSize)
|
let infoSize = self.infoNode.measure(constrainedSize)
|
||||||
let titleInfoSpacing: CGFloat = 0.0
|
let titleInfoSpacing: CGFloat = 0.0
|
||||||
@ -128,7 +128,6 @@ public final class VoiceChatController: ViewController {
|
|||||||
let isEmpty: Bool
|
let isEmpty: Bool
|
||||||
let crossFade: Bool
|
let crossFade: Bool
|
||||||
let count: Int
|
let count: Int
|
||||||
let isExpanded: Bool
|
|
||||||
let animated: Bool
|
let animated: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,14 +362,14 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction, isExpanded: Bool) -> ListTransition {
|
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction) -> ListTransition {
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||||
|
|
||||||
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, isExpanded: isExpanded, animated: true)
|
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private weak var controller: VoiceChatController?
|
private weak var controller: VoiceChatController?
|
||||||
@ -414,7 +413,6 @@ public final class VoiceChatController: ViewController {
|
|||||||
private var currentCallMembers: [GroupCallParticipantsContext.Participant]?
|
private var currentCallMembers: [GroupCallParticipantsContext.Participant]?
|
||||||
private var currentInvitedPeers: [Peer]?
|
private var currentInvitedPeers: [Peer]?
|
||||||
private var currentSpeakingPeers: Set<PeerId>?
|
private var currentSpeakingPeers: Set<PeerId>?
|
||||||
private var currentIsExpanded: Bool = false
|
|
||||||
private var currentContentOffset: CGFloat?
|
private var currentContentOffset: CGFloat?
|
||||||
private var ignoreScrolling = false
|
private var ignoreScrolling = false
|
||||||
private var accountPeer: Peer?
|
private var accountPeer: Peer?
|
||||||
@ -476,6 +474,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.listNode = ListView()
|
self.listNode = ListView()
|
||||||
self.listNode.verticalScrollIndicatorColor = UIColor(white: 1.0, alpha: 0.3)
|
self.listNode.verticalScrollIndicatorColor = UIColor(white: 1.0, alpha: 0.3)
|
||||||
self.listNode.clipsToBounds = true
|
self.listNode.clipsToBounds = true
|
||||||
|
self.listNode.scroller.bounces = false
|
||||||
|
|
||||||
self.topPanelNode = ASDisplayNode()
|
self.topPanelNode = ASDisplayNode()
|
||||||
self.topPanelNode.clipsToBounds = false
|
self.topPanelNode.clipsToBounds = false
|
||||||
@ -886,7 +885,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: callMembers?.participants ?? [], invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [], isExpanded: strongSelf.currentIsExpanded)
|
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: callMembers?.participants ?? [], invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [])
|
||||||
|
|
||||||
let subtitle = strongSelf.presentationData.strings.VoiceChat_Panel_Members(Int32(max(1, callMembers?.totalCount ?? 0)))
|
let subtitle = strongSelf.presentationData.strings.VoiceChat_Panel_Members(Int32(max(1, callMembers?.totalCount ?? 0)))
|
||||||
strongSelf.currentSubtitle = subtitle
|
strongSelf.currentSubtitle = subtitle
|
||||||
@ -907,7 +906,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
if !strongSelf.didSetDataReady {
|
if !strongSelf.didSetDataReady {
|
||||||
strongSelf.accountPeer = accountPeer
|
strongSelf.accountPeer = accountPeer
|
||||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set(), isExpanded: strongSelf.currentIsExpanded)
|
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
||||||
|
|
||||||
if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel {
|
if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel {
|
||||||
let addressName = channel.addressName ?? ""
|
let addressName = channel.addressName ?? ""
|
||||||
@ -1100,39 +1099,10 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, transition in
|
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, transition in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.currentContentOffset = offset
|
strongSelf.currentContentOffset = offset
|
||||||
|
if strongSelf.animation == nil && !strongSelf.animatingExpansion {
|
||||||
strongSelf.updateFloatingHeaderOffset(offset: offset, transition: transition)
|
strongSelf.updateFloatingHeaderOffset(offset: offset, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.listNode.endedInteractiveDragging = { [weak self] in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strongSelf.ignoreScrolling {
|
|
||||||
Queue.mainQueue().after(0.5) {
|
|
||||||
strongSelf.ignoreScrolling = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.listNode.visibleContentOffsetChanged = { [weak self] offset in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch offset {
|
|
||||||
case let .known(value):
|
|
||||||
// strongSelf.updateFloatingHeaderOffset(offset: -value + strongSelf.listNode.insets.top, transition: strongSelf.listNode.isTracking ? .immediate : .animated(duration: 0.4, curve: .linear))
|
|
||||||
|
|
||||||
if value > 5, !strongSelf.currentIsExpanded && strongSelf.listNode.isTracking && !strongSelf.ignoreScrolling {
|
|
||||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers:strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set(), isExpanded: true)
|
|
||||||
strongSelf.ignoreScrolling = true
|
|
||||||
} else if value < -5, strongSelf.currentIsExpanded && strongSelf.listNode.isTracking && !strongSelf.ignoreScrolling {
|
|
||||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? [], isExpanded: false)
|
|
||||||
strongSelf.ignoreScrolling = true
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1223,7 +1193,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set(), isExpanded: self.currentIsExpanded)
|
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||||
@ -1268,7 +1238,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
if let (layout, navigationHeight) = self.validLayout {
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||||
}
|
}
|
||||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set(), isExpanded: self.currentIsExpanded)
|
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1341,7 +1311,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateFloatingHeaderOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
|
private func updateFloatingHeaderOffset(offset: CGFloat, transition: ContainedViewLayoutTransition, completion: (() -> Void)? = nil) {
|
||||||
guard let (layout, _) = self.validLayout else {
|
guard let (layout, _) = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1352,9 +1322,22 @@ public final class VoiceChatController: ViewController {
|
|||||||
let bottomAreaHeight: CGFloat = 268.0
|
let bottomAreaHeight: CGFloat = 268.0
|
||||||
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
|
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
|
||||||
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
|
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
|
||||||
let topInset = self.topInset ?? listSize.height
|
let topInset: CGFloat
|
||||||
|
if let (panInitialTopInset, panOffset) = self.panGestureArguments {
|
||||||
|
if self.isExpanded {
|
||||||
|
topInset = min(self.topInset ?? listSize.height, panInitialTopInset + max(0.0, panOffset))
|
||||||
|
} else {
|
||||||
|
topInset = max(0.0, panInitialTopInset + min(0.0, panOffset))
|
||||||
|
}
|
||||||
|
} else if let _ = self.animation {
|
||||||
|
topInset = self.listNode.frame.minY - listTopInset
|
||||||
|
} else if let currentTopInset = self.topInset {
|
||||||
|
topInset = self.isExpanded ? 0.0 : currentTopInset
|
||||||
|
} else {
|
||||||
|
topInset = listSize.height
|
||||||
|
}
|
||||||
|
|
||||||
var offset = offset + topInset
|
let offset = offset + topInset
|
||||||
self.floatingHeaderOffset = offset
|
self.floatingHeaderOffset = offset
|
||||||
|
|
||||||
let rawPanelOffset = offset + listTopInset - topPanelHeight
|
let rawPanelOffset = offset + listTopInset - topPanelHeight
|
||||||
@ -1374,7 +1357,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
if !topPanelFrame.equalTo(previousTopPanelFrame) {
|
if !topPanelFrame.equalTo(previousTopPanelFrame) {
|
||||||
self.topPanelNode.frame = topPanelFrame
|
self.topPanelNode.frame = topPanelFrame
|
||||||
let positionDelta = CGPoint(x: 0.0, y: topPanelFrame.minY - previousTopPanelFrame.minY)
|
let positionDelta = CGPoint(x: 0.0, y: topPanelFrame.minY - previousTopPanelFrame.minY)
|
||||||
transition.animateOffsetAdditive(node: self.topPanelNode, offset: positionDelta.y)
|
transition.animateOffsetAdditive(layer: self.topPanelNode.layer, offset: positionDelta.y, completion: completion)
|
||||||
|
|
||||||
self.backgroundNode.frame = backgroundFrame
|
self.backgroundNode.frame = backgroundFrame
|
||||||
let backgroundPositionDelta = CGPoint(x: 0.0, y: previousBackgroundFrame.minY - backgroundFrame.minY)
|
let backgroundPositionDelta = CGPoint(x: 0.0, y: previousBackgroundFrame.minY - backgroundFrame.minY)
|
||||||
@ -1387,6 +1370,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.rightBorderNode.frame = rightBorderFrame
|
self.rightBorderNode.frame = rightBorderFrame
|
||||||
let rightBorderPositionDelta = CGPoint(x: 0.0, y: previousRightBorderFrame.minY - rightBorderFrame.minY)
|
let rightBorderPositionDelta = CGPoint(x: 0.0, y: previousRightBorderFrame.minY - rightBorderFrame.minY)
|
||||||
transition.animatePositionAdditive(node: self.rightBorderNode, offset: rightBorderPositionDelta)
|
transition.animatePositionAdditive(node: self.rightBorderNode, offset: rightBorderPositionDelta)
|
||||||
|
} else {
|
||||||
|
completion?()
|
||||||
}
|
}
|
||||||
self.topPanelBackgroundNode.frame = CGRect(x: 0.0, y: topPanelHeight - 24.0, width: layout.size.width, height: 24.0)
|
self.topPanelBackgroundNode.frame = CGRect(x: 0.0, y: topPanelHeight - 24.0, width: layout.size.width, height: 24.0)
|
||||||
|
|
||||||
@ -1422,19 +1407,17 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isFullscreen = false
|
var isFullscreen = false
|
||||||
func updateColors(fullscreen: Bool) {
|
func updateIsFullscreen(_ isFullscreen: Bool) {
|
||||||
guard self.isFullscreen != fullscreen, let (layout, _) = self.validLayout else {
|
guard self.isFullscreen != isFullscreen, let (layout, _) = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.isFullscreen = fullscreen
|
self.isFullscreen = isFullscreen
|
||||||
|
|
||||||
self.controller?.statusBar.statusBarStyle = fullscreen ? .White : .Ignore
|
self.controller?.statusBar.statusBarStyle = isFullscreen ? .White : .Ignore
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .linear)
|
|
||||||
|
|
||||||
let topPanelHeight: CGFloat = 63.0
|
let topPanelHeight: CGFloat = 63.0
|
||||||
let topEdgeFrame: CGRect
|
let topEdgeFrame: CGRect
|
||||||
if self.isFullscreen {
|
if isFullscreen {
|
||||||
let offset: CGFloat
|
let offset: CGFloat
|
||||||
if let statusBarHeight = layout.statusBarHeight {
|
if let statusBarHeight = layout.statusBarHeight {
|
||||||
offset = statusBarHeight
|
offset = statusBarHeight
|
||||||
@ -1445,16 +1428,17 @@ public final class VoiceChatController: ViewController {
|
|||||||
} else {
|
} else {
|
||||||
topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: topPanelHeight)
|
topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: topPanelHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .linear)
|
||||||
transition.updateFrame(node: self.topPanelEdgeNode, frame: topEdgeFrame)
|
transition.updateFrame(node: self.topPanelEdgeNode, frame: topEdgeFrame)
|
||||||
transition.updateCornerRadius(node: self.topPanelEdgeNode, cornerRadius: fullscreen ? layout.deviceMetrics.screenCornerRadius - 0.5 : 12.0)
|
transition.updateCornerRadius(node: self.topPanelEdgeNode, cornerRadius: isFullscreen ? layout.deviceMetrics.screenCornerRadius - 0.5 : 12.0)
|
||||||
// transition.updateBackgroundColor(node: self.dimNode, color: fullscreen ? fullscreenBackgroundColor : dimColor)
|
transition.updateBackgroundColor(node: self.topPanelBackgroundNode, color: isFullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.topPanelBackgroundNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
transition.updateBackgroundColor(node: self.topPanelEdgeNode, color: isFullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.topPanelEdgeNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
transition.updateBackgroundColor(node: self.backgroundNode, color: isFullscreen ? panelBackgroundColor : secondaryPanelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.backgroundNode, color: fullscreen ? panelBackgroundColor : secondaryPanelBackgroundColor)
|
transition.updateBackgroundColor(node: self.bottomPanelBackgroundNode, color: isFullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.bottomPanelBackgroundNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
transition.updateBackgroundColor(node: self.leftBorderNode, color: isFullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.leftBorderNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
transition.updateBackgroundColor(node: self.rightBorderNode, color: isFullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.rightBorderNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
transition.updateBackgroundColor(node: self.rightBorderNode, color: isFullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
||||||
transition.updateBackgroundColor(node: self.rightBorderNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
|
|
||||||
|
|
||||||
if let snapshotView = self.topCornersNode.view.snapshotContentTree() {
|
if let snapshotView = self.topCornersNode.view.snapshotContentTree() {
|
||||||
snapshotView.frame = self.topCornersNode.frame
|
snapshotView.frame = self.topCornersNode.frame
|
||||||
@ -1464,7 +1448,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
snapshotView?.removeFromSuperview()
|
snapshotView?.removeFromSuperview()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
self.topCornersNode.image = cornersImage(top: true, bottom: false, dark: fullscreen)
|
self.topCornersNode.image = cornersImage(top: true, bottom: false, dark: isFullscreen)
|
||||||
|
|
||||||
if let snapshotView = self.bottomCornersNode.view.snapshotContentTree() {
|
if let snapshotView = self.bottomCornersNode.view.snapshotContentTree() {
|
||||||
snapshotView.frame = self.bottomCornersNode.bounds
|
snapshotView.frame = self.bottomCornersNode.bounds
|
||||||
@ -1474,10 +1458,10 @@ public final class VoiceChatController: ViewController {
|
|||||||
snapshotView?.removeFromSuperview()
|
snapshotView?.removeFromSuperview()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
self.bottomCornersNode.image = cornersImage(top: false, bottom: true, dark: fullscreen)
|
self.bottomCornersNode.image = cornersImage(top: false, bottom: true, dark: isFullscreen)
|
||||||
|
|
||||||
self.optionsButton.setImage(optionsButtonImage(dark: fullscreen), animated: transition.isAnimated)
|
self.optionsButton.setImage(optionsButtonImage(dark: isFullscreen), animated: transition.isAnimated)
|
||||||
self.closeButton.setImage(closeButtonImage(dark: fullscreen), animated: transition.isAnimated)
|
self.closeButton.setImage(closeButtonImage(dark: isFullscreen), animated: transition.isAnimated)
|
||||||
|
|
||||||
self.updateTitle(transition: transition)
|
self.updateTitle(transition: transition)
|
||||||
}
|
}
|
||||||
@ -1536,6 +1520,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
|
|
||||||
let soundImage: CallControllerButtonItemNode.Content.Image
|
let soundImage: CallControllerButtonItemNode.Content.Image
|
||||||
var soundAppearance: CallControllerButtonItemNode.Content.Appearance = audioButtonAppearance
|
var soundAppearance: CallControllerButtonItemNode.Content.Appearance = audioButtonAppearance
|
||||||
|
var soundTitle: String = self.presentationData.strings.Call_Speaker
|
||||||
switch audioMode {
|
switch audioMode {
|
||||||
case .none, .builtin:
|
case .none, .builtin:
|
||||||
soundImage = .speaker
|
soundImage = .speaker
|
||||||
@ -1543,7 +1528,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
soundImage = .speaker
|
soundImage = .speaker
|
||||||
soundAppearance = .blurred(isFilled: true)
|
soundAppearance = .blurred(isFilled: true)
|
||||||
case .headphones:
|
case .headphones:
|
||||||
soundImage = .bluetooth
|
soundImage = .headphones
|
||||||
|
soundTitle = self.presentationData.strings.Call_Audio
|
||||||
case let .bluetooth(type):
|
case let .bluetooth(type):
|
||||||
switch type {
|
switch type {
|
||||||
case .generic:
|
case .generic:
|
||||||
@ -1553,10 +1539,11 @@ public final class VoiceChatController: ViewController {
|
|||||||
case .airpodsPro:
|
case .airpodsPro:
|
||||||
soundImage = .airpodsPro
|
soundImage = .airpodsPro
|
||||||
}
|
}
|
||||||
|
soundTitle = self.presentationData.strings.Call_Audio
|
||||||
}
|
}
|
||||||
|
|
||||||
let sideButtonSize = CGSize(width: 60.0, height: 60.0)
|
let sideButtonSize = CGSize(width: 60.0, height: 60.0)
|
||||||
self.audioOutputNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: soundAppearance, image: soundImage), text: self.presentationData.strings.VoiceChat_Audio, transition: .animated(duration: 0.3, curve: .linear))
|
self.audioOutputNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: soundAppearance, image: soundImage), text: soundTitle, transition: .animated(duration: 0.3, curve: .linear))
|
||||||
|
|
||||||
self.leaveNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: .color(.custom(0x602522)), image: .end), text: self.presentationData.strings.VoiceChat_Leave, transition: .immediate)
|
self.leaveNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: .color(.custom(0x602522)), image: .end), text: self.presentationData.strings.VoiceChat_Leave, transition: .immediate)
|
||||||
}
|
}
|
||||||
@ -1583,6 +1570,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
insets.right = layout.safeInsets.right + sideInset
|
insets.right = layout.safeInsets.right + sideInset
|
||||||
|
|
||||||
let topPanelHeight: CGFloat = 63.0
|
let topPanelHeight: CGFloat = 63.0
|
||||||
|
if let _ = self.panGestureArguments {
|
||||||
|
} else {
|
||||||
let topEdgeFrame: CGRect
|
let topEdgeFrame: CGRect
|
||||||
if self.isFullscreen {
|
if self.isFullscreen {
|
||||||
let offset: CGFloat
|
let offset: CGFloat
|
||||||
@ -1596,12 +1585,28 @@ public final class VoiceChatController: ViewController {
|
|||||||
topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: topPanelHeight)
|
topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: topPanelHeight)
|
||||||
}
|
}
|
||||||
transition.updateFrame(node: self.topPanelEdgeNode, frame: topEdgeFrame)
|
transition.updateFrame(node: self.topPanelEdgeNode, frame: topEdgeFrame)
|
||||||
|
}
|
||||||
|
|
||||||
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
|
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
|
||||||
let listTopInset = layoutTopInset + topPanelHeight
|
let listTopInset = layoutTopInset + topPanelHeight
|
||||||
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
|
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
|
||||||
|
|
||||||
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset + (self.topInset ?? listSize.height)), size: listSize))
|
let topInset: CGFloat
|
||||||
|
if let (panInitialTopInset, panOffset) = self.panGestureArguments {
|
||||||
|
if self.isExpanded {
|
||||||
|
topInset = min(self.topInset ?? listSize.height, panInitialTopInset + max(0.0, panOffset))
|
||||||
|
} else {
|
||||||
|
topInset = max(0.0, panInitialTopInset + min(0.0, panOffset))
|
||||||
|
}
|
||||||
|
} else if let currentTopInset = self.topInset {
|
||||||
|
topInset = self.isExpanded ? 0.0 : currentTopInset
|
||||||
|
} else {
|
||||||
|
topInset = listSize.height
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.animation == nil {
|
||||||
|
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset + topInset), size: listSize))
|
||||||
|
}
|
||||||
|
|
||||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listSize, insets: insets, duration: duration, curve: curve)
|
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listSize, insets: insets, duration: duration, curve: curve)
|
||||||
@ -1778,24 +1783,24 @@ public final class VoiceChatController: ViewController {
|
|||||||
let listTopInset = layoutTopInset + 63.0
|
let listTopInset = layoutTopInset + 63.0
|
||||||
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
|
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
|
||||||
|
|
||||||
let previousIsExpanded = self.currentIsExpanded
|
self.topInset = max(0.0, max(listSize.height - itemsHeight, listSize.height - 46.0 - floor(56.0 * 3.5)))
|
||||||
self.currentIsExpanded = transition.isExpanded
|
|
||||||
self.topInset = max(0.0, transition.isExpanded ? 0.0 : max(listSize.height - itemsHeight, listSize.height - 46.0 - floor(56.0 * 3.5)))
|
|
||||||
|
|
||||||
let frameTransition: ContainedViewLayoutTransition
|
if !self.isExpanded {
|
||||||
if previousIsExpanded != self.currentIsExpanded {
|
let targetY = listTopInset + (self.topInset ?? listSize.height)
|
||||||
frameTransition = .animated(duration: 0.4, curve: .spring)
|
if self.listNode.frame.minY != targetY && !self.animatingExpansion && self.panGestureArguments == nil {
|
||||||
} else {
|
self.animation = ListViewAnimation(from: self.listNode.frame.minY, to: targetY, duration: 0.4, curve: listViewAnimationCurveEaseInOut, beginAt: CACurrentMediaTime(), update: { [weak self] _, currentValue in
|
||||||
frameTransition = .animated(duration: 0.4, curve: .easeInOut)
|
if let strongSelf = self {
|
||||||
|
var frame = strongSelf.listNode.frame
|
||||||
|
frame.origin.y = currentValue
|
||||||
|
strongSelf.listNode.frame = frame
|
||||||
|
strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .immediate)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.updateAnimation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
frameTransition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset + (self.topInset ?? listSize.height)), size: listSize))
|
|
||||||
|
|
||||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: frameTransition)
|
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: nil, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listSize, insets: insets, duration: duration, curve: curve)
|
|
||||||
|
|
||||||
self.updateColors(fullscreen: transition.isExpanded)
|
|
||||||
|
|
||||||
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, updateOpaqueState: nil, completion: { [weak self] _ in
|
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1804,12 +1809,42 @@ public final class VoiceChatController: ViewController {
|
|||||||
strongSelf.controller?.contentsReady.set(true)
|
strongSelf.controller?.contentsReady.set(true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if previousIsExpanded != self.currentIsExpanded {
|
}
|
||||||
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: frameTransition)
|
|
||||||
|
|
||||||
|
private var animator: ConstantDisplayLinkAnimator?
|
||||||
|
private var animation: ListViewAnimation?
|
||||||
|
private func updateAnimation() {
|
||||||
|
var animate = false
|
||||||
|
let timestamp = CACurrentMediaTime()
|
||||||
|
|
||||||
|
if let animation = self.animation {
|
||||||
|
animation.applyAt(timestamp)
|
||||||
|
|
||||||
|
if animation.completeAt(timestamp) {
|
||||||
|
self.animation = nil
|
||||||
|
} else {
|
||||||
|
animate = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: [GroupCallParticipantsContext.Participant], invitedPeers: [Peer], speakingPeers: Set<PeerId>, isExpanded: Bool) {
|
if animate {
|
||||||
|
let animator: ConstantDisplayLinkAnimator
|
||||||
|
if let current = self.animator {
|
||||||
|
animator = current
|
||||||
|
} else {
|
||||||
|
animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||||
|
self?.updateAnimation()
|
||||||
|
})
|
||||||
|
self.animator = animator
|
||||||
|
}
|
||||||
|
animator.isPaused = false
|
||||||
|
} else {
|
||||||
|
self.animator?.isPaused = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: [GroupCallParticipantsContext.Participant], invitedPeers: [Peer], speakingPeers: Set<PeerId>) {
|
||||||
self.currentCallMembers = callMembers
|
self.currentCallMembers = callMembers
|
||||||
self.currentSpeakingPeers = speakingPeers
|
self.currentSpeakingPeers = speakingPeers
|
||||||
self.currentInvitedPeers = invitedPeers
|
self.currentInvitedPeers = invitedPeers
|
||||||
@ -1874,7 +1909,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.currentEntries = entries
|
self.currentEntries = entries
|
||||||
|
|
||||||
let presentationData = self.presentationData.withUpdated(theme: self.darkTheme)
|
let presentationData = self.presentationData.withUpdated(theme: self.darkTheme)
|
||||||
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!, isExpanded: isExpanded ?? self.currentIsExpanded)
|
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!)
|
||||||
self.enqueueTransition(transition)
|
self.enqueueTransition(transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1882,56 +1917,190 @@ public final class VoiceChatController: ViewController {
|
|||||||
// if let callState = self.callState, case .connected = callState.networkState, let muteState = callState.muteState, !muteState.canUnmute {
|
// if let callState = self.callState, case .connected = callState.networkState, let muteState = callState.muteState, !muteState.canUnmute {
|
||||||
// return false
|
// return false
|
||||||
// }
|
// }
|
||||||
if let recognizer = gestureRecognizer as? UIPanGestureRecognizer {
|
// if let recognizer = gestureRecognizer as? UIPanGestureRecognizer {
|
||||||
let location = recognizer.location(in: self.view)
|
// let location = recognizer.location(in: self.view)
|
||||||
if let view = super.hitTest(location, with: nil) {
|
// if let view = super.hitTest(location, with: nil) {
|
||||||
if let gestureRecognizers = view.gestureRecognizers, view != self.view {
|
// if let gestureRecognizers = view.gestureRecognizers, view != self.view {
|
||||||
for gestureRecognizer in gestureRecognizers {
|
// for gestureRecognizer in gestureRecognizers {
|
||||||
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer, gestureRecognizer.isEnabled {
|
// if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer, gestureRecognizer.isEnabled {
|
||||||
if panGestureRecognizer.state != .began {
|
// if panGestureRecognizer.state != .began {
|
||||||
panGestureRecognizer.isEnabled = false
|
// panGestureRecognizer.isEnabled = false
|
||||||
panGestureRecognizer.isEnabled = true
|
// panGestureRecognizer.isEnabled = true
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isExpanded = false
|
||||||
|
private var animatingExpansion = false
|
||||||
|
private var panGestureArguments: (topInset: CGFloat, offset: CGFloat)?
|
||||||
|
|
||||||
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||||
switch recognizer.state {
|
switch recognizer.state {
|
||||||
case .began:
|
case .began:
|
||||||
break
|
let topInset: CGFloat
|
||||||
|
if self.isExpanded {
|
||||||
|
topInset = 0.0
|
||||||
|
} else if let currentTopInset = self.topInset {
|
||||||
|
topInset = currentTopInset
|
||||||
|
} else {
|
||||||
|
topInset = self.listNode.frame.height
|
||||||
|
}
|
||||||
|
self.panGestureArguments = (topInset, 0.0)
|
||||||
case .changed:
|
case .changed:
|
||||||
|
var translation = recognizer.translation(in: self.contentContainer.view).y
|
||||||
|
var topInset: CGFloat = 0.0
|
||||||
|
if let (currentTopInset, currentPanOffset) = self.panGestureArguments {
|
||||||
|
topInset = currentTopInset
|
||||||
|
|
||||||
|
if case let .known(value) = self.listNode.visibleContentOffset(), value > 0 {
|
||||||
|
translation = currentPanOffset
|
||||||
|
if self.isExpanded {
|
||||||
|
recognizer.setTranslation(CGPoint(), in: self.contentContainer.view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.panGestureArguments = (currentTopInset, translation)
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentOffset = topInset + translation
|
||||||
|
if currentOffset < 20.0 {
|
||||||
|
self.updateIsFullscreen(true)
|
||||||
|
} else if currentOffset > 40.0 {
|
||||||
|
self.updateIsFullscreen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.isExpanded {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if currentOffset > 0.0 {
|
||||||
|
self.listNode.scroller.panGestureRecognizer.setTranslation(CGPoint(), in: self.listNode.scroller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate)
|
||||||
|
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .immediate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.isExpanded {
|
||||||
|
var bounds = self.contentContainer.bounds
|
||||||
|
bounds.origin.y = -translation
|
||||||
|
bounds.origin.y = min(0.0, bounds.origin.y)
|
||||||
|
self.contentContainer.bounds = bounds
|
||||||
|
}
|
||||||
|
case .ended:
|
||||||
let translation = recognizer.translation(in: self.contentContainer.view)
|
let translation = recognizer.translation(in: self.contentContainer.view)
|
||||||
|
var velocity = recognizer.velocity(in: self.contentContainer.view)
|
||||||
|
|
||||||
|
if case let .known(value) = self.listNode.visibleContentOffset(), value > 0 {
|
||||||
|
velocity = CGPoint()
|
||||||
|
}
|
||||||
|
|
||||||
var bounds = self.contentContainer.bounds
|
var bounds = self.contentContainer.bounds
|
||||||
bounds.origin.y = -translation.y
|
bounds.origin.y = -translation.y
|
||||||
bounds.origin.y = min(0.0, bounds.origin.y)
|
bounds.origin.y = min(0.0, bounds.origin.y)
|
||||||
self.contentContainer.bounds = bounds
|
|
||||||
case .ended:
|
|
||||||
let translation = recognizer.translation(in: self.contentContainer.view)
|
|
||||||
var bounds = self.contentContainer.bounds
|
|
||||||
bounds.origin.y = -translation.y
|
|
||||||
|
|
||||||
let velocity = recognizer.velocity(in: self.contentContainer.view)
|
let offset: CGFloat
|
||||||
|
if let (inset, panOffset) = self.panGestureArguments {
|
||||||
if (bounds.minY < -60.0 || velocity.y > 300.0) {
|
offset = inset + panOffset
|
||||||
self.controller?.dismiss(closing: false)
|
|
||||||
} else {
|
} else {
|
||||||
|
offset = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let topInset: CGFloat
|
||||||
|
if let currentTopInset = self.topInset {
|
||||||
|
topInset = currentTopInset
|
||||||
|
} else {
|
||||||
|
topInset = self.listNode.frame.height
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.isExpanded {
|
||||||
|
self.panGestureArguments = nil
|
||||||
|
if velocity.y > 300.0 || offset > topInset / 2.0 {
|
||||||
|
self.isExpanded = false
|
||||||
|
self.updateIsFullscreen(false)
|
||||||
|
self.animatingExpansion = true
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
|
}
|
||||||
|
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: {
|
||||||
|
self.animatingExpansion = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.updateIsFullscreen(true)
|
||||||
|
self.animatingExpansion = true
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
|
}
|
||||||
|
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: {
|
||||||
|
self.animatingExpansion = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.panGestureArguments = nil
|
||||||
|
var dismissing = false
|
||||||
|
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) {
|
||||||
|
self.controller?.dismiss(closing: false)
|
||||||
|
dismissing = true
|
||||||
|
} else if velocity.y < -300.0 || offset < topInset / 2.0 {
|
||||||
|
self.isExpanded = true
|
||||||
|
self.updateIsFullscreen(true)
|
||||||
|
self.animatingExpansion = true
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
|
}
|
||||||
|
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: {
|
||||||
|
self.animatingExpansion = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.updateIsFullscreen(false)
|
||||||
|
self.animatingExpansion = true
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
|
}
|
||||||
|
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: {
|
||||||
|
self.animatingExpansion = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !dismissing {
|
||||||
var bounds = self.contentContainer.bounds
|
var bounds = self.contentContainer.bounds
|
||||||
let previousBounds = bounds
|
let previousBounds = bounds
|
||||||
bounds.origin.y = 0.0
|
bounds.origin.y = 0.0
|
||||||
self.contentContainer.bounds = bounds
|
self.contentContainer.bounds = bounds
|
||||||
self.contentContainer.layer.animateBounds(from: previousBounds, to: self.contentContainer.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
self.contentContainer.layer.animateBounds(from: previousBounds, to: self.contentContainer.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
|
self.panGestureArguments = nil
|
||||||
|
|
||||||
let previousBounds = self.contentContainer.bounds
|
let previousBounds = self.contentContainer.bounds
|
||||||
var bounds = self.contentContainer.bounds
|
var bounds = self.contentContainer.bounds
|
||||||
bounds.origin.y = 0.0
|
bounds.origin.y = 0.0
|
||||||
self.contentContainer.bounds = bounds
|
self.contentContainer.bounds = bounds
|
||||||
self.contentContainer.layer.animateBounds(from: previousBounds, to: self.contentContainer.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
self.contentContainer.layer.animateBounds(from: previousBounds, to: self.contentContainer.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||||
|
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
|
}
|
||||||
|
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: {
|
||||||
|
self.animatingExpansion = false
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1941,7 +2110,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
let result = super.hitTest(point, with: event)
|
let result = super.hitTest(point, with: event)
|
||||||
|
|
||||||
if result === self.topPanelNode.view {
|
if result === self.topPanelNode.view {
|
||||||
return self.listNode.view
|
return self.view
|
||||||
}
|
}
|
||||||
|
|
||||||
if result === self.bottomPanelNode.view {
|
if result === self.bottomPanelNode.view {
|
||||||
@ -2071,9 +2240,13 @@ public final class VoiceChatController: ViewController {
|
|||||||
if let navigationController = self.navigationController as? NavigationController {
|
if let navigationController = self.navigationController as? NavigationController {
|
||||||
let count = navigationController.viewControllers.count
|
let count = navigationController.viewControllers.count
|
||||||
if count == 2 || navigationController.viewControllers[count - 2] is ChatController {
|
if count == 2 || navigationController.viewControllers[count - 2] is ChatController {
|
||||||
|
if case .active(.cantSpeak) = self.controllerNode.actionButton.stateValue {
|
||||||
|
} else if let chatController = navigationController.viewControllers[count - 2] as? ChatController, chatController.isSendButtonVisible {
|
||||||
|
} else {
|
||||||
self.detachActionButton()
|
self.detachActionButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.isDisconnected = true
|
self.isDisconnected = true
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
|
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
|
||||||
if hidden {
|
if hidden {
|
||||||
if slide {
|
if slide {
|
||||||
|
actionButton.isHidden = false
|
||||||
transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint(x: slideOffset, y: 0.0))
|
transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint(x: slideOffset, y: 0.0))
|
||||||
} else {
|
} else {
|
||||||
actionButton.layer.removeAllAnimations()
|
actionButton.layer.removeAllAnimations()
|
||||||
@ -64,10 +65,10 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actionButton.isHidden = false
|
actionButton.isHidden = false
|
||||||
|
actionButton.layer.removeAllAnimations()
|
||||||
if slide {
|
if slide {
|
||||||
transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint())
|
transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint())
|
||||||
} else {
|
} else {
|
||||||
actionButton.layer.removeAllAnimations()
|
|
||||||
actionButton.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
actionButton.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,10 +92,13 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
actionButton.update(snap: true, animated: !self.isSlidOffscreen)
|
actionButton.update(snap: true, animated: !self.isSlidOffscreen && !self.isButtonHidden)
|
||||||
if self.isSlidOffscreen {
|
if self.isSlidOffscreen {
|
||||||
actionButton.layer.sublayerTransform = CATransform3DMakeTranslation(slideOffset, 0.0, 0.0)
|
actionButton.layer.sublayerTransform = CATransform3DMakeTranslation(slideOffset, 0.0, 0.0)
|
||||||
return
|
return
|
||||||
|
} else if self.isButtonHidden {
|
||||||
|
actionButton.isHidden = true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetPosition = actionButton.position
|
let targetPosition = actionButton.position
|
||||||
@ -125,12 +129,14 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var animating = false
|
private var animating = false
|
||||||
|
private var dismissed = false
|
||||||
func animateOut(reclaim: Bool, completion: @escaping (Bool) -> Void) {
|
func animateOut(reclaim: Bool, completion: @escaping (Bool) -> Void) {
|
||||||
guard let actionButton = self.controller?.actionButton, let layout = self.validLayout else {
|
guard let actionButton = self.controller?.actionButton, let layout = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if reclaim {
|
if reclaim {
|
||||||
|
self.dismissed = true
|
||||||
let targetPosition = CGPoint(x: layout.size.width / 2.0, y: layout.size.height - layout.intrinsicInsets.bottom - 268.0 / 2.0)
|
let targetPosition = CGPoint(x: layout.size.width / 2.0, y: layout.size.height - layout.intrinsicInsets.bottom - 268.0 / 2.0)
|
||||||
if self.isSlidOffscreen {
|
if self.isSlidOffscreen {
|
||||||
self.isSlidOffscreen = false
|
self.isSlidOffscreen = false
|
||||||
@ -139,6 +145,13 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
actionButton.update(snap: false, animated: false)
|
actionButton.update(snap: false, animated: false)
|
||||||
actionButton.position = CGPoint(x: targetPosition.x, y: 268.0 / 2.0)
|
actionButton.position = CGPoint(x: targetPosition.x, y: 268.0 / 2.0)
|
||||||
completion(true)
|
completion(true)
|
||||||
|
} else if self.isButtonHidden {
|
||||||
|
actionButton.isHidden = false
|
||||||
|
actionButton.layer.removeAllAnimations()
|
||||||
|
actionButton.layer.sublayerTransform = CATransform3DIdentity
|
||||||
|
actionButton.update(snap: false, animated: false)
|
||||||
|
actionButton.position = CGPoint(x: targetPosition.x, y: 268.0 / 2.0)
|
||||||
|
completion(true)
|
||||||
} else {
|
} else {
|
||||||
self.animating = true
|
self.animating = true
|
||||||
let sourcePoint = actionButton.position
|
let sourcePoint = actionButton.position
|
||||||
@ -193,17 +206,18 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var didAnimateIn = false
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = layout
|
self.validLayout = layout
|
||||||
|
|
||||||
if let actionButton = self.controller?.actionButton, !self.animating {
|
if let actionButton = self.controller?.actionButton, !self.animating && !self.dismissed {
|
||||||
let convertedRect = actionButton.view.convert(actionButton.bounds, to: self.view)
|
let convertedRect = actionButton.view.convert(actionButton.bounds, to: self.view)
|
||||||
let insets = layout.insets(options: [.input])
|
let insets = layout.insets(options: [.input])
|
||||||
transition.updatePosition(node: actionButton, position: CGPoint(x: layout.size.width - layout.safeInsets.right - 21.0, y: layout.size.height - insets.bottom - 22.0))
|
transition.updatePosition(node: actionButton, position: CGPoint(x: layout.size.width - layout.safeInsets.right - 21.0, y: layout.size.height - insets.bottom - 22.0))
|
||||||
|
|
||||||
if actionButton.supernode !== self {
|
if actionButton.supernode !== self && !self.didAnimateIn {
|
||||||
|
self.didAnimateIn = true
|
||||||
self.addSubnode(actionButton)
|
self.addSubnode(actionButton)
|
||||||
|
|
||||||
self.animateIn(from: convertedRect)
|
self.animateIn(from: convertedRect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,15 +238,18 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = .Ignore
|
self.statusBar.statusBarStyle = .Ignore
|
||||||
self.additionalSideInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 75.0)
|
|
||||||
|
|
||||||
|
if case .active(.cantSpeak) = actionButton.stateValue {
|
||||||
|
} else {
|
||||||
|
self.additionalSideInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 75.0)
|
||||||
|
}
|
||||||
if let navigationController = navigationController {
|
if let navigationController = navigationController {
|
||||||
let controllers: Signal<[UIViewController], NoError> = .single([])
|
let controllers: Signal<[UIViewController], NoError> = .single([])
|
||||||
|> then(navigationController.viewControllersSignal)
|
|> then(navigationController.viewControllersSignal)
|
||||||
let overlayControllers: Signal<[UIViewController], NoError> = .single([])
|
let overlayControllers: Signal<[UIViewController], NoError> = .single([])
|
||||||
|> then(navigationController.overlayControllersSignal)
|
|> then(navigationController.overlayControllersSignal)
|
||||||
|
|
||||||
self.disposable = (combineLatest(queue: Queue.mainQueue(), controllers, overlayControllers)).start(next: { [weak self] controllers, overlayControllers in
|
self.disposable = (combineLatest(queue: Queue.mainQueue(), controllers, overlayControllers, actionButton.state)).start(next: { [weak self] controllers, overlayControllers, state in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var hasVoiceChatController = false
|
var hasVoiceChatController = false
|
||||||
var overlayControllersCount = 0
|
var overlayControllersCount = 0
|
||||||
@ -248,19 +265,37 @@ public final class VoiceChatOverlayController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var slide = true
|
||||||
var hidden = true
|
var hidden = true
|
||||||
var animated = true
|
var animated = true
|
||||||
if controllers.count == 1 || controllers.last is ChatController {
|
if controllers.count == 1 || controllers.last is ChatController {
|
||||||
|
if let chatController = controllers.last as? ChatController, chatController.isSendButtonVisible {
|
||||||
|
slide = false
|
||||||
|
animated = false
|
||||||
|
} else {
|
||||||
hidden = false
|
hidden = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if overlayControllersCount > 0 {
|
if overlayControllersCount > 0 {
|
||||||
hidden = true
|
hidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .active(.cantSpeak) = state {
|
||||||
|
hidden = true
|
||||||
|
}
|
||||||
if hasVoiceChatController {
|
if hasVoiceChatController {
|
||||||
hidden = false
|
hidden = false
|
||||||
animated = false
|
animated = false
|
||||||
}
|
}
|
||||||
strongSelf.controllerNode.update(hidden: hidden, slide: true, animated: animated)
|
|
||||||
|
strongSelf.controllerNode.update(hidden: hidden, slide: slide, animated: animated)
|
||||||
|
|
||||||
|
let previousInsets = strongSelf.additionalSideInsets
|
||||||
|
strongSelf.additionalSideInsets = hidden ? UIEdgeInsets() : UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 75.0)
|
||||||
|
|
||||||
|
if previousInsets != strongSelf.additionalSideInsets {
|
||||||
|
navigationController.requestLayout(transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1001,6 +1001,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
|||||||
updatedState.readOutbox(MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: maxId), timestamp: nil)
|
updatedState.readOutbox(MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), namespace: Namespaces.Message.Cloud, id: maxId), timestamp: nil)
|
||||||
case let .updateChannel(channelId):
|
case let .updateChannel(channelId):
|
||||||
updatedState.addExternallyUpdatedPeerId(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId))
|
updatedState.addExternallyUpdatedPeerId(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId))
|
||||||
|
case let .updateChat(chatId):
|
||||||
|
updatedState.addExternallyUpdatedPeerId(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))
|
||||||
case let .updateReadHistoryInbox(_, folderId, peer, maxId, stillUnreadCount, pts, _):
|
case let .updateReadHistoryInbox(_, folderId, peer, maxId, stillUnreadCount, pts, _):
|
||||||
updatedState.resetIncomingReadState(groupId: PeerGroupId(rawValue: folderId ?? 0), peerId: peer.peerId, namespace: Namespaces.Message.Cloud, maxIncomingReadId: maxId, count: stillUnreadCount, pts: pts)
|
updatedState.resetIncomingReadState(groupId: PeerGroupId(rawValue: folderId ?? 0), peerId: peer.peerId, namespace: Namespaces.Message.Cloud, maxIncomingReadId: maxId, count: stillUnreadCount, pts: pts)
|
||||||
case let .updateReadHistoryOutbox(peer, maxId, _, _):
|
case let .updateReadHistoryOutbox(peer, maxId, _, _):
|
||||||
@ -1334,6 +1336,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
|||||||
}
|
}
|
||||||
case let .updateGroupCall(channelId, call):
|
case let .updateGroupCall(channelId, call):
|
||||||
updatedState.updateGroupCall(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), call: call)
|
updatedState.updateGroupCall(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), call: call)
|
||||||
|
updatedState.updateGroupCall(peerId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: channelId), call: call)
|
||||||
case let .updateLangPackTooLong(langCode):
|
case let .updateLangPackTooLong(langCode):
|
||||||
updatedState.updateLangPack(langCode: langCode, difference: nil)
|
updatedState.updateLangPack(langCode: langCode, difference: nil)
|
||||||
case let .updateLangPack(difference):
|
case let .updateLangPack(difference):
|
||||||
@ -2966,6 +2969,8 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
|||||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||||
if let current = current as? CachedChannelData {
|
if let current = current as? CachedChannelData {
|
||||||
return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash))
|
return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash))
|
||||||
|
} else if let current = current as? CachedGroupData {
|
||||||
|
return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash))
|
||||||
} else {
|
} else {
|
||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
@ -2997,6 +3002,12 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
|||||||
} else {
|
} else {
|
||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
|
} else if let current = current as? CachedGroupData {
|
||||||
|
if let activeCall = current.activeCall, activeCall.id == callId {
|
||||||
|
return current.withUpdatedActiveCall(nil)
|
||||||
|
} else {
|
||||||
|
return current
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
|
@ -126,8 +126,8 @@ public enum CreateGroupCallError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCallInfo, CreateGroupCallError> {
|
public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCallInfo, CreateGroupCallError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
|> castError(CreateGroupCallError.self)
|
|> castError(CreateGroupCallError.self)
|
||||||
|> mapToSignal { inputPeer -> Signal<GroupCallInfo, CreateGroupCallError> in
|
|> mapToSignal { inputPeer -> Signal<GroupCallInfo, CreateGroupCallError> in
|
||||||
@ -135,7 +135,7 @@ public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCal
|
|||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
return account.network.request(Api.functions.phone.createGroupCall(channel: inputPeer, randomId: Int32.random(in: Int32.min ... Int32.max)))
|
return account.network.request(Api.functions.phone.createGroupCall(peer: inputPeer, randomId: Int32.random(in: Int32.min ... Int32.max)))
|
||||||
|> mapError { error -> CreateGroupCallError in
|
|> mapError { error -> CreateGroupCallError in
|
||||||
if error.errorDescription == "ANONYMOUS_CALLS_DISABLED" {
|
if error.errorDescription == "ANONYMOUS_CALLS_DISABLED" {
|
||||||
return .anonymousNotAllowed
|
return .anonymousNotAllowed
|
||||||
@ -162,6 +162,8 @@ public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCal
|
|||||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||||
if let cachedData = cachedData as? CachedChannelData {
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash))
|
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash))
|
||||||
|
} else if let cachedData = cachedData as? CachedGroupData {
|
||||||
|
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash))
|
||||||
} else {
|
} else {
|
||||||
return cachedData
|
return cachedData
|
||||||
}
|
}
|
||||||
@ -283,7 +285,10 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
|||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|> mapToSignal { updates -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
|> mapToSignal { updates -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
||||||
let admins = account.postbox.transaction { transaction -> Api.InputChannel? in
|
|
||||||
|
let admins: Signal<(Set<PeerId>, [Api.User]), JoinGroupCallError>
|
||||||
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
|
admins = account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||||
}
|
}
|
||||||
|> castError(JoinGroupCallError.self)
|
|> castError(JoinGroupCallError.self)
|
||||||
@ -297,9 +302,54 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
|||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|> map { admins -> (Set<PeerId>, [Api.User]) in
|
||||||
|
var adminIds = Set<PeerId>()
|
||||||
|
var apiUsers: [Api.User] = []
|
||||||
|
|
||||||
let channel = account.postbox.transaction { transaction -> TelegramChannel? in
|
switch admins {
|
||||||
return transaction.getPeer(peerId) as? TelegramChannel
|
case let .channelParticipants(_, participants, users):
|
||||||
|
apiUsers.append(contentsOf: users)
|
||||||
|
|
||||||
|
for participant in participants {
|
||||||
|
let parsedParticipant = ChannelParticipant(apiParticipant: participant)
|
||||||
|
switch parsedParticipant {
|
||||||
|
case .creator:
|
||||||
|
adminIds.insert(parsedParticipant.peerId)
|
||||||
|
case let .member(_, _, adminInfo, _, _):
|
||||||
|
if let adminInfo = adminInfo, adminInfo.rights.flags.contains(.canManageCalls) {
|
||||||
|
adminIds.insert(parsedParticipant.peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (adminIds, apiUsers)
|
||||||
|
}
|
||||||
|
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||||
|
admins = account.postbox.transaction { transaction -> (Set<PeerId>, [Api.User]) in
|
||||||
|
var result = Set<PeerId>()
|
||||||
|
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData {
|
||||||
|
if let participants = cachedData.participants {
|
||||||
|
for participant in participants.participants {
|
||||||
|
if case .creator = participant {
|
||||||
|
result.insert(participant.peerId)
|
||||||
|
} else if case .admin = participant {
|
||||||
|
result.insert(participant.peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (result, [])
|
||||||
|
}
|
||||||
|
|> castError(JoinGroupCallError.self)
|
||||||
|
} else {
|
||||||
|
admins = .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
let peer = account.postbox.transaction { transaction -> Peer? in
|
||||||
|
return transaction.getPeer(peerId)
|
||||||
}
|
}
|
||||||
|> castError(JoinGroupCallError.self)
|
|> castError(JoinGroupCallError.self)
|
||||||
|
|
||||||
@ -313,15 +363,23 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
|||||||
return .generic
|
return .generic
|
||||||
},
|
},
|
||||||
admins,
|
admins,
|
||||||
channel
|
peer
|
||||||
)
|
)
|
||||||
|> mapToSignal { result, state, admins, channel -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
|> mapToSignal { result, state, admins, peer -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
||||||
guard let channel = channel else {
|
guard let peer = peer else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
var state = state
|
var state = state
|
||||||
|
if let channel = peer as? TelegramChannel {
|
||||||
state.isCreator = channel.flags.contains(.isCreator)
|
state.isCreator = channel.flags.contains(.isCreator)
|
||||||
|
} else if let group = peer as? TelegramGroup {
|
||||||
|
if case .creator = group.role {
|
||||||
|
state.isCreator = true
|
||||||
|
} else {
|
||||||
|
state.isCreator = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
account.stateManager.addUpdates(updates)
|
account.stateManager.addUpdates(updates)
|
||||||
|
|
||||||
@ -351,26 +409,9 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
|||||||
}
|
}
|
||||||
|
|
||||||
var apiUsers: [Api.User] = []
|
var apiUsers: [Api.User] = []
|
||||||
var adminIds = Set<PeerId>()
|
|
||||||
|
|
||||||
switch admins {
|
let (adminIds, adminUsers) = admins
|
||||||
case let .channelParticipants(_, participants, users):
|
apiUsers.append(contentsOf: adminUsers)
|
||||||
apiUsers.append(contentsOf: users)
|
|
||||||
|
|
||||||
for participant in participants {
|
|
||||||
let parsedParticipant = ChannelParticipant(apiParticipant: participant)
|
|
||||||
switch parsedParticipant {
|
|
||||||
case .creator:
|
|
||||||
adminIds.insert(parsedParticipant.peerId)
|
|
||||||
case let .member(_, _, adminInfo, _, _):
|
|
||||||
if let adminInfo = adminInfo, adminInfo.rights.flags.contains(.canManageCalls) {
|
|
||||||
adminIds.insert(parsedParticipant.peerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
state.adminIds = adminIds
|
state.adminIds = adminIds
|
||||||
|
|
||||||
@ -440,6 +481,8 @@ public func stopGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
|||||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||||
if let cachedData = cachedData as? CachedChannelData {
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
return cachedData.withUpdatedActiveCall(nil)
|
return cachedData.withUpdatedActiveCall(nil)
|
||||||
|
} else if let cachedData = cachedData as? CachedGroupData {
|
||||||
|
return cachedData.withUpdatedActiveCall(nil)
|
||||||
} else {
|
} else {
|
||||||
return cachedData
|
return cachedData
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ extension StickerPackCollectionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var thumbnailRepresentation: TelegramMediaImageRepresentation?
|
var thumbnailRepresentation: TelegramMediaImageRepresentation?
|
||||||
if let thumb = thumb, let thumbDcId = thumbDcId {
|
if let thumb = thumb?.first, let thumbDcId = thumbDcId {
|
||||||
thumbnailRepresentation = telegramStickerPackThumbnailRepresentationFromApiSize(datacenterId: thumbDcId, size: thumb)
|
thumbnailRepresentation = telegramStickerPackThumbnailRepresentationFromApiSize(datacenterId: thumbDcId, size: thumb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +292,14 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
|
|||||||
hasScheduledMessages = true
|
hasScheduledMessages = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var updatedActiveCall: CachedChannelData.ActiveCall?
|
||||||
|
if let inputCall = chatFull.call {
|
||||||
|
switch inputCall {
|
||||||
|
case let .inputGroupCall(id, accessHash):
|
||||||
|
updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in
|
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in
|
||||||
let previous: CachedGroupData
|
let previous: CachedGroupData
|
||||||
if let current = current as? CachedGroupData {
|
if let current = current as? CachedGroupData {
|
||||||
@ -309,6 +317,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
|
|||||||
.withUpdatedHasScheduledMessages(hasScheduledMessages)
|
.withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||||
.withUpdatedInvitedBy(invitedBy)
|
.withUpdatedInvitedBy(invitedBy)
|
||||||
.withUpdatedPhoto(photo)
|
.withUpdatedPhoto(photo)
|
||||||
|
.withUpdatedActiveCall(updatedActiveCall)
|
||||||
})
|
})
|
||||||
case .channelFull:
|
case .channelFull:
|
||||||
break
|
break
|
||||||
|
@ -251,6 +251,8 @@ extension Api.Update {
|
|||||||
switch self {
|
switch self {
|
||||||
case let .updateChannel(channelId):
|
case let .updateChannel(channelId):
|
||||||
return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)]
|
return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)]
|
||||||
|
case let .updateChat(chatId):
|
||||||
|
return [PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)]
|
||||||
case let .updateChannelTooLong(_, channelId, _):
|
case let .updateChannelTooLong(_, channelId, _):
|
||||||
return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)]
|
return [PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)]
|
||||||
case let .updateChatParticipantAdd(chatId, userId, inviterId, _, _):
|
case let .updateChatParticipantAdd(chatId, userId, inviterId, _, _):
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -405,13 +405,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
}
|
}
|
||||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||||
case let .groupPhoneCall(_, _, duration):
|
case let .groupPhoneCall(_, _, duration):
|
||||||
let titleString: String
|
|
||||||
if let duration = duration {
|
if let duration = duration {
|
||||||
titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).0
|
let titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).0
|
||||||
} else {
|
|
||||||
titleString = strings.Notification_VoiceChatStarted
|
|
||||||
}
|
|
||||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||||
|
} else {
|
||||||
|
var attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)]
|
||||||
|
let titleString = strings.Notification_VoiceChatStarted(authorName)
|
||||||
|
attributedString = addAttributesToStringWithRanges(titleString, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
|
||||||
|
}
|
||||||
case let .customText(text, entities):
|
case let .customText(text, entities):
|
||||||
attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false)
|
attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false)
|
||||||
case let .botDomainAccessGranted(domain):
|
case let .botDomainAccessGranted(domain):
|
||||||
|
12
submodules/TelegramUI/Images.xcassets/Call/CallHeadphonesButton.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Call/CallHeadphonesButton.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "ic_call_headphones.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
submodules/TelegramUI/Images.xcassets/Call/CallHeadphonesButton.imageset/ic_call_headphones.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Call/CallHeadphonesButton.imageset/ic_call_headphones.pdf
vendored
Normal file
Binary file not shown.
Binary file not shown.
@ -318,7 +318,7 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
}
|
}
|
||||||
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
|
||||||
if let current = current {
|
if let current = current {
|
||||||
if current is TelegramChannel {
|
if current is TelegramChannel || current is TelegramGroup {
|
||||||
strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_VoiceChatInProgressTitle, text: presentationData.strings.Call_VoiceChatInProgressMessage(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.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_VoiceChatInProgressTitle, text: presentationData.strings.Call_VoiceChatInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -364,7 +364,7 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
}
|
}
|
||||||
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
|
||||||
if let current = current {
|
if let current = current {
|
||||||
if current is TelegramChannel {
|
if current is TelegramChannel || current is TelegramGroup {
|
||||||
strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_VoiceChatInProgressTitle, text: presentationData.strings.Call_VoiceChatInProgressCallMessage(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.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_VoiceChatInProgressTitle, text: presentationData.strings.Call_VoiceChatInProgressCallMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
@ -3753,6 +3753,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
pinnedMessageId = cachedData.pinnedMessageId
|
pinnedMessageId = cachedData.pinnedMessageId
|
||||||
} else if let cachedData = combinedInitialData.cachedData as? CachedGroupData {
|
} else if let cachedData = combinedInitialData.cachedData as? CachedGroupData {
|
||||||
pinnedMessageId = cachedData.pinnedMessageId
|
pinnedMessageId = cachedData.pinnedMessageId
|
||||||
|
if let activeCall = cachedData.activeCall {
|
||||||
|
activeGroupCallInfo = ChatActiveGroupCallInfo(activeCall: activeCall)
|
||||||
|
}
|
||||||
} else if let _ = combinedInitialData.cachedData as? CachedSecretChatData {
|
} else if let _ = combinedInitialData.cachedData as? CachedSecretChatData {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3908,6 +3911,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
pinnedMessageId = cachedData.pinnedMessageId
|
pinnedMessageId = cachedData.pinnedMessageId
|
||||||
} else if let cachedData = cachedData as? CachedGroupData {
|
} else if let cachedData = cachedData as? CachedGroupData {
|
||||||
pinnedMessageId = cachedData.pinnedMessageId
|
pinnedMessageId = cachedData.pinnedMessageId
|
||||||
|
if let activeCall = cachedData.activeCall {
|
||||||
|
activeGroupCallInfo = ChatActiveGroupCallInfo(activeCall: activeCall)
|
||||||
|
}
|
||||||
} else if let _ = cachedData as? CachedSecretChatData {
|
} else if let _ = cachedData as? CachedSecretChatData {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6221,9 +6227,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let shouldBeActive = combineLatest(self.context.sharedContext.mediaManager.audioSession.isPlaybackActive() |> deliverOnMainQueue, self.chatDisplayNode.historyNode.hasVisiblePlayableItemNodes)
|
let hasActiveCalls: Signal<Bool, NoError>
|
||||||
|> mapToSignal { [weak self] isPlaybackActive, hasVisiblePlayableItemNodes -> Signal<Bool, NoError> in
|
if let callManager = self.context.sharedContext.callManager as? PresentationCallManagerImpl {
|
||||||
if hasVisiblePlayableItemNodes && !isPlaybackActive {
|
hasActiveCalls = callManager.hasActiveCalls
|
||||||
|
} else {
|
||||||
|
hasActiveCalls = .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
let shouldBeActive = combineLatest(self.context.sharedContext.mediaManager.audioSession.isPlaybackActive() |> deliverOnMainQueue, self.chatDisplayNode.historyNode.hasVisiblePlayableItemNodes, hasActiveCalls)
|
||||||
|
|> mapToSignal { [weak self] isPlaybackActive, hasVisiblePlayableItemNodes, hasActiveCalls -> Signal<Bool, NoError> in
|
||||||
|
if hasVisiblePlayableItemNodes && !isPlaybackActive && !hasActiveCalls {
|
||||||
return Signal<Bool, NoError> { [weak self] subscriber in
|
return Signal<Bool, NoError> { [weak self] subscriber in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
@ -7060,7 +7073,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.saveInterfaceState(includeScrollState: false)
|
self.saveInterfaceState(includeScrollState: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let navigationController = self.navigationController as? NavigationController {
|
if let navigationController = self.navigationController as? NavigationController, self.traceVisibility() && isTopmostChatController(self) {
|
||||||
var voiceChatOverlayController: VoiceChatOverlayController?
|
var voiceChatOverlayController: VoiceChatOverlayController?
|
||||||
for controller in navigationController.globalOverlayControllers {
|
for controller in navigationController.globalOverlayControllers {
|
||||||
if let controller = controller as? VoiceChatOverlayController {
|
if let controller = controller as? VoiceChatOverlayController {
|
||||||
@ -7070,11 +7083,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let controller = voiceChatOverlayController {
|
if let controller = voiceChatOverlayController {
|
||||||
var hidden = false
|
controller.update(hidden: self.isSendButtonVisible, slide: false, animated: true)
|
||||||
if self.presentationInterfaceState.interfaceState.editMessage != nil || self.presentationInterfaceState.interfaceState.forwardMessageIds != nil || self.presentationInterfaceState.interfaceState.composeInputState.inputText.string.count > 0 {
|
|
||||||
hidden = true
|
|
||||||
}
|
|
||||||
controller.update(hidden: hidden, slide: false, animated: true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7669,11 +7678,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}, openCamera: { [weak self] cameraView, menuController in
|
}, openCamera: { [weak self] cameraView, menuController in
|
||||||
if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
||||||
if let callManager = strongSelf.context.sharedContext.callManager as? PresentationCallManagerImpl, callManager.hasActiveGroupCall {
|
var photoOnly = false
|
||||||
return
|
if let callManager = strongSelf.context.sharedContext.callManager as? PresentationCallManagerImpl, callManager.hasActiveCall {
|
||||||
|
photoOnly = true
|
||||||
}
|
}
|
||||||
|
|
||||||
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: menuController, parentController: strongSelf, editingMedia: editMediaOptions != nil, saveCapturedPhotos: settings.storeEditedPhotos, mediaGrouping: true, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: menuController, parentController: strongSelf, editingMedia: editMediaOptions != nil, saveCapturedPhotos: settings.storeEditedPhotos, mediaGrouping: true, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if editMediaOptions != nil {
|
if editMediaOptions != nil {
|
||||||
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
||||||
@ -11307,6 +11317,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
//return self.chatDisplayNode.acceptEmbeddedTitlePeekContent(content: content)
|
//return self.chatDisplayNode.acceptEmbeddedTitlePeekContent(content: content)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var isSendButtonVisible: Bool {
|
||||||
|
if self.presentationInterfaceState.interfaceState.editMessage != nil || self.presentationInterfaceState.interfaceState.forwardMessageIds != nil || self.presentationInterfaceState.interfaceState.composeInputState.inputText.string.count > 0 {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||||
|
@ -1236,7 +1236,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
|
|
||||||
let searchLayoutClearButtonSize = CGSize(width: 44.0, height: minimalHeight)
|
let searchLayoutClearButtonSize = CGSize(width: 44.0, height: minimalHeight)
|
||||||
var textFieldInsets = self.textFieldInsets(metrics: metrics)
|
var textFieldInsets = self.textFieldInsets(metrics: metrics)
|
||||||
if additionalSideInsets.right > 0.0 && self.text.isEmpty {
|
if additionalSideInsets.right > 0.0 {
|
||||||
textFieldInsets.right += additionalSideInsets.right / 3.0
|
textFieldInsets.right += additionalSideInsets.right / 3.0
|
||||||
}
|
}
|
||||||
self.actionButtons.micButton.isHidden = additionalSideInsets.right > 0.0
|
self.actionButtons.micButton.isHidden = additionalSideInsets.right > 0.0
|
||||||
|
@ -11,7 +11,7 @@ import ShareController
|
|||||||
import LegacyUI
|
import LegacyUI
|
||||||
import LegacyMediaPickerUI
|
import LegacyMediaPickerUI
|
||||||
|
|
||||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) {
|
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||||
@ -23,7 +23,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch
|
|||||||
|
|
||||||
let controller: TGCameraController
|
let controller: TGCameraController
|
||||||
if let cameraView = cameraView, let previewView = cameraView.previewView() {
|
if let cameraView = cameraView, let previewView = cameraView.previewView() {
|
||||||
controller = TGCameraController(context: legacyController.context, saveEditedPhotos: saveCapturedPhotos && !isSecretChat, saveCapturedMedia: saveCapturedPhotos && !isSecretChat, camera: previewView.camera, previewView: previewView, intent: TGCameraControllerGenericIntent)
|
controller = TGCameraController(context: legacyController.context, saveEditedPhotos: saveCapturedPhotos && !isSecretChat, saveCapturedMedia: saveCapturedPhotos && !isSecretChat, camera: previewView.camera, previewView: previewView, intent: photoOnly ? TGCameraControllerGenericPhotoOnlyIntent : TGCameraControllerGenericIntent)
|
||||||
controller.inhibitMultipleCapture = editingMedia
|
controller.inhibitMultipleCapture = editingMedia
|
||||||
} else {
|
} else {
|
||||||
controller = TGCameraController()
|
controller = TGCameraController()
|
||||||
|
@ -109,6 +109,7 @@ public final class NotificationContainerController: ViewController {
|
|||||||
let toAlpha: CGFloat = value ? 0.0 : 1.0
|
let toAlpha: CGFloat = value ? 0.0 : 1.0
|
||||||
self.controllerNode.alpha = toAlpha
|
self.controllerNode.alpha = toAlpha
|
||||||
self.controllerNode.layer.animateAlpha(from: fromAlpha, to: toAlpha, duration: 0.2)
|
self.controllerNode.layer.animateAlpha(from: fromAlpha, to: toAlpha, duration: 0.2)
|
||||||
|
self.controllerNode.isUserInteractionEnabled = !value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3036,7 +3036,15 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let group = peer as? TelegramGroup {
|
} else if let group = peer as? TelegramGroup {
|
||||||
|
var canManageGroupCalls = false
|
||||||
if case .creator = group.role {
|
if case .creator = group.role {
|
||||||
|
canManageGroupCalls = true
|
||||||
|
} else if case let .admin(rights, _) = group.role {
|
||||||
|
if rights.flags.contains(.canManageCalls) {
|
||||||
|
canManageGroupCalls = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if canManageGroupCalls {
|
||||||
items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_CreateVoiceChat, color: .accent, action: { [weak self] in
|
items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_CreateVoiceChat, color: .accent, action: { [weak self] in
|
||||||
dismissAction()
|
dismissAction()
|
||||||
|
|
||||||
@ -3044,18 +3052,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.activeActionDisposable.set((convertGroupToSupergroup(account: strongSelf.context.account, peerId: group.id)
|
strongSelf.createAndJoinGroupCall(peerId: group.id)
|
||||||
|> deliverOnMainQueue).start(next: { peerId in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let controller = strongSelf.controller, let navigationController = controller.navigationController as? NavigationController {
|
|
||||||
rebuildControllerStackAfterSupergroupUpgrade(controller: controller, navigationController: navigationController)
|
|
||||||
|
|
||||||
strongSelf.createAndJoinGroupCall(peerId: peerId)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3212,6 +3209,17 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
self.createAndJoinGroupCall(peerId: peer.id)
|
self.createAndJoinGroupCall(peerId: peer.id)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
} else if let peer = self.data?.peer as? TelegramGroup {
|
||||||
|
guard let cachedGroupData = self.data?.cachedData as? CachedGroupData else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let activeCall = cachedGroupData.activeCall {
|
||||||
|
self.context.joinGroupCall(peerId: peer.id, activeCall: activeCall)
|
||||||
|
} else {
|
||||||
|
self.createAndJoinGroupCall(peerId: peer.id)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let peer = self.data?.peer as? TelegramUser, let cachedUserData = self.data?.cachedData as? CachedUserData else {
|
guard let peer = self.data?.peer as? TelegramUser, let cachedUserData = self.data?.cachedData as? CachedUserData else {
|
||||||
@ -3226,7 +3234,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func createAndJoinGroupCall(peerId: PeerId) {
|
private func createAndJoinGroupCall(peerId: PeerId) {
|
||||||
if let callManager = self.context.sharedContext.callManager {
|
if let _ = self.context.sharedContext.callManager {
|
||||||
let startCall: (Bool) -> Void = { [weak self] endCurrentIfAny in
|
let startCall: (Bool) -> Void = { [weak self] endCurrentIfAny in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -3273,34 +3281,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = (callManager.currentGroupCallSignal
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] activeCall in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let activeCall = activeCall {
|
|
||||||
let currentPeerId = activeCall.peerId
|
|
||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> (Peer?, Peer?) in
|
|
||||||
return (transaction.getPeer(peerId), transaction.getPeer(currentPeerId))
|
|
||||||
} |> deliverOnMainQueue).start(next: { [weak self] peer, current in
|
|
||||||
if let peer = peer {
|
|
||||||
if let strongSelf = self, let current = current {
|
|
||||||
strongSelf.controller?.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: {
|
|
||||||
startCall(true)
|
startCall(true)
|
||||||
})]), in: .window(.root))
|
|
||||||
} else {
|
|
||||||
strongSelf.controller?.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_ExternalCallInProgressMessage, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
|
||||||
})]), in: .window(.root))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
startCall(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user