mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
WIP
This commit is contained in:
parent
d1d533a443
commit
765ae45e0b
2
.bazelrc
2
.bazelrc
@ -4,8 +4,6 @@ build --action_env=ZERO_AR_DATE=1
|
|||||||
build --strategy=Genrule=local
|
build --strategy=Genrule=local
|
||||||
build --apple_platform_type=ios
|
build --apple_platform_type=ios
|
||||||
build --cxxopt='-std=c++14'
|
build --cxxopt='-std=c++14'
|
||||||
build --per_file_copt="third-party/webrtc/.*\.m$","@-fno-stack-protector"
|
|
||||||
build --per_file_copt="third-party/webrtc/.*\.mm$","@-fno-stack-protector"
|
|
||||||
build --per_file_copt="third-party/webrtc/.*\.cpp$","@-std=c++14"
|
build --per_file_copt="third-party/webrtc/.*\.cpp$","@-std=c++14"
|
||||||
build --per_file_copt="third-party/webrtc/.*\.cc$","@-std=c++14"
|
build --per_file_copt="third-party/webrtc/.*\.cc$","@-std=c++14"
|
||||||
build --per_file_copt="third-party/webrtc/.*\.mm$","@-std=c++14"
|
build --per_file_copt="third-party/webrtc/.*\.mm$","@-std=c++14"
|
||||||
|
@ -2612,6 +2612,7 @@ Unused sets are archived when you add more.";
|
|||||||
"Channel.AdminLog.CanAddAdmins" = "Add New Admins";
|
"Channel.AdminLog.CanAddAdmins" = "Add New Admins";
|
||||||
"Channel.AdminLog.CanBeAnonymous" = "Remain Anonymous";
|
"Channel.AdminLog.CanBeAnonymous" = "Remain Anonymous";
|
||||||
"Channel.AdminLog.CanEditMessages" = "Edit Messages";
|
"Channel.AdminLog.CanEditMessages" = "Edit Messages";
|
||||||
|
"Channel.AdminLog.CanManageCalls" = "Manage Calls";
|
||||||
|
|
||||||
"Channel.AdminLog.MessageToggleInvitesOn" = "%@ enabled group invites";
|
"Channel.AdminLog.MessageToggleInvitesOn" = "%@ enabled group invites";
|
||||||
"Channel.AdminLog.MessageToggleInvitesOff" = "%@ disabled group invites";
|
"Channel.AdminLog.MessageToggleInvitesOff" = "%@ disabled group invites";
|
||||||
|
@ -163,13 +163,19 @@ public struct PresentationGroupCallState: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var networkState: NetworkState
|
public var networkState: NetworkState
|
||||||
|
public var canManageCall: Bool
|
||||||
|
public var adminIds: Set<PeerId>
|
||||||
public var isMuted: Bool
|
public var isMuted: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
networkState: NetworkState,
|
networkState: NetworkState,
|
||||||
|
canManageCall: Bool,
|
||||||
|
adminIds: Set<PeerId>,
|
||||||
isMuted: Bool
|
isMuted: Bool
|
||||||
) {
|
) {
|
||||||
self.networkState = networkState
|
self.networkState = networkState
|
||||||
|
self.canManageCall = canManageCall
|
||||||
|
self.adminIds = adminIds
|
||||||
self.isMuted = isMuted
|
self.isMuted = isMuted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,6 +212,11 @@ public struct PresentationGroupCallMemberState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum PresentationGroupCallMuteAction: Equatable {
|
||||||
|
case muted(isPushToTalkActive: Bool)
|
||||||
|
case unmuted
|
||||||
|
}
|
||||||
|
|
||||||
public protocol PresentationGroupCall: class {
|
public protocol PresentationGroupCall: class {
|
||||||
var account: Account { get }
|
var account: Account { get }
|
||||||
var accountContext: AccountContext { get }
|
var accountContext: AccountContext { get }
|
||||||
@ -222,10 +233,10 @@ public protocol PresentationGroupCall: class {
|
|||||||
var myAudioLevel: Signal<Float, NoError> { get }
|
var myAudioLevel: Signal<Float, NoError> { get }
|
||||||
var isMuted: Signal<Bool, NoError> { get }
|
var isMuted: Signal<Bool, NoError> { get }
|
||||||
|
|
||||||
func leave() -> Signal<Bool, NoError>
|
func leave(terminateIfPossible: Bool) -> Signal<Bool, NoError>
|
||||||
|
|
||||||
func toggleIsMuted()
|
func toggleIsMuted()
|
||||||
func setIsMuted(_ value: Bool)
|
func setIsMuted(action: PresentationGroupCallMuteAction)
|
||||||
func setCurrentAudioOutput(_ output: AudioSessionOutput)
|
func setCurrentAudioOutput(_ output: AudioSessionOutput)
|
||||||
|
|
||||||
func updateMuteState(peerId: PeerId, isMuted: Bool)
|
func updateMuteState(peerId: PeerId, isMuted: Bool)
|
||||||
|
@ -489,6 +489,8 @@ private func stringForRight(strings: PresentationStrings, right: TelegramChatAdm
|
|||||||
return strings.Channel_EditAdmin_PermissionAddAdmins
|
return strings.Channel_EditAdmin_PermissionAddAdmins
|
||||||
} else if right.contains(.canBeAnonymous) {
|
} else if right.contains(.canBeAnonymous) {
|
||||||
return strings.Channel_AdminLog_CanBeAnonymous
|
return strings.Channel_AdminLog_CanBeAnonymous
|
||||||
|
} else if right.contains(.canManageCalls) {
|
||||||
|
return strings.Channel_AdminLog_CanManageCalls
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -511,6 +513,8 @@ private func rightDependencies(_ right: TelegramChatAdminRightsFlags) -> [Telegr
|
|||||||
return []
|
return []
|
||||||
} else if right.contains(.canAddAdmins) {
|
} else if right.contains(.canAddAdmins) {
|
||||||
return []
|
return []
|
||||||
|
} else if right.contains(.canManageCalls) {
|
||||||
|
return []
|
||||||
} else if right.contains(.canBeAnonymous) {
|
} else if right.contains(.canBeAnonymous) {
|
||||||
return []
|
return []
|
||||||
} else {
|
} else {
|
||||||
@ -611,6 +615,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
|
|||||||
.canBanUsers,
|
.canBanUsers,
|
||||||
.canInviteUsers,
|
.canInviteUsers,
|
||||||
.canPinMessages,
|
.canPinMessages,
|
||||||
|
.canManageCalls,
|
||||||
.canBeAnonymous,
|
.canBeAnonymous,
|
||||||
.canAddAdmins
|
.canAddAdmins
|
||||||
]
|
]
|
||||||
|
@ -20,6 +20,7 @@ public struct TelegramChatAdminRightsFlags: OptionSet {
|
|||||||
public static let canPinMessages = TelegramChatAdminRightsFlags(rawValue: 1 << 7)
|
public static let canPinMessages = TelegramChatAdminRightsFlags(rawValue: 1 << 7)
|
||||||
public static let canAddAdmins = TelegramChatAdminRightsFlags(rawValue: 1 << 9)
|
public static let canAddAdmins = TelegramChatAdminRightsFlags(rawValue: 1 << 9)
|
||||||
public static let canBeAnonymous = TelegramChatAdminRightsFlags(rawValue: 1 << 10)
|
public static let canBeAnonymous = TelegramChatAdminRightsFlags(rawValue: 1 << 10)
|
||||||
|
public static let canManageCalls = TelegramChatAdminRightsFlags(rawValue: 1 << 11)
|
||||||
|
|
||||||
public static var groupSpecific: TelegramChatAdminRightsFlags = [
|
public static var groupSpecific: TelegramChatAdminRightsFlags = [
|
||||||
.canChangeInfo,
|
.canChangeInfo,
|
||||||
@ -28,7 +29,8 @@ public struct TelegramChatAdminRightsFlags: OptionSet {
|
|||||||
.canInviteUsers,
|
.canInviteUsers,
|
||||||
.canPinMessages,
|
.canPinMessages,
|
||||||
.canBeAnonymous,
|
.canBeAnonymous,
|
||||||
.canAddAdmins
|
.canAddAdmins,
|
||||||
|
.canManageCalls
|
||||||
]
|
]
|
||||||
|
|
||||||
public static var broadcastSpecific: TelegramChatAdminRightsFlags = [
|
public static var broadcastSpecific: TelegramChatAdminRightsFlags = [
|
||||||
|
@ -134,7 +134,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[1511503333] = { return Api.InputEncryptedFile.parse_inputEncryptedFile($0) }
|
dict[1511503333] = { return Api.InputEncryptedFile.parse_inputEncryptedFile($0) }
|
||||||
dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) }
|
dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) }
|
||||||
dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) }
|
dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) }
|
||||||
dict[-1985949076] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
dict[1454409673] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
||||||
dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) }
|
dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) }
|
||||||
dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) }
|
dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) }
|
||||||
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
dict[1571494644] = { return Api.ExportedMessageLink.parse_exportedMessageLink($0) }
|
||||||
@ -503,7 +503,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1495959709] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) }
|
dict[-1495959709] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) }
|
||||||
dict[411017418] = { return Api.SecureValue.parse_secureValue($0) }
|
dict[411017418] = { return Api.SecureValue.parse_secureValue($0) }
|
||||||
dict[-316748368] = { return Api.SecureValueHash.parse_secureValueHash($0) }
|
dict[-316748368] = { return Api.SecureValueHash.parse_secureValueHash($0) }
|
||||||
dict[1447862232] = { return Api.phone.GroupCall.parse_groupCall($0) }
|
dict[-1738792825] = { return Api.phone.GroupCall.parse_groupCall($0) }
|
||||||
dict[-398136321] = { return Api.messages.SearchCounter.parse_searchCounter($0) }
|
dict[-398136321] = { return Api.messages.SearchCounter.parse_searchCounter($0) }
|
||||||
dict[-2128698738] = { return Api.auth.CheckedPhone.parse_checkedPhone($0) }
|
dict[-2128698738] = { return Api.auth.CheckedPhone.parse_checkedPhone($0) }
|
||||||
dict[-1188055347] = { return Api.PageListItem.parse_pageListItemText($0) }
|
dict[-1188055347] = { return Api.PageListItem.parse_pageListItemText($0) }
|
||||||
@ -531,7 +531,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-2042159726] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoSHA512($0) }
|
dict[-2042159726] = { return Api.SecurePasswordKdfAlgo.parse_securePasswordKdfAlgoSHA512($0) }
|
||||||
dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) }
|
dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) }
|
||||||
dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) }
|
dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) }
|
||||||
dict[1021016465] = { return Api.phone.GroupParticipants.parse_groupParticipants($0) }
|
dict[-1661028051] = { return Api.phone.GroupParticipants.parse_groupParticipants($0) }
|
||||||
dict[-2066640507] = { return Api.messages.AffectedMessages.parse_affectedMessages($0) }
|
dict[-2066640507] = { return Api.messages.AffectedMessages.parse_affectedMessages($0) }
|
||||||
dict[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($0) }
|
dict[-402498398] = { return Api.messages.SavedGifs.parse_savedGifsNotModified($0) }
|
||||||
dict[772213157] = { return Api.messages.SavedGifs.parse_savedGifs($0) }
|
dict[772213157] = { return Api.messages.SavedGifs.parse_savedGifs($0) }
|
||||||
|
@ -5358,17 +5358,18 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
public enum GroupCallParticipant: TypeConstructorDescription {
|
public enum GroupCallParticipant: TypeConstructorDescription {
|
||||||
case groupCallParticipant(flags: Int32, userId: Int32, date: Int32, source: Int32)
|
case groupCallParticipant(flags: Int32, userId: Int32, date: Int32, activeDate: Int32?, source: Int32)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .groupCallParticipant(let flags, let userId, let date, let source):
|
case .groupCallParticipant(let flags, let userId, let date, let activeDate, let source):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1985949076)
|
buffer.appendInt32(1454409673)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(userId, buffer: buffer, boxed: false)
|
serializeInt32(userId, buffer: buffer, boxed: false)
|
||||||
serializeInt32(date, buffer: buffer, boxed: false)
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(activeDate!, buffer: buffer, boxed: false)}
|
||||||
serializeInt32(source, buffer: buffer, boxed: false)
|
serializeInt32(source, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -5376,8 +5377,8 @@ public extension Api {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .groupCallParticipant(let flags, let userId, let date, let source):
|
case .groupCallParticipant(let flags, let userId, let date, let activeDate, let source):
|
||||||
return ("groupCallParticipant", [("flags", flags), ("userId", userId), ("date", date), ("source", source)])
|
return ("groupCallParticipant", [("flags", flags), ("userId", userId), ("date", date), ("activeDate", activeDate), ("source", source)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5389,13 +5390,16 @@ public extension Api {
|
|||||||
var _3: Int32?
|
var _3: Int32?
|
||||||
_3 = reader.readInt32()
|
_3 = reader.readInt32()
|
||||||
var _4: Int32?
|
var _4: Int32?
|
||||||
_4 = reader.readInt32()
|
if Int(_1!) & Int(1 << 3) != 0 {_4 = reader.readInt32() }
|
||||||
|
var _5: Int32?
|
||||||
|
_5 = reader.readInt32()
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
let _c4 = _4 != nil
|
let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
let _c5 = _5 != nil
|
||||||
return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, userId: _2!, date: _3!, source: _4!)
|
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||||
|
return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, userId: _2!, date: _3!, activeDate: _4, source: _5!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1649,13 +1649,13 @@ public struct photos {
|
|||||||
public extension Api {
|
public extension Api {
|
||||||
public struct phone {
|
public struct phone {
|
||||||
public enum GroupCall: TypeConstructorDescription {
|
public enum GroupCall: TypeConstructorDescription {
|
||||||
case groupCall(call: Api.GroupCall, sources: [Int32], participants: [Api.GroupCallParticipant], users: [Api.User])
|
case groupCall(call: Api.GroupCall, sources: [Int32], participants: [Api.GroupCallParticipant], participantsNextOffset: String, users: [Api.User])
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .groupCall(let call, let sources, let participants, let users):
|
case .groupCall(let call, let sources, let participants, let participantsNextOffset, let users):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1447862232)
|
buffer.appendInt32(-1738792825)
|
||||||
}
|
}
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
@ -1668,6 +1668,7 @@ public struct phone {
|
|||||||
for item in participants {
|
for item in participants {
|
||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
}
|
}
|
||||||
|
serializeString(participantsNextOffset, buffer: buffer, boxed: false)
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(users.count))
|
buffer.appendInt32(Int32(users.count))
|
||||||
for item in users {
|
for item in users {
|
||||||
@ -1679,8 +1680,8 @@ public struct phone {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .groupCall(let call, let sources, let participants, let users):
|
case .groupCall(let call, let sources, let participants, let participantsNextOffset, let users):
|
||||||
return ("groupCall", [("call", call), ("sources", sources), ("participants", participants), ("users", users)])
|
return ("groupCall", [("call", call), ("sources", sources), ("participants", participants), ("participantsNextOffset", participantsNextOffset), ("users", users)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1697,16 +1698,19 @@ public struct phone {
|
|||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipant.self)
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipant.self)
|
||||||
}
|
}
|
||||||
var _4: [Api.User]?
|
var _4: String?
|
||||||
|
_4 = parseString(reader)
|
||||||
|
var _5: [Api.User]?
|
||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
_5 = 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
|
||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
let _c5 = _5 != nil
|
||||||
return Api.phone.GroupCall.groupCall(call: _1!, sources: _2!, participants: _3!, users: _4!)
|
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||||
|
return Api.phone.GroupCall.groupCall(call: _1!, sources: _2!, participants: _3!, participantsNextOffset: _4!, users: _5!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -1715,13 +1719,13 @@ public struct phone {
|
|||||||
|
|
||||||
}
|
}
|
||||||
public enum GroupParticipants: TypeConstructorDescription {
|
public enum GroupParticipants: TypeConstructorDescription {
|
||||||
case groupParticipants(count: Int32, participants: [Api.GroupCallParticipant], users: [Api.User], version: Int32)
|
case groupParticipants(count: Int32, participants: [Api.GroupCallParticipant], nextOffset: String, users: [Api.User], version: Int32)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .groupParticipants(let count, let participants, let users, let version):
|
case .groupParticipants(let count, let participants, let nextOffset, let users, let version):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1021016465)
|
buffer.appendInt32(-1661028051)
|
||||||
}
|
}
|
||||||
serializeInt32(count, buffer: buffer, boxed: false)
|
serializeInt32(count, buffer: buffer, boxed: false)
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
@ -1729,6 +1733,7 @@ public struct phone {
|
|||||||
for item in participants {
|
for item in participants {
|
||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
}
|
}
|
||||||
|
serializeString(nextOffset, buffer: buffer, boxed: false)
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(users.count))
|
buffer.appendInt32(Int32(users.count))
|
||||||
for item in users {
|
for item in users {
|
||||||
@ -1741,8 +1746,8 @@ public struct phone {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .groupParticipants(let count, let participants, let users, let version):
|
case .groupParticipants(let count, let participants, let nextOffset, let users, let version):
|
||||||
return ("groupParticipants", [("count", count), ("participants", participants), ("users", users), ("version", version)])
|
return ("groupParticipants", [("count", count), ("participants", participants), ("nextOffset", nextOffset), ("users", users), ("version", version)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1753,18 +1758,21 @@ public struct phone {
|
|||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipant.self)
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.GroupCallParticipant.self)
|
||||||
}
|
}
|
||||||
var _3: [Api.User]?
|
var _3: String?
|
||||||
|
_3 = parseString(reader)
|
||||||
|
var _4: [Api.User]?
|
||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
}
|
}
|
||||||
var _4: Int32?
|
var _5: Int32?
|
||||||
_4 = reader.readInt32()
|
_5 = reader.readInt32()
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
let _c5 = _5 != nil
|
||||||
return Api.phone.GroupParticipants.groupParticipants(count: _1!, participants: _2!, users: _3!, version: _4!)
|
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||||
|
return Api.phone.GroupParticipants.groupParticipants(count: _1!, participants: _2!, nextOffset: _3!, users: _4!, version: _5!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -7258,12 +7266,13 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func joinGroupCall(call: Api.InputGroupCall, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
public static func joinGroupCall(flags: Int32, call: Api.InputGroupCall, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(893342305)
|
buffer.appendInt32(1604095586)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
params.serialize(buffer, true)
|
params.serialize(buffer, true)
|
||||||
return (FunctionDescription(name: "phone.joinGroupCall", parameters: [("call", call), ("params", params)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
return (FunctionDescription(name: "phone.joinGroupCall", parameters: [("flags", flags), ("call", call), ("params", params)]), 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() {
|
||||||
@ -7273,11 +7282,12 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func leaveGroupCall(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
public static func leaveGroupCall(call: Api.InputGroupCall, source: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1625919071)
|
buffer.appendInt32(1342404601)
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
return (FunctionDescription(name: "phone.leaveGroupCall", parameters: [("call", call)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
serializeInt32(source, buffer: buffer, boxed: false)
|
||||||
|
return (FunctionDescription(name: "phone.leaveGroupCall", parameters: [("call", call), ("source", source)]), 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() {
|
||||||
@ -7332,6 +7342,22 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func toggleGroupCallSettings(flags: Int32, call: Api.InputGroupCall, joinMuted: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
|
let buffer = Buffer()
|
||||||
|
buffer.appendInt32(1958458429)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
call.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {joinMuted!.serialize(buffer, true)}
|
||||||
|
return (FunctionDescription(name: "phone.toggleGroupCallSettings", parameters: [("flags", flags), ("call", call), ("joinMuted", joinMuted)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||||
|
let reader = BufferReader(buffer)
|
||||||
|
var result: Api.Updates?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static func getGroupCall(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.GroupCall>) {
|
public static func getGroupCall(call: Api.InputGroupCall) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.GroupCall>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(209498135)
|
buffer.appendInt32(209498135)
|
||||||
@ -7346,13 +7372,13 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getGroupParticipants(call: Api.InputGroupCall, maxDate: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.GroupParticipants>) {
|
public static func getGroupParticipants(call: Api.InputGroupCall, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.phone.GroupParticipants>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-566111310)
|
buffer.appendInt32(-1374089052)
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
serializeInt32(maxDate, buffer: buffer, boxed: false)
|
serializeString(offset, buffer: buffer, boxed: false)
|
||||||
serializeInt32(limit, buffer: buffer, boxed: false)
|
serializeInt32(limit, buffer: buffer, boxed: false)
|
||||||
return (FunctionDescription(name: "phone.getGroupParticipants", parameters: [("call", call), ("maxDate", maxDate), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.GroupParticipants? in
|
return (FunctionDescription(name: "phone.getGroupParticipants", parameters: [("call", call), ("offset", offset), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.phone.GroupParticipants? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.phone.GroupParticipants?
|
var result: Api.phone.GroupParticipants?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
@ -151,15 +151,23 @@ final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
|||||||
call.toggleIsMuted()
|
call.toggleIsMuted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var actionButtonPressGestureStartTime: Double = 0.0
|
||||||
|
|
||||||
@objc private func micButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
@objc private func micButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||||
guard let call = self.currentData?.groupCall else {
|
guard let call = self.currentData?.groupCall else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch gestureRecognizer.state {
|
switch gestureRecognizer.state {
|
||||||
case .began:
|
case .began:
|
||||||
call.setIsMuted(false)
|
self.actionButtonPressGestureStartTime = CACurrentMediaTime()
|
||||||
|
call.setIsMuted(action: .muted(isPushToTalkActive: true))
|
||||||
case .ended, .cancelled:
|
case .ended, .cancelled:
|
||||||
call.setIsMuted(true)
|
let timestamp = CACurrentMediaTime()
|
||||||
|
if timestamp - self.actionButtonPressGestureStartTime < 0.2 {
|
||||||
|
call.toggleIsMuted()
|
||||||
|
} else {
|
||||||
|
call.setIsMuted(action: .muted(isPushToTalkActive: false))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -598,7 +598,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
}
|
}
|
||||||
if let currentGroupCall = self.currentGroupCallValue {
|
if let currentGroupCall = self.currentGroupCallValue {
|
||||||
if endCurrentIfAny {
|
if endCurrentIfAny {
|
||||||
let endSignal = currentGroupCall.leave()
|
let endSignal = currentGroupCall.leave(terminateIfPossible: false)
|
||||||
|> filter { $0 }
|
|> filter { $0 }
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|
@ -18,6 +18,8 @@ private extension PresentationGroupCallState {
|
|||||||
static var initialValue: PresentationGroupCallState {
|
static var initialValue: PresentationGroupCallState {
|
||||||
return PresentationGroupCallState(
|
return PresentationGroupCallState(
|
||||||
networkState: .connecting,
|
networkState: .connecting,
|
||||||
|
canManageCall: false,
|
||||||
|
adminIds: Set(),
|
||||||
isMuted: true
|
isMuted: true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -93,10 +95,18 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
private var summaryStateDisposable: Disposable?
|
private var summaryStateDisposable: Disposable?
|
||||||
|
|
||||||
private let isMutedPromise = ValuePromise<Bool>(true)
|
private var isMutedValue: PresentationGroupCallMuteAction = .muted(isPushToTalkActive: false)
|
||||||
private var isMutedValue = true
|
private let isMutedPromise = ValuePromise<PresentationGroupCallMuteAction>(.muted(isPushToTalkActive: false))
|
||||||
public var isMuted: Signal<Bool, NoError> {
|
public var isMuted: Signal<Bool, NoError> {
|
||||||
return self.isMutedPromise.get()
|
return self.isMutedPromise.get()
|
||||||
|
|> map { value -> Bool in
|
||||||
|
switch value {
|
||||||
|
case let .muted(isPushToTalkActive):
|
||||||
|
return isPushToTalkActive
|
||||||
|
case .unmuted:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let audioOutputStatePromise = Promise<([AudioSessionOutput], AudioSessionOutput?)>(([], nil))
|
private let audioOutputStatePromise = Promise<([AudioSessionOutput], AudioSessionOutput?)>(([], nil))
|
||||||
@ -380,8 +390,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
strongSelf.requestDisposable.set((joinGroupCall(
|
strongSelf.requestDisposable.set((joinGroupCall(
|
||||||
account: strongSelf.account,
|
account: strongSelf.account,
|
||||||
|
peerId: strongSelf.peerId,
|
||||||
callId: callInfo.id,
|
callId: callInfo.id,
|
||||||
accessHash: callInfo.accessHash,
|
accessHash: callInfo.accessHash,
|
||||||
|
preferMuted: true,
|
||||||
joinPayload: joinPayload
|
joinPayload: joinPayload
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue).start(next: { joinCallResult in
|
|> deliverOnMainQueue).start(next: { joinCallResult in
|
||||||
@ -464,6 +476,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
if case let .estabilished(callInfo, clientParams, _, initialState) = internalState {
|
if case let .estabilished(callInfo, clientParams, _, initialState) = internalState {
|
||||||
self.summaryInfoState.set(.single(SummaryInfoState(info: callInfo)))
|
self.summaryInfoState.set(.single(SummaryInfoState(info: callInfo)))
|
||||||
|
|
||||||
|
self.stateValue.canManageCall = initialState.isCreator
|
||||||
|
|
||||||
self.ssrcMapping.removeAll()
|
self.ssrcMapping.removeAll()
|
||||||
var ssrcs: [UInt32] = []
|
var ssrcs: [UInt32] = []
|
||||||
for participant in initialState.participants {
|
for participant in initialState.participants {
|
||||||
@ -501,6 +515,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
strongSelf.membersValue = memberStates
|
strongSelf.membersValue = memberStates
|
||||||
|
|
||||||
|
strongSelf.stateValue.adminIds = state.adminIds
|
||||||
|
|
||||||
strongSelf.summaryParticipantsState.set(.single(SummaryParticipantsState(
|
strongSelf.summaryParticipantsState.set(.single(SummaryParticipantsState(
|
||||||
participantCount: state.totalCount,
|
participantCount: state.totalCount,
|
||||||
topParticipants: topParticipants
|
topParticipants: topParticipants
|
||||||
@ -551,25 +567,49 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func leave() -> Signal<Bool, NoError> {
|
public func leave(terminateIfPossible: Bool) -> Signal<Bool, NoError> {
|
||||||
if case let .estabilished(callInfo, _, _, _) = self.internalState {
|
if case let .estabilished(callInfo, _, localSsrc, _) = self.internalState {
|
||||||
self.leaveDisposable.set((leaveGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash)
|
if terminateIfPossible {
|
||||||
|
self.leaveDisposable.set((stopGroupCall(account: self.account, peerId: self.peerId, callId: callInfo.id, accessHash: callInfo.accessHash)
|
||||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
self?._canBeRemoved.set(.single(true))
|
self?._canBeRemoved.set(.single(true))
|
||||||
}))
|
}))
|
||||||
|
} else {
|
||||||
|
self.leaveDisposable.set((leaveGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, source: localSsrc)
|
||||||
|
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
|
self?._canBeRemoved.set(.single(true))
|
||||||
|
}))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
return self._canBeRemoved.get()
|
return self._canBeRemoved.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func toggleIsMuted() {
|
public func toggleIsMuted() {
|
||||||
self.setIsMuted(!self.isMutedValue)
|
switch self.isMutedValue {
|
||||||
|
case .muted:
|
||||||
|
self.setIsMuted(action: .unmuted)
|
||||||
|
case .unmuted:
|
||||||
|
self.setIsMuted(action: .muted(isPushToTalkActive: false))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setIsMuted(_ value: Bool) {
|
public func setIsMuted(action: PresentationGroupCallMuteAction) {
|
||||||
self.isMutedValue = value
|
if self.isMutedValue == action {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isMutedValue = action
|
||||||
self.isMutedPromise.set(self.isMutedValue)
|
self.isMutedPromise.set(self.isMutedValue)
|
||||||
self.callContext?.setIsMuted(self.isMutedValue)
|
let isEffectivelyMuted: Bool
|
||||||
|
switch self.isMutedValue {
|
||||||
|
case let .muted(isPushToTalkActive):
|
||||||
|
isEffectivelyMuted = !isPushToTalkActive
|
||||||
|
self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: true)
|
||||||
|
case .unmuted:
|
||||||
|
isEffectivelyMuted = false
|
||||||
|
self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: false)
|
||||||
|
}
|
||||||
|
self.callContext?.setIsMuted(isEffectivelyMuted)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
public func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
||||||
@ -590,7 +630,29 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func updateMuteState(peerId: PeerId, isMuted: Bool) {
|
public func updateMuteState(peerId: PeerId, isMuted: Bool) {
|
||||||
self.participantsContext?.updateMuteState(peerId: peerId, muteState: isMuted ? GroupCallParticipantsContext.Participant.MuteState(canUnmute: peerId == self.accountContext.account.peerId) : nil)
|
let canThenUnmute: Bool
|
||||||
|
if isMuted {
|
||||||
|
if peerId == self.accountContext.account.peerId {
|
||||||
|
canThenUnmute = true
|
||||||
|
} else if self.stateValue.canManageCall {
|
||||||
|
if self.stateValue.adminIds.contains(peerId) {
|
||||||
|
canThenUnmute = true
|
||||||
|
} else {
|
||||||
|
canThenUnmute = false
|
||||||
|
}
|
||||||
|
} else if self.stateValue.adminIds.contains(self.accountContext.account.peerId) {
|
||||||
|
canThenUnmute = true
|
||||||
|
} else {
|
||||||
|
canThenUnmute = true
|
||||||
|
}
|
||||||
|
self.participantsContext?.updateMuteState(peerId: peerId, muteState: isMuted ? GroupCallParticipantsContext.Participant.MuteState(canUnmute: canThenUnmute) : nil)
|
||||||
|
} else {
|
||||||
|
if peerId == self.accountContext.account.peerId {
|
||||||
|
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil)
|
||||||
|
} else {
|
||||||
|
self.participantsContext?.updateMuteState(peerId: peerId, muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestCall() {
|
private func requestCall() {
|
||||||
|
@ -348,18 +348,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if entry.muteState == nil {
|
if let callState = strongSelf.callState, (callState.canManageCall || callState.adminIds.contains(strongSelf.context.account.peerId)) {
|
||||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_MutePeer, icon: { theme in
|
if let muteState = entry.muteState, !muteState.canUnmute {
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Call/Context Menu/Mute"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, action: { _, f in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
strongSelf.call.updateMuteState(peerId: peer.id, isMuted: true)
|
|
||||||
f(.default)
|
|
||||||
})))
|
|
||||||
} else {
|
|
||||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_UnmutePeer, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_UnmutePeer, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Call/Context Menu/Unmute"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Call/Context Menu/Unmute"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
@ -370,6 +360,18 @@ public final class VoiceChatController: ViewController {
|
|||||||
strongSelf.call.updateMuteState(peerId: peer.id, isMuted: false)
|
strongSelf.call.updateMuteState(peerId: peer.id, isMuted: false)
|
||||||
f(.default)
|
f(.default)
|
||||||
})))
|
})))
|
||||||
|
} else {
|
||||||
|
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_MutePeer, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Call/Context Menu/Mute"), color: theme.actionSheet.primaryTextColor)
|
||||||
|
}, action: { _, f in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.call.updateMuteState(peerId: peer.id, isMuted: true)
|
||||||
|
f(.default)
|
||||||
|
})))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.id != strongSelf.context.account.peerId {
|
if peer.id != strongSelf.context.account.peerId {
|
||||||
@ -574,12 +576,24 @@ public final class VoiceChatController: ViewController {
|
|||||||
strongSelf.controller?.present(shareController, in: .window(.root))
|
strongSelf.controller?.present(shareController, in: .window(.root))
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
if let callState = strongSelf.callState, callState.canManageCall {
|
||||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_EndVoiceChat, textColor: .destructive, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_EndVoiceChat, 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: { _, f in
|
}, action: { _, f in
|
||||||
f(.dismissWithoutContent)
|
f(.dismissWithoutContent)
|
||||||
|
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (strongSelf.call.leave(terminateIfPossible: true)
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(completed: {
|
||||||
|
self?.controller?.dismiss()
|
||||||
|
})
|
||||||
})))
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(VoiceChatContextExtractedContentSource(controller: controller, sourceNode: strongOptionsButton.extractedContainerNode, keepInPlace: true)), items: .single(items), reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(VoiceChatContextExtractedContentSource(controller: controller, sourceNode: strongOptionsButton.extractedContainerNode, keepInPlace: true)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||||
@ -607,12 +621,12 @@ public final class VoiceChatController: ViewController {
|
|||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.actionButtonPressGesture(_:)))
|
let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.actionButtonPressGesture(_:)))
|
||||||
longTapRecognizer.minimumPressDuration = 0.1
|
longTapRecognizer.minimumPressDuration = 0.001
|
||||||
self.actionButton.view.addGestureRecognizer(longTapRecognizer)
|
self.actionButton.view.addGestureRecognizer(longTapRecognizer)
|
||||||
|
|
||||||
let panRecognizer = CallPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
let panRecognizer = CallPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||||
panRecognizer.shouldBegin = { [weak self] _ in
|
panRecognizer.shouldBegin = { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
guard let _ = self else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -625,22 +639,35 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func leavePressed() {
|
@objc private func leavePressed() {
|
||||||
self.leaveDisposable.set((self.call.leave()
|
self.leaveDisposable.set((self.call.leave(terminateIfPossible: false)
|
||||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
self?.controller?.dismiss()
|
self?.controller?.dismiss()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var actionButtonPressGestureStartTime: Double = 0.0
|
||||||
|
|
||||||
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||||
|
guard let callState = self.callState else {
|
||||||
|
return
|
||||||
|
}
|
||||||
switch gestureRecognizer.state {
|
switch gestureRecognizer.state {
|
||||||
case .began:
|
case .began:
|
||||||
self.pushingToTalk = true
|
self.actionButtonPressGestureStartTime = CACurrentMediaTime()
|
||||||
self.actionButton.pressing = true
|
self.actionButton.pressing = true
|
||||||
self.call.setIsMuted(false)
|
if callState.isMuted {
|
||||||
|
self.pushingToTalk = true
|
||||||
|
self.call.setIsMuted(action: .muted(isPushToTalkActive: true))
|
||||||
|
}
|
||||||
case .ended, .cancelled:
|
case .ended, .cancelled:
|
||||||
self.pushingToTalk = false
|
self.pushingToTalk = false
|
||||||
self.actionButton.pressing = false
|
self.actionButton.pressing = false
|
||||||
self.call.setIsMuted(true)
|
let timestamp = CACurrentMediaTime()
|
||||||
|
if callState.isMuted || timestamp - self.actionButtonPressGestureStartTime < 0.1 {
|
||||||
|
self.call.toggleIsMuted()
|
||||||
|
} else {
|
||||||
|
self.call.setIsMuted(action: .muted(isPushToTalkActive: false))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -748,7 +775,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
let actionButtonSubtitle: String
|
let actionButtonSubtitle: String
|
||||||
let audioButtonAppearance: CallControllerButtonItemNode.Content.Appearance
|
let audioButtonAppearance: CallControllerButtonItemNode.Content.Appearance
|
||||||
var actionButtonEnabled = true
|
var actionButtonEnabled = true
|
||||||
if let callState = callState {
|
if let callState = self.callState {
|
||||||
isMicOn = !callState.isMuted
|
isMicOn = !callState.isMuted
|
||||||
|
|
||||||
switch callState.networkState {
|
switch callState.networkState {
|
||||||
|
@ -50,7 +50,7 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int
|
|||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<GroupCallSummary?, GetCurrentGroupCallError> in
|
|> mapToSignal { result -> Signal<GroupCallSummary?, GetCurrentGroupCallError> in
|
||||||
switch result {
|
switch result {
|
||||||
case let .groupCall(call, _, participants, users):
|
case let .groupCall(call, _, participants, _, users):
|
||||||
return account.postbox.transaction { transaction -> GroupCallSummary? in
|
return account.postbox.transaction { transaction -> GroupCallSummary? in
|
||||||
guard let info = GroupCallInfo(call) else {
|
guard let info = GroupCallInfo(call) else {
|
||||||
return nil
|
return nil
|
||||||
@ -76,7 +76,7 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int
|
|||||||
|
|
||||||
loop: for participant in participants {
|
loop: for participant in participants {
|
||||||
switch participant {
|
switch participant {
|
||||||
case let .groupCallParticipant(flags, userId, date, source):
|
case let .groupCallParticipant(flags, userId, date, activeDate, source):
|
||||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||||
let ssrc = UInt32(bitPattern: source)
|
let ssrc = UInt32(bitPattern: source)
|
||||||
guard let peer = transaction.getPeer(peerId) else {
|
guard let peer = transaction.getPeer(peerId) else {
|
||||||
@ -127,8 +127,6 @@ public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCal
|
|||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<GroupCallInfo, CreateGroupCallError> in
|
|> mapToSignal { result -> Signal<GroupCallInfo, CreateGroupCallError> in
|
||||||
account.stateManager.addUpdates(result)
|
|
||||||
|
|
||||||
var parsedCall: GroupCallInfo?
|
var parsedCall: GroupCallInfo?
|
||||||
loop: for update in result.allUpdates {
|
loop: for update in result.allUpdates {
|
||||||
switch update {
|
switch update {
|
||||||
@ -140,11 +138,24 @@ public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let parsedCall = parsedCall {
|
guard let callInfo = parsedCall else {
|
||||||
return .single(parsedCall)
|
|
||||||
} else {
|
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return account.postbox.transaction { transaction -> GroupCallInfo in
|
||||||
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||||
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
|
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash))
|
||||||
|
} else {
|
||||||
|
return cachedData
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
account.stateManager.addUpdates(result)
|
||||||
|
|
||||||
|
return callInfo
|
||||||
|
}
|
||||||
|
|> castError(CreateGroupCallError.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,8 +164,8 @@ public enum GetGroupCallParticipantsError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, maxDate: Int32, limit: Int32) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, offset: String, limit: Int32) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||||
return account.network.request(Api.functions.phone.getGroupParticipants(call: .inputGroupCall(id: callId, accessHash: accessHash), maxDate: maxDate, limit: limit))
|
return account.network.request(Api.functions.phone.getGroupParticipants(call: .inputGroupCall(id: callId, accessHash: accessHash), offset: offset, limit: limit))
|
||||||
|> mapError { _ -> GetGroupCallParticipantsError in
|
|> mapError { _ -> GetGroupCallParticipantsError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
@ -163,12 +174,19 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
|||||||
var parsedParticipants: [GroupCallParticipantsContext.Participant] = []
|
var parsedParticipants: [GroupCallParticipantsContext.Participant] = []
|
||||||
let totalCount: Int
|
let totalCount: Int
|
||||||
let version: Int32
|
let version: Int32
|
||||||
|
let nextParticipantsFetchOffset: String?
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case let .groupParticipants(count, participants, users, apiVersion):
|
case let .groupParticipants(count, participants, nextOffset, users, apiVersion):
|
||||||
totalCount = Int(count)
|
totalCount = Int(count)
|
||||||
version = apiVersion
|
version = apiVersion
|
||||||
|
|
||||||
|
if participants.count != 0 && !nextOffset.isEmpty {
|
||||||
|
nextParticipantsFetchOffset = nextOffset
|
||||||
|
} else {
|
||||||
|
nextParticipantsFetchOffset = nil
|
||||||
|
}
|
||||||
|
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||||
|
|
||||||
@ -187,7 +205,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
|||||||
|
|
||||||
loop: for participant in participants {
|
loop: for participant in participants {
|
||||||
switch participant {
|
switch participant {
|
||||||
case let .groupCallParticipant(flags, userId, date, source):
|
case let .groupCallParticipant(flags, userId, date, activeDate, source):
|
||||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||||
let ssrc = UInt32(bitPattern: source)
|
let ssrc = UInt32(bitPattern: source)
|
||||||
guard let peer = transaction.getPeer(peerId) else {
|
guard let peer = transaction.getPeer(peerId) else {
|
||||||
@ -202,6 +220,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
|||||||
peer: peer,
|
peer: peer,
|
||||||
ssrc: ssrc,
|
ssrc: ssrc,
|
||||||
joinTimestamp: date,
|
joinTimestamp: date,
|
||||||
|
activityTimestamp: activeDate,
|
||||||
muteState: muteState
|
muteState: muteState
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -210,6 +229,9 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
|||||||
|
|
||||||
return GroupCallParticipantsContext.State(
|
return GroupCallParticipantsContext.State(
|
||||||
participants: parsedParticipants,
|
participants: parsedParticipants,
|
||||||
|
nextParticipantsFetchOffset: nextParticipantsFetchOffset,
|
||||||
|
adminIds: Set(),
|
||||||
|
isCreator: false,
|
||||||
totalCount: totalCount,
|
totalCount: totalCount,
|
||||||
version: version
|
version: version
|
||||||
)
|
)
|
||||||
@ -227,23 +249,56 @@ public struct JoinGroupCallResult {
|
|||||||
public var state: GroupCallParticipantsContext.State
|
public var state: GroupCallParticipantsContext.State
|
||||||
}
|
}
|
||||||
|
|
||||||
public func joinGroupCall(account: Account, callId: Int64, accessHash: Int64, joinPayload: String) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, accessHash: Int64, preferMuted: Bool, joinPayload: String) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
||||||
return account.network.request(Api.functions.phone.joinGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash), params: .dataJSON(data: joinPayload)))
|
var flags: Int32 = 0
|
||||||
|
if preferMuted {
|
||||||
|
flags |= (1 << 0)
|
||||||
|
}
|
||||||
|
return account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), params: .dataJSON(data: joinPayload)))
|
||||||
|> mapError { _ -> JoinGroupCallError in
|
|> mapError { _ -> JoinGroupCallError in
|
||||||
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
|
||||||
|
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||||
|
}
|
||||||
|
|> castError(JoinGroupCallError.self)
|
||||||
|
|> mapToSignal { inputChannel -> Signal<Api.channels.ChannelParticipants, JoinGroupCallError> in
|
||||||
|
guard let inputChannel = inputChannel else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: 0))
|
||||||
|
|> mapError { _ -> JoinGroupCallError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let channel = account.postbox.transaction { transaction -> TelegramChannel? in
|
||||||
|
return transaction.getPeer(peerId) as? TelegramChannel
|
||||||
|
}
|
||||||
|
|> castError(JoinGroupCallError.self)
|
||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
account.network.request(Api.functions.phone.getGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
||||||
|> mapError { _ -> JoinGroupCallError in
|
|> mapError { _ -> JoinGroupCallError in
|
||||||
return .generic
|
return .generic
|
||||||
},
|
},
|
||||||
getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, maxDate: 0, limit: 100)
|
getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", limit: 100)
|
||||||
|> mapError { _ -> JoinGroupCallError in
|
|> mapError { _ -> JoinGroupCallError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
},
|
||||||
|
admins,
|
||||||
|
channel
|
||||||
)
|
)
|
||||||
|> mapToSignal { result, state -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
|> mapToSignal { result, state, admins, channel -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
||||||
|
guard let channel = channel else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var state = state
|
||||||
|
state.isCreator = channel.flags.contains(.isCreator)
|
||||||
|
|
||||||
account.stateManager.addUpdates(updates)
|
account.stateManager.addUpdates(updates)
|
||||||
|
|
||||||
var maybeParsedCall: GroupCallInfo?
|
var maybeParsedCall: GroupCallInfo?
|
||||||
@ -261,12 +316,55 @@ public func joinGroupCall(account: Account, callId: Int64, accessHash: Int64, jo
|
|||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var apiUsers: [Api.User] = []
|
||||||
|
var adminIds = Set<PeerId>()
|
||||||
|
|
||||||
|
switch admins {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
state.adminIds = adminIds
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case let .groupCall(call, sources, _, users):
|
case let .groupCall(call, sources, _, _, users):
|
||||||
guard let _ = GroupCallInfo(call) else {
|
guard let _ = GroupCallInfo(call) else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiUsers.append(contentsOf: users)
|
||||||
|
|
||||||
|
var peers: [Peer] = []
|
||||||
|
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||||
|
|
||||||
|
for user in apiUsers {
|
||||||
|
let telegramUser = TelegramUser(user: user)
|
||||||
|
peers.append(telegramUser)
|
||||||
|
if let presence = TelegramUserPresence(apiUser: user) {
|
||||||
|
peerPresences[telegramUser.id] = presence
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return account.postbox.transaction { transaction -> JoinGroupCallResult in
|
return account.postbox.transaction { transaction -> JoinGroupCallResult in
|
||||||
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||||
|
|
||||||
return JoinGroupCallResult(
|
return JoinGroupCallResult(
|
||||||
callInfo: parsedCall,
|
callInfo: parsedCall,
|
||||||
state: state
|
state: state
|
||||||
@ -282,8 +380,8 @@ public enum LeaveGroupCallError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func leaveGroupCall(account: Account, callId: Int64, accessHash: Int64) -> Signal<Never, LeaveGroupCallError> {
|
public func leaveGroupCall(account: Account, callId: Int64, accessHash: Int64, source: UInt32) -> Signal<Never, LeaveGroupCallError> {
|
||||||
return account.network.request(Api.functions.phone.leaveGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
return account.network.request(Api.functions.phone.leaveGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash), source: Int32(bitPattern: source)))
|
||||||
|> mapError { _ -> LeaveGroupCallError in
|
|> mapError { _ -> LeaveGroupCallError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
@ -294,15 +392,25 @@ public enum StopGroupCallError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stopGroupCall(account: Account, callId: Int64, accessHash: Int64) -> Signal<Never, StopGroupCallError> {
|
public func stopGroupCall(account: Account, peerId: PeerId, callId: Int64, accessHash: Int64) -> Signal<Never, StopGroupCallError> {
|
||||||
return account.network.request(Api.functions.phone.discardGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
return account.network.request(Api.functions.phone.discardGroupCall(call: .inputGroupCall(id: callId, accessHash: accessHash)))
|
||||||
|> mapError { _ -> StopGroupCallError in
|
|> mapError { _ -> StopGroupCallError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|> mapToSignal { result -> Signal<Never, StopGroupCallError> in
|
|> mapToSignal { result -> Signal<Never, StopGroupCallError> in
|
||||||
account.stateManager.addUpdates(result)
|
return account.postbox.transaction { transaction -> Void in
|
||||||
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||||
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
|
return cachedData.withUpdatedActiveCall(nil)
|
||||||
|
} else {
|
||||||
|
return cachedData
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return .complete()
|
account.stateManager.addUpdates(result)
|
||||||
|
}
|
||||||
|
|> castError(StopGroupCallError.self)
|
||||||
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,6 +463,7 @@ public final class GroupCallParticipantsContext {
|
|||||||
public var peer: Peer
|
public var peer: Peer
|
||||||
public var ssrc: UInt32
|
public var ssrc: UInt32
|
||||||
public var joinTimestamp: Int32
|
public var joinTimestamp: Int32
|
||||||
|
public var activityTimestamp: Int32?
|
||||||
public var muteState: MuteState?
|
public var muteState: MuteState?
|
||||||
|
|
||||||
public static func ==(lhs: Participant, rhs: Participant) -> Bool {
|
public static func ==(lhs: Participant, rhs: Participant) -> Bool {
|
||||||
@ -367,6 +476,9 @@ public final class GroupCallParticipantsContext {
|
|||||||
if lhs.joinTimestamp != rhs.joinTimestamp {
|
if lhs.joinTimestamp != rhs.joinTimestamp {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.activityTimestamp != rhs.activityTimestamp {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.muteState != rhs.muteState {
|
if lhs.muteState != rhs.muteState {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -376,6 +488,9 @@ public final class GroupCallParticipantsContext {
|
|||||||
|
|
||||||
public struct State: Equatable {
|
public struct State: Equatable {
|
||||||
public var participants: [Participant]
|
public var participants: [Participant]
|
||||||
|
public var nextParticipantsFetchOffset: String?
|
||||||
|
public var adminIds: Set<PeerId>
|
||||||
|
public var isCreator: Bool
|
||||||
public var totalCount: Int
|
public var totalCount: Int
|
||||||
public var version: Int32
|
public var version: Int32
|
||||||
}
|
}
|
||||||
@ -416,6 +531,7 @@ public final class GroupCallParticipantsContext {
|
|||||||
public var peerId: PeerId
|
public var peerId: PeerId
|
||||||
public var ssrc: UInt32
|
public var ssrc: UInt32
|
||||||
public var joinTimestamp: Int32
|
public var joinTimestamp: Int32
|
||||||
|
public var activityTimestamp: Int32?
|
||||||
public var muteState: Participant.MuteState?
|
public var muteState: Participant.MuteState?
|
||||||
public var isRemoved: Bool
|
public var isRemoved: Bool
|
||||||
}
|
}
|
||||||
@ -561,9 +677,16 @@ public final class GroupCallParticipantsContext {
|
|||||||
updatedOverlayState.pendingMuteStateChanges.removeValue(forKey: peerId)
|
updatedOverlayState.pendingMuteStateChanges.removeValue(forKey: peerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nextParticipantsFetchOffset = strongSelf.stateValue.state.nextParticipantsFetchOffset
|
||||||
|
let adminIds = strongSelf.stateValue.state.adminIds
|
||||||
|
let isCreator = strongSelf.stateValue.state.isCreator
|
||||||
|
|
||||||
strongSelf.stateValue = InternalState(
|
strongSelf.stateValue = InternalState(
|
||||||
state: State(
|
state: State(
|
||||||
participants: Array(updatedParticipants.reversed()),
|
participants: Array(updatedParticipants.reversed()),
|
||||||
|
nextParticipantsFetchOffset: nextParticipantsFetchOffset,
|
||||||
|
adminIds: adminIds,
|
||||||
|
isCreator: isCreator,
|
||||||
totalCount: updatedTotalCount,
|
totalCount: updatedTotalCount,
|
||||||
version: update.version
|
version: update.version
|
||||||
),
|
),
|
||||||
@ -577,8 +700,7 @@ public final class GroupCallParticipantsContext {
|
|||||||
private func resetStateFromServer() {
|
private func resetStateFromServer() {
|
||||||
self.updateQueue.removeAll()
|
self.updateQueue.removeAll()
|
||||||
|
|
||||||
self.disposable.set((
|
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", limit: 100)
|
||||||
getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, maxDate: 0, limit: 100)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -615,9 +737,10 @@ public final class GroupCallParticipantsContext {
|
|||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if muteState != nil {
|
if let muteState = muteState, !muteState.canUnmute {
|
||||||
flags |= 1 << 0
|
flags |= 1 << 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return account.network.request(Api.functions.phone.editGroupCallMember(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), userId: inputUser))
|
return account.network.request(Api.functions.phone.editGroupCallMember(flags: flags, call: .inputGroupCall(id: id, accessHash: accessHash), userId: inputUser))
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||||
@ -664,7 +787,7 @@ extension GroupCallParticipantsContext.StateUpdate {
|
|||||||
var participantUpdates: [GroupCallParticipantsContext.StateUpdate.ParticipantUpdate] = []
|
var participantUpdates: [GroupCallParticipantsContext.StateUpdate.ParticipantUpdate] = []
|
||||||
for participant in participants {
|
for participant in participants {
|
||||||
switch participant {
|
switch participant {
|
||||||
case let .groupCallParticipant(flags, userId, date, source):
|
case let .groupCallParticipant(flags, userId, date, activeDate, source):
|
||||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
|
||||||
let ssrc = UInt32(bitPattern: source)
|
let ssrc = UInt32(bitPattern: source)
|
||||||
var muteState: GroupCallParticipantsContext.Participant.MuteState?
|
var muteState: GroupCallParticipantsContext.Participant.MuteState?
|
||||||
@ -677,6 +800,7 @@ extension GroupCallParticipantsContext.StateUpdate {
|
|||||||
peerId: peerId,
|
peerId: peerId,
|
||||||
ssrc: ssrc,
|
ssrc: ssrc,
|
||||||
joinTimestamp: date,
|
joinTimestamp: date,
|
||||||
|
activityTimestamp: activeDate,
|
||||||
muteState: muteState,
|
muteState: muteState,
|
||||||
isRemoved: isRemoved
|
isRemoved: isRemoved
|
||||||
))
|
))
|
||||||
|
@ -13,6 +13,7 @@ public enum TelegramChannelPermission {
|
|||||||
case addAdmins
|
case addAdmins
|
||||||
case changeInfo
|
case changeInfo
|
||||||
case canBeAnonymous
|
case canBeAnonymous
|
||||||
|
case manageCalls
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension TelegramChannel {
|
public extension TelegramChannel {
|
||||||
@ -124,6 +125,11 @@ public extension TelegramChannel {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
case .manageCalls:
|
||||||
|
if let adminRights = self.adminRights, adminRights.flags.contains(.canManageCalls) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
case .canBeAnonymous:
|
case .canBeAnonymous:
|
||||||
if let adminRights = self.adminRights, adminRights.flags.contains(.canBeAnonymous) {
|
if let adminRights = self.adminRights, adminRights.flags.contains(.canBeAnonymous) {
|
||||||
return true
|
return true
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -718,7 +718,8 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
(.canEditMessages, self.presentationData.strings.Channel_AdminLog_CanEditMessages),
|
(.canEditMessages, self.presentationData.strings.Channel_AdminLog_CanEditMessages),
|
||||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
||||||
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
||||||
(.canAddAdmins, self.presentationData.strings.Channel_AdminLog_CanAddAdmins)
|
(.canAddAdmins, self.presentationData.strings.Channel_AdminLog_CanAddAdmins),
|
||||||
|
(.canManageCalls, self.presentationData.strings.Channel_AdminLog_CanManageCalls)
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
order = [
|
order = [
|
||||||
@ -728,7 +729,8 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
(.canInviteUsers, self.presentationData.strings.Channel_AdminLog_CanInviteUsers),
|
||||||
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
(.canPinMessages, self.presentationData.strings.Channel_AdminLog_CanPinMessages),
|
||||||
(.canBeAnonymous, self.presentationData.strings.Channel_AdminLog_CanBeAnonymous),
|
(.canBeAnonymous, self.presentationData.strings.Channel_AdminLog_CanBeAnonymous),
|
||||||
(.canAddAdmins, self.presentationData.strings.Channel_AdminLog_CanAddAdmins)
|
(.canAddAdmins, self.presentationData.strings.Channel_AdminLog_CanAddAdmins),
|
||||||
|
(.canManageCalls, self.presentationData.strings.Channel_AdminLog_CanManageCalls)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit aeaa63b502a1ee88feef282af739980001138993
|
Subproject commit 9e25105d8662f54b7151070225c5866d0f0a6231
|
Loading…
x
Reference in New Issue
Block a user