mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Topics
This commit is contained in:
parent
9a013c85c9
commit
99396ec7d4
@ -509,12 +509,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
var canManage: Bool = false
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
canManage = true
|
||||
}
|
||||
|
||||
if canManage {
|
||||
//TODO:localize
|
||||
items.append(.action(ContextMenuActionItem(text: isPinned ? "Unpin" : "Pin", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
f(.default)
|
||||
@ -714,7 +709,15 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
|
||||
}
|
||||
})))
|
||||
|
||||
if canManage || threadData.isOwnedByMe {
|
||||
var canManage = false
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canManage = true
|
||||
} else if channel.adminRights != nil {
|
||||
canManage = true
|
||||
} else if threadData.isOwnedByMe {
|
||||
canManage = true
|
||||
}
|
||||
if canManage {
|
||||
//TODO:localize
|
||||
items.append(.action(ContextMenuActionItem(text: threadData.isClosed ? "Restart" : "Close", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: threadData.isClosed ? "Chat/Context Menu/Play": "Chat/Context Menu/Pause"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
f(.default)
|
||||
|
@ -1590,10 +1590,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
||||
controller.navigationPresentation = .modal
|
||||
|
||||
controller.completion = { title, fileId in
|
||||
controller.completion = { [weak controller] title, fileId in
|
||||
controller?.isInProgress = true
|
||||
|
||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).start(next: { topicId in
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text).start()
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
})
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
@ -2631,12 +2635,17 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create)
|
||||
controller.navigationPresentation = .modal
|
||||
controller.completion = { title, fileId in
|
||||
|
||||
controller.completion = { [weak controller] title, fileId in
|
||||
controller?.isInProgress = true
|
||||
|
||||
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).start(next: { topicId in
|
||||
if let navigationController = (sourceController.navigationController as? NavigationController) {
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text).start()
|
||||
}
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
})
|
||||
}
|
||||
sourceController.push(controller)
|
||||
@ -3709,6 +3718,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
//TODO:localize
|
||||
items.append(ActionSheetTextItem(title: "This will delete the topic with all its messages", parseMarkdown: true))
|
||||
items.append(ActionSheetButtonItem(title: "Delete", color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
self?.commitDeletePeerThread(peerId: peerId, threadId: threadId)
|
||||
|
@ -330,10 +330,10 @@ private func groupReferenceRevealOptions(strings: PresentationStrings, theme: Pr
|
||||
return options
|
||||
}
|
||||
|
||||
private func forumRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isMuted: Bool?, isClosed: Bool, isPinned: Bool, isEditing: Bool, canManage: Bool) -> [ItemListRevealOption] {
|
||||
private func forumRevealOptions(strings: PresentationStrings, theme: PresentationTheme, isMuted: Bool?, isClosed: Bool, isPinned: Bool, isEditing: Bool, canPin: Bool, canManage: Bool) -> [ItemListRevealOption] {
|
||||
var options: [ItemListRevealOption] = []
|
||||
if !isEditing {
|
||||
if canManage {
|
||||
if canPin {
|
||||
if isPinned {
|
||||
options.append(ItemListRevealOption(key: RevealOptionKey.unpin.rawValue, title: strings.DialogList_Unpin, icon: unpinIcon, color: theme.list.itemDisclosureActions.constructive.fillColor, textColor: theme.list.itemDisclosureActions.constructive.foregroundColor))
|
||||
} else {
|
||||
@ -1852,16 +1852,18 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
if case .forum = item.chatListLocation {
|
||||
if case let .chat(itemPeer) = contentPeer, case let .channel(channel) = itemPeer.peer {
|
||||
var canManage = false
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canManage = true
|
||||
} else if channel.adminRights != nil {
|
||||
canManage = true
|
||||
} else if let threadInfo = threadInfo, threadInfo.isOwner {
|
||||
canManage = true
|
||||
} else if let threadInfo {
|
||||
canManage = threadInfo.isOwner
|
||||
}
|
||||
var isClosed = false
|
||||
if let threadInfo {
|
||||
isClosed = threadInfo.isClosed
|
||||
}
|
||||
peerRevealOptions = forumRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isMuted: (currentMutedIconImage != nil), isClosed: isClosed, isPinned: isPinned, isEditing: item.editing, canManage: canManage)
|
||||
peerRevealOptions = forumRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isMuted: (currentMutedIconImage != nil), isClosed: isClosed, isPinned: isPinned, isEditing: item.editing, canPin: channel.hasPermission(.pinMessages), canManage: canManage)
|
||||
peerLeftRevealOptions = []
|
||||
} else {
|
||||
peerRevealOptions = []
|
||||
|
@ -270,7 +270,12 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
||||
}
|
||||
}
|
||||
default:
|
||||
hideAuthor = true
|
||||
switch action.action {
|
||||
case .topicCreated, .topicEdited:
|
||||
hideAuthor = false
|
||||
default:
|
||||
hideAuthor = true
|
||||
}
|
||||
if let (text, textSpoilers, customEmojiRangesValue) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
|
||||
messageText = text
|
||||
spoilers = textSpoilers
|
||||
|
@ -226,7 +226,7 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title:
|
||||
}
|
||||
|
||||
if let topicId = topicId {
|
||||
return resolveForumThreads(postbox: account.postbox, network: account.network, ids: [])
|
||||
return resolveForumThreads(postbox: account.postbox, network: account.network, ids: [MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))])
|
||||
|> castError(CreateForumChannelTopicError.self)
|
||||
|> map { _ -> Int64 in
|
||||
return topicId
|
||||
|
@ -31,6 +31,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/EmojiTextAttachmentView:EmojiTextAttachmentView",
|
||||
"//submodules/Components/PagerComponent:PagerComponent",
|
||||
"//submodules/PremiumUI",
|
||||
"//submodules/ProgressNavigationButtonNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -15,6 +15,7 @@ import MultilineTextComponent
|
||||
import EmojiStatusComponent
|
||||
import Postbox
|
||||
import PremiumUI
|
||||
import ProgressNavigationButtonNode
|
||||
|
||||
private final class TitleFieldComponent: Component {
|
||||
typealias EnvironmentType = Empty
|
||||
@ -162,6 +163,8 @@ private final class TitleFieldComponent: Component {
|
||||
placeholderComponentView.frame = CGRect(origin: CGPoint(x: 62.0, y: floorToScreenPixels((availableSize.height - placeholderSize.height) / 2.0) + 1.0 - UIScreenPixel), size: placeholderSize)
|
||||
}
|
||||
|
||||
self.placeholderView.view?.isHidden = !component.text.isEmpty
|
||||
|
||||
let iconSize = self.iconView.update(
|
||||
transition: .easeInOut(duration: 0.2),
|
||||
component: AnyComponent(EmojiStatusComponent(
|
||||
@ -782,10 +785,32 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
||||
case edit(topic: EngineMessageHistoryThread.Info)
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
private let mode: Mode
|
||||
|
||||
private var doneBarItem: UIBarButtonItem?
|
||||
|
||||
private var state: (String, Int64?) = ("", nil)
|
||||
public var completion: (String, Int64?) -> Void = { _, _ in }
|
||||
|
||||
public var isInProgress: Bool = false {
|
||||
didSet {
|
||||
if self.isInProgress != oldValue {
|
||||
if self.isInProgress {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: presentationData.theme.rootController.navigationBar.accentTextColor))
|
||||
} else {
|
||||
//TODO:localize
|
||||
self.navigationItem.rightBarButtonItem = self.doneBarItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext, peerId: EnginePeer.Id, mode: ForumCreateTopicScreen.Mode) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
|
||||
var titleUpdatedImpl: ((String) -> Void)?
|
||||
var iconUpdatedImpl: ((Int64?) -> Void)?
|
||||
var openPremiumImpl: (() -> Void)?
|
||||
@ -802,12 +827,14 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
||||
let title: String
|
||||
let doneTitle: String
|
||||
switch mode {
|
||||
case .create:
|
||||
title = "New Topic"
|
||||
doneTitle = "Create"
|
||||
case .edit:
|
||||
title = "Edit Topic"
|
||||
doneTitle = "Done"
|
||||
case .create:
|
||||
title = "New Topic"
|
||||
doneTitle = "Create"
|
||||
case let .edit(topic):
|
||||
title = "Edit Topic"
|
||||
doneTitle = "Done"
|
||||
|
||||
self.state = (topic.title, topic.icon)
|
||||
}
|
||||
|
||||
self.title = title
|
||||
@ -815,20 +842,21 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: doneTitle, style: .done, target: self, action: #selector(self.createPressed))
|
||||
self.navigationItem.rightBarButtonItem?.isEnabled = false
|
||||
self.doneBarItem = UIBarButtonItem(title: doneTitle, style: .done, target: self, action: #selector(self.createPressed))
|
||||
self.navigationItem.rightBarButtonItem = self.doneBarItem
|
||||
self.doneBarItem?.isEnabled = false
|
||||
|
||||
if case .edit = mode {
|
||||
self.navigationItem.rightBarButtonItem?.isEnabled = true
|
||||
self.doneBarItem?.isEnabled = true
|
||||
}
|
||||
|
||||
titleUpdatedImpl = { [weak self] title in
|
||||
guard let strongSelf = self else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
strongSelf.navigationItem.rightBarButtonItem?.isEnabled = !title.isEmpty
|
||||
self.doneBarItem?.isEnabled = !title.isEmpty
|
||||
|
||||
strongSelf.state = (title, strongSelf.state.1)
|
||||
self.state = (title, self.state.1)
|
||||
}
|
||||
|
||||
iconUpdatedImpl = { [weak self] fileId in
|
||||
|
@ -3038,7 +3038,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
case let .replyThread(replyThreadMessage):
|
||||
let peerId = replyThreadMessage.messageId.peerId
|
||||
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, animated: true, completion: nil)
|
||||
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, forceInCurrentChat: true, animated: true, completion: nil)
|
||||
case .feed:
|
||||
//TODO:implement
|
||||
break
|
||||
|
@ -262,7 +262,9 @@ func canReplyInChat(_ chatPresentationInterfaceState: ChatPresentationInterfaceS
|
||||
if let threadData = chatPresentationInterfaceState.threadData {
|
||||
if threadData.isClosed {
|
||||
var canManage = false
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canManage = true
|
||||
} else if channel.adminRights != nil {
|
||||
canManage = true
|
||||
} else if threadData.isOwn {
|
||||
canManage = true
|
||||
|
@ -162,7 +162,9 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
||||
if let threadData = chatPresentationInterfaceState.threadData {
|
||||
if threadData.isClosed {
|
||||
var canManage = false
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canManage = true
|
||||
} else if channel.adminRights != nil {
|
||||
canManage = true
|
||||
} else if threadData.isOwn {
|
||||
canManage = true
|
||||
|
@ -61,7 +61,9 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
||||
if let threadData = chatPresentationInterfaceState.threadData {
|
||||
if threadData.isClosed {
|
||||
var canManage = false
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canManage = true
|
||||
} else if channel.adminRights != nil {
|
||||
canManage = true
|
||||
} else if threadData.isOwn {
|
||||
canManage = true
|
||||
|
@ -102,7 +102,9 @@ private func peerButtons(_ state: ChatPresentationInterfaceState) -> [ChatReport
|
||||
if let threadData = state.threadData {
|
||||
if threadData.isClosed {
|
||||
var canManage = false
|
||||
if channel.hasPermission(.pinMessages) {
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canManage = true
|
||||
} else if channel.adminRights != nil {
|
||||
canManage = true
|
||||
} else if threadData.isOwn {
|
||||
canManage = true
|
||||
@ -597,7 +599,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
if let renderedPeer = interfaceState.renderedPeer {
|
||||
chatPeer = renderedPeer.peers[renderedPeer.peerId]
|
||||
}
|
||||
if let chatPeer = chatPeer, let invitedBy = interfaceState.contactStatus?.invitedBy {
|
||||
if let chatPeer = chatPeer, (updatedButtons.contains(.block) || updatedButtons.contains(.reportSpam) || updatedButtons.contains(.reportUserSpam)), let invitedBy = interfaceState.contactStatus?.invitedBy {
|
||||
var inviteInfoTransition = transition
|
||||
let inviteInfoNode: ChatInfoTitlePanelInviteInfoNode
|
||||
if let current = self.inviteInfoNode {
|
||||
|
@ -1189,7 +1189,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
||||
return result
|
||||
}
|
||||
|
||||
func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?, isContact: Bool?) -> Bool {
|
||||
func peerInfoCanEdit(peer: Peer?, threadData: MessageHistoryThreadData?, cachedData: CachedPeerData?, isContact: Bool?) -> Bool {
|
||||
if let user = peer as? TelegramUser {
|
||||
if user.isDeleted {
|
||||
return false
|
||||
@ -1199,14 +1199,26 @@ func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?, isContact: Bool?)
|
||||
}
|
||||
return true
|
||||
} else if let peer = peer as? TelegramChannel {
|
||||
if peer.flags.contains(.isCreator) {
|
||||
return true
|
||||
} else if peer.hasPermission(.changeInfo) {
|
||||
return true
|
||||
} else if let _ = peer.adminRights {
|
||||
return true
|
||||
if peer.flags.contains(.isForum) {
|
||||
if peer.flags.contains(.isCreator) {
|
||||
return true
|
||||
} else if let threadData = threadData, threadData.isOwnedByMe {
|
||||
return true
|
||||
} else if let _ = peer.adminRights {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if peer.flags.contains(.isCreator) {
|
||||
return true
|
||||
} else if peer.hasPermission(.changeInfo) {
|
||||
return true
|
||||
} else if let _ = peer.adminRights {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
} else if let peer = peer as? TelegramGroup {
|
||||
if case .creator = peer.role {
|
||||
return true
|
||||
|
@ -8183,7 +8183,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .qrCode, isForExpandedView: false))
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true))
|
||||
} else if peerInfoCanEdit(peer: self.data?.peer, cachedData: self.data?.cachedData, isContact: self.data?.isContact) {
|
||||
} else if peerInfoCanEdit(peer: self.data?.peer, threadData: self.data?.threadData, cachedData: self.data?.cachedData, isContact: self.data?.isContact) {
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
}
|
||||
if self.state.selectedMessageIds == nil {
|
||||
@ -9602,6 +9602,31 @@ func presentAddMembersImpl(context: AccountContext, updatedPresentationData: (in
|
||||
contactsController?.dismiss()
|
||||
}, completed: {
|
||||
contactsController?.dismiss()
|
||||
|
||||
let mappedPeerIds: [EnginePeer.Id] = peers.compactMap { peer -> EnginePeer.Id? in
|
||||
switch peer {
|
||||
case let .peer(id):
|
||||
return id
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if !mappedPeerIds.isEmpty {
|
||||
let _ = (context.engine.data.get(EngineDataMap(mappedPeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))))
|
||||
|> deliverOnMainQueue).start(next: { maybePeers in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let peers = maybePeers.compactMap { $0.value }
|
||||
|
||||
//TODO:localize
|
||||
let text: String
|
||||
if peers.count == 1 {
|
||||
text = "**\(peers[0].displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** added to the group."
|
||||
} else {
|
||||
text = "**\(peers.count)** members added to the group."
|
||||
}
|
||||
parentController?.present(UndoOverlayController(presentationData: presentationData, content: .peers(context: context, peers: peers, title: nil, text: text, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
})
|
||||
}
|
||||
}))
|
||||
}))
|
||||
contactsController.dismissed = {
|
||||
|
@ -27,6 +27,7 @@ swift_library(
|
||||
"//submodules/AvatarNode:AvatarNode",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/ComponentFlow:ComponentFlow",
|
||||
"//submodules/AnimatedAvatarSetNode:AnimatedAvatarSetNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -42,6 +42,7 @@ public enum UndoOverlayContent {
|
||||
case image(image: UIImage, text: String)
|
||||
case notificationSoundAdded(title: String, text: String, action: (() -> Void)?)
|
||||
case universal(animation: String, scale: CGFloat, colors: [String: UIColor], title: String?, text: String, customUndoText: String?)
|
||||
case peers(context: AccountContext, peers: [EnginePeer], title: String?, text: String, customUndoText: String?)
|
||||
}
|
||||
|
||||
public enum UndoOverlayAction {
|
||||
|
@ -17,6 +17,7 @@ import AnimationUI
|
||||
import StickerResources
|
||||
import AvatarNode
|
||||
import AccountContext
|
||||
import AnimatedAvatarSetNode
|
||||
|
||||
final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let elevatedLayout: Bool
|
||||
@ -25,6 +26,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let timerTextNode: ImmediateTextNode
|
||||
private let avatarNode: AvatarNode?
|
||||
private let iconNode: ASImageNode?
|
||||
private var multiAvatarsNode: AnimatedAvatarSetNode?
|
||||
private var multiAvatarsSize: CGSize?
|
||||
private var iconImageSize: CGSize?
|
||||
private let iconCheckNode: RadialStatusNode?
|
||||
private let animationNode: AnimationNode?
|
||||
@ -872,6 +875,44 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = true
|
||||
self.originalRemainingSeconds = 5
|
||||
case let .peers(context, peers, title, text, customUndoText):
|
||||
self.avatarNode = nil
|
||||
let multiAvatarsNode = AnimatedAvatarSetNode()
|
||||
self.multiAvatarsNode = multiAvatarsNode
|
||||
let avatarsContext = AnimatedAvatarSetContext()
|
||||
self.multiAvatarsSize = multiAvatarsNode.update(context: context, content: avatarsContext.update(peers: peers, animated: false), itemSize: CGSize(width: 28.0, height: 28.0), animated: false, synchronousLoad: false)
|
||||
|
||||
self.iconNode = nil
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = nil
|
||||
self.animatedStickerNode = nil
|
||||
if let title = title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
} else {
|
||||
self.titleNode.attributedText = nil
|
||||
}
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
let link = MarkdownAttributeSet(font: Font.regular(14.0), textColor: undoTextColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { contents in
|
||||
return ("URL", contents)
|
||||
}), textAlignment: .natural)
|
||||
self.textNode.attributedText = attributedText
|
||||
|
||||
if text.contains("](") {
|
||||
isUserInteractionEnabled = true
|
||||
}
|
||||
self.originalRemainingSeconds = isUserInteractionEnabled ? 5 : 3
|
||||
|
||||
self.textNode.maximumNumberOfLines = 5
|
||||
|
||||
if let customUndoText = customUndoText {
|
||||
undoText = customUndoText
|
||||
displayUndo = true
|
||||
} else {
|
||||
displayUndo = false
|
||||
}
|
||||
}
|
||||
|
||||
self.remainingSeconds = self.originalRemainingSeconds
|
||||
@ -900,7 +941,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
switch content {
|
||||
case .removedChat:
|
||||
self.panelWrapperNode.addSubnode(self.timerTextNode)
|
||||
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent, .notificationSoundAdded, .universal:
|
||||
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent, .notificationSoundAdded, .universal, .peers:
|
||||
if self.textNode.tapAttributeAction != nil || displayUndo {
|
||||
self.isUserInteractionEnabled = true
|
||||
} else {
|
||||
@ -927,6 +968,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.animationNode?.isUserInteractionEnabled = false
|
||||
self.iconCheckNode?.isUserInteractionEnabled = false
|
||||
self.avatarNode?.isUserInteractionEnabled = false
|
||||
self.multiAvatarsNode?.isUserInteractionEnabled = false
|
||||
self.slotMachineNode?.isUserInteractionEnabled = false
|
||||
self.animatedStickerNode?.isUserInteractionEnabled = false
|
||||
|
||||
@ -938,6 +980,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.animatedStickerNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.multiAvatarsNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.panelWrapperNode.addSubnode(self.buttonNode)
|
||||
self.panelWrapperNode.addSubnode(self.titleNode)
|
||||
self.panelWrapperNode.addSubnode(self.textNode)
|
||||
@ -1088,7 +1131,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
if iconSize.width > leftInset {
|
||||
leftInset = iconSize.width - 8.0
|
||||
}
|
||||
} else if let multiAvatarsSize = self.multiAvatarsSize {
|
||||
leftInset = 13.0 + multiAvatarsSize.width + 20.0
|
||||
}
|
||||
|
||||
let rightInset: CGFloat = 16.0
|
||||
var contentHeight: CGFloat = 20.0
|
||||
|
||||
@ -1228,6 +1274,11 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
let avatarSize: CGFloat = 30.0
|
||||
transition.updateFrame(node: avatarNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - avatarSize) / 2.0), y: floor((contentHeight - avatarSize) / 2.0)), size: CGSize(width: avatarSize, height: avatarSize)))
|
||||
}
|
||||
|
||||
if let multiAvatarsNode = self.multiAvatarsNode, let multiAvatarsSize = self.multiAvatarsSize {
|
||||
let avatarsFrame = CGRect(origin: CGPoint(x: 13.0, y: floor((contentHeight - multiAvatarsSize.height) / 2.0) + verticalOffset), size: multiAvatarsSize)
|
||||
transition.updateFrame(node: multiAvatarsNode, frame: avatarsFrame)
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn(asReplacement: Bool) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user