Merge branches 'master' and 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-03-20 16:14:12 +05:00
commit 22dd971d51
30 changed files with 3725 additions and 3542 deletions

View File

@ -3,7 +3,7 @@
@implementation Serialization @implementation Serialization
- (NSUInteger)currentLayer { - (NSUInteger)currentLayer {
return 125; return 126;
} }
- (id _Nullable)parseMessage:(NSData * _Nullable)data { - (id _Nullable)parseMessage:(NSData * _Nullable)data {

View File

@ -6297,3 +6297,5 @@ Sorry for the inconvenience.";
"VoiceChat.ForwardTooltip.Chat" = "Invite link forwarded to **%@**"; "VoiceChat.ForwardTooltip.Chat" = "Invite link forwarded to **%@**";
"VoiceChat.ForwardTooltip.TwoChats" = "Invite link forwarded to **%@** and **%@**"; "VoiceChat.ForwardTooltip.TwoChats" = "Invite link forwarded to **%@** and **%@**";
"VoiceChat.ForwardTooltip.ManyChats" = "Invite link forwarded to **%@** and %@ others"; "VoiceChat.ForwardTooltip.ManyChats" = "Invite link forwarded to **%@** and %@ others";
"GroupRemoved.ViewChannelInfo" = "View Channel";

View File

@ -1023,6 +1023,8 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
} else { } else {
updateFlags = [] updateFlags = []
} }
} else {
updateFlags = adminInfo?.rights.rights
} }
} }
currentRank = rank currentRank = rank

View File

@ -389,8 +389,16 @@ private func channelAdminsControllerEntries(presentationData: PresentationData,
if id == accountPeerId { if id == accountPeerId {
canEdit = false canEdit = false
} else if let adminInfo = adminInfo { } else if let adminInfo = adminInfo {
if peer.flags.contains(.isCreator) || adminInfo.promotedBy == accountPeerId { if peer.flags.contains(.isCreator) {
canEdit = true canEdit = true
canOpen = true
} else if adminInfo.promotedBy == accountPeerId {
canEdit = true
if let adminRights = peer.adminRights {
if adminRights.rights.isEmpty {
canOpen = false
}
}
} else { } else {
canEdit = false canEdit = false
} }

View File

@ -274,7 +274,8 @@ public func channelBlacklistController(context: AccountContext, peerId: PeerId)
let updateState: ((ChannelBlacklistControllerState) -> ChannelBlacklistControllerState) -> Void = { f in let updateState: ((ChannelBlacklistControllerState) -> ChannelBlacklistControllerState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) }) statePromise.set(stateValue.modify { f($0) })
} }
var getNavigationControllerImpl: (() -> NavigationController?)?
var presentControllerImpl: ((ViewController, Any?) -> Void)? var presentControllerImpl: ((ViewController, Any?) -> Void)?
var pushControllerImpl: ((ViewController) -> Void)? var pushControllerImpl: ((ViewController) -> Void)?
var dismissInputImpl: (() -> Void)? var dismissInputImpl: (() -> Void)?
@ -364,9 +365,19 @@ public func channelBlacklistController(context: AccountContext, peerId: PeerId)
if !participant.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder).isEmpty { if !participant.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder).isEmpty {
items.append(ActionSheetTextItem(title: participant.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))) items.append(ActionSheetTextItem(title: participant.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)))
} }
items.append(ActionSheetButtonItem(title: presentationData.strings.GroupRemoved_ViewUserInfo, action: { [weak actionSheet] in let viewInfoTitle: String
if participant.peer is TelegramChannel {
viewInfoTitle = presentationData.strings.GroupRemoved_ViewChannelInfo
} else {
viewInfoTitle = presentationData.strings.GroupRemoved_ViewUserInfo
}
items.append(ActionSheetButtonItem(title: viewInfoTitle, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: participant.peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { if participant.peer is TelegramChannel {
if let navigationController = getNavigationControllerImpl?() {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(participant.peer.id)))
}
} else if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: participant.peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) {
pushControllerImpl?(infoController) pushControllerImpl?(infoController)
} }
})) }))
@ -520,6 +531,9 @@ public func channelBlacklistController(context: AccountContext, peerId: PeerId)
(controller.navigationController as? NavigationController)?.pushViewController(c) (controller.navigationController as? NavigationController)?.pushViewController(c)
} }
} }
getNavigationControllerImpl = { [weak controller] in
return controller?.navigationController as? NavigationController
}
dismissInputImpl = { [weak controller] in dismissInputImpl = { [weak controller] in
controller?.view.endEditing(true) controller?.view.endEditing(true)
} }

View File

@ -88,7 +88,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-347535331] = { return Api.RecentMeUrl.parse_recentMeUrlChatInvite($0) } dict[-347535331] = { return Api.RecentMeUrl.parse_recentMeUrlChatInvite($0) }
dict[-1140172836] = { return Api.RecentMeUrl.parse_recentMeUrlStickerSet($0) } dict[-1140172836] = { return Api.RecentMeUrl.parse_recentMeUrlStickerSet($0) }
dict[-797791052] = { return Api.RestrictionReason.parse_restrictionReason($0) } dict[-797791052] = { return Api.RestrictionReason.parse_restrictionReason($0) }
dict[-177282392] = { return Api.channels.ChannelParticipants.parse_channelParticipants($0) } dict[-1699676497] = { return Api.channels.ChannelParticipants.parse_channelParticipants($0) }
dict[-266911767] = { return Api.channels.ChannelParticipants.parse_channelParticipantsNotModified($0) } dict[-266911767] = { return Api.channels.ChannelParticipants.parse_channelParticipantsNotModified($0) }
dict[-599948721] = { return Api.RichText.parse_textEmpty($0) } dict[-599948721] = { return Api.RichText.parse_textEmpty($0) }
dict[1950782688] = { return Api.RichText.parse_textPlain($0) } dict[1950782688] = { return Api.RichText.parse_textPlain($0) }
@ -122,7 +122,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[84438264] = { return Api.WallPaperSettings.parse_wallPaperSettings($0) } dict[84438264] = { return Api.WallPaperSettings.parse_wallPaperSettings($0) }
dict[-1519029347] = { return Api.EmojiURL.parse_emojiURL($0) } dict[-1519029347] = { return Api.EmojiURL.parse_emojiURL($0) }
dict[1611985938] = { return Api.StatsGroupTopAdmin.parse_statsGroupTopAdmin($0) } dict[1611985938] = { return Api.StatsGroupTopAdmin.parse_statsGroupTopAdmin($0) }
dict[-791039645] = { return Api.channels.ChannelParticipant.parse_channelParticipant($0) } dict[-541588713] = { return Api.channels.ChannelParticipant.parse_channelParticipant($0) }
dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) } dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) }
dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) } dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) }
dict[-1432995067] = { return Api.storage.FileType.parse_fileUnknown($0) } dict[-1432995067] = { return Api.storage.FileType.parse_fileUnknown($0) }
@ -287,7 +287,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) } dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) }
dict[1149094475] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) } dict[1149094475] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) }
dict[-859915345] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) } dict[-859915345] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
dict[470789295] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) } dict[1352785878] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) }
dict[-1010402965] = { return Api.ChannelParticipant.parse_channelParticipantLeft($0) } dict[-1010402965] = { return Api.ChannelParticipant.parse_channelParticipantLeft($0) }
dict[-1567730343] = { return Api.MessageUserVote.parse_messageUserVote($0) } dict[-1567730343] = { return Api.MessageUserVote.parse_messageUserVote($0) }
dict[909603888] = { return Api.MessageUserVote.parse_messageUserVoteInputOption($0) } dict[909603888] = { return Api.MessageUserVote.parse_messageUserVoteInputOption($0) }
@ -471,6 +471,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) }
dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) } dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) }
dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) }
dict[423690591] = { return Api.ChatBannedRights.parse_chatBannedRightsChannel($0) }
dict[1968737087] = { return Api.InputClientProxy.parse_inputClientProxy($0) } dict[1968737087] = { return Api.InputClientProxy.parse_inputClientProxy($0) }
dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) } dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) }
dict[-886477832] = { return Api.LabeledPrice.parse_labeledPrice($0) } dict[-886477832] = { return Api.LabeledPrice.parse_labeledPrice($0) }

View File

@ -7362,7 +7362,7 @@ public extension Api {
case channelParticipantSelf(userId: Int32, inviterId: Int32, date: Int32) case channelParticipantSelf(userId: Int32, inviterId: Int32, date: Int32)
case channelParticipantCreator(flags: Int32, userId: Int32, adminRights: Api.ChatAdminRights, rank: String?) case channelParticipantCreator(flags: Int32, userId: Int32, adminRights: Api.ChatAdminRights, rank: String?)
case channelParticipantAdmin(flags: Int32, userId: Int32, inviterId: Int32?, promotedBy: Int32, date: Int32, adminRights: Api.ChatAdminRights, rank: String?) case channelParticipantAdmin(flags: Int32, userId: Int32, inviterId: Int32?, promotedBy: Int32, date: Int32, adminRights: Api.ChatAdminRights, rank: String?)
case channelParticipantBanned(flags: Int32, userId: Int32, kickedBy: Int32, date: Int32, bannedRights: Api.ChatBannedRights) case channelParticipantBanned(flags: Int32, peer: Api.Peer, kickedBy: Int32, date: Int32, bannedRights: Api.ChatBannedRights)
case channelParticipantLeft(userId: Int32) case channelParticipantLeft(userId: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
@ -7403,12 +7403,12 @@ public extension Api {
adminRights.serialize(buffer, true) adminRights.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {serializeString(rank!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {serializeString(rank!, buffer: buffer, boxed: false)}
break break
case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights): case .channelParticipantBanned(let flags, let peer, let kickedBy, let date, let bannedRights):
if boxed { if boxed {
buffer.appendInt32(470789295) buffer.appendInt32(1352785878)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(userId, buffer: buffer, boxed: false) peer.serialize(buffer, true)
serializeInt32(kickedBy, buffer: buffer, boxed: false) serializeInt32(kickedBy, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
bannedRights.serialize(buffer, true) bannedRights.serialize(buffer, true)
@ -7432,8 +7432,8 @@ public extension Api {
return ("channelParticipantCreator", [("flags", flags), ("userId", userId), ("adminRights", adminRights), ("rank", rank)]) return ("channelParticipantCreator", [("flags", flags), ("userId", userId), ("adminRights", adminRights), ("rank", rank)])
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights, let rank): case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights, let rank):
return ("channelParticipantAdmin", [("flags", flags), ("userId", userId), ("inviterId", inviterId), ("promotedBy", promotedBy), ("date", date), ("adminRights", adminRights), ("rank", rank)]) return ("channelParticipantAdmin", [("flags", flags), ("userId", userId), ("inviterId", inviterId), ("promotedBy", promotedBy), ("date", date), ("adminRights", adminRights), ("rank", rank)])
case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights): case .channelParticipantBanned(let flags, let peer, let kickedBy, let date, let bannedRights):
return ("channelParticipantBanned", [("flags", flags), ("userId", userId), ("kickedBy", kickedBy), ("date", date), ("bannedRights", bannedRights)]) return ("channelParticipantBanned", [("flags", flags), ("peer", peer), ("kickedBy", kickedBy), ("date", date), ("bannedRights", bannedRights)])
case .channelParticipantLeft(let userId): case .channelParticipantLeft(let userId):
return ("channelParticipantLeft", [("userId", userId)]) return ("channelParticipantLeft", [("userId", userId)])
} }
@ -7526,8 +7526,10 @@ public extension Api {
public static func parse_channelParticipantBanned(_ reader: BufferReader) -> ChannelParticipant? { public static func parse_channelParticipantBanned(_ reader: BufferReader) -> ChannelParticipant? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
var _2: Int32? var _2: Api.Peer?
_2 = reader.readInt32() if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Int32? var _3: Int32?
_3 = reader.readInt32() _3 = reader.readInt32()
var _4: Int32? var _4: Int32?
@ -7542,7 +7544,7 @@ public extension Api {
let _c4 = _4 != nil let _c4 = _4 != nil
let _c5 = _5 != nil let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 { if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.ChannelParticipant.channelParticipantBanned(flags: _1!, userId: _2!, kickedBy: _3!, date: _4!, bannedRights: _5!) return Api.ChannelParticipant.channelParticipantBanned(flags: _1!, peer: _2!, kickedBy: _3!, date: _4!, bannedRights: _5!)
} }
else { else {
return nil return nil
@ -12067,6 +12069,7 @@ public extension Api {
} }
public enum ChatBannedRights: TypeConstructorDescription { public enum ChatBannedRights: TypeConstructorDescription {
case chatBannedRights(flags: Int32, untilDate: Int32) case chatBannedRights(flags: Int32, untilDate: Int32)
case chatBannedRightsChannel(flags: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -12077,6 +12080,12 @@ public extension Api {
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(untilDate, buffer: buffer, boxed: false) serializeInt32(untilDate, buffer: buffer, boxed: false)
break break
case .chatBannedRightsChannel(let flags):
if boxed {
buffer.appendInt32(423690591)
}
serializeInt32(flags, buffer: buffer, boxed: false)
break
} }
} }
@ -12084,6 +12093,8 @@ public extension Api {
switch self { switch self {
case .chatBannedRights(let flags, let untilDate): case .chatBannedRights(let flags, let untilDate):
return ("chatBannedRights", [("flags", flags), ("untilDate", untilDate)]) return ("chatBannedRights", [("flags", flags), ("untilDate", untilDate)])
case .chatBannedRightsChannel(let flags):
return ("chatBannedRightsChannel", [("flags", flags)])
} }
} }
@ -12101,6 +12112,17 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_chatBannedRightsChannel(_ reader: BufferReader) -> ChatBannedRights? {
var _1: Int32?
_1 = reader.readInt32()
let _c1 = _1 != nil
if _c1 {
return Api.ChatBannedRights.chatBannedRightsChannel(flags: _1!)
}
else {
return nil
}
}
} }
public enum InputClientProxy: TypeConstructorDescription { public enum InputClientProxy: TypeConstructorDescription {

View File

@ -1,14 +1,14 @@
public extension Api { public extension Api {
public struct channels { public struct channels {
public enum ChannelParticipants: TypeConstructorDescription { public enum ChannelParticipants: TypeConstructorDescription {
case channelParticipants(count: Int32, participants: [Api.ChannelParticipant], users: [Api.User]) case channelParticipants(count: Int32, participants: [Api.ChannelParticipant], chats: [Api.Chat], users: [Api.User])
case channelParticipantsNotModified case channelParticipantsNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .channelParticipants(let count, let participants, let users): case .channelParticipants(let count, let participants, let chats, let users):
if boxed { if boxed {
buffer.appendInt32(-177282392) buffer.appendInt32(-1699676497)
} }
serializeInt32(count, buffer: buffer, boxed: false) serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
@ -17,6 +17,11 @@ public struct channels {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count)) buffer.appendInt32(Int32(users.count))
for item in users { for item in users {
item.serialize(buffer, true) item.serialize(buffer, true)
@ -33,8 +38,8 @@ public struct channels {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .channelParticipants(let count, let participants, let users): case .channelParticipants(let count, let participants, let chats, let users):
return ("channelParticipants", [("count", count), ("participants", participants), ("users", users)]) return ("channelParticipants", [("count", count), ("participants", participants), ("chats", chats), ("users", users)])
case .channelParticipantsNotModified: case .channelParticipantsNotModified:
return ("channelParticipantsNotModified", []) return ("channelParticipantsNotModified", [])
} }
@ -47,15 +52,20 @@ public struct channels {
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChannelParticipant.self) _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChannelParticipant.self)
} }
var _3: [Api.User]? var _3: [Api.Chat]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
if _c1 && _c2 && _c3 { let _c4 = _4 != nil
return Api.channels.ChannelParticipants.channelParticipants(count: _1!, participants: _2!, users: _3!) if _c1 && _c2 && _c3 && _c4 {
return Api.channels.ChannelParticipants.channelParticipants(count: _1!, participants: _2!, chats: _3!, users: _4!)
} }
else { else {
return nil return nil
@ -67,16 +77,21 @@ public struct channels {
} }
public enum ChannelParticipant: TypeConstructorDescription { public enum ChannelParticipant: TypeConstructorDescription {
case channelParticipant(participant: Api.ChannelParticipant, users: [Api.User]) case channelParticipant(participant: Api.ChannelParticipant, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .channelParticipant(let participant, let users): case .channelParticipant(let participant, let chats, let users):
if boxed { if boxed {
buffer.appendInt32(-791039645) buffer.appendInt32(-541588713)
} }
participant.serialize(buffer, true) participant.serialize(buffer, true)
buffer.appendInt32(481674261) buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count)) buffer.appendInt32(Int32(users.count))
for item in users { for item in users {
item.serialize(buffer, true) item.serialize(buffer, true)
@ -87,8 +102,8 @@ public struct channels {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .channelParticipant(let participant, let users): case .channelParticipant(let participant, let chats, let users):
return ("channelParticipant", [("participant", participant), ("users", users)]) return ("channelParticipant", [("participant", participant), ("chats", chats), ("users", users)])
} }
} }
@ -97,14 +112,19 @@ public struct channels {
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant _1 = Api.parse(reader, signature: signature) as? Api.ChannelParticipant
} }
var _2: [Api.User]? var _2: [Api.Chat]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _3: [Api.User]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
if _c1 && _c2 { let _c3 = _3 != nil
return Api.channels.ChannelParticipant.channelParticipant(participant: _1!, users: _2!) if _c1 && _c2 && _c3 {
return Api.channels.ChannelParticipant.channelParticipant(participant: _1!, chats: _2!, users: _3!)
} }
else { else {
return nil return nil

View File

@ -4376,12 +4376,12 @@ public extension Api {
}) })
} }
public static func getParticipant(channel: Api.InputChannel, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.channels.ChannelParticipant>) { public static func getParticipant(channel: Api.InputChannel, participant: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.channels.ChannelParticipant>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1416484774) buffer.appendInt32(-1599378234)
channel.serialize(buffer, true) channel.serialize(buffer, true)
userId.serialize(buffer, true) participant.serialize(buffer, true)
return (FunctionDescription(name: "channels.getParticipant", parameters: [("channel", channel), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.channels.ChannelParticipant? in return (FunctionDescription(name: "channels.getParticipant", parameters: [("channel", channel), ("participant", participant)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.channels.ChannelParticipant? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.channels.ChannelParticipant? var result: Api.channels.ChannelParticipant?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -4624,13 +4624,13 @@ public extension Api {
}) })
} }
public static func editBanned(channel: Api.InputChannel, userId: Api.InputUser, bannedRights: Api.ChatBannedRights) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) { public static func editBanned(channel: Api.InputChannel, participant: Api.InputPeer, bannedRights: Api.ChatBannedRights) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1920559378) buffer.appendInt32(-1763259007)
channel.serialize(buffer, true) channel.serialize(buffer, true)
userId.serialize(buffer, true) participant.serialize(buffer, true)
bannedRights.serialize(buffer, true) bannedRights.serialize(buffer, true)
return (FunctionDescription(name: "channels.editBanned", parameters: [("channel", channel), ("userId", userId), ("bannedRights", bannedRights)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in return (FunctionDescription(name: "channels.editBanned", parameters: [("channel", channel), ("participant", participant), ("bannedRights", bannedRights)]), 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() {

View File

@ -3,6 +3,17 @@ import SwiftSignalKit
import AVFoundation import AVFoundation
import UIKit import UIKit
private var managedAudioSessionLogger: (String) -> Void = { _ in }
public func setManagedAudioSessionLogger(_ f: @escaping (String) -> Void) {
managedAudioSessionLogger = f
}
func managedAudioSessionLog(_ what: @autoclosure () -> String) {
managedAudioSessionLogger(what())
}
public enum ManagedAudioSessionType: Equatable { public enum ManagedAudioSessionType: Equatable {
case ambient case ambient
case play case play
@ -208,11 +219,15 @@ public final class ManagedAudioSession {
}) })
NotificationCenter.default.addObserver(forName: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance(), queue: nil, using: { [weak self] notification in NotificationCenter.default.addObserver(forName: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance(), queue: nil, using: { [weak self] notification in
managedAudioSessionLog("Interruption received")
guard let info = notification.userInfo, guard let info = notification.userInfo,
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt, let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return return
} }
managedAudioSessionLog("Interruption type: \(type)")
queue.async { queue.async {
if let strongSelf = self { if let strongSelf = self {
@ -222,6 +237,17 @@ public final class ManagedAudioSession {
} }
} }
}) })
NotificationCenter.default.addObserver(forName: AVAudioSession.mediaServicesWereLostNotification, object: AVAudioSession.sharedInstance(), queue: nil, using: { [weak self] _ in
managedAudioSessionLog("Media Services were lost")
queue.after(1.0, {
if let strongSelf = self {
if let (type, outputMode) = strongSelf.currentTypeAndOutputMode {
strongSelf.setup(type: type, outputMode: outputMode, activateNow: true)
}
}
})
})
queue.async { queue.async {
self.isHeadsetPluggedInValue = self.isHeadsetPluggedIn() self.isHeadsetPluggedInValue = self.isHeadsetPluggedIn()
@ -524,7 +550,7 @@ public final class ManagedAudioSession {
private func updateHolders(interruption: Bool = false) { private func updateHolders(interruption: Bool = false) {
assert(self.queue.isCurrent()) assert(self.queue.isCurrent())
print("holder count \(self.holders.count)") managedAudioSessionLog("holder count \(self.holders.count)")
if !self.holders.isEmpty { if !self.holders.isEmpty {
var activeIndex: Int? var activeIndex: Int?
@ -625,7 +651,7 @@ public final class ManagedAudioSession {
assert(self.queue.isCurrent()) assert(self.queue.isCurrent())
let route = AVAudioSession.sharedInstance().currentRoute let route = AVAudioSession.sharedInstance().currentRoute
//print("\(route)") //managedAudioSessionLog("\(route)")
for desc in route.outputs { for desc in route.outputs {
if desc.portType == .headphones || desc.portType == .bluetoothA2DP || desc.portType == .bluetoothHFP { if desc.portType == .headphones || desc.portType == .bluetoothA2DP || desc.portType == .bluetoothHFP {
return true return true
@ -643,13 +669,13 @@ public final class ManagedAudioSession {
let wasPlaybackActive = self.currentTypeAndOutputMode?.0.isPlay ?? false let wasPlaybackActive = self.currentTypeAndOutputMode?.0.isPlay ?? false
self.currentTypeAndOutputMode = nil self.currentTypeAndOutputMode = nil
print("ManagedAudioSession setting active false") managedAudioSessionLog("ManagedAudioSession setting active false")
do { do {
try AVAudioSession.sharedInstance().setActive(false, options: [.notifyOthersOnDeactivation]) try AVAudioSession.sharedInstance().setActive(false, options: [.notifyOthersOnDeactivation])
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
try AVAudioSession.sharedInstance().setPreferredInput(nil) try AVAudioSession.sharedInstance().setPreferredInput(nil)
} catch let error { } catch let error {
print("ManagedAudioSession applyNone error \(error), waiting") managedAudioSessionLog("ManagedAudioSession applyNone error \(error), waiting")
Thread.sleep(forTimeInterval: 2.0) Thread.sleep(forTimeInterval: 2.0)
@ -658,7 +684,7 @@ public final class ManagedAudioSession {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
try AVAudioSession.sharedInstance().setPreferredInput(nil) try AVAudioSession.sharedInstance().setPreferredInput(nil)
} catch let error { } catch let error {
print("ManagedAudioSession applyNone repeated error \(error), giving up") managedAudioSessionLog("ManagedAudioSession applyNone repeated error \(error), giving up")
} }
} }
@ -687,7 +713,7 @@ public final class ManagedAudioSession {
do { do {
let nativeCategory = nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue, outputMode: outputMode) let nativeCategory = nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue, outputMode: outputMode)
print("ManagedAudioSession setting category for \(type) (native: \(nativeCategory)) activateNow: \(activateNow)") managedAudioSessionLog("ManagedAudioSession setting category for \(type) (native: \(nativeCategory)) activateNow: \(activateNow)")
var options: AVAudioSession.CategoryOptions = [] var options: AVAudioSession.CategoryOptions = []
switch type { switch type {
case .play, .ambient: case .play, .ambient:
@ -703,7 +729,7 @@ public final class ManagedAudioSession {
case .record, .voiceCall, .videoCall: case .record, .voiceCall, .videoCall:
options.insert(.allowBluetooth) options.insert(.allowBluetooth)
} }
print("ManagedAudioSession setting active true") managedAudioSessionLog("ManagedAudioSession setting active true")
let mode: AVAudioSession.Mode let mode: AVAudioSession.Mode
switch type { switch type {
case .voiceCall: case .voiceCall:
@ -720,7 +746,7 @@ public final class ManagedAudioSession {
try AVAudioSession.sharedInstance().setMode(mode) try AVAudioSession.sharedInstance().setMode(mode)
} }
} catch let error { } catch let error {
print("ManagedAudioSession setup error \(error)") managedAudioSessionLog("ManagedAudioSession setup error \(error)")
} }
} }
@ -741,7 +767,7 @@ public final class ManagedAudioSession {
} }
private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws { private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws {
print("ManagedAudioSession setup \(outputMode) for \(type)") managedAudioSessionLog("ManagedAudioSession setup \(outputMode) for \(type)")
var resetToBuiltin = false var resetToBuiltin = false
switch outputMode { switch outputMode {
case .system: case .system:
@ -831,21 +857,21 @@ public final class ManagedAudioSession {
try AVAudioSession.sharedInstance().setActive(true, options: [.notifyOthersOnDeactivation]) try AVAudioSession.sharedInstance().setActive(true, options: [.notifyOthersOnDeactivation])
print("\(CFAbsoluteTimeGetCurrent()) AudioSession activate: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") managedAudioSessionLog("\(CFAbsoluteTimeGetCurrent()) AudioSession activate: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
try self.setupOutputMode(outputMode, type: type) try self.setupOutputMode(outputMode, type: type)
print("\(CFAbsoluteTimeGetCurrent()) AudioSession setupOutputMode: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") managedAudioSessionLog("\(CFAbsoluteTimeGetCurrent()) AudioSession setupOutputMode: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
self.updateCurrentAudioRouteInfo() self.updateCurrentAudioRouteInfo()
print("\(CFAbsoluteTimeGetCurrent()) AudioSession updateCurrentAudioRouteInfo: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") managedAudioSessionLog("\(CFAbsoluteTimeGetCurrent()) AudioSession updateCurrentAudioRouteInfo: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
if case .voiceCall = type { if case .voiceCall = type {
try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.005) try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.005)
} }
} catch let error { } catch let error {
print("ManagedAudioSession activate error \(error)") managedAudioSessionLog("ManagedAudioSession activate error \(error)")
} }
} }
} }
@ -858,7 +884,7 @@ public final class ManagedAudioSession {
public func callKitActivatedAudioSession() { public func callKitActivatedAudioSession() {
/*self.queue.async { /*self.queue.async {
print("ManagedAudioSession callKitDeactivatedAudioSession") managedAudioSessionLog("ManagedAudioSession callKitDeactivatedAudioSession")
self.callKitAudioSessionIsActive = true self.callKitAudioSessionIsActive = true
self.updateHolders() self.updateHolders()
}*/ }*/
@ -866,7 +892,7 @@ public final class ManagedAudioSession {
public func callKitDeactivatedAudioSession() { public func callKitDeactivatedAudioSession() {
/*self.queue.async { /*self.queue.async {
print("ManagedAudioSession callKitDeactivatedAudioSession") managedAudioSessionLog("ManagedAudioSession callKitDeactivatedAudioSession")
self.callKitAudioSessionIsActive = false self.callKitAudioSessionIsActive = false
self.updateHolders() self.updateHolders()
}*/ }*/

View File

@ -1174,6 +1174,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.VoiceChat_ChatFullAlertText, actions: [ strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.VoiceChat_ChatFullAlertText, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {}) TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})
]), on: .root, blockInteraction: false, completion: {}) ]), on: .root, blockInteraction: false, completion: {})
} else if case .invalidJoinAsPeer = error {
let peerId = strongSelf.peerId
let _ = (strongSelf.accountContext.account.postbox.transaction { transaction -> Void in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData {
return current.withUpdatedCallJoinPeerId(nil)
} else if let current = current as? CachedGroupData {
return current.withUpdatedCallJoinPeerId(nil)
} else {
return current
}
})
}).start()
} }
strongSelf.markAsCanBeRemoved() strongSelf.markAsCanBeRemoved()
})) }))
@ -1364,7 +1377,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
var initialState = initialState var initialState = initialState
var serviceState: GroupCallParticipantsContext.ServiceState? var serviceState: GroupCallParticipantsContext.ServiceState?
if let participantsContext = self.participantsContext, let immediateState = participantsContext.immediateState { if let participantsContext = self.participantsContext, let immediateState = participantsContext.immediateState {
initialState.mergeActivity(from: immediateState, myPeerId: myPeerId, previousMyPeerId: self.ignorePreviousJoinAsPeerId?.0) initialState.mergeActivity(from: immediateState, myPeerId: myPeerId, previousMyPeerId: self.ignorePreviousJoinAsPeerId?.0, mergeActivityTimestamps: true)
serviceState = participantsContext.serviceState serviceState = participantsContext.serviceState
} }
@ -1678,16 +1691,23 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
strongSelf.isRequestingMissingSsrcs = false strongSelf.isRequestingMissingSsrcs = false
strongSelf.missingSsrcs.subtract(requestedSsrcs) strongSelf.missingSsrcs.subtract(requestedSsrcs)
var addedParticipants: [(UInt32, String?)] = [] var addedParticipants: [(UInt32, Int32?, String?)] = []
for participant in state.participants { for participant in state.participants {
if let ssrc = participant.ssrc { if let ssrc = participant.ssrc {
addedParticipants.append((ssrc, participant.jsonParams)) addedParticipants.append((ssrc, participant.volume, participant.jsonParams))
} }
} }
if !addedParticipants.isEmpty { if !addedParticipants.isEmpty {
strongSelf.callContext?.addParticipants(participants: addedParticipants) for (ssrc, volume, _) in addedParticipants {
if let volume = volume {
strongSelf.callContext?.setVolume(ssrc: ssrc, volume: Double(volume) / 10000.0)
}
}
strongSelf.callContext?.addParticipants(participants: addedParticipants.map { ssrc, _, params in
return (ssrc, params)
})
} }
strongSelf.maybeRequestMissingSsrcs() strongSelf.maybeRequestMissingSsrcs()

View File

@ -1285,7 +1285,7 @@ public final class VoiceChatController: ViewController {
f(.dismissWithoutContent) f(.dismissWithoutContent)
}))) })))
if let callState = strongSelf.callState, (callState.canManageCall && !callState.adminIds.contains(peer.id) && peer.id.namespace != Namespaces.Peer.CloudChannel) { if let callState = strongSelf.callState, (callState.canManageCall && !callState.adminIds.contains(peer.id)) {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
}, action: { [weak self] c, _ in }, action: { [weak self] c, _ in
@ -3187,7 +3187,7 @@ public final class VoiceChatController: ViewController {
if allEqual { if allEqual {
disableAnimation = true disableAnimation = true
} }
} else if abs(previousEntries.count - entries.count) > 2 { } else if abs(previousEntries.count - entries.count) > 10 {
disableAnimation = true disableAnimation = true
} }

View File

@ -205,7 +205,7 @@ extension ChannelParticipant {
case let .channelParticipantBanned(flags, userId, restrictedBy, date, bannedRights): case let .channelParticipantBanned(flags, userId, restrictedBy, date, bannedRights):
let hasLeft = (flags & (1 << 0)) != 0 let hasLeft = (flags & (1 << 0)) != 0
let banInfo = ChannelParticipantBannedInfo(rights: TelegramChatBannedRights(apiBannedRights: bannedRights), restrictedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: restrictedBy), timestamp: date, isMember: !hasLeft) let banInfo = ChannelParticipantBannedInfo(rights: TelegramChatBannedRights(apiBannedRights: bannedRights), restrictedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: restrictedBy), timestamp: date, isMember: !hasLeft)
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: nil, banInfo: banInfo, rank: nil) self = .member(id: userId.peerId, invitedAt: date, adminInfo: nil, banInfo: banInfo, rank: nil)
case let .channelParticipantAdmin(flags, userId, _, promotedBy, date, adminRights, rank: rank): case let .channelParticipantAdmin(flags, userId, _, promotedBy, date, adminRights, rank: rank):
self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: promotedBy), canBeEditedByAccountPeer: (flags & (1 << 0)) != 0), banInfo: nil, rank: rank) self = .member(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), invitedAt: date, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(apiAdminRights: adminRights) ?? TelegramChatAdminRights(rights: []), promotedBy: PeerId(namespace: Namespaces.Peer.CloudUser, id: promotedBy), canBeEditedByAccountPeer: (flags & (1 << 0)) != 0), banInfo: nil, rank: rank)
case let .channelParticipantSelf(userId, _, date): case let .channelParticipantSelf(userId, _, date):

View File

@ -13,7 +13,7 @@ public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedC
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<[RenderedChannelParticipant], NoError> in |> mapToSignal { result -> Signal<[RenderedChannelParticipant], NoError> in
switch result { switch result {
case let .channelParticipants(count, participants, users): case let .channelParticipants(count, participants, chats, users):
var items: [RenderedChannelParticipant] = [] var items: [RenderedChannelParticipant] = []
var peers: [PeerId: Peer] = [:] var peers: [PeerId: Peer] = [:]
@ -58,7 +58,7 @@ public func channelAdminIds(postbox: Postbox, network: Network, peerId: PeerId,
let api = Api.functions.channels.getParticipants(channel: apiChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: hash) let api = Api.functions.channels.getParticipants(channel: apiChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: hash)
return network.request(api) |> retryRequest |> mapToSignal { result in return network.request(api) |> retryRequest |> mapToSignal { result in
switch result { switch result {
case let .channelParticipants(_, participants, users): case let .channelParticipants(_, participants, _, users):
let users = users.filter({ user in let users = users.filter({ user in
return participants.contains(where: { participant in return participants.contains(where: { participant in
switch participant { switch participant {

View File

@ -26,9 +26,9 @@ private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: Cha
|> map { result -> [RenderedChannelParticipant] in |> map { result -> [RenderedChannelParticipant] in
var items: [RenderedChannelParticipant] = [] var items: [RenderedChannelParticipant] = []
switch result { switch result {
case let .channelParticipants(_, participants, users): case let .channelParticipants(_, participants, chats, users):
var peers: [PeerId: Peer] = [:] var peers: [PeerId: Peer] = [:]
var presences:[PeerId: PeerPresence] = [:] var presences: [PeerId: PeerPresence] = [:]
for user in users { for user in users {
let peer = TelegramUser(user: user) let peer = TelegramUser(user: user)
peers[peer.id] = peer peers[peer.id] = peer
@ -36,6 +36,11 @@ private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: Cha
presences[peer.id] = presence presences[peer.id] = presence
} }
} }
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers[groupOrChannel.id] = groupOrChannel
}
}
for participant in CachedChannelParticipants(apiParticipants: participants).participants { for participant in CachedChannelParticipants(apiParticipants: participants).participants {
if let peer = peers[participant.peerId] { if let peer = peers[participant.peerId] {
@ -133,7 +138,7 @@ public func updateChannelMemberBannedRights(account: Account, peerId: PeerId, me
return fetchChannelParticipant(account: account, peerId: peerId, participantId: memberId) return fetchChannelParticipant(account: account, peerId: peerId, participantId: memberId)
|> mapToSignal { currentParticipant -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in |> mapToSignal { currentParticipant -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in
return account.postbox.transaction { transaction -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in return account.postbox.transaction { transaction -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in
if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer), let _ = transaction.getPeer(account.peerId), let memberPeer = transaction.getPeer(memberId), let inputUser = apiInputUser(memberPeer) { if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer), let _ = transaction.getPeer(account.peerId), let memberPeer = transaction.getPeer(memberId), let inputPeer = apiInputPeer(memberPeer) {
let updatedParticipant: ChannelParticipant let updatedParticipant: ChannelParticipant
if let currentParticipant = currentParticipant, case let .member(_, invitedAt, _, currentBanInfo, _) = currentParticipant { if let currentParticipant = currentParticipant, case let .member(_, invitedAt, _, currentBanInfo, _) = currentParticipant {
let banInfo: ChannelParticipantBannedInfo? let banInfo: ChannelParticipantBannedInfo?
@ -152,8 +157,23 @@ public func updateChannelMemberBannedRights(account: Account, peerId: PeerId, me
} }
updatedParticipant = ChannelParticipant.member(id: memberId, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: nil, banInfo: banInfo, rank: nil) updatedParticipant = ChannelParticipant.member(id: memberId, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: nil, banInfo: banInfo, rank: nil)
} }
let apiRights: Api.ChatBannedRights
if let rights = rights, !rights.flags.isEmpty {
if memberId.namespace == Namespaces.Peer.CloudChannel {
apiRights = .chatBannedRightsChannel(flags: 1 << 0)
} else {
apiRights = rights.apiBannedRights
}
} else {
if memberId.namespace == Namespaces.Peer.CloudChannel {
apiRights = .chatBannedRightsChannel(flags: 0)
} else {
apiRights = .chatBannedRights(flags: 0, untilDate: 0)
}
}
return account.network.request(Api.functions.channels.editBanned(channel: inputChannel, userId: inputUser, bannedRights: rights?.apiBannedRights ?? Api.ChatBannedRights.chatBannedRights(flags: 0, untilDate: 0))) return account.network.request(Api.functions.channels.editBanned(channel: inputChannel, participant: inputPeer, bannedRights: apiRights))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in |> mapToSignal { result -> Signal<(ChannelParticipant?, RenderedChannelParticipant?, Bool), NoError> in
account.stateManager.addUpdates(result) account.stateManager.addUpdates(result)

View File

@ -83,7 +83,7 @@ public func channelMembers(postbox: Postbox, network: Network, accountPeerId: Pe
return postbox.transaction { transaction -> [RenderedChannelParticipant]? in return postbox.transaction { transaction -> [RenderedChannelParticipant]? in
var items: [RenderedChannelParticipant] = [] var items: [RenderedChannelParticipant] = []
switch result { switch result {
case let .channelParticipants(_, participants, users): case let .channelParticipants(_, participants, chats, users):
var peers: [PeerId: Peer] = [:] var peers: [PeerId: Peer] = [:]
var presences: [PeerId: PeerPresence] = [:] var presences: [PeerId: PeerPresence] = [:]
for user in users { for user in users {
@ -93,6 +93,11 @@ public func channelMembers(postbox: Postbox, network: Network, accountPeerId: Pe
presences[peer.id] = presence presences[peer.id] = presence
} }
} }
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers[groupOrChannel.id] = groupOrChannel
}
}
updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in
return updated return updated
}) })

View File

@ -38,7 +38,7 @@ func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signa
if let current = current as? CachedChannelData { if let current = current as? CachedChannelData {
let adminCount: Int32 let adminCount: Int32
switch admins { switch admins {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _, _):
adminCount = count adminCount = count
case .channelParticipantsNotModified: case .channelParticipantsNotModified:
assertionFailure() assertionFailure()
@ -46,7 +46,7 @@ func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signa
} }
let memberCount: Int32 let memberCount: Int32
switch members { switch members {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _, _):
memberCount = count memberCount = count
case .channelParticipantsNotModified: case .channelParticipantsNotModified:
assertionFailure() assertionFailure()
@ -54,7 +54,7 @@ func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signa
} }
let bannedCount: Int32 let bannedCount: Int32
switch banned { switch banned {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _, _):
bannedCount = count bannedCount = count
case .channelParticipantsNotModified: case .channelParticipantsNotModified:
assertionFailure() assertionFailure()
@ -62,7 +62,7 @@ func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signa
} }
let kickedCount: Int32 let kickedCount: Int32
switch kicked { switch kicked {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _, _):
kickedCount = count kickedCount = count
case .channelParticipantsNotModified: case .channelParticipantsNotModified:
assertionFailure() assertionFailure()

View File

@ -367,6 +367,7 @@ public enum JoinGroupCallError {
case generic case generic
case anonymousNotAllowed case anonymousNotAllowed
case tooManyParticipants case tooManyParticipants
case invalidJoinAsPeer
} }
public struct JoinGroupCallResult { public struct JoinGroupCallResult {
@ -408,6 +409,8 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal
return .anonymousNotAllowed return .anonymousNotAllowed
} else if error.errorDescription == "GROUPCALL_PARTICIPANTS_TOO_MUCH" { } else if error.errorDescription == "GROUPCALL_PARTICIPANTS_TOO_MUCH" {
return .tooManyParticipants return .tooManyParticipants
} else if error.errorDescription == "JOIN_AS_PEER_INVALID" {
return .invalidJoinAsPeer
} }
return .generic return .generic
} }
@ -745,9 +748,11 @@ public final class GroupCallParticipantsContext {
self.about = about self.about = about
} }
public mutating func mergeActivity(from other: Participant) { public mutating func mergeActivity(from other: Participant, mergeActivityTimestamp: Bool) {
self.activityRank = other.activityRank self.activityRank = other.activityRank
self.activityTimestamp = other.activityTimestamp if mergeActivityTimestamp {
self.activityTimestamp = other.activityTimestamp
}
} }
public static func ==(lhs: Participant, rhs: Participant) -> Bool { public static func ==(lhs: Participant, rhs: Participant) -> Bool {
@ -847,7 +852,7 @@ public final class GroupCallParticipantsContext {
public var totalCount: Int public var totalCount: Int
public var version: Int32 public var version: Int32
public mutating func mergeActivity(from other: State, myPeerId: PeerId, previousMyPeerId: PeerId?) { public mutating func mergeActivity(from other: State, myPeerId: PeerId?, previousMyPeerId: PeerId?, mergeActivityTimestamps: Bool) {
var indexMap: [PeerId: Int] = [:] var indexMap: [PeerId: Int] = [:]
for i in 0 ..< other.participants.count { for i in 0 ..< other.participants.count {
indexMap[other.participants[i].peer.id] = i indexMap[other.participants[i].peer.id] = i
@ -855,7 +860,7 @@ public final class GroupCallParticipantsContext {
for i in 0 ..< self.participants.count { for i in 0 ..< self.participants.count {
if let index = indexMap[self.participants[i].peer.id] { if let index = indexMap[self.participants[i].peer.id] {
self.participants[i].mergeActivity(from: other.participants[index]) self.participants[i].mergeActivity(from: other.participants[index], mergeActivityTimestamp: mergeActivityTimestamps)
if self.participants[i].peer.id == myPeerId || self.participants[i].peer.id == previousMyPeerId { if self.participants[i].peer.id == myPeerId || self.participants[i].peer.id == previousMyPeerId {
self.participants[i].joinTimestamp = other.participants[index].joinTimestamp self.participants[i].joinTimestamp = other.participants[index].joinTimestamp
} }
@ -1510,6 +1515,8 @@ public final class GroupCallParticipantsContext {
} }
strongSelf.isLoadingMore = false strongSelf.isLoadingMore = false
strongSelf.shouldResetStateFromServer = false strongSelf.shouldResetStateFromServer = false
var state = state
state.mergeActivity(from: strongSelf.stateValue.state, myPeerId: nil, previousMyPeerId: nil, mergeActivityTimestamps: false)
strongSelf.stateValue.state = state strongSelf.stateValue.state = state
strongSelf.endedProcessingUpdate() strongSelf.endedProcessingUpdate()
})) }))
@ -2129,12 +2136,12 @@ public func getAudioBroadcastPart(dataSource: AudioBroadcastDataSource, callId:
status: .rejoinNeeded, status: .rejoinNeeded,
responseTimestamp: responseTimestamp responseTimestamp: responseTimestamp
)) ))
} else if error.errorDescription.hasPrefix("FLOOD_WAIT") { } else if error.errorDescription.hasPrefix("FLOOD_WAIT") || error.errorDescription == "TIME_TOO_BIG" {
return .single(GetAudioBroadcastPartResult( return .single(GetAudioBroadcastPartResult(
status: .notReady, status: .notReady,
responseTimestamp: responseTimestamp responseTimestamp: responseTimestamp
)) ))
} else if error.errorDescription == "TIME_INVALID" || error.errorDescription == "TIME_TOO_SMALL" || error.errorDescription == "TIME_TOO_BIG" { } else if error.errorDescription == "TIME_INVALID" || error.errorDescription == "TIME_TOO_SMALL" {
return .single(GetAudioBroadcastPartResult( return .single(GetAudioBroadcastPartResult(
status: .resyncNeeded, status: .resyncNeeded,
responseTimestamp: responseTimestamp responseTimestamp: responseTimestamp

View File

@ -38,7 +38,7 @@ public func joinChannel(account: Account, peerId: PeerId, hash: String?) -> Sign
|> mapToSignal { updates -> Signal<RenderedChannelParticipant?, JoinChannelError> in |> mapToSignal { updates -> Signal<RenderedChannelParticipant?, JoinChannelError> in
account.stateManager.addUpdates(updates) account.stateManager.addUpdates(updates)
return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, userId: .inputUserSelf)) return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, participant: .inputPeerSelf))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.channels.ChannelParticipant?, JoinChannelError> in |> `catch` { _ -> Signal<Api.channels.ChannelParticipant?, JoinChannelError> in
return .single(nil) return .single(nil)
@ -59,7 +59,7 @@ public func joinChannel(account: Account, peerId: PeerId, hash: String?) -> Sign
} }
let updatedParticipant: ChannelParticipant let updatedParticipant: ChannelParticipant
switch result { switch result {
case let .channelParticipant(participant, _): case let .channelParticipant(participant, _, _):
updatedParticipant = ChannelParticipant(apiParticipant: participant) updatedParticipant = ChannelParticipant(apiParticipant: participant)
} }
if case let .member(_, _, maybeAdminInfo, _, _) = updatedParticipant { if case let .member(_, _, maybeAdminInfo, _, _) = updatedParticipant {

View File

@ -129,12 +129,12 @@ public enum UpdateChannelAdminRightsError {
public func fetchChannelParticipant(account: Account, peerId: PeerId, participantId: PeerId) -> Signal<ChannelParticipant?, NoError> { public func fetchChannelParticipant(account: Account, peerId: PeerId, participantId: PeerId) -> Signal<ChannelParticipant?, NoError> {
return account.postbox.transaction { transaction -> Signal<ChannelParticipant?, NoError> in return account.postbox.transaction { transaction -> Signal<ChannelParticipant?, NoError> in
if let peer = transaction.getPeer(peerId), let adminPeer = transaction.getPeer(participantId), let inputUser = apiInputUser(adminPeer) { if let peer = transaction.getPeer(peerId), let adminPeer = transaction.getPeer(participantId), let inputPeer = apiInputPeer(adminPeer) {
if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) {
return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, userId: inputUser)) return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, participant: inputPeer))
|> map { result -> ChannelParticipant? in |> map { result -> ChannelParticipant? in
switch result { switch result {
case let .channelParticipant(participant, _): case let .channelParticipant(participant, _, _):
return ChannelParticipant(apiParticipant: participant) return ChannelParticipant(apiParticipant: participant)
} }
} }

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization { public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt { public func currentLayer() -> UInt {
return 125 return 126
} }
public func parseMessage(_ data: Data!) -> Any! { public func parseMessage(_ data: Data!) -> Any! {

View File

@ -9,6 +9,9 @@ extension TelegramChatBannedRights {
switch apiBannedRights { switch apiBannedRights {
case let .chatBannedRights(flags, untilDate): case let .chatBannedRights(flags, untilDate):
self.init(flags: TelegramChatBannedRightsFlags(rawValue: flags), untilDate: untilDate) self.init(flags: TelegramChatBannedRightsFlags(rawValue: flags), untilDate: untilDate)
case let .chatBannedRightsChannel(flags):
let isKicked = (flags & (1 << 0)) != 0
self.init(flags: [.banReadMessages], untilDate: Int32.max)
} }
} }

View File

@ -338,7 +338,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
} }
return .single(nil) return .single(nil)
} }
let participantSignal = network.request(Api.functions.channels.getParticipant(channel: inputChannel, userId: .inputUserSelf)) let participantSignal = network.request(Api.functions.channels.getParticipant(channel: inputChannel, participant: .inputPeerSelf))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { error -> Signal<Api.channels.ChannelParticipant?, NoError> in |> `catch` { error -> Signal<Api.channels.ChannelParticipant?, NoError> in
return .single(nil) return .single(nil)
@ -442,7 +442,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
if let participantResult = participantResult { if let participantResult = participantResult {
switch participantResult { switch participantResult {
case let .channelParticipant(_, users): case let .channelParticipant(_, chats, users):
for user in users { for user in users {
if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
peers.append(telegramUser) peers.append(telegramUser)
@ -451,6 +451,11 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
} }
} }
} }
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers.append(groupOrChannel)
}
}
} }
} }
@ -482,7 +487,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
var invitedBy: PeerId? var invitedBy: PeerId?
if let participantResult = participantResult { if let participantResult = participantResult {
switch participantResult { switch participantResult {
case let.channelParticipant(participant, _): case let.channelParticipant(participant, _, _):
switch participant { switch participant {
case let .channelParticipantSelf(_, inviterId, _): case let .channelParticipantSelf(_, inviterId, _):
invitedBy = PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId) invitedBy = PeerId(namespace: Namespaces.Peer.CloudUser, id: inviterId)

View File

@ -32,6 +32,7 @@ import TelegramIntents
import AccountUtils import AccountUtils
import CoreSpotlight import CoreSpotlight
import LightweightAccountData import LightweightAccountData
import TelegramAudio
#if canImport(BackgroundTasks) #if canImport(BackgroundTasks)
import BackgroundTasks import BackgroundTasks
@ -438,6 +439,11 @@ final class SharedApplicationContext {
let logsPath = rootPath + "/logs" let logsPath = rootPath + "/logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: logsPath)) Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: logsPath))
setManagedAudioSessionLogger({ s in
Logger.shared.log("ManagedAudioSession", s)
Logger.shared.shortLog("ManagedAudioSession", s)
})
if let contents = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath + "/accounts-metadata"), includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) { if let contents = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath + "/accounts-metadata"), includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) {
for url in contents { for url in contents {

View File

@ -4327,7 +4327,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
//effectiveCachedDataReady = .single(true) //effectiveCachedDataReady = .single(true)
effectiveCachedDataReady = self.cachedDataReady.get() effectiveCachedDataReady = self.cachedDataReady.get()
} }
self.ready.set(combineLatest(self.chatDisplayNode.historyNode.historyState.get(), self._chatLocationInfoReady.get(), effectiveCachedDataReady, initialData) |> map { _, chatLocationInfoReady, cachedDataReady, _ in self.ready.set(combineLatest(queue: .mainQueue(),
self.chatDisplayNode.historyNode.historyState.get(),
self._chatLocationInfoReady.get(),
effectiveCachedDataReady,
initialData
)
|> map { _, chatLocationInfoReady, cachedDataReady, _ in
return chatLocationInfoReady && cachedDataReady return chatLocationInfoReady && cachedDataReady
}) })

View File

@ -512,6 +512,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
let canReadHistory = Promise<Bool>() let canReadHistory = Promise<Bool>()
private var canReadHistoryValue: Bool = false private var canReadHistoryValue: Bool = false
private var canReadHistoryDisposable: Disposable? private var canReadHistoryDisposable: Disposable?
private var messageIdsScheduledForMarkAsSeen = Set<MessageId>()
private var chatHistoryLocationValue: ChatHistoryLocationInput? { private var chatHistoryLocationValue: ChatHistoryLocationInput? {
didSet { didSet {
@ -669,12 +671,11 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.messageMentionProcessingManager.process = { [weak self, weak context] messageIds in self.messageMentionProcessingManager.process = { [weak self, weak context] messageIds in
if let strongSelf = self { if let strongSelf = self {
let _ = (strongSelf.canReadHistory.get() if strongSelf.canReadHistoryValue {
|> take(1)).start(next: { [weak context] canReadHistory in context?.account.viewTracker.updateMarkMentionsSeenForMessageIds(messageIds: messageIds)
if canReadHistory { } else {
context?.account.viewTracker.updateMarkMentionsSeenForMessageIds(messageIds: messageIds) strongSelf.messageIdsScheduledForMarkAsSeen.formUnion(messageIds)
} }
})
} }
} }
@ -1073,11 +1074,17 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.readHistoryDisposable.set(readHistory.start()) self.readHistoryDisposable.set(readHistory.start())
self.canReadHistoryDisposable = (self.canReadHistory.get() |> deliverOnMainQueue).start(next: { [weak self] value in self.canReadHistoryDisposable = (self.canReadHistory.get() |> deliverOnMainQueue).start(next: { [weak self, weak context] value in
if let strongSelf = self { if let strongSelf = self {
if strongSelf.canReadHistoryValue != value { if strongSelf.canReadHistoryValue != value {
strongSelf.canReadHistoryValue = value strongSelf.canReadHistoryValue = value
strongSelf.updateReadHistoryActions() strongSelf.updateReadHistoryActions()
if strongSelf.canReadHistoryValue && !strongSelf.messageIdsScheduledForMarkAsSeen.isEmpty {
let messageIds = strongSelf.messageIdsScheduledForMarkAsSeen
strongSelf.messageIdsScheduledForMarkAsSeen.removeAll()
context?.account.viewTracker.updateMarkMentionsSeenForMessageIds(messageIds: messageIds)
}
} }
} }
}) })

View File

@ -100,7 +100,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
self.closeButton.displaysAsynchronously = false self.closeButton.displaysAsynchronously = false
self.lineNode = ASImageNode() self.lineNode = ASImageNode()
self.lineNode.displayWithoutProcessing = true self.lineNode.displayWithoutProcessing = false
self.lineNode.displaysAsynchronously = false self.lineNode.displaysAsynchronously = false
self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme) self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme)
@ -158,6 +158,11 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
strongSelf.actionArea.accessibilityLabel = "\(headerString). From: \(authors).\n\(text)" strongSelf.actionArea.accessibilityLabel = "\(headerString). From: \(authors).\n\(text)"
strongSelf.setNeedsLayout() strongSelf.setNeedsLayout()
if let subnodes = strongSelf.subnodes {
for subnode in subnodes {
subnode.setNeedsDisplay()
}
}
} }
})) }))
} }
@ -196,6 +201,9 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 45.0) return CGSize(width: constrainedSize.width, height: 45.0)
} }
override func updateState(size: CGSize, interfaceState: ChatPresentationInterfaceState) {
}
override func layout() { override func layout() {
super.layout() super.layout()

@ -1 +1 @@
Subproject commit c0a62629f968091c21fcdb3d5519f1e77d593079 Subproject commit 194449a2dd5a2bcb56a487e691842111bf5adf5f