mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Stories
This commit is contained in:
parent
284d963b07
commit
aa637d96d7
24 changed files with 554 additions and 60 deletions
|
|
@ -684,11 +684,12 @@ final class ContextControllerNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||
self.contentReady.set(.single(true))
|
||||
|
||||
let transitionInfo = source.transitionInfo()
|
||||
if let transitionInfo = transitionInfo {
|
||||
if let transitionInfo {
|
||||
let referenceView = transitionInfo.referenceView
|
||||
self.contentContainerNode.contentNode = .reference(view: referenceView)
|
||||
self.contentAreaInScreenSpace = transitionInfo.contentAreaInScreenSpace
|
||||
self.customPosition = transitionInfo.customPosition
|
||||
|
||||
var projectedFrame = convertFrame(referenceView.bounds, from: referenceView, to: self.view)
|
||||
projectedFrame.origin.x += transitionInfo.insets.left
|
||||
projectedFrame.size.width -= transitionInfo.insets.left + transitionInfo.insets.right
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ private final class ContextControllerActionsListCustomItemNode: ASDisplayNode, C
|
|||
getController: self.getController,
|
||||
actionSelected: { result in
|
||||
switch result {
|
||||
case .dismissWithoutContent:
|
||||
case .default, .dismissWithoutContent:
|
||||
self.requestDismiss(result)
|
||||
default:
|
||||
break
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
|
||||
dict[-565420653] = { return Api.GeoPointAddress.parse_geoPointAddress($0) }
|
||||
dict[-29248689] = { return Api.GlobalPrivacySettings.parse_globalPrivacySettings($0) }
|
||||
dict[-674602536] = { return Api.GroupCall.parse_groupCall($0) }
|
||||
dict[-273500649] = { return Api.GroupCall.parse_groupCall($0) }
|
||||
dict[2004925620] = { return Api.GroupCall.parse_groupCallDiscarded($0) }
|
||||
dict[-297595771] = { return Api.GroupCallDonor.parse_groupCallDonor($0) }
|
||||
dict[445316222] = { return Api.GroupCallMessage.parse_groupCallMessage($0) }
|
||||
|
|
@ -588,7 +588,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||
dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) }
|
||||
dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) }
|
||||
dict[1456486804] = { return Api.MessageAction.parse_messageActionGiftCode($0) }
|
||||
dict[1818391802] = { return Api.MessageAction.parse_messageActionGiftPremium($0) }
|
||||
dict[1223234306] = { return Api.MessageAction.parse_messageActionGiftPremium($0) }
|
||||
dict[1171632161] = { return Api.MessageAction.parse_messageActionGiftStars($0) }
|
||||
dict[-1465661799] = { return Api.MessageAction.parse_messageActionGiftTon($0) }
|
||||
dict[-1475391004] = { return Api.MessageAction.parse_messageActionGiveawayLaunch($0) }
|
||||
|
|
|
|||
|
|
@ -1044,7 +1044,7 @@ public extension Api {
|
|||
case messageActionGameScore(gameId: Int64, score: Int32)
|
||||
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
|
||||
case messageActionGiftCode(flags: Int32, boostPeer: Api.Peer?, months: Int32, slug: String, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
|
||||
case messageActionGiftPremium(flags: Int32, currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
|
||||
case messageActionGiftPremium(flags: Int32, currency: String, amount: Int64, days: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
|
||||
case messageActionGiftStars(flags: Int32, currency: String, amount: Int64, stars: Int64, cryptoCurrency: String?, cryptoAmount: Int64?, transactionId: String?)
|
||||
case messageActionGiftTon(flags: Int32, currency: String, amount: Int64, cryptoCurrency: String, cryptoAmount: Int64, transactionId: String?)
|
||||
case messageActionGiveawayLaunch(flags: Int32, stars: Int64?)
|
||||
|
|
@ -1235,14 +1235,14 @@ public extension Api {
|
|||
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 4) != 0 {message!.serialize(buffer, true)}
|
||||
break
|
||||
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount, let message):
|
||||
case .messageActionGiftPremium(let flags, let currency, let amount, let days, let cryptoCurrency, let cryptoAmount, let message):
|
||||
if boxed {
|
||||
buffer.appendInt32(1818391802)
|
||||
buffer.appendInt32(1223234306)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(currency, buffer: buffer, boxed: false)
|
||||
serializeInt64(amount, buffer: buffer, boxed: false)
|
||||
serializeInt32(months, buffer: buffer, boxed: false)
|
||||
serializeInt32(days, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(cryptoCurrency!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
|
||||
|
|
@ -1627,8 +1627,8 @@ public extension Api {
|
|||
return ("messageActionGeoProximityReached", [("fromId", fromId as Any), ("toId", toId as Any), ("distance", distance as Any)])
|
||||
case .messageActionGiftCode(let flags, let boostPeer, let months, let slug, let currency, let amount, let cryptoCurrency, let cryptoAmount, let message):
|
||||
return ("messageActionGiftCode", [("flags", flags as Any), ("boostPeer", boostPeer as Any), ("months", months as Any), ("slug", slug as Any), ("currency", currency as Any), ("amount", amount as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
|
||||
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount, let message):
|
||||
return ("messageActionGiftPremium", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("months", months as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
|
||||
case .messageActionGiftPremium(let flags, let currency, let amount, let days, let cryptoCurrency, let cryptoAmount, let message):
|
||||
return ("messageActionGiftPremium", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("days", days as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
|
||||
case .messageActionGiftStars(let flags, let currency, let amount, let stars, let cryptoCurrency, let cryptoAmount, let transactionId):
|
||||
return ("messageActionGiftStars", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("stars", stars as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("transactionId", transactionId as Any)])
|
||||
case .messageActionGiftTon(let flags, let currency, let amount, let cryptoCurrency, let cryptoAmount, let transactionId):
|
||||
|
|
@ -1991,7 +1991,7 @@ public extension Api {
|
|||
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.MessageAction.messageActionGiftPremium(flags: _1!, currency: _2!, amount: _3!, months: _4!, cryptoCurrency: _5, cryptoAmount: _6, message: _7)
|
||||
return Api.MessageAction.messageActionGiftPremium(flags: _1!, currency: _2!, amount: _3!, days: _4!, cryptoCurrency: _5, cryptoAmount: _6, message: _7)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -10854,6 +10854,22 @@ public extension Api.functions.phone {
|
|||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.phone {
|
||||
static func saveDefaultSendAs(call: Api.InputGroupCall, sendAs: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1097313745)
|
||||
call.serialize(buffer, true)
|
||||
sendAs.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "phone.saveDefaultSendAs", parameters: [("call", String(describing: call)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.phone {
|
||||
static func sendConferenceCallBroadcast(call: Api.InputGroupCall, block: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
|
|
@ -10887,15 +10903,16 @@ public extension Api.functions.phone {
|
|||
}
|
||||
}
|
||||
public extension Api.functions.phone {
|
||||
static func sendGroupCallMessage(flags: Int32, call: Api.InputGroupCall, randomId: Int64, message: Api.TextWithEntities, allowPaidStars: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func sendGroupCallMessage(flags: Int32, call: Api.InputGroupCall, randomId: Int64, message: Api.TextWithEntities, allowPaidStars: Int64?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(445465039)
|
||||
buffer.appendInt32(-1311697904)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
call.serialize(buffer, true)
|
||||
serializeInt64(randomId, buffer: buffer, boxed: false)
|
||||
message.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(allowPaidStars!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "phone.sendGroupCallMessage", parameters: [("flags", String(describing: flags)), ("call", String(describing: call)), ("randomId", String(describing: randomId)), ("message", String(describing: message)), ("allowPaidStars", String(describing: allowPaidStars))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
if Int(flags) & Int(1 << 1) != 0 {sendAs!.serialize(buffer, true)}
|
||||
return (FunctionDescription(name: "phone.sendGroupCallMessage", parameters: [("flags", String(describing: flags)), ("call", String(describing: call)), ("randomId", String(describing: randomId)), ("message", String(describing: message)), ("allowPaidStars", String(describing: allowPaidStars)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
|
|
|
|||
|
|
@ -1222,14 +1222,14 @@ public extension Api {
|
|||
}
|
||||
public extension Api {
|
||||
enum GroupCall: TypeConstructorDescription {
|
||||
case groupCall(flags: Int32, id: Int64, accessHash: Int64, participantsCount: Int32, title: String?, streamDcId: Int32?, recordStartDate: Int32?, scheduleDate: Int32?, unmutedVideoCount: Int32?, unmutedVideoLimit: Int32, version: Int32, inviteLink: String?, sendPaidMessagesStars: Int64?)
|
||||
case groupCall(flags: Int32, id: Int64, accessHash: Int64, participantsCount: Int32, title: String?, streamDcId: Int32?, recordStartDate: Int32?, scheduleDate: Int32?, unmutedVideoCount: Int32?, unmutedVideoLimit: Int32, version: Int32, inviteLink: String?, sendPaidMessagesStars: Int64?, defaultSendAs: Api.Peer?)
|
||||
case groupCallDiscarded(id: Int64, accessHash: Int64, duration: Int32)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars):
|
||||
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars, let defaultSendAs):
|
||||
if boxed {
|
||||
buffer.appendInt32(-674602536)
|
||||
buffer.appendInt32(-273500649)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
|
|
@ -1244,6 +1244,7 @@ public extension Api {
|
|||
serializeInt32(version, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 16) != 0 {serializeString(inviteLink!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 20) != 0 {serializeInt64(sendPaidMessagesStars!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 21) != 0 {defaultSendAs!.serialize(buffer, true)}
|
||||
break
|
||||
case .groupCallDiscarded(let id, let accessHash, let duration):
|
||||
if boxed {
|
||||
|
|
@ -1258,8 +1259,8 @@ public extension Api {
|
|||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars):
|
||||
return ("groupCall", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("participantsCount", participantsCount as Any), ("title", title as Any), ("streamDcId", streamDcId as Any), ("recordStartDate", recordStartDate as Any), ("scheduleDate", scheduleDate as Any), ("unmutedVideoCount", unmutedVideoCount as Any), ("unmutedVideoLimit", unmutedVideoLimit as Any), ("version", version as Any), ("inviteLink", inviteLink as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any)])
|
||||
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars, let defaultSendAs):
|
||||
return ("groupCall", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("participantsCount", participantsCount as Any), ("title", title as Any), ("streamDcId", streamDcId as Any), ("recordStartDate", recordStartDate as Any), ("scheduleDate", scheduleDate as Any), ("unmutedVideoCount", unmutedVideoCount as Any), ("unmutedVideoLimit", unmutedVideoLimit as Any), ("version", version as Any), ("inviteLink", inviteLink as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any), ("defaultSendAs", defaultSendAs as Any)])
|
||||
case .groupCallDiscarded(let id, let accessHash, let duration):
|
||||
return ("groupCallDiscarded", [("id", id as Any), ("accessHash", accessHash as Any), ("duration", duration as Any)])
|
||||
}
|
||||
|
|
@ -1292,6 +1293,10 @@ public extension Api {
|
|||
if Int(_1!) & Int(1 << 16) != 0 {_12 = parseString(reader) }
|
||||
var _13: Int64?
|
||||
if Int(_1!) & Int(1 << 20) != 0 {_13 = reader.readInt64() }
|
||||
var _14: Api.Peer?
|
||||
if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() {
|
||||
_14 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
|
|
@ -1305,8 +1310,9 @@ public extension Api {
|
|||
let _c11 = _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 16) == 0) || _12 != nil
|
||||
let _c13 = (Int(_1!) & Int(1 << 20) == 0) || _13 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
|
||||
return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, participantsCount: _4!, title: _5, streamDcId: _6, recordStartDate: _7, scheduleDate: _8, unmutedVideoCount: _9, unmutedVideoLimit: _10!, version: _11!, inviteLink: _12, sendPaidMessagesStars: _13)
|
||||
let _c14 = (Int(_1!) & Int(1 << 21) == 0) || _14 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
|
||||
return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, participantsCount: _4!, title: _5, streamDcId: _6, recordStartDate: _7, scheduleDate: _8, unmutedVideoCount: _9, unmutedVideoLimit: _10!, version: _11!, inviteLink: _12, sendPaidMessagesStars: _13, defaultSendAs: _14)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
|||
isVideoEnabled: state.isVideoEnabled,
|
||||
unmutedVideoLimit: state.unmutedVideoLimit,
|
||||
isStream: state.isStream,
|
||||
isCreator: state.isCreator
|
||||
isCreator: state.isCreator,
|
||||
defaultSendAs: state.defaultSendAs
|
||||
),
|
||||
topParticipants: topParticipants,
|
||||
participantCount: state.totalCount,
|
||||
|
|
|
|||
|
|
@ -1689,7 +1689,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
isVideoEnabled: callInfo.isVideoEnabled,
|
||||
unmutedVideoLimit: callInfo.unmutedVideoLimit,
|
||||
isStream: callInfo.isStream,
|
||||
isCreator: callInfo.isCreator
|
||||
isCreator: callInfo.isCreator,
|
||||
defaultSendAs: callInfo.defaultSendAs
|
||||
)), audioSessionControl: self.audioSessionControl)
|
||||
} else {
|
||||
self.summaryInfoState.set(.single(SummaryInfoState(info: GroupCallInfo(
|
||||
|
|
@ -1707,7 +1708,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
isVideoEnabled: state.isVideoEnabled,
|
||||
unmutedVideoLimit: state.unmutedVideoLimit,
|
||||
isStream: callInfo.isStream,
|
||||
isCreator: callInfo.isCreator
|
||||
isCreator: callInfo.isCreator,
|
||||
defaultSendAs: callInfo.defaultSendAs
|
||||
))))
|
||||
|
||||
self.summaryParticipantsState.set(.single(SummaryParticipantsState(
|
||||
|
|
@ -1787,7 +1789,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
isVideoEnabled: false,
|
||||
unmutedVideoLimit: 0,
|
||||
isStream: true,
|
||||
isCreator: false
|
||||
isCreator: false,
|
||||
defaultSendAs: nil
|
||||
)
|
||||
} else {
|
||||
activeCallInfo = nil
|
||||
|
|
@ -2691,7 +2694,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
isVideoEnabled: state.isVideoEnabled,
|
||||
unmutedVideoLimit: state.unmutedVideoLimit,
|
||||
isStream: callInfo.isStream,
|
||||
isCreator: callInfo.isCreator
|
||||
isCreator: callInfo.isCreator,
|
||||
defaultSendAs: callInfo.defaultSendAs
|
||||
))))
|
||||
|
||||
self.summaryParticipantsState.set(.single(SummaryParticipantsState(
|
||||
|
|
|
|||
|
|
@ -4906,7 +4906,7 @@ func replayFinalState(
|
|||
}
|
||||
|
||||
switch call {
|
||||
case let .groupCall(flags, _, _, participantsCount, title, _, recordStartDate, scheduleDate, _, _, _, _, sendPaidMessagesStars):
|
||||
case let .groupCall(flags, _, _, participantsCount, title, _, recordStartDate, scheduleDate, _, _, _, _, sendPaidMessagesStars, _):
|
||||
let isMin = (flags & (1 << 19)) != 0
|
||||
let isMuted = (flags & (1 << 1)) != 0
|
||||
let canChange = (flags & (1 << 2)) != 0
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ public struct Namespaces {
|
|||
public static let cachedProfileGiftsCollections: Int8 = 48
|
||||
public static let cachedProfileSavedMusic: Int8 = 49
|
||||
public static let cachedChatThemes: Int8 = 50
|
||||
public static let cachedLiveStorySendAsPeers: Int8 = 51
|
||||
}
|
||||
|
||||
public struct UnorderedItemList {
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ public struct GroupCallInfo: Equatable {
|
|||
public var unmutedVideoLimit: Int
|
||||
public var isStream: Bool
|
||||
public var isCreator: Bool
|
||||
public var defaultSendAs: EnginePeer.Id?
|
||||
|
||||
public init(
|
||||
id: Int64,
|
||||
|
|
@ -115,7 +116,8 @@ public struct GroupCallInfo: Equatable {
|
|||
isVideoEnabled: Bool,
|
||||
unmutedVideoLimit: Int,
|
||||
isStream: Bool,
|
||||
isCreator: Bool
|
||||
isCreator: Bool,
|
||||
defaultSendAs: EnginePeer.Id?
|
||||
) {
|
||||
self.id = id
|
||||
self.accessHash = accessHash
|
||||
|
|
@ -132,6 +134,7 @@ public struct GroupCallInfo: Equatable {
|
|||
self.unmutedVideoLimit = unmutedVideoLimit
|
||||
self.isStream = isStream
|
||||
self.isCreator = isCreator
|
||||
self.defaultSendAs = defaultSendAs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +146,7 @@ public struct GroupCallSummary: Equatable {
|
|||
extension GroupCallInfo {
|
||||
init?(_ call: Api.GroupCall) {
|
||||
switch call {
|
||||
case let .groupCall(flags, id, accessHash, participantsCount, title, streamDcId, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars):
|
||||
case let .groupCall(flags, id, accessHash, participantsCount, title, streamDcId, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars, defaultSendAs):
|
||||
self.init(
|
||||
id: id,
|
||||
accessHash: accessHash,
|
||||
|
|
@ -159,7 +162,8 @@ extension GroupCallInfo {
|
|||
isVideoEnabled: (flags & (1 << 9)) != 0,
|
||||
unmutedVideoLimit: Int(unmutedVideoLimit),
|
||||
isStream: (flags & (1 << 12)) != 0,
|
||||
isCreator: (flags & (1 << 15)) != 0
|
||||
isCreator: (flags & (1 << 15)) != 0,
|
||||
defaultSendAs: defaultSendAs?.peerId
|
||||
)
|
||||
case .groupCallDiscarded:
|
||||
return nil
|
||||
|
|
@ -773,7 +777,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||
maybeParsedCall = GroupCallInfo(call)
|
||||
|
||||
switch call {
|
||||
case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars):
|
||||
case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars, defaultSendAs):
|
||||
let isMin = (flags & (1 << 19)) != 0
|
||||
let isMuted = (flags & (1 << 1)) != 0
|
||||
let canChange = (flags & (1 << 2)) != 0
|
||||
|
|
@ -787,6 +791,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||
state.scheduleTimestamp = scheduleDate
|
||||
state.isVideoEnabled = isMin ? state.isVideoEnabled : isVideoEnabled
|
||||
state.unmutedVideoLimit = Int(unmutedVideoLimit)
|
||||
state.defaultSendAs = defaultSendAs?.peerId
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
@ -1429,6 +1434,7 @@ public final class GroupCallParticipantsContext {
|
|||
public var unmutedVideoLimit: Int
|
||||
public var isStream: Bool
|
||||
public var sendPaidMessagesStars: Int64?
|
||||
public var defaultSendAs: PeerId?
|
||||
public var version: Int32
|
||||
|
||||
public mutating func mergeActivity(from other: State, myPeerId: PeerId?, previousMyPeerId: PeerId?, mergeActivityTimestamps: Bool) {
|
||||
|
|
@ -3836,7 +3842,7 @@ public final class GroupCallMessagesContext {
|
|||
|
||||
private var messageLifeTimer: SwiftSignalKit.Timer?
|
||||
|
||||
private var pendingSendStars: (fromId: PeerId, messageId: Int64, amount: Int64)?
|
||||
private var pendingSendStars: (fromPeer: Peer, messageId: Int64, amount: Int64)?
|
||||
private var pendingSendStarsTimer: SwiftSignalKit.Timer?
|
||||
|
||||
init(queue: Queue, account: Account, callId: Int64, reference: InternalGroupCallReference, e2eContext: ConferenceCallE2EContext?, messageLifetime: Int32, isLiveStream: Bool) {
|
||||
|
|
@ -4269,6 +4275,16 @@ public final class GroupCallMessagesContext {
|
|||
if paidStars != nil {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
var sendAs: Api.InputPeer?
|
||||
if fromId != self.account.peerId {
|
||||
guard let fromPeer else {
|
||||
return
|
||||
}
|
||||
sendAs = apiInputPeer(fromPeer)
|
||||
}
|
||||
if sendAs != nil {
|
||||
flags |= 1 << 1
|
||||
}
|
||||
self.sendMessageDisposables.add((self.account.network.request(Api.functions.phone.sendGroupCallMessage(
|
||||
flags: flags,
|
||||
call: self.reference.apiInputGroupCall,
|
||||
|
|
@ -4277,7 +4293,8 @@ public final class GroupCallMessagesContext {
|
|||
text: text,
|
||||
entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())
|
||||
),
|
||||
allowPaidStars: paidStars
|
||||
allowPaidStars: paidStars,
|
||||
sendAs: sendAs
|
||||
)) |> deliverOn(self.queue)).startStrict(next: { [weak self] updates in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -4322,6 +4339,13 @@ public final class GroupCallMessagesContext {
|
|||
|
||||
var flags: Int32 = 0
|
||||
flags |= 1 << 0
|
||||
var sendAs: Api.InputPeer?
|
||||
if pendingSendStars.fromPeer.id != self.account.peerId {
|
||||
sendAs = apiInputPeer(pendingSendStars.fromPeer)
|
||||
}
|
||||
if sendAs != nil {
|
||||
flags |= 1 << 1
|
||||
}
|
||||
self.sendMessageDisposables.add((self.account.network.request(Api.functions.phone.sendGroupCallMessage(
|
||||
flags: flags,
|
||||
call: self.reference.apiInputGroupCall,
|
||||
|
|
@ -4330,7 +4354,8 @@ public final class GroupCallMessagesContext {
|
|||
text: "",
|
||||
entities: []
|
||||
),
|
||||
allowPaidStars: pendingSendStars.amount
|
||||
allowPaidStars: pendingSendStars.amount,
|
||||
sendAs: sendAs
|
||||
)) |> deliverOn(self.queue)).startStrict(next: { [weak self] updates in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -4347,7 +4372,7 @@ public final class GroupCallMessagesContext {
|
|||
if let index = state.pinnedMessages.firstIndex(where: { $0.id == Message.Id(space: .local, id: pendingSendStars.messageId) }) {
|
||||
state.pinnedMessages[index] = state.pinnedMessages[index].withId(Message.Id(space: .remote, id: Int64(id)))
|
||||
}
|
||||
Impl.addStateStars(state: &state, peerId: pendingSendStars.fromId, isMy: true, amount: pendingSendStars.amount)
|
||||
Impl.addStateStars(state: &state, peerId: pendingSendStars.fromPeer.id, isMy: true, amount: pendingSendStars.amount)
|
||||
state.pendingMyStars = 0
|
||||
self.state = state
|
||||
break
|
||||
|
|
@ -4384,7 +4409,7 @@ public final class GroupCallMessagesContext {
|
|||
return transaction.getPeer(fromId)
|
||||
}
|
||||
|> deliverOn(self.queue)).startStandalone(next: { [weak self] fromPeer in
|
||||
guard let self else {
|
||||
guard let self, let fromPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -4395,7 +4420,7 @@ public final class GroupCallMessagesContext {
|
|||
totalAmount = pendingSendStarsValue.amount + amount
|
||||
|
||||
self.pendingSendStars = (
|
||||
fromId: fromId,
|
||||
fromPeer: fromPeer,
|
||||
messageId: pendingSendStarsValue.messageId,
|
||||
amount: totalAmount
|
||||
)
|
||||
|
|
@ -4406,7 +4431,7 @@ public final class GroupCallMessagesContext {
|
|||
arc4random_buf(&randomId, 8)
|
||||
|
||||
self.pendingSendStars = (
|
||||
fromId: fromId,
|
||||
fromPeer: fromPeer,
|
||||
messageId: randomId,
|
||||
amount: amount
|
||||
)
|
||||
|
|
@ -4437,7 +4462,7 @@ public final class GroupCallMessagesContext {
|
|||
state.messages.append(Message(
|
||||
id: Message.Id(space: .local, id: pendingSendStarsValue.messageId),
|
||||
stableId: stableId,
|
||||
author: fromPeer.flatMap(EnginePeer.init),
|
||||
author: EnginePeer(fromPeer),
|
||||
text: "",
|
||||
entities: [],
|
||||
date: currentTime,
|
||||
|
|
@ -4464,7 +4489,7 @@ public final class GroupCallMessagesContext {
|
|||
state.pinnedMessages.append(Message(
|
||||
id: Message.Id(space: .local, id: pendingSendStarsValue.messageId),
|
||||
stableId: stableId,
|
||||
author: fromPeer.flatMap(EnginePeer.init),
|
||||
author: EnginePeer(fromPeer),
|
||||
text: "",
|
||||
entities: [],
|
||||
date: currentTime,
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ func _internal_cachedPeerSendAsAvailablePeers(account: Account, peerId: PeerId)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
func _internal_peerSendAsAvailablePeers(accountPeerId: PeerId, network: Network, postbox: Postbox, peerId: PeerId) -> Signal<[SendAsPeer], NoError> {
|
||||
return postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peerId)
|
||||
|
|
@ -216,3 +215,113 @@ func _internal_updatePeerSendAsPeer(account: Account, peerId: PeerId, sendAs: Pe
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_cachedLiveStorySendAsAvailablePeers(account: Account, peerId: PeerId) -> Signal<[SendAsPeer], NoError> {
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: peerId.toInt64())
|
||||
return account.postbox.transaction { transaction -> ([SendAsPeer], Int32)? in
|
||||
let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedLiveStorySendAsPeers, key: key))?.get(CachedSendAsPeers.self)
|
||||
if let cached = cached {
|
||||
var peers: [SendAsPeer] = []
|
||||
for peerId in cached.peerIds {
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
var subscribers: Int32?
|
||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
|
||||
subscribers = cachedData.participantsSummary.memberCount
|
||||
}
|
||||
peers.append(SendAsPeer(peer: peer, subscribers: subscribers, isPremiumRequired: cached.premiumRequiredPeerIds.contains(peer.id)))
|
||||
}
|
||||
}
|
||||
return (peers, cached.timestamp)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> mapToSignal { cachedPeersAndTimestamp -> Signal<[SendAsPeer], NoError> in
|
||||
let initialSignal: Signal<[SendAsPeer], NoError>
|
||||
if let (cachedPeers, _) = cachedPeersAndTimestamp {
|
||||
initialSignal = .single(cachedPeers)
|
||||
} else {
|
||||
initialSignal = .complete()
|
||||
}
|
||||
return initialSignal
|
||||
|> then(_internal_liveStorySendAsAvailablePeers(account: account, peerId: peerId)
|
||||
|> mapToSignal { peers -> Signal<[SendAsPeer], NoError> in
|
||||
return account.postbox.transaction { transaction -> [SendAsPeer] in
|
||||
let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
var premiumRequiredPeerIds = Set<PeerId>()
|
||||
for peer in peers {
|
||||
if peer.isPremiumRequired {
|
||||
premiumRequiredPeerIds.insert(peer.peer.id)
|
||||
}
|
||||
}
|
||||
if let entry = CodableEntry(CachedSendAsPeers(peerIds: peers.map { $0.peer.id }, premiumRequiredPeerIds: premiumRequiredPeerIds, timestamp: currentTimestamp)) {
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedLiveStorySendAsPeers, key: key), entry: entry)
|
||||
}
|
||||
return peers
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_liveStorySendAsAvailablePeers(account: Account, peerId: PeerId) -> Signal<[SendAsPeer], NoError> {
|
||||
return account.postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peerId)
|
||||
}
|
||||
|> mapToSignal { peer -> Signal<[SendAsPeer], NoError> in
|
||||
guard let peer else {
|
||||
return .single([])
|
||||
}
|
||||
guard let inputPeer = apiInputPeer(peer) else {
|
||||
return .single([])
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.channels.getSendAs(flags: 1 << 1, peer: inputPeer))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.channels.SendAsPeers?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<[SendAsPeer], NoError> in
|
||||
guard let result = result else {
|
||||
return .single([])
|
||||
}
|
||||
switch result {
|
||||
case let .sendAsPeers(sendAsPeers, chats, _):
|
||||
return account.postbox.transaction { transaction -> [SendAsPeer] in
|
||||
var subscribers: [PeerId: Int32] = [:]
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: [])
|
||||
|
||||
var premiumRequiredPeerIds = Set<PeerId>()
|
||||
for sendAsPeer in sendAsPeers {
|
||||
if case let .sendAsPeer(flags, peer) = sendAsPeer, (flags & (1 << 0)) != 0 {
|
||||
premiumRequiredPeerIds.insert(peer.peerId)
|
||||
}
|
||||
}
|
||||
for chat in chats {
|
||||
if let groupOrChannel = parsedPeers.get(chat.peerId) {
|
||||
switch chat {
|
||||
case let .channel(_, _, _, _, _, _, _, _, _, _, _, _, participantsCount, _, _, _, _, _, _, _, _, _, _):
|
||||
if let participantsCount = participantsCount {
|
||||
subscribers[groupOrChannel.id] = participantsCount
|
||||
}
|
||||
case let .chat(_, _, _, _, participantsCount, _, _, _, _, _):
|
||||
subscribers[groupOrChannel.id] = participantsCount
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: parsedPeers)
|
||||
|
||||
var peers: [Peer] = []
|
||||
for chat in chats {
|
||||
if let peer = transaction.getPeer(chat.peerId) {
|
||||
peers.append(peer)
|
||||
}
|
||||
}
|
||||
return peers.map { SendAsPeer(peer: $0, subscribers: subscribers[$0.id], isPremiumRequired: premiumRequiredPeerIds.contains($0.id)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1175,6 +1175,10 @@ public extension TelegramEngine {
|
|||
return _internal_updatePeerSendAsPeer(account: self.account, peerId: peerId, sendAs: sendAs)
|
||||
}
|
||||
|
||||
public func liveStorySendAsAvailablePeers(peerId: PeerId) -> Signal<[SendAsPeer], NoError> {
|
||||
return _internal_cachedLiveStorySendAsAvailablePeers(account: self.account, peerId: peerId)
|
||||
}
|
||||
|
||||
public func updatePeerReactionSettings(peerId: PeerId, reactionSettings: PeerReactionSettings) -> Signal<Never, UpdatePeerAllowedReactionsError> {
|
||||
return _internal_updatePeerReactionSettings(account: account, peerId: peerId, reactionSettings: reactionSettings)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -495,6 +495,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/EdgeEffect",
|
||||
"//submodules/TelegramUI/Components/AttachmentFileController",
|
||||
"//submodules/TelegramUI/Components/Contacts/NewContactScreen",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatSendAsContextMenu",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
"//build-system:ios_sim_arm64": [],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatSendAsContextMenu",
|
||||
module_name = "ChatSendAsContextMenu",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display",
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/ContextUI",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
"//submodules/AvatarNode",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/UndoUI",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -13,24 +13,26 @@ import AvatarNode
|
|||
import AccountContext
|
||||
import UndoUI
|
||||
|
||||
final class ChatSendAsPeerListContextItem: ContextMenuCustomItem {
|
||||
public final class ChatSendAsPeerListContextItem: ContextMenuCustomItem {
|
||||
let context: AccountContext
|
||||
let chatPeerId: PeerId
|
||||
let peers: [SendAsPeer]
|
||||
let selectedPeerId: PeerId?
|
||||
let isPremium: Bool
|
||||
let action: (EnginePeer) -> Void
|
||||
let presentToast: (EnginePeer) -> Void
|
||||
|
||||
init(context: AccountContext, chatPeerId: PeerId, peers: [SendAsPeer], selectedPeerId: PeerId?, isPremium: Bool, presentToast: @escaping (EnginePeer) -> Void) {
|
||||
public init(context: AccountContext, chatPeerId: PeerId, peers: [SendAsPeer], selectedPeerId: PeerId?, isPremium: Bool, action: @escaping (EnginePeer) -> Void, presentToast: @escaping (EnginePeer) -> Void) {
|
||||
self.context = context
|
||||
self.chatPeerId = chatPeerId
|
||||
self.peers = peers
|
||||
self.selectedPeerId = selectedPeerId
|
||||
self.isPremium = isPremium
|
||||
self.action = action
|
||||
self.presentToast = presentToast
|
||||
}
|
||||
|
||||
func node(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) -> ContextMenuCustomNode {
|
||||
public func node(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) -> ContextMenuCustomNode {
|
||||
return ChatSendAsPeerListContextItemNode(presentationData: presentationData, item: self, getController: getController, actionSelected: actionSelected)
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +117,7 @@ private final class ChatSendAsPeerListContextItemNode: ASDisplayNode, ContextMen
|
|||
}
|
||||
|
||||
if peer.peer.id != item.selectedPeerId {
|
||||
let _ = item.context.engine.peers.updatePeerSendAsPeer(peerId: item.chatPeerId, sendAs: peer.peer.id).startStandalone()
|
||||
item.action(EnginePeer(peer.peer))
|
||||
}
|
||||
})
|
||||
let actionNode = ContextActionNode(presentationData: presentationData, action: action, getController: getController, actionSelected: actionSelected, requestLayout: {}, requestUpdateAction: { _, _ in
|
||||
|
|
@ -103,6 +103,38 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
public final class SendAsConfiguration: Equatable {
|
||||
public let currentPeer: EnginePeer
|
||||
public let subscriberCount: Int?
|
||||
public let isPremiumLocked: Bool
|
||||
public let isSelecting: Bool
|
||||
public let action: (UIView, ContextGesture?) -> Void
|
||||
|
||||
public init(currentPeer: EnginePeer, subscriberCount: Int?, isPremiumLocked: Bool, isSelecting: Bool, action: @escaping (UIView, ContextGesture?) -> Void) {
|
||||
self.currentPeer = currentPeer
|
||||
self.subscriberCount = subscriberCount
|
||||
self.isPremiumLocked = isPremiumLocked
|
||||
self.isSelecting = isSelecting
|
||||
self.action = action
|
||||
}
|
||||
|
||||
public static func ==(lhs: SendAsConfiguration, rhs: SendAsConfiguration) -> Bool {
|
||||
if lhs.currentPeer != rhs.currentPeer {
|
||||
return false
|
||||
}
|
||||
if lhs.subscriberCount != rhs.subscriberCount {
|
||||
return false
|
||||
}
|
||||
if lhs.isPremiumLocked != rhs.isPremiumLocked {
|
||||
return false
|
||||
}
|
||||
if lhs.isSelecting != rhs.isSelecting {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
let externalState: ExternalState
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
|
|
@ -111,6 +143,7 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
let inlineActions: [InlineAction]
|
||||
let leftAction: LeftAction?
|
||||
let rightAction: RightAction?
|
||||
let sendAsConfiguration: SendAsConfiguration?
|
||||
let placeholder: String
|
||||
let paidMessagePrice: StarsAmount?
|
||||
let sendColor: UIColor?
|
||||
|
|
@ -131,6 +164,7 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
inlineActions: [InlineAction],
|
||||
leftAction: LeftAction?,
|
||||
rightAction: RightAction?,
|
||||
sendAsConfiguration: SendAsConfiguration?,
|
||||
placeholder: String,
|
||||
paidMessagePrice: StarsAmount?,
|
||||
sendColor: UIColor?,
|
||||
|
|
@ -150,6 +184,7 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
self.inlineActions = inlineActions
|
||||
self.leftAction = leftAction
|
||||
self.rightAction = rightAction
|
||||
self.sendAsConfiguration = sendAsConfiguration
|
||||
self.placeholder = placeholder
|
||||
self.paidMessagePrice = paidMessagePrice
|
||||
self.sendColor = sendColor
|
||||
|
|
@ -187,6 +222,9 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
if lhs.rightAction != rhs.rightAction {
|
||||
return false
|
||||
}
|
||||
if lhs.sendAsConfiguration != rhs.sendAsConfiguration {
|
||||
return false
|
||||
}
|
||||
if lhs.placeholder != rhs.placeholder {
|
||||
return false
|
||||
}
|
||||
|
|
@ -582,7 +620,11 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
},
|
||||
openInviteRequests: {
|
||||
},
|
||||
openSendAsPeer: { _, _ in
|
||||
openSendAsPeer: { [weak self] sourceNode, gesture in
|
||||
guard let self, let component = self.component, let sendAsConfiguration = component.sendAsConfiguration else {
|
||||
return
|
||||
}
|
||||
sendAsConfiguration.action(sourceNode.view, gesture)
|
||||
},
|
||||
presentChatRequestAdminInfo: {
|
||||
},
|
||||
|
|
@ -722,6 +764,14 @@ public final class ChatTextInputPanelComponent: Component {
|
|||
}
|
||||
presentationInterfaceState = presentationInterfaceState.updatedSendPaidMessageStars(component.paidMessagePrice)
|
||||
|
||||
if let sendAsConfiguration = component.sendAsConfiguration {
|
||||
presentationInterfaceState = presentationInterfaceState.updatedSendAsPeers([SendAsPeer(
|
||||
peer: sendAsConfiguration.currentPeer._asPeer(),
|
||||
subscribers: sendAsConfiguration.subscriberCount.flatMap(Int32.init(clamping:)),
|
||||
isPremiumRequired: sendAsConfiguration.isPremiumLocked
|
||||
)]).updatedShowSendAsPeers(sendAsConfiguration.isSelecting).updatedCurrentSendAsPeerId(sendAsConfiguration.currentPeer.id)
|
||||
}
|
||||
|
||||
let panelNode: ChatTextInputPanelNode
|
||||
if let current = self.panelNode {
|
||||
panelNode = current
|
||||
|
|
|
|||
|
|
@ -192,6 +192,38 @@ public final class MessageInputPanelComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
public final class SendAsConfiguration: Equatable {
|
||||
public let currentPeer: EnginePeer
|
||||
public let subscriberCount: Int?
|
||||
public let isPremiumLocked: Bool
|
||||
public let isSelecting: Bool
|
||||
public let action: (UIView, ContextGesture?) -> Void
|
||||
|
||||
public init(currentPeer: EnginePeer, subscriberCount: Int?, isPremiumLocked: Bool, isSelecting: Bool, action: @escaping (UIView, ContextGesture?) -> Void) {
|
||||
self.currentPeer = currentPeer
|
||||
self.subscriberCount = subscriberCount
|
||||
self.isPremiumLocked = isPremiumLocked
|
||||
self.isSelecting = isSelecting
|
||||
self.action = action
|
||||
}
|
||||
|
||||
public static func ==(lhs: SendAsConfiguration, rhs: SendAsConfiguration) -> Bool {
|
||||
if lhs.currentPeer != rhs.currentPeer {
|
||||
return false
|
||||
}
|
||||
if lhs.subscriberCount != rhs.subscriberCount {
|
||||
return false
|
||||
}
|
||||
if lhs.isPremiumLocked != rhs.isPremiumLocked {
|
||||
return false
|
||||
}
|
||||
if lhs.isSelecting != rhs.isSelecting {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public let externalState: ExternalState
|
||||
public let context: AccountContext
|
||||
public let theme: PresentationTheme
|
||||
|
|
@ -255,6 +287,7 @@ public final class MessageInputPanelComponent: Component {
|
|||
public let toggleLiveChatExpanded: (() -> Void)?
|
||||
public let sendStarsAction: ((UIView, Bool) -> Void)?
|
||||
public let starStars: StarStats?
|
||||
public let sendAsConfiguration: SendAsConfiguration?
|
||||
|
||||
public init(
|
||||
externalState: ExternalState,
|
||||
|
|
@ -319,7 +352,8 @@ public final class MessageInputPanelComponent: Component {
|
|||
liveChatState: LiveChatState? = nil,
|
||||
toggleLiveChatExpanded: (() -> Void)? = nil,
|
||||
sendStarsAction: ((UIView, Bool) -> Void)? = nil,
|
||||
starStars: StarStats? = nil
|
||||
starStars: StarStats? = nil,
|
||||
sendAsConfiguration: SendAsConfiguration? = nil
|
||||
) {
|
||||
self.externalState = externalState
|
||||
self.context = context
|
||||
|
|
@ -384,6 +418,7 @@ public final class MessageInputPanelComponent: Component {
|
|||
self.toggleLiveChatExpanded = toggleLiveChatExpanded
|
||||
self.sendStarsAction = sendStarsAction
|
||||
self.starStars = starStars
|
||||
self.sendAsConfiguration = sendAsConfiguration
|
||||
}
|
||||
|
||||
public static func ==(lhs: MessageInputPanelComponent, rhs: MessageInputPanelComponent) -> Bool {
|
||||
|
|
@ -519,6 +554,9 @@ public final class MessageInputPanelComponent: Component {
|
|||
if lhs.starStars != rhs.starStars {
|
||||
return false
|
||||
}
|
||||
if lhs.sendAsConfiguration != rhs.sendAsConfiguration {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -968,6 +1006,16 @@ public final class MessageInputPanelComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
let sendAsConfiguration = component.sendAsConfiguration.flatMap { value in
|
||||
return ChatTextInputPanelComponent.SendAsConfiguration(
|
||||
currentPeer: value.currentPeer,
|
||||
subscriberCount: value.subscriberCount,
|
||||
isPremiumLocked: value.isPremiumLocked,
|
||||
isSelecting: value.isSelecting,
|
||||
action: value.action
|
||||
)
|
||||
}
|
||||
|
||||
let inputPanelSize = inputPanel.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ChatTextInputPanelComponent(
|
||||
|
|
@ -994,6 +1042,7 @@ public final class MessageInputPanelComponent: Component {
|
|||
}
|
||||
component.sendStarsAction?(sourceView, true)
|
||||
}),
|
||||
sendAsConfiguration: sendAsConfiguration,
|
||||
placeholder: placeholder,
|
||||
paidMessagePrice: component.sendPaidMessageStars,
|
||||
sendColor: component.sendPaidMessageStars.flatMap { value in
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/StarsParticleEffect",
|
||||
"//submodules/TelegramUI/Components/AnimatedTextComponent",
|
||||
"//submodules/TelegramUI/Components/AdminUserActionsSheet",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatSendAsContextMenu",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ private final class PinnedBarComponent: Component {
|
|||
self.isUpdating = false
|
||||
}
|
||||
|
||||
let previousComponent = self.component
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
|
|
@ -325,8 +326,21 @@ private final class PinnedBarComponent: Component {
|
|||
|
||||
let listInsets = UIEdgeInsets(top: 0.0, left: insets.left, bottom: 0.0, right: insets.right)
|
||||
let listFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))
|
||||
|
||||
var listTransition = transition
|
||||
var animateIn = false
|
||||
if let previousComponent {
|
||||
if previousComponent.messages.isEmpty {
|
||||
listTransition = listTransition.withAnimation(.none)
|
||||
animateIn = true
|
||||
}
|
||||
} else {
|
||||
listTransition = listTransition.withAnimation(.none)
|
||||
animateIn = true
|
||||
}
|
||||
|
||||
let _ = self.list.update(
|
||||
transition: transition,
|
||||
transition: listTransition,
|
||||
component: AnyComponent(AsyncListComponent(
|
||||
externalState: self.listState,
|
||||
items: listItems,
|
||||
|
|
@ -343,6 +357,10 @@ private final class PinnedBarComponent: Component {
|
|||
}
|
||||
transition.setPosition(view: listView, position: CGRect(origin: CGPoint(), size: listFrame.size).center)
|
||||
transition.setBounds(view: listView, bounds: CGRect(origin: CGPoint(), size: listFrame.size))
|
||||
|
||||
if animateIn {
|
||||
transition.animateAlpha(view: listView, from: 0.0, to: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.listContainer, frame: listFrame)
|
||||
|
|
|
|||
|
|
@ -2628,7 +2628,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
let isFirstTime = self.component == nil
|
||||
|
||||
if self.component == nil {
|
||||
self.sendMessageContext.setup(context: component.context, view: self, inputPanelExternalState: self.inputPanelExternalState, keyboardInputData: component.keyboardInputData)
|
||||
self.sendMessageContext.setup(component: component, view: self, inputPanelExternalState: self.inputPanelExternalState, keyboardInputData: component.keyboardInputData)
|
||||
|
||||
/*#if DEBUG
|
||||
class Target: NSObject {
|
||||
|
|
@ -2963,6 +2963,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
|
||||
var liveChatState: MessageInputPanelComponent.LiveChatState?
|
||||
var starStats: MessageInputPanelComponent.StarStats?
|
||||
var sendAsConfiguration: MessageInputPanelComponent.SendAsConfiguration?
|
||||
var sendPaidMessageStars = isLiveStream ? self.sendMessageContext.currentLiveStreamMessageStars : component.slice.additionalPeerData.sendPaidMessageStars
|
||||
if let visibleItemView = self.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View {
|
||||
if let liveChatStateValue = visibleItemView.liveChatState {
|
||||
|
|
@ -2985,6 +2986,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
sendPaidMessageStars = StarsAmount(value: minMessagePrice, nanos: 0)
|
||||
}
|
||||
}
|
||||
|
||||
sendAsConfiguration = self.sendMessageContext.currentSendAsConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3244,7 +3247,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
self.sendMessageContext.performSendStars(view: self, buttonView: sourceView, count: 1, isFromExpandedView: false)
|
||||
}
|
||||
} : nil,
|
||||
starStars: starStats
|
||||
starStars: starStats,
|
||||
sendAsConfiguration: sendAsConfiguration
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: inputPanelAvailableWidth, height: 200.0)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import TextFieldComponent
|
|||
import StickerPackPreviewUI
|
||||
import OpenInExternalAppUI
|
||||
import SafariServices
|
||||
//import MediaPasteboardUI
|
||||
import WebPBinding
|
||||
import ContextUI
|
||||
import ChatScheduleTimeController
|
||||
|
|
@ -53,6 +52,7 @@ import AudioWaveform
|
|||
import ChatMessagePaymentAlertController
|
||||
import ChatSendStarsScreen
|
||||
import AnimatedTextComponent
|
||||
import ChatSendAsContextMenu
|
||||
|
||||
private var ObjCKey_DeinitWatcher: Int?
|
||||
|
||||
|
|
@ -105,6 +105,11 @@ final class StoryItemSetContainerSendMessage {
|
|||
var currentLiveStreamMessageStars: StarsAmount?
|
||||
weak var currentSendStarsUndoController: UndoOverlayController?
|
||||
|
||||
var sendAsData: (isPremium: Bool, availablePeers: [(peer: EnginePeer, subscriberCount: Int?, isPremiumRequired: Bool)])?
|
||||
var currentSendAsConfiguration: MessageInputPanelComponent.SendAsConfiguration?
|
||||
var sendAsContextPeerId: EnginePeer.Id?
|
||||
var sendAsDisposable: Disposable?
|
||||
|
||||
private(set) var isMediaRecordingLocked: Bool = false
|
||||
var wasRecordingDismissed: Bool = false
|
||||
|
||||
|
|
@ -118,10 +123,11 @@ final class StoryItemSetContainerSendMessage {
|
|||
self.resolvePeerByNameDisposable.dispose()
|
||||
self.inputMediaNodeDataDisposable?.dispose()
|
||||
self.currentTooltipUpdateTimer?.invalidate()
|
||||
self.sendAsDisposable?.dispose()
|
||||
}
|
||||
|
||||
func setup(context: AccountContext, view: StoryItemSetContainerComponent.View, inputPanelExternalState: MessageInputPanelComponent.ExternalState, keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>) {
|
||||
self.context = context
|
||||
func setup(component: StoryItemSetContainerComponent, view: StoryItemSetContainerComponent.View, inputPanelExternalState: MessageInputPanelComponent.ExternalState, keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>) {
|
||||
self.context = component.context
|
||||
self.inputPanelExternalState = inputPanelExternalState
|
||||
self.view = view
|
||||
|
||||
|
|
@ -208,6 +214,73 @@ final class StoryItemSetContainerSendMessage {
|
|||
}
|
||||
)
|
||||
self.inputMediaInteraction?.forceTheme = defaultDarkColorPresentationTheme
|
||||
|
||||
if let peerId = component.slice.item.peerId {
|
||||
self.sendAsDisposable = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
component.context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: component.context.account.peerId)
|
||||
),
|
||||
component.context.engine.peers.liveStorySendAsAvailablePeers(peerId: peerId)
|
||||
).startStrict(next: { [weak self, weak view] accountPeer, peers in
|
||||
guard let self, let view, let accountPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
let isPremium = accountPeer.isPremium
|
||||
|
||||
var availablePeers: [(peer: EnginePeer, subscriberCount: Int?, isPremiumRequired: Bool)] = []
|
||||
availablePeers.append((
|
||||
peer: accountPeer,
|
||||
subscriberCount: nil,
|
||||
isPremiumRequired: false
|
||||
))
|
||||
for peer in peers {
|
||||
if peer.peer.id == accountPeer.id {
|
||||
continue
|
||||
}
|
||||
availablePeers.append((
|
||||
peer: EnginePeer(peer.peer),
|
||||
subscriberCount: peer.subscribers.flatMap(Int.init),
|
||||
isPremiumRequired: peer.isPremiumRequired
|
||||
))
|
||||
}
|
||||
|
||||
self.sendAsData = (
|
||||
isPremium: isPremium,
|
||||
availablePeers: availablePeers
|
||||
)
|
||||
|
||||
//TODO:localize
|
||||
if "".isEmpty {
|
||||
let sendAsConfiguration = MessageInputPanelComponent.SendAsConfiguration(
|
||||
currentPeer: accountPeer,
|
||||
subscriberCount: nil,
|
||||
isPremiumLocked: false,
|
||||
isSelecting: false,
|
||||
action: { [weak self, weak view] sourceView, gesture in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.openSendAsSelection(view: view, sourceView: sourceView, gesture: gesture)
|
||||
}
|
||||
)
|
||||
if self.currentSendAsConfiguration != sendAsConfiguration {
|
||||
self.currentSendAsConfiguration = sendAsConfiguration
|
||||
if !view.isUpdatingComponent {
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.currentSendAsConfiguration != nil {
|
||||
self.currentSendAsConfiguration = nil
|
||||
if !view.isUpdatingComponent {
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func toggleInputMode() {
|
||||
|
|
@ -281,7 +354,7 @@ final class StoryItemSetContainerSendMessage {
|
|||
self.inputMediaNode = inputMediaNode
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkPresentationTheme)
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
let presentationInterfaceState = ChatPresentationInterfaceState(
|
||||
chatWallpaper: .builtin(WallpaperSettings()),
|
||||
theme: presentationData.theme,
|
||||
|
|
@ -3954,11 +4027,11 @@ final class StoryItemSetContainerSendMessage {
|
|||
peerId: peerId,
|
||||
reactSubject: .liveStream(peerId: peerId, storyId: focusedItem.storyItem.id, minAmount: Int(minAmount)),
|
||||
topPeers: topPeers,
|
||||
completion: { [weak view] amount, privacy, isBecomingTop, transitionOut in
|
||||
guard let view, let component = view.component else {
|
||||
completion: { [weak self, weak view] amount, _, _, _ in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
let _ = component.context.engine.messages.sendStoryStars(peerId: component.slice.effectivePeer.id, id: component.slice.item.storyItem.id, count: Int(amount)).startStandalone()
|
||||
self.performSendStars(view: view, buttonView: nil, count: Int(amount), isFromExpandedView: true)
|
||||
}).get()
|
||||
if let initialData {
|
||||
controller.push(ChatSendStarsScreen(
|
||||
|
|
@ -3970,12 +4043,17 @@ final class StoryItemSetContainerSendMessage {
|
|||
}
|
||||
}
|
||||
|
||||
func performSendStars(view: StoryItemSetContainerComponent.View, buttonView: UIView, count: Int, isFromExpandedView: Bool) {
|
||||
func performSendStars(view: StoryItemSetContainerComponent.View, buttonView: UIView?, count: Int, isFromExpandedView: Bool) {
|
||||
guard let component = view.component else {
|
||||
return
|
||||
}
|
||||
|
||||
if isFromExpandedView {
|
||||
if let currentSendStarsUndoController = self.currentSendStarsUndoController {
|
||||
self.currentSendStarsUndoController = nil
|
||||
currentSendStarsUndoController.dismiss()
|
||||
}
|
||||
|
||||
self.commitSendStars(view: view, count: count, delay: false)
|
||||
} else {
|
||||
Task { @MainActor [weak view] in
|
||||
|
|
@ -4009,7 +4087,7 @@ final class StoryItemSetContainerSendMessage {
|
|||
}
|
||||
}
|
||||
|
||||
if let reactionItem {
|
||||
if let reactionItem, let buttonView {
|
||||
let targetFrame = buttonView.convert(buttonView.bounds, to: view)
|
||||
|
||||
let targetView = UIView(frame: targetFrame)
|
||||
|
|
@ -4145,6 +4223,94 @@ final class StoryItemSetContainerSendMessage {
|
|||
|
||||
call.sendStars(amount: Int64(count), delay: delay)
|
||||
}
|
||||
|
||||
private func openSendAsSelection(view: StoryItemSetContainerComponent.View, sourceView: UIView, gesture: ContextGesture?) {
|
||||
guard let component = view.component, let sendAsData = self.sendAsData, let currentSendAsConfiguration = self.currentSendAsConfiguration, let controller = component.controller() else {
|
||||
return
|
||||
}
|
||||
|
||||
let focusedItem = component.slice.item
|
||||
guard let peerId = focusedItem.peerId else {
|
||||
return
|
||||
}
|
||||
let isPremium = sendAsData.isPremium
|
||||
|
||||
let mappedPeers = sendAsData.availablePeers.map { peer in
|
||||
return SendAsPeer(
|
||||
peer: peer.peer._asPeer(),
|
||||
subscribers: peer.subscriberCount.flatMap(Int32.init(clamping:)),
|
||||
isPremiumRequired: peer.isPremiumRequired
|
||||
)
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.custom(ChatSendAsPeerTitleContextItem(text: component.strings.Conversation_SendMesageAs.uppercased()), false))
|
||||
items.append(.custom(ChatSendAsPeerListContextItem(
|
||||
context: component.context,
|
||||
chatPeerId: peerId,
|
||||
peers: mappedPeers,
|
||||
selectedPeerId: currentSendAsConfiguration.currentPeer.id,
|
||||
isPremium: isPremium,
|
||||
action: { [weak self] peer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
},
|
||||
presentToast: { [weak view] peer in
|
||||
guard let view, let component = view.component, let controller = component.controller() else {
|
||||
return
|
||||
}
|
||||
HapticFeedback().impact()
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .invitedToVoiceChat(context: component.context, peer: peer, title: nil, text: presentationData.strings.Conversation_SendMesageAsPremiumInfo, action: presentationData.strings.EmojiInput_PremiumEmojiToast_Action, duration: 3), elevatedLayout: false, action: { [weak view] action in
|
||||
guard let view, let component = view.component, let controller = component.controller() else {
|
||||
return true
|
||||
}
|
||||
if case .undo = action {
|
||||
view.endEditing(true)
|
||||
|
||||
let introScreen = PremiumIntroScreen(context: component.context, source: .settings)
|
||||
controller.push(introScreen)
|
||||
}
|
||||
return true
|
||||
}), in: .current)
|
||||
}),
|
||||
false
|
||||
))
|
||||
|
||||
final class ReferenceSource: ContextReferenceContentSource {
|
||||
let controller: ViewController
|
||||
let sourceView: UIView
|
||||
let insets: UIEdgeInsets
|
||||
let contentInsets: UIEdgeInsets
|
||||
|
||||
init(controller: ViewController, sourceView: UIView, insets: UIEdgeInsets, contentInsets: UIEdgeInsets = UIEdgeInsets()) {
|
||||
self.controller = controller
|
||||
self.sourceView = sourceView
|
||||
self.insets = insets
|
||||
self.contentInsets = contentInsets
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds.inset(by: self.insets), insets: self.contentInsets, actionsPosition: .top)
|
||||
}
|
||||
}
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(ReferenceSource(controller: controller, sourceView: sourceView, insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), contentInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture, workaroundUseLegacyImplementation: false)
|
||||
contextController.dismissed = { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
controller.presentInGlobalOverlay(contextController)
|
||||
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
|
||||
public class StoryProgressPauseContext {
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ import ChatMediaInputStickerGridItem
|
|||
import AdsInfoScreen
|
||||
import PostSuggestionsSettingsScreen
|
||||
import ChatSendStarsScreen
|
||||
import ChatSendAsContextMenu
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func reloadChatLocation(chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, historyNode: ChatHistoryListNodeImpl, apply: @escaping ((ContainedViewLayoutTransition?) -> Void) -> Void) {
|
||||
|
|
@ -3896,7 +3897,12 @@ extension ChatControllerImpl {
|
|||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.custom(ChatSendAsPeerTitleContextItem(text: strongSelf.presentationInterfaceState.strings.Conversation_SendMesageAs.uppercased()), false))
|
||||
items.append(.custom(ChatSendAsPeerListContextItem(context: strongSelf.context, chatPeerId: peerId, peers: peers, selectedPeerId: myPeerId, isPremium: isPremium, presentToast: { [weak self] peer in
|
||||
items.append(.custom(ChatSendAsPeerListContextItem(context: strongSelf.context, chatPeerId: peerId, peers: peers, selectedPeerId: myPeerId, isPremium: isPremium, action: { [weak self] peer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self.context.engine.peers.updatePeerSendAsPeer(peerId: peerId, sendAs: peer.id).startStandalone()
|
||||
}, presentToast: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
HapticFeedback().impact()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue