UI improvements

This commit is contained in:
Ali 2023-01-27 11:21:05 +01:00
parent 2f46baf863
commit 05b4d6f3ca
12 changed files with 524 additions and 203 deletions

View File

@ -46,15 +46,18 @@ public final class PagerComponentChildEnvironment: Equatable {
public let containerInsets: UIEdgeInsets
public let onChildScrollingUpdate: (ContentScrollingUpdate) -> Void
public let onWantsExclusiveModeUpdated: (Bool) -> Void
public let scrollToTop: ActionSlot<Void>
init(
containerInsets: UIEdgeInsets,
onChildScrollingUpdate: @escaping (ContentScrollingUpdate) -> Void,
onWantsExclusiveModeUpdated: @escaping (Bool) -> Void
onWantsExclusiveModeUpdated: @escaping (Bool) -> Void,
scrollToTop: ActionSlot<Void>
) {
self.containerInsets = containerInsets
self.onChildScrollingUpdate = onChildScrollingUpdate
self.onWantsExclusiveModeUpdated = onWantsExclusiveModeUpdated
self.scrollToTop = scrollToTop
}
public static func ==(lhs: PagerComponentChildEnvironment, rhs: PagerComponentChildEnvironment) -> Bool {
@ -296,6 +299,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
var scrollingPanelOffsetToBottomEdge: CGFloat = .greatestFiniteMagnitude
var scrollingPanelOffsetFraction: CGFloat = 0.0
var wantsExclusiveMode: Bool = false
let scrollToTop = ActionSlot<Void>()
init(view: ComponentHostView<(ChildEnvironmentType, PagerComponentChildEnvironment)>) {
self.view = view
@ -368,7 +372,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
case .began:
self.paneTransitionGestureState = PaneTransitionGestureState()
case .changed:
if let centralId = self.centralId, let component = self.component, let centralIndex = component.contents.firstIndex(where: { $0.id == centralId }), var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
if let centralId = self.centralId, let component = self.component, let centralIndex = component.contents.firstIndex(where: { $0.id == centralId }), let centralView = self.contentViews[centralId], !centralView.wantsExclusiveMode, var paneTransitionGestureState = self.paneTransitionGestureState, self.bounds.width > 0.0 {
var fraction = recognizer.translation(in: self).x / self.bounds.width
if centralIndex <= 0 {
fraction = min(0.0, fraction)
@ -463,6 +467,8 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
if self.isTopPanelExpanded {
updateTopPanelExpanded = true
}
} else {
self.contentViews[id]?.scrollToTop.invoke(Void())
}
if updateTopPanelExpanded {
@ -843,7 +849,8 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
return
}
strongSelf.onChildWantsExclusiveModeUpdated(id: id, wantsExclusiveMode: wantsExclusiveMode)
}
},
scrollToTop: contentView.scrollToTop
)
let _ = contentView.view.update(

View File

@ -228,7 +228,7 @@ static int32_t fixedTimeDifferenceValue = 0;
_isTestingEnvironment = isTestingEnvironment;
_useTempAuthKeys = useTempAuthKeys;
#if DEBUG
_tempKeyExpiration = 1 * 60 * 60;
_tempKeyExpiration = 10 * 60;
#else
_tempKeyExpiration = 24 * 60 * 60;
#endif

View File

@ -552,206 +552,435 @@ public final class ShareController: ViewController {
})
}
self.controllerNode.share = { [weak self] text, peerIds, topicIds, showNames, silently in
guard let strongSelf = self else {
guard let self else {
return .complete()
}
var shareSignals: [Signal<[MessageId?], NoError>] = []
var subject = strongSelf.subject
if let segmentedValues = strongSelf.segmentedValues {
let selectedValue = segmentedValues[strongSelf.controllerNode.selectedSegmentedIndex]
subject = selectedValue.subject
}
func transformMessages(_ messages: [EnqueueMessage], showNames: Bool, silently: Bool) -> [EnqueueMessage] {
return messages.map { message in
return message.withUpdatedAttributes({ attributes in
var attributes = attributes
if !showNames {
attributes.append(ForwardOptionsMessageAttribute(hideNames: true, hideCaptions: false))
}
if silently {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
return attributes
})
}
}
switch subject {
case let .url(url):
for peerId in peerIds {
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: url + "\n\n" + text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
} else {
messages.append(.message(text: url, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .text(string):
for peerId in peerIds {
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages.append(.message(text: string, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .quote(string, url):
for peerId in peerIds {
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
let entities = generateChatInputTextEntities(attributedText)
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .image(representations):
for peerId in peerIds {
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: Int64.random(in: Int64.min ... Int64.max)), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])), replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .media(mediaReference):
var sendTextAsCaption = false
if mediaReference.media is TelegramMediaImage || mediaReference.media is TelegramMediaFile {
sendTextAsCaption = true
return self.currentContext.engine.data.get(EngineDataMap(
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
))
|> castError(ShareControllerError.self)
|> mapToSignal { [weak self] peers -> Signal<ShareState, ShareControllerError> in
guard let strongSelf = self else {
return .complete()
}
for peerId in peerIds {
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
var shareSignals: [Signal<[MessageId?], NoError>] = []
var subject = strongSelf.subject
if let segmentedValues = strongSelf.segmentedValues {
let selectedValue = segmentedValues[strongSelf.controllerNode.selectedSegmentedIndex]
subject = selectedValue.subject
}
func transformMessages(_ messages: [EnqueueMessage], showNames: Bool, silently: Bool) -> [EnqueueMessage] {
return messages.map { message in
return message.withUpdatedAttributes({ attributes in
var attributes = attributes
if !showNames {
attributes.append(ForwardOptionsMessageAttribute(hideNames: true, hideCaptions: false))
}
if silently {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
return attributes
})
}
}
switch subject {
case let .url(url):
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var banSendText = false
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
banSendText = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
banSendText = true
}
if banSendText {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: url + "\n\n" + text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
} else {
messages.append(.message(text: url, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .text(string):
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var banSendText = false
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
banSendText = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
banSendText = true
}
if banSendText {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages.append(.message(text: string, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .quote(string, url):
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var banSendText = false
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
banSendText = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
banSendText = true
}
if banSendText {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
let entities = generateChatInputTextEntities(attributedText)
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .image(representations):
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var banSendPhotos = false
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendPhotos) != nil {
banSendPhotos = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendPhotos) {
banSendPhotos = true
}
if banSendPhotos {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: Int64.random(in: Int64.min ... Int64.max)), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])), replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .media(mediaReference):
var sendTextAsCaption = false
if mediaReference.media is TelegramMediaImage || mediaReference.media is TelegramMediaFile {
sendTextAsCaption = true
}
var messages: [EnqueueMessage] = []
if !text.isEmpty && !sendTextAsCaption {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var banSendType = false
if mediaReference.media is TelegramMediaImage {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendPhotos) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendPhotos) {
banSendType = true
}
} else if let file = mediaReference.media as? TelegramMediaFile {
if file.isSticker || file.isAnimated {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendStickers) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendStickers) {
banSendType = true
}
} else if file.isInstantVideo {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendInstantVideos) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendInstantVideos) {
banSendType = true
}
} else if file.isVoice {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVoice) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVoice) {
banSendType = true
}
} else if file.isMusic {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendMusic) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendMusic) {
banSendType = true
}
} else if file.isVideo {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVideos) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVideos) {
banSendType = true
}
} else {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendFiles) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendFiles) {
banSendType = true
}
}
}
if banSendType {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty && !sendTextAsCaption {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages.append(.message(text: sendTextAsCaption ? text : "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
messages.append(.message(text: sendTextAsCaption ? text : "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .mapMedia(media):
for peerId in peerIds {
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
case let .mapMedia(media):
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var banSendText = false
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
banSendText = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
banSendText = true
}
if banSendText {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
var replyToMessageId: MessageId?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
case let .messages(messages):
for peerId in peerIds {
guard let maybePeer = peers[peerId], let peer = maybePeer else {
continue
}
var replyToMessageId: MessageId?
var threadId: Int64?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
threadId = topicId
}
var messagesToEnqueue: [EnqueueMessage] = []
if !text.isEmpty {
var banSendText = false
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
banSendText = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
banSendText = true
}
if banSendText {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
messagesToEnqueue.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
for message in messages {
for media in message.media {
var banSendType = false
if media is TelegramMediaImage {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendPhotos) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendPhotos) {
banSendType = true
}
} else if let file = media as? TelegramMediaFile {
if file.isSticker || file.isAnimated {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendStickers) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendStickers) {
banSendType = true
}
} else if file.isInstantVideo {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendInstantVideos) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendInstantVideos) {
banSendType = true
}
} else if file.isVoice {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVoice) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVoice) {
banSendType = true
}
} else if file.isMusic {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendMusic) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendMusic) {
banSendType = true
}
} else if file.isVideo {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVideos) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVideos) {
banSendType = true
}
} else {
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendFiles) != nil {
banSendType = true
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendFiles) {
banSendType = true
}
}
}
if banSendType {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
return .complete()
}
}
messagesToEnqueue.append(.forward(source: message.id, threadId: threadId, grouping: .auto, attributes: [], correlationId: nil))
}
messagesToEnqueue = transformMessages(messagesToEnqueue, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
}
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
messages = transformMessages(messages, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .messages(messages):
for peerId in peerIds {
var replyToMessageId: MessageId?
var threadId: Int64?
if let topicId = topicIds[peerId] {
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
threadId = topicId
}
var messagesToEnqueue: [EnqueueMessage] = []
if !text.isEmpty {
messagesToEnqueue.append(.message(text: text, attributes: [], inlineStickers: [:], mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
}
for message in messages {
messagesToEnqueue.append(.forward(source: message.id, threadId: threadId, grouping: .auto, attributes: [], correlationId: nil))
}
messagesToEnqueue = transformMessages(messagesToEnqueue, showNames: showNames, silently: silently)
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
}
case let .fromExternal(f):
return f(peerIds, topicIds, text, strongSelf.currentAccount, silently)
|> map { state -> ShareState in
switch state {
case let .fromExternal(f):
return f(peerIds, topicIds, text, strongSelf.currentAccount, silently)
|> map { state -> ShareState in
switch state {
case let .preparing(long):
return .preparing(long)
case let .progress(value):
return .progress(value)
case .done:
return .done
}
}
}
}
let account = strongSelf.currentAccount
let queue = Queue.mainQueue()
var displayedError = false
return combineLatest(queue: queue, shareSignals)
|> castError(ShareControllerError.self)
|> mapToSignal { messageIdSets -> Signal<ShareState, ShareControllerError> in
var statuses: [Signal<(MessageId, PendingMessageStatus?, PendingMessageFailureReason?), ShareControllerError>] = []
for messageIds in messageIdSets {
for case let id? in messageIds {
statuses.append(account.pendingMessageManager.pendingMessageStatus(id)
|> castError(ShareControllerError.self)
|> map { status, error -> (MessageId, PendingMessageStatus?, PendingMessageFailureReason?) in
return (id, status, error)
})
let account = strongSelf.currentAccount
let queue = Queue.mainQueue()
var displayedError = false
return combineLatest(queue: queue, shareSignals)
|> castError(ShareControllerError.self)
|> mapToSignal { messageIdSets -> Signal<ShareState, ShareControllerError> in
var statuses: [Signal<(MessageId, PendingMessageStatus?, PendingMessageFailureReason?), ShareControllerError>] = []
for messageIds in messageIdSets {
for case let id? in messageIds {
statuses.append(account.pendingMessageManager.pendingMessageStatus(id)
|> castError(ShareControllerError.self)
|> map { status, error -> (MessageId, PendingMessageStatus?, PendingMessageFailureReason?) in
return (id, status, error)
})
}
}
}
return combineLatest(queue: queue, statuses)
|> mapToSignal { statuses -> Signal<ShareState, ShareControllerError> in
var hasStatuses = false
for (id, status, error) in statuses {
if let error = error {
Queue.mainQueue().async {
let _ = TelegramEngine(account: account).messages.deleteMessagesInteractively(messageIds: [id], type: .forEveryone).start()
let _ = (TelegramEngine(account: account).data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: id.peerId))
|> deliverOnMainQueue).start(next: { peer in
guard let strongSelf = self, let peer = peer else {
return
}
if !displayedError, case .slowmodeActive = error {
displayedError = true
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
})
return combineLatest(queue: queue, statuses)
|> mapToSignal { statuses -> Signal<ShareState, ShareControllerError> in
var hasStatuses = false
for (id, status, error) in statuses {
if let error = error {
Queue.mainQueue().async {
let _ = TelegramEngine(account: account).messages.deleteMessagesInteractively(messageIds: [id], type: .forEveryone).start()
let _ = (TelegramEngine(account: account).data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: id.peerId))
|> deliverOnMainQueue).start(next: { peer in
guard let strongSelf = self, let peer = peer else {
return
}
if !displayedError {
if case .slowmodeActive = error {
displayedError = true
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
} else if case .mediaRestricted = error {
displayedError = true
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
}
})
}
}
if status != nil {
hasStatuses = true
}
}
if status != nil {
hasStatuses = true
if !hasStatuses {
return .single(.done)
}
return .complete()
}
if !hasStatuses {
return .single(.done)
}
return .complete()
|> take(1)
}
|> take(1)
}
}
self.controllerNode.shareExternal = { [weak self] _ in
@ -1261,3 +1490,73 @@ public func presentExternalShare(context: AccountContext, text: String, parentCo
}
context.sharedContext.applicationBindings.presentNativeController(activityController)
}
private func restrictedSendingContentsText(peer: EnginePeer, presentationData: PresentationData) -> String {
//TODO:localize
var itemList: [String] = []
let order: [TelegramChatBannedRightsFlags] = [
.banSendText,
.banSendPhotos,
.banSendVideos,
.banSendVoice,
.banSendInstantVideos,
.banSendFiles,
.banSendMusic,
.banSendStickers
]
for right in order {
if case let .channel(channel) = peer {
if channel.hasBannedPermission(right) != nil {
continue
}
} else if case let .legacyGroup(group) = peer {
if group.hasBannedPermission(right) {
continue
}
}
var title: String?
switch right {
case .banSendText:
title = "text messages"
case .banSendPhotos:
title = "photos"
case .banSendVideos:
title = "videos"
case .banSendVoice:
title = "voice messages"
case .banSendInstantVideos:
title = "video messages"
case .banSendFiles:
title = "files"
case .banSendMusic:
title = "music"
case .banSendStickers:
title = "Stickers & GIFs"
default:
break
}
if let title {
itemList.append(title)
}
}
if itemList.isEmpty {
return "Sending messages is disabled in \(peer.compactDisplayTitle)"
}
var itemListString = ""
for i in 0 ..< itemList.count {
if i != 0 {
itemListString.append(", ")
}
if i == itemList.count - 1 && i != 0 {
itemListString.append("and ")
}
itemListString.append(itemList[i])
}
return "The admins of \(peer.compactDisplayTitle) group only allow to send \(itemListString)."
}

View File

@ -178,7 +178,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
displaySearchWithPlaceholder: nil,
searchCategories: nil,
searchInitiallyHidden: true,
searchState: .empty
searchState: .empty(hasResults: false)
)
))
@ -386,7 +386,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
displaySearchWithPlaceholder: presentationData.strings.Common_Search,
searchCategories: searchCategories,
searchInitiallyHidden: true,
searchState: .empty
searchState: .empty(hasResults: false)
)
)
}
@ -419,7 +419,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
displaySearchWithPlaceholder: presentationData.strings.Common_Search,
searchCategories: searchCategories,
searchInitiallyHidden: true,
searchState: .empty
searchState: .empty(hasResults: false)
)
)
}
@ -1495,7 +1495,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
)
}
if let emoji = inputData.emoji {
let defaultSearchState: EmojiPagerContentComponent.SearchState = emojiSearchResult.isPreset ? .active : .empty
let defaultSearchState: EmojiPagerContentComponent.SearchState = emojiSearchResult.isPreset ? .active : .empty(hasResults: true)
inputData.emoji = emoji.withUpdatedItemGroups(panelItemGroups: emoji.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: EmojiPagerContentComponent.ContentId(id: emojiSearchResult.id, version: emojiSearchResult.version), emptySearchResults: emptySearchResults, searchState: emojiSearchState.isSearching ? .searching : defaultSearchState)
}
} else if emojiSearchState.isSearching {
@ -1514,7 +1514,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
)
}
if let stickers = inputData.stickers {
let defaultSearchState: EmojiPagerContentComponent.SearchState = stickerSearchResult.isPreset ? .active : .empty
let defaultSearchState: EmojiPagerContentComponent.SearchState = stickerSearchResult.isPreset ? .active : .empty(hasResults: true)
inputData.stickers = stickers.withUpdatedItemGroups(panelItemGroups: stickers.panelItemGroups, contentItemGroups: stickerSearchResult.groups, itemContentUniqueId: EmojiPagerContentComponent.ContentId(id: stickerSearchResult.id, version: stickerSearchResult.version), emptySearchResults: stickerSearchResults, searchState: stickerSearchState.isSearching ? .searching : defaultSearchState)
}
} else if stickerSearchState.isSearching {

View File

@ -1278,7 +1278,7 @@ private final class GroupEmbeddedView: UIScrollView, UIScrollViewDelegate, Pager
}
for (_, itemLayer) in self.visibleItemLayers {
if itemLayer.frame.inset(by: UIEdgeInsets(top: 6.0, left: itemLayout.itemSpacing, bottom: 6.0, right: itemLayout.itemSpacing)).contains(point) {
if itemLayer.frame.inset(by: UIEdgeInsets(top: -6.0, left: -itemLayout.itemSpacing, bottom: -6.0, right: -itemLayout.itemSpacing)).contains(point) {
self.performItemAction(itemLayer.item, self, itemLayer.frame, itemLayer)
return true
}
@ -2104,7 +2104,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
var hasText = false
if let textField = self.textField {
textField.textColor = theme.contextMenu.primaryColor
transition.setFrame(view: textField, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + sideTextInset, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.width - sideTextInset, height: backgroundFrame.height)))
transition.setFrame(view: textField, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + sideTextInset, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.width - sideTextInset - 32.0, height: backgroundFrame.height)))
if let text = textField.text, !text.isEmpty {
hasText = true
@ -2556,8 +2556,8 @@ public final class EmojiPagerContentComponent: Component {
case detailed
}
public enum SearchState {
case empty
public enum SearchState: Equatable {
case empty(hasResults: Bool)
case searching
case active
}
@ -4382,11 +4382,11 @@ public final class EmojiPagerContentComponent: Component {
}
public func scrollToItemGroup(id supergroupId: AnyHashable, subgroupId: Int32?, animated: Bool) {
guard let component = self.component, let pagerEnvironment = self.pagerEnvironment, let itemLayout = self.itemLayout else {
guard let component = self.component, let itemGroup = component.contentItemGroups.first(where: { $0.supergroupId == supergroupId }), let pagerEnvironment = self.pagerEnvironment, let itemLayout = self.itemLayout else {
return
}
if self.isSearchActivated {
if !component.contentItemGroups.contains(where: { $0.groupId == supergroupId }), self.isSearchActivated {
self.visibleSearchHeader?.clearCategorySearch()
return
}
@ -4446,6 +4446,10 @@ public final class EmojiPagerContentComponent: Component {
highlightFrame.size.width = self.scrollView.bounds.width - 4.0 - highlightFrame.minX
}
if (itemGroup.isPremiumLocked || itemGroup.isFeatured), !itemGroup.isEmbedded, case .compact = itemLayout.layoutType {
highlightFrame.size.height += 6.0
}
highlightLayer.frame = highlightFrame
self.scrollView.layer.insertSublayer(highlightLayer, at: 0)
highlightLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: 0.8, removeOnCompletion: false, completion: { [weak highlightLayer] _ in
@ -5122,7 +5126,7 @@ public final class EmojiPagerContentComponent: Component {
scrollView.layer.removeAllAnimations()
}
if self.isSearchActivated, let component = self.component, component.searchState == .empty, !component.searchAlwaysActive, let visibleSearchHeader = self.visibleSearchHeader, visibleSearchHeader.currentPresetSearchTerm == nil {
if self.isSearchActivated, let component = self.component, component.searchState == .empty(hasResults: false), !component.searchAlwaysActive, let visibleSearchHeader = self.visibleSearchHeader, visibleSearchHeader.currentPresetSearchTerm == nil {
scrollView.isScrollEnabled = false
DispatchQueue.main.async {
scrollView.isScrollEnabled = true
@ -6122,6 +6126,14 @@ public final class EmojiPagerContentComponent: Component {
self.pagerEnvironment = pagerEnvironment
pagerEnvironment.scrollToTop.connect { [weak self] in
guard let self else {
return
}
self.scrollView.setContentOffset(CGPoint(), animated: true)
}
self.updateIsWarpEnabled(isEnabled: component.warpContentsOnEdges)
if let longTapRecognizer = self.longTapRecognizer {
@ -7714,7 +7726,7 @@ public final class EmojiPagerContentComponent: Component {
contentItemGroups: allItemGroups,
itemLayoutType: .compact,
itemContentUniqueId: nil,
searchState: .empty,
searchState: .empty(hasResults: false),
warpContentsOnEdges: isReactionSelection || isStatusSelection || isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
displaySearchWithPlaceholder: displaySearchWithPlaceholder,
searchCategories: searchCategories,
@ -8236,7 +8248,7 @@ public final class EmojiPagerContentComponent: Component {
contentItemGroups: allItemGroups,
itemLayoutType: .detailed,
itemContentUniqueId: nil,
searchState: .empty,
searchState: .empty(hasResults: false),
warpContentsOnEdges: isProfilePhotoEmojiSelection || isGroupPhotoEmojiSelection,
displaySearchWithPlaceholder: hasSearch ? strings.StickersSearch_SearchStickersPlaceholder : nil,
searchCategories: searchCategories,

View File

@ -391,7 +391,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
contentItemGroups: self.itemGroups,
itemLayoutType: .compact,
itemContentUniqueId: EmojiPagerContentComponent.ContentId(id: "main", version: 0),
searchState: .empty,
searchState: .empty(hasResults: false),
warpContentsOnEdges: false,
displaySearchWithPlaceholder: "Search Emoji",
searchCategories: nil,
@ -411,7 +411,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
iconFile: nil
)
}
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: EmojiPagerContentComponent.ContentId(id: emojiSearchResult.id, version: 0), emptySearchResults: emptySearchResults, searchState: .active)
emojiContent = emojiContent.withUpdatedItemGroups(panelItemGroups: emojiContent.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: EmojiPagerContentComponent.ContentId(id: emojiSearchResult.id, version: 0), emptySearchResults: emptySearchResults, searchState: .empty(hasResults: true))
}
let _ = self.keyboardView.update(

View File

@ -1814,8 +1814,8 @@ public final class EntityKeyboardTopPanelComponent: Component {
let itemFrame = CGRect(origin: CGPoint(x: itemOuterFrame.minX + floor((itemOuterFrame.width - itemSize.width) / 2.0), y: itemOuterFrame.minY + floor((itemOuterFrame.height - itemSize.height) / 2.0)), size: itemSize)
itemTransition.setFrame(view: itemView, frame: itemFrame)
transition.setSublayerTransform(view: itemView, transform: CATransform3DMakeScale(scale, scale, 1.0))
transition.setAlpha(view: itemView, alpha: self.visibilityFraction)
itemTransition.setSublayerTransform(view: itemView, transform: CATransform3DMakeScale(scale, scale, 1.0))
itemTransition.setAlpha(view: itemView, alpha: self.visibilityFraction)
}
}
var removedIds: [AnyHashable] = []

View File

@ -8612,7 +8612,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if bannedMediaInput {
strongSelf.controllerInteraction?.displayUndo(.info(title: nil, text: strongSelf.restrictedSendingContentsText()))
strongSelf.controllerInteraction?.displayUndo(.universal(animation: "premium_unlock", scale: 1.0, colors: ["__allcolors__": UIColor(white: 1.0, alpha: 1.0)], title: nil, text: strongSelf.restrictedSendingContentsText(), customUndoText: nil))
return
}
@ -8754,7 +8754,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch displayType {
case .tooltip:
if displayToast {
strongSelf.controllerInteraction?.displayUndo(.info(title: nil, text: banDescription))
strongSelf.controllerInteraction?.displayUndo(.universal(animation: "premium_unlock", scale: 1.0, colors: ["__allcolors__": UIColor(white: 1.0, alpha: 1.0)], title: nil, text: banDescription, customUndoText: nil))
} else {
var rect: CGRect?
let isStickers: Bool = subject == .stickers
@ -8924,7 +8924,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if bannedMediaInput {
strongSelf.controllerInteraction?.displayUndo(.info(title: nil, text: strongSelf.restrictedSendingContentsText()))
strongSelf.controllerInteraction?.displayUndo(.universal(animation: "premium_unlock", scale: 1.0, colors: ["__allcolors__": UIColor(white: 1.0, alpha: 1.0)], title: nil, text: strongSelf.restrictedSendingContentsText(), customUndoText: nil))
return
}

View File

@ -368,6 +368,8 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
}
}
}
} else if case let .replyThread(message) = chatLocation, message.isForumPost {
automaticDownloadPeerId = message.messageId.peerId
}
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadPeerId: automaticDownloadPeerId, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, topicAuthorId: topicAuthorId, hasBots: hasBots, translateToLanguage: translateToLanguage)

View File

@ -933,7 +933,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
return
}
//TODO:localize
controller.controllerInteraction?.displayUndo(.info(title: nil, text: controller.restrictedSendingContentsText()))
controller.controllerInteraction?.displayUndo(.universal(animation: "premium_unlock", scale: 1.0, colors: ["__allcolors__": UIColor(white: 1.0, alpha: 1.0)], title: nil, text: controller.restrictedSendingContentsText(), customUndoText: nil))
} else {
strongSelf.ensureFocused()
}

View File

@ -830,6 +830,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.avatarNode = nil
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: animation, colors: colors, scale: scale)
self.animatedStickerNode = nil
if let title = title {

View File

@ -1,5 +1,5 @@
{
"app": "9.3.3",
"app": "9.4",
"bazel": "5.3.1",
"xcode": "14.1"
}