mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Poll and sticker pack improvements
This commit is contained in:
parent
f0c1f3ff3e
commit
203acd8567
@ -1200,7 +1200,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
|||||||
|
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize())
|
||||||
|
|
||||||
parentController.present(TooltipScreen(text: text, icon: .chatListPress, location: location, shouldDismissOnTouch: { point in
|
parentController.present(TooltipScreen(text: text, icon: .chatListPress, location: .point(location), shouldDismissOnTouch: { point in
|
||||||
guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
|
guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ public extension ContainerViewLayout {
|
|||||||
func insets(options: ContainerViewLayoutInsetOptions) -> UIEdgeInsets {
|
func insets(options: ContainerViewLayoutInsetOptions) -> UIEdgeInsets {
|
||||||
var insets = self.intrinsicInsets
|
var insets = self.intrinsicInsets
|
||||||
if let statusBarHeight = self.statusBarHeight, options.contains(.statusBar) {
|
if let statusBarHeight = self.statusBarHeight, options.contains(.statusBar) {
|
||||||
insets.top += statusBarHeight
|
insets.top = max(statusBarHeight, insets.top)
|
||||||
}
|
}
|
||||||
if let inputHeight = self.inputHeight, options.contains(.input) {
|
if let inputHeight = self.inputHeight, options.contains(.input) {
|
||||||
insets.bottom = max(inputHeight, insets.bottom)
|
insets.bottom = max(inputHeight, insets.bottom)
|
||||||
|
@ -56,7 +56,7 @@ public final class PresentationContext {
|
|||||||
|
|
||||||
private var presentationDisposables = DisposableSet()
|
private var presentationDisposables = DisposableSet()
|
||||||
|
|
||||||
var topLevelSubview: () -> UIView? = { nil }
|
public var topLevelSubview: () -> UIView? = { nil }
|
||||||
|
|
||||||
var isCurrentlyOpaque: Bool {
|
var isCurrentlyOpaque: Bool {
|
||||||
for (controller, _) in self.controllers {
|
for (controller, _) in self.controllers {
|
||||||
|
@ -548,16 +548,6 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction,
|
|||||||
for info in resultingCollectionInfos {
|
for info in resultingCollectionInfos {
|
||||||
resultingInfos[info.0.id] = info
|
resultingInfos[info.0.id] = info
|
||||||
}
|
}
|
||||||
for (id, info) in resultingInfos {
|
|
||||||
if info.0.shortName.lowercased() == "thevirus" {
|
|
||||||
print("id1 = \(id)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (id, info) in localInfos {
|
|
||||||
if info.shortName.lowercased() == "thevirus" {
|
|
||||||
print("id1 = \(id)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let resolvedItems = resolveStickerPacks(network: network, remoteInfos: resultingInfos, localInfos: localInfos)
|
let resolvedItems = resolveStickerPacks(network: network, remoteInfos: resultingInfos, localInfos: localInfos)
|
||||||
|
|
||||||
|
@ -373,6 +373,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
super.init(context: context, navigationBarPresentationData: navigationBarPresentationData, mediaAccessoryPanelVisibility: mediaAccessoryPanelVisibility, locationBroadcastPanelSource: locationBroadcastPanelSource)
|
super.init(context: context, navigationBarPresentationData: navigationBarPresentationData, mediaAccessoryPanelVisibility: mediaAccessoryPanelVisibility, locationBroadcastPanelSource: locationBroadcastPanelSource)
|
||||||
|
|
||||||
|
self.automaticallyControlPresentationContextLayout = false
|
||||||
self.blocksBackgroundWhenInOverlay = true
|
self.blocksBackgroundWhenInOverlay = true
|
||||||
|
|
||||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||||
@ -1950,7 +1951,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var foundItemNode: ListViewItemNode?
|
|
||||||
|
/*var foundItemNode: ListViewItemNode?
|
||||||
strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? ChatMessageItemView {
|
if let itemNode = itemNode as? ChatMessageItemView {
|
||||||
if sourceNode.view.isDescendant(of: itemNode.view) {
|
if sourceNode.view.isDescendant(of: itemNode.view) {
|
||||||
@ -1959,6 +1961,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let foundItemNode = foundItemNode {
|
if let foundItemNode = foundItemNode {
|
||||||
|
|
||||||
let absoluteFrame = sourceNode.view.convert(sourceNode.bounds, to: strongSelf.view).insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0)
|
let absoluteFrame = sourceNode.view.convert(sourceNode.bounds, to: strongSelf.view).insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0)
|
||||||
let tooltipScreen = TooltipScreen(text: solution.text, textEntities: solution.entities, icon: nil, location: absoluteFrame, shouldDismissOnTouch: { point in
|
let tooltipScreen = TooltipScreen(text: solution.text, textEntities: solution.entities, icon: nil, location: absoluteFrame, shouldDismissOnTouch: { point in
|
||||||
return .dismiss(consume: absoluteFrame.contains(point))
|
return .dismiss(consume: absoluteFrame.contains(point))
|
||||||
@ -2012,7 +2015,82 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
strongSelf.currentMessageTooltipScreens.append((tooltipScreen, foundItemNode))
|
strongSelf.currentMessageTooltipScreens.append((tooltipScreen, foundItemNode))
|
||||||
strongSelf.present(tooltipScreen, in: .current)
|
strongSelf.present(tooltipScreen, in: .current)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
var found = false
|
||||||
|
strongSelf.forEachController({ controller in
|
||||||
|
if let controller = controller as? TooltipScreen {
|
||||||
|
if controller.text == solution.text && controller.textEntities == solution.entities {
|
||||||
|
found = true
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if found {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let tooltipScreen = TooltipScreen(text: solution.text, textEntities: solution.entities, icon: .info, location: .top, shouldDismissOnTouch: { point in
|
||||||
|
return .ignore
|
||||||
|
}, openActiveTextItem: { item, action in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch item {
|
||||||
|
case let .url(url):
|
||||||
|
switch action {
|
||||||
|
case .tap:
|
||||||
|
strongSelf.openUrl(url, concealed: false)
|
||||||
|
case .longTap:
|
||||||
|
strongSelf.controllerInteraction?.longTap(.url(url), nil)
|
||||||
|
}
|
||||||
|
case let .mention(peerId, mention):
|
||||||
|
switch action {
|
||||||
|
case .tap:
|
||||||
|
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil)
|
||||||
|
case .longTap:
|
||||||
|
strongSelf.controllerInteraction?.longTap(.peerMention(peerId, mention), nil)
|
||||||
|
}
|
||||||
|
case let .textMention(mention):
|
||||||
|
switch action {
|
||||||
|
case .tap:
|
||||||
|
strongSelf.controllerInteraction?.openPeerMention(mention)
|
||||||
|
case .longTap:
|
||||||
|
strongSelf.controllerInteraction?.longTap(.mention(mention), nil)
|
||||||
|
}
|
||||||
|
case let .botCommand(command):
|
||||||
|
switch action {
|
||||||
|
case .tap:
|
||||||
|
strongSelf.controllerInteraction?.sendBotCommand(nil, command)
|
||||||
|
case .longTap:
|
||||||
|
strongSelf.controllerInteraction?.longTap(.command(command), nil)
|
||||||
|
}
|
||||||
|
case let .hashtag(hashtag):
|
||||||
|
switch action {
|
||||||
|
case .tap:
|
||||||
|
strongSelf.controllerInteraction?.openHashtag(nil, hashtag)
|
||||||
|
case .longTap:
|
||||||
|
strongSelf.controllerInteraction?.longTap(.hashtag(hashtag), nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/*tooltipScreen.becameDismissed = { tooltipScreen in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.currentMessageTooltipScreens.removeAll(where: { $0.0 === tooltipScreen })
|
||||||
|
}
|
||||||
|
strongSelf.currentMessageTooltipScreens.append((tooltipScreen, foundItemNode))*/
|
||||||
|
|
||||||
|
strongSelf.forEachController({ controller in
|
||||||
|
if let controller = controller as? TooltipScreen {
|
||||||
|
controller.dismiss()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
strongSelf.present(tooltipScreen, in: .current)
|
||||||
}, requestMessageUpdate: { [weak self] id in
|
}, requestMessageUpdate: { [weak self] id in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
|
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
|
||||||
|
@ -247,6 +247,13 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
self.controller?.presentationContext.topLevelSubview = { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return strongSelf.titleAccessoryPanelContainer.view
|
||||||
|
}
|
||||||
|
|
||||||
self.setViewBlock({
|
self.setViewBlock({
|
||||||
return ChatControllerNodeView()
|
return ChatControllerNodeView()
|
||||||
})
|
})
|
||||||
@ -1087,6 +1094,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
listInsets.top = listInsets.top + messageActionSheetControllerAdditionalInset
|
listInsets.top = listInsets.top + messageActionSheetControllerAdditionalInset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var childredLayout = layout
|
||||||
|
childredLayout.intrinsicInsets = UIEdgeInsets(top: listInsets.bottom, left: listInsets.right, bottom: listInsets.top, right: listInsets.left)
|
||||||
|
self.controller?.presentationContext.containerLayoutUpdated(childredLayout, transition: transition)
|
||||||
|
|
||||||
listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, scrollIndicatorInsets: listScrollIndicatorInsets, duration: duration, curve: curve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems), additionalScrollDistance, scrollToTop, { [weak self] in
|
listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, scrollIndicatorInsets: listScrollIndicatorInsets, duration: duration, curve: curve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems), additionalScrollDistance, scrollToTop, { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.notifyTransitionCompletionListeners(transition: transition)
|
strongSelf.notifyTransitionCompletionListeners(transition: transition)
|
||||||
|
@ -1579,10 +1579,14 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
placeholderNode = self.gifPane.searchPlaceholderNode
|
placeholderNode = self.gifPane.searchPlaceholderNode
|
||||||
paneIsEmpty = self.gifPane.isEmpty
|
paneIsEmpty = self.gifPane.isEmpty
|
||||||
case .sticker:
|
case .sticker:
|
||||||
|
paneIsEmpty = true
|
||||||
self.stickerPane.gridNode.forEachItemNode { itemNode in
|
self.stickerPane.gridNode.forEachItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? PaneSearchBarPlaceholderNode {
|
if let itemNode = itemNode as? PaneSearchBarPlaceholderNode {
|
||||||
placeholderNode = itemNode
|
placeholderNode = itemNode
|
||||||
}
|
}
|
||||||
|
if let _ = itemNode as? ChatMediaInputStickerGridItemNode {
|
||||||
|
paneIsEmpty = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case .trending:
|
case .trending:
|
||||||
/*self.trendingPane.gridNode.forEachItemNode { itemNode in
|
/*self.trendingPane.gridNode.forEachItemNode { itemNode in
|
||||||
|
@ -87,7 +87,7 @@ final class TrendingPanePackEntry: Identifiable, Comparable {
|
|||||||
|
|
||||||
func item(account: Account, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
|
func item(account: Account, interaction: TrendingPaneInteraction, grid: Bool) -> GridItem {
|
||||||
let info = self.info
|
let info = self.info
|
||||||
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, installed: self.installed, unread: self.unread, open: {
|
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: false, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, installed: self.installed, unread: self.unread, open: {
|
||||||
interaction.openPack(info)
|
interaction.openPack(info)
|
||||||
}, install: {
|
}, install: {
|
||||||
interaction.installPack(info)
|
interaction.installPack(info)
|
||||||
|
@ -1009,6 +1009,10 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let message = item.message
|
let message = item.message
|
||||||
|
|
||||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||||
|
var isBotChat: Bool = false
|
||||||
|
if let peer = item.message.peers[item.message.id.peerId] as? TelegramUser, peer.botInfo != nil {
|
||||||
|
isBotChat = true
|
||||||
|
}
|
||||||
|
|
||||||
let additionalTextRightInset: CGFloat = 24.0
|
let additionalTextRightInset: CGFloat = 24.0
|
||||||
|
|
||||||
@ -1120,8 +1124,11 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
let (typeLayout, typeApply) = makeTypeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: typeText, font: labelsFont, textColor: messageTheme.secondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (typeLayout, typeApply) = makeTypeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: typeText, font: labelsFont, textColor: messageTheme.secondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let votersString: String
|
let votersString: String?
|
||||||
if let poll = poll, let totalVoters = poll.results.totalVoters {
|
|
||||||
|
if isBotChat {
|
||||||
|
votersString = nil
|
||||||
|
} else if let poll = poll, let totalVoters = poll.results.totalVoters {
|
||||||
switch poll.kind {
|
switch poll.kind {
|
||||||
case .poll:
|
case .poll:
|
||||||
if totalVoters == 0 {
|
if totalVoters == 0 {
|
||||||
@ -1139,7 +1146,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
} else {
|
} else {
|
||||||
votersString = " "
|
votersString = " "
|
||||||
}
|
}
|
||||||
let (votersLayout, votersApply) = makeVotersLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: votersString, font: labelsFont, textColor: messageTheme.secondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets))
|
let (votersLayout, votersApply) = makeVotersLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: votersString ?? "", font: labelsFont, textColor: messageTheme.secondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets))
|
||||||
|
|
||||||
let (buttonSubmitInactiveTextLayout, buttonSubmitInactiveTextApply) = makeSubmitInactiveTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.MessagePoll_SubmitVote, font: Font.regular(17.0), textColor: messageTheme.accentControlDisabledColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets))
|
let (buttonSubmitInactiveTextLayout, buttonSubmitInactiveTextApply) = makeSubmitInactiveTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.MessagePoll_SubmitVote, font: Font.regular(17.0), textColor: messageTheme.accentControlDisabledColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets))
|
||||||
let (buttonSubmitActiveTextLayout, buttonSubmitActiveTextApply) = makeSubmitActiveTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.MessagePoll_SubmitVote, font: Font.regular(17.0), textColor: messageTheme.polls.bar), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets))
|
let (buttonSubmitActiveTextLayout, buttonSubmitActiveTextApply) = makeSubmitActiveTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.MessagePoll_SubmitVote, font: Font.regular(17.0), textColor: messageTheme.polls.bar), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets))
|
||||||
@ -1274,7 +1281,11 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let optionsVotersSpacing: CGFloat = 11.0
|
let optionsVotersSpacing: CGFloat = 11.0
|
||||||
let optionsButtonSpacing: CGFloat = 9.0
|
let optionsButtonSpacing: CGFloat = 9.0
|
||||||
let votersBottomSpacing: CGFloat = 11.0
|
let votersBottomSpacing: CGFloat = 11.0
|
||||||
|
if votersString != nil {
|
||||||
resultSize.height += optionsVotersSpacing + votersLayout.size.height + votersBottomSpacing
|
resultSize.height += optionsVotersSpacing + votersLayout.size.height + votersBottomSpacing
|
||||||
|
} else {
|
||||||
|
resultSize.height += 26.0
|
||||||
|
}
|
||||||
|
|
||||||
let buttonSubmitInactiveTextFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonSubmitInactiveTextLayout.size.width) / 2.0), y: optionsButtonSpacing), size: buttonSubmitInactiveTextLayout.size)
|
let buttonSubmitInactiveTextFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonSubmitInactiveTextLayout.size.width) / 2.0), y: optionsButtonSpacing), size: buttonSubmitInactiveTextLayout.size)
|
||||||
let buttonSubmitActiveTextFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonSubmitActiveTextLayout.size.width) / 2.0), y: optionsButtonSpacing), size: buttonSubmitActiveTextLayout.size)
|
let buttonSubmitActiveTextFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonSubmitActiveTextLayout.size.width) / 2.0), y: optionsButtonSpacing), size: buttonSubmitActiveTextLayout.size)
|
||||||
@ -1437,7 +1448,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
strongSelf.timerNode = timerNode
|
strongSelf.timerNode = timerNode
|
||||||
strongSelf.addSubnode(timerNode)
|
strongSelf.addSubnode(timerNode)
|
||||||
timerNode.reachedTimeout = {
|
timerNode.reachedTimeout = {
|
||||||
guard let strongSelf = self, let item = strongSelf.item else {
|
guard let strongSelf = self, let _ = strongSelf.item else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//item.controllerInteraction.requestMessageUpdate(item.message.id)
|
//item.controllerInteraction.requestMessageUpdate(item.message.id)
|
||||||
@ -1502,6 +1513,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
strongSelf.avatarsNode.frame = avatarsFrame
|
strongSelf.avatarsNode.frame = avatarsFrame
|
||||||
strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size)
|
strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size)
|
||||||
strongSelf.avatarsNode.update(context: item.context, peers: avatarPeers, synchronousLoad: synchronousLoad)
|
strongSelf.avatarsNode.update(context: item.context, peers: avatarPeers, synchronousLoad: synchronousLoad)
|
||||||
|
strongSelf.avatarsNode.isHidden = isBotChat
|
||||||
let alphaTransition: ContainedViewLayoutTransition
|
let alphaTransition: ContainedViewLayoutTransition
|
||||||
if animation.isAnimated {
|
if animation.isAnimated {
|
||||||
alphaTransition = .animated(duration: 0.25, curve: .easeInOut)
|
alphaTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
@ -1542,6 +1554,11 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isBotChat: Bool = false
|
||||||
|
if let peer = item.message.peers[item.message.id.peerId] as? TelegramUser, peer.botInfo != nil {
|
||||||
|
isBotChat = true
|
||||||
|
}
|
||||||
|
|
||||||
let disableAllActions = false
|
let disableAllActions = false
|
||||||
|
|
||||||
var hasSelection = false
|
var hasSelection = false
|
||||||
@ -1593,8 +1610,14 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
} else {
|
} else {
|
||||||
if case .public = poll.publicity, hasResults, !disableAllActions {
|
if case .public = poll.publicity, hasResults, !disableAllActions {
|
||||||
self.votersNode.isHidden = true
|
self.votersNode.isHidden = true
|
||||||
|
|
||||||
|
if isBotChat {
|
||||||
|
self.buttonViewResultsTextNode.isHidden = true
|
||||||
|
self.buttonNode.isHidden = true
|
||||||
|
} else {
|
||||||
self.buttonViewResultsTextNode.isHidden = false
|
self.buttonViewResultsTextNode.isHidden = false
|
||||||
self.buttonNode.isHidden = false
|
self.buttonNode.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
if Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
if Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
||||||
self.buttonNode.isUserInteractionEnabled = false
|
self.buttonNode.isUserInteractionEnabled = false
|
||||||
@ -1650,11 +1673,16 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
var isBotChat: Bool = false
|
||||||
|
if let item = self.item, let peer = item.message.peers[item.message.id.peerId] as? TelegramUser, peer.botInfo != nil {
|
||||||
|
isBotChat = true
|
||||||
|
}
|
||||||
|
|
||||||
for optionNode in self.optionNodes {
|
for optionNode in self.optionNodes {
|
||||||
if optionNode.frame.contains(point), case .tap = gesture {
|
if optionNode.frame.contains(point), case .tap = gesture {
|
||||||
if optionNode.isUserInteractionEnabled {
|
if optionNode.isUserInteractionEnabled {
|
||||||
return .ignore
|
return .ignore
|
||||||
} else if let result = optionNode.currentResult, let item = self.item, !Namespaces.Message.allScheduled.contains(item.message.id.namespace), let poll = self.poll, let option = optionNode.option {
|
} else if let result = optionNode.currentResult, let item = self.item, !Namespaces.Message.allScheduled.contains(item.message.id.namespace), let poll = self.poll, let option = optionNode.option, !isBotChat {
|
||||||
switch poll.publicity {
|
switch poll.publicity {
|
||||||
case .anonymous:
|
case .anonymous:
|
||||||
let string: String
|
let string: String
|
||||||
|
@ -89,7 +89,7 @@ private final class FeaturedPackEntry: Identifiable, Comparable {
|
|||||||
|
|
||||||
func item(account: Account, interaction: FeaturedInteraction, grid: Bool) -> GridItem {
|
func item(account: Account, interaction: FeaturedInteraction, grid: Bool) -> GridItem {
|
||||||
let info = self.info
|
let info = self.info
|
||||||
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, installed: self.installed, unread: self.unread, open: {
|
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, listAppearance: true, info: self.info, topItems: self.topItems, grid: grid, topSeparator: self.topSeparator, installed: self.installed, unread: self.unread, open: {
|
||||||
interaction.openPack(info)
|
interaction.openPack(info)
|
||||||
}, install: {
|
}, install: {
|
||||||
interaction.installPack(info, !self.installed)
|
interaction.installPack(info, !self.installed)
|
||||||
@ -303,6 +303,9 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
|||||||
self.searchNode?.updateActivity = { [weak self] activity in
|
self.searchNode?.updateActivity = { [weak self] activity in
|
||||||
self?.controller?.searchNavigationNode?.setActivity(activity)
|
self?.controller?.searchNavigationNode?.setActivity(activity)
|
||||||
}
|
}
|
||||||
|
self.searchNode?.deactivateSearchBar = { [weak self] in
|
||||||
|
self?.view.endEditing(true)
|
||||||
|
}
|
||||||
|
|
||||||
let interaction = FeaturedInteraction(
|
let interaction = FeaturedInteraction(
|
||||||
installPack: { [weak self] info, install in
|
installPack: { [weak self] info, install in
|
||||||
@ -478,6 +481,15 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
|||||||
self.loadMoreDisposable.dispose()
|
self.loadMoreDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updatePresentationData(presentationData: PresentationData) {
|
||||||
|
self.presentationData = presentationData
|
||||||
|
|
||||||
|
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||||
|
|
||||||
|
self.searchNode?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private func loadMore() {
|
private func loadMore() {
|
||||||
if self.isLoadingMore || !self.canLoadMore {
|
if self.isLoadingMore || !self.canLoadMore {
|
||||||
return
|
return
|
||||||
@ -506,6 +518,8 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
|||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
|
self.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
|
|
||||||
self.view.addGestureRecognizer(PeekControllerGestureRecognizer(contentAtPoint: { [weak self] point in
|
self.view.addGestureRecognizer(PeekControllerGestureRecognizer(contentAtPoint: { [weak self] point in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return nil
|
return nil
|
||||||
@ -667,7 +681,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
|||||||
if let searchNode = self.searchNode {
|
if let searchNode = self.searchNode {
|
||||||
let searchNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top))
|
let searchNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top))
|
||||||
transition.updateFrame(node: searchNode, frame: searchNodeFrame)
|
transition.updateFrame(node: searchNode, frame: searchNodeFrame)
|
||||||
searchNode.updateLayout(size: searchNodeFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: insets.bottom, inputHeight: layout.inputHeight ?? 0.0, deviceMetrics: layout.deviceMetrics, transition: transition)
|
searchNode.updateLayout(size: searchNodeFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: insets.bottom + layout.safeInsets.bottom, inputHeight: layout.inputHeight ?? 0.0, deviceMetrics: layout.deviceMetrics, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemSize: CGSize
|
let itemSize: CGSize
|
||||||
@ -677,7 +691,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode {
|
|||||||
itemSize = CGSize(width: layout.size.width, height: 128.0)
|
itemSize = CGSize(width: layout.size.width, height: 128.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: UIEdgeInsets(top: insets.top, left: layout.safeInsets.left, bottom: insets.bottom, right: layout.safeInsets.right), preloadSize: 300.0, type: .fixed(itemSize: itemSize, fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: UIEdgeInsets(top: insets.top, left: layout.safeInsets.left, bottom: insets.bottom + layout.safeInsets.bottom, right: layout.safeInsets.right), preloadSize: 300.0, type: .fixed(itemSize: itemSize, fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
|
|
||||||
transition.updateFrame(node: self.gridNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)))
|
transition.updateFrame(node: self.gridNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)))
|
||||||
|
|
||||||
@ -751,6 +765,7 @@ final class FeaturedStickersScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
|
private var presentationDataDisposable: Disposable?
|
||||||
|
|
||||||
private let _ready = Promise<Bool>()
|
private let _ready = Promise<Bool>()
|
||||||
override public var ready: Promise<Bool> {
|
override public var ready: Promise<Bool> {
|
||||||
@ -777,12 +792,36 @@ final class FeaturedStickersScreen: ViewController {
|
|||||||
self.searchNavigationNode = searchNavigationNode
|
self.searchNavigationNode = searchNavigationNode
|
||||||
|
|
||||||
self.navigationBar?.setContentNode(searchNavigationNode, animated: false)
|
self.navigationBar?.setContentNode(searchNavigationNode, animated: false)
|
||||||
|
|
||||||
|
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||||
|
if let strongSelf = self {
|
||||||
|
let previous = strongSelf.presentationData
|
||||||
|
strongSelf.presentationData = presentationData
|
||||||
|
|
||||||
|
if previous.theme !== presentationData.theme || previous.strings !== presentationData.strings {
|
||||||
|
strongSelf.updatePresentationData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
required init(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.presentationDataDisposable?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updatePresentationData() {
|
||||||
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
|
self.searchNavigationNode?.updatePresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
||||||
|
|
||||||
|
self.controllerNode.updatePresentationData(presentationData: presentationData)
|
||||||
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = FeaturedStickersScreenNode(
|
self.displayNode = FeaturedStickersScreenNode(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
@ -816,8 +855,8 @@ final class FeaturedStickersScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class SearchNavigationContentNode: NavigationBarContentNode {
|
private final class SearchNavigationContentNode: NavigationBarContentNode {
|
||||||
private let theme: PresentationTheme
|
private var theme: PresentationTheme
|
||||||
private let strings: PresentationStrings
|
private var strings: PresentationStrings
|
||||||
|
|
||||||
private let cancel: () -> Void
|
private let cancel: () -> Void
|
||||||
|
|
||||||
@ -851,6 +890,13 @@ private final class SearchNavigationContentNode: NavigationBarContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updatePresentationData(theme: PresentationTheme, strings: PresentationStrings) {
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
|
||||||
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: theme), strings: strings)
|
||||||
|
}
|
||||||
|
|
||||||
func setQueryUpdated(_ f: @escaping (String, String?) -> Void) {
|
func setQueryUpdated(_ f: @escaping (String, String?) -> Void) {
|
||||||
self.queryUpdated = f
|
self.queryUpdated = f
|
||||||
}
|
}
|
||||||
@ -951,7 +997,7 @@ private enum FeaturedSearchEntry: Identifiable, Comparable {
|
|||||||
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
|
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
|
||||||
})
|
})
|
||||||
case let .global(_, info, topItems, installed, topSeparator):
|
case let .global(_, info, topItems, installed, topSeparator):
|
||||||
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
|
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
|
||||||
interaction.open(info)
|
interaction.open(info)
|
||||||
}, install: {
|
}, install: {
|
||||||
interaction.install(info, topItems, !installed)
|
interaction.install(info, topItems, !installed)
|
||||||
|
@ -104,7 +104,7 @@ private enum StickerSearchEntry: Identifiable, Comparable {
|
|||||||
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
|
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
|
||||||
})
|
})
|
||||||
case let .global(_, info, topItems, installed, topSeparator):
|
case let .global(_, info, topItems, installed, topSeparator):
|
||||||
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
|
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, listAppearance: false, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
|
||||||
interaction.open(info)
|
interaction.open(info)
|
||||||
}, install: {
|
}, install: {
|
||||||
interaction.install(info, topItems, !installed)
|
interaction.install(info, topItems, !installed)
|
||||||
|
@ -37,6 +37,7 @@ final class StickerPaneSearchGlobalItem: GridItem {
|
|||||||
let account: Account
|
let account: Account
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
|
let listAppearance: Bool
|
||||||
let info: StickerPackCollectionInfo
|
let info: StickerPackCollectionInfo
|
||||||
let topItems: [StickerPackItem]
|
let topItems: [StickerPackItem]
|
||||||
let grid: Bool
|
let grid: Bool
|
||||||
@ -53,10 +54,11 @@ final class StickerPaneSearchGlobalItem: GridItem {
|
|||||||
return self.grid ? nil : (128.0 + (self.topSeparator ? 12.0 : 0.0))
|
return self.grid ? nil : (128.0 + (self.topSeparator ? 12.0 : 0.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, info: StickerPackCollectionInfo, topItems: [StickerPackItem], grid: Bool, topSeparator: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
|
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, listAppearance: Bool, info: StickerPackCollectionInfo, topItems: [StickerPackItem], grid: Bool, topSeparator: Bool, installed: Bool, installing: Bool = false, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
self.listAppearance = listAppearance
|
||||||
self.info = info
|
self.info = info
|
||||||
self.topItems = topItems
|
self.topItems = topItems
|
||||||
self.grid = grid
|
self.grid = grid
|
||||||
@ -95,6 +97,9 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
private let installTextNode: TextNode
|
private let installTextNode: TextNode
|
||||||
private let installBackgroundNode: ASImageNode
|
private let installBackgroundNode: ASImageNode
|
||||||
private let installButtonNode: HighlightTrackingButtonNode
|
private let installButtonNode: HighlightTrackingButtonNode
|
||||||
|
private let uninstallTextNode: TextNode
|
||||||
|
private let uninstallBackgroundNode: ASImageNode
|
||||||
|
private let uninstallButtonNode: HighlightTrackingButtonNode
|
||||||
private var itemNodes: [TrendingTopItemNode]
|
private var itemNodes: [TrendingTopItemNode]
|
||||||
private let topSeparatorNode: ASDisplayNode
|
private let topSeparatorNode: ASDisplayNode
|
||||||
|
|
||||||
@ -149,6 +154,18 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
|
|
||||||
self.installButtonNode = HighlightTrackingButtonNode()
|
self.installButtonNode = HighlightTrackingButtonNode()
|
||||||
|
|
||||||
|
self.uninstallTextNode = TextNode()
|
||||||
|
self.uninstallTextNode.isUserInteractionEnabled = false
|
||||||
|
self.uninstallTextNode.contentMode = .left
|
||||||
|
self.uninstallTextNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
|
self.uninstallBackgroundNode = ASImageNode()
|
||||||
|
self.uninstallBackgroundNode.isLayerBacked = true
|
||||||
|
self.uninstallBackgroundNode.displayWithoutProcessing = true
|
||||||
|
self.uninstallBackgroundNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.uninstallButtonNode = HighlightTrackingButtonNode()
|
||||||
|
|
||||||
self.topSeparatorNode = ASDisplayNode()
|
self.topSeparatorNode = ASDisplayNode()
|
||||||
self.topSeparatorNode.isLayerBacked = true
|
self.topSeparatorNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -162,6 +179,9 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
self.addSubnode(self.installBackgroundNode)
|
self.addSubnode(self.installBackgroundNode)
|
||||||
self.addSubnode(self.installTextNode)
|
self.addSubnode(self.installTextNode)
|
||||||
self.addSubnode(self.installButtonNode)
|
self.addSubnode(self.installButtonNode)
|
||||||
|
self.addSubnode(self.uninstallBackgroundNode)
|
||||||
|
self.addSubnode(self.uninstallTextNode)
|
||||||
|
self.addSubnode(self.uninstallButtonNode)
|
||||||
self.addSubnode(self.topSeparatorNode)
|
self.addSubnode(self.topSeparatorNode)
|
||||||
|
|
||||||
self.installButtonNode.highligthedChanged = { [weak self] highlighted in
|
self.installButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
@ -179,8 +199,24 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.installButtonNode.addTarget(self, action: #selector(self.installPressed), forControlEvents: .touchUpInside)
|
self.installButtonNode.addTarget(self, action: #selector(self.installPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
|
self.uninstallButtonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.uninstallBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.uninstallBackgroundNode.alpha = 0.4
|
||||||
|
strongSelf.uninstallTextNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
strongSelf.uninstallTextNode.alpha = 0.4
|
||||||
|
} else {
|
||||||
|
strongSelf.uninstallBackgroundNode.alpha = 1.0
|
||||||
|
strongSelf.uninstallBackgroundNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
strongSelf.uninstallTextNode.alpha = 1.0
|
||||||
|
strongSelf.uninstallTextNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.uninstallButtonNode.addTarget(self, action: #selector(self.installPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -219,9 +255,14 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
|
|
||||||
self.topSeparatorNode.isHidden = !item.topSeparator
|
self.topSeparatorNode.isHidden = !item.topSeparator
|
||||||
self.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: CGSize(width: params.width - 16.0 * 2.0, height: UIScreenPixel))
|
self.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: CGSize(width: params.width - 16.0 * 2.0, height: UIScreenPixel))
|
||||||
|
if item.listAppearance {
|
||||||
|
self.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
|
||||||
|
} else {
|
||||||
self.topSeparatorNode.backgroundColor = item.theme.chat.inputMediaPanel.stickersSectionTextColor.withAlphaComponent(0.3)
|
self.topSeparatorNode.backgroundColor = item.theme.chat.inputMediaPanel.stickersSectionTextColor.withAlphaComponent(0.3)
|
||||||
|
}
|
||||||
|
|
||||||
let makeInstallLayout = TextNode.asyncLayout(self.installTextNode)
|
let makeInstallLayout = TextNode.asyncLayout(self.installTextNode)
|
||||||
|
let makeUninstallLayout = TextNode.asyncLayout(self.uninstallTextNode)
|
||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
let makeDescriptionLayout = TextNode.asyncLayout(self.descriptionNode)
|
let makeDescriptionLayout = TextNode.asyncLayout(self.descriptionNode)
|
||||||
|
|
||||||
@ -229,33 +270,37 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
self.appliedItem = item
|
self.appliedItem = item
|
||||||
|
|
||||||
var updateButtonBackgroundImage: UIImage?
|
var updateButtonBackgroundImage: UIImage?
|
||||||
if currentItem?.theme !== item.theme || currentItem?.installed != item.installed {
|
var updateUninstallButtonBackgroundImage: UIImage?
|
||||||
if item.installed {
|
if currentItem?.theme !== item.theme {
|
||||||
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddedPackButtonImage(item.theme)
|
updateUninstallButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddedPackButtonImage(item.theme)
|
||||||
} else {
|
|
||||||
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(item.theme)
|
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(item.theme)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let unreadImage = PresentationResourcesItemList.stickerUnreadDotImage(item.theme)
|
let unreadImage = PresentationResourcesItemList.stickerUnreadDotImage(item.theme)
|
||||||
|
|
||||||
let leftInset: CGFloat = 14.0
|
let leftInset: CGFloat = 14.0
|
||||||
let rightInset: CGFloat = 16.0
|
let rightInset: CGFloat = 16.0
|
||||||
|
|
||||||
let (installLayout, installApply) = makeInstallLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.installed ? item.strings.Stickers_Installed : item.strings.Stickers_Install, font: buttonFont, textColor: item.installed ? item.theme.list.itemCheckColors.fillColor : item.theme.list.itemCheckColors.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (installLayout, installApply) = makeInstallLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.Stickers_Install, font: buttonFont, textColor: item.theme.list.itemCheckColors.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.info.title, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset - 20.0 - installLayout.size.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (uninstallLayout, uninstallApply) = makeUninstallLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.Stickers_Installed, font: buttonFont, textColor: item.theme.list.itemCheckColors.fillColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.info.title, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset - 20.0 - max(installLayout.size.width, uninstallLayout.size.width), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let (descriptionLayout, descriptionApply) = makeDescriptionLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.StickerPack_StickerCount(item.info.count), font: statusFont, textColor: item.theme.chat.inputMediaPanel.stickersSectionTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (descriptionLayout, descriptionApply) = makeDescriptionLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.StickerPack_StickerCount(item.info.count), font: statusFont, textColor: item.theme.chat.inputMediaPanel.stickersSectionTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let strongSelf = self
|
let strongSelf = self
|
||||||
|
|
||||||
let _ = installApply()
|
let _ = installApply()
|
||||||
|
let _ = uninstallApply()
|
||||||
let _ = titleApply()
|
let _ = titleApply()
|
||||||
let _ = descriptionApply()
|
let _ = descriptionApply()
|
||||||
|
|
||||||
if let updateButtonBackgroundImage = updateButtonBackgroundImage {
|
if let updateButtonBackgroundImage = updateButtonBackgroundImage {
|
||||||
strongSelf.installBackgroundNode.image = updateButtonBackgroundImage
|
strongSelf.installBackgroundNode.image = updateButtonBackgroundImage
|
||||||
}
|
}
|
||||||
|
if let updateUninstallButtonBackgroundImage = updateUninstallButtonBackgroundImage {
|
||||||
|
strongSelf.uninstallBackgroundNode.image = updateUninstallButtonBackgroundImage
|
||||||
|
}
|
||||||
|
|
||||||
let installWidth: CGFloat = installLayout.size.width + 32.0
|
let installWidth: CGFloat = installLayout.size.width + 32.0
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: params.width - params.rightInset - rightInset - installWidth, y: 4.0 + topOffset), size: CGSize(width: installWidth, height: 28.0))
|
let buttonFrame = CGRect(origin: CGPoint(x: params.width - params.rightInset - rightInset - installWidth, y: 4.0 + topOffset), size: CGSize(width: installWidth, height: 28.0))
|
||||||
@ -263,9 +308,19 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
|||||||
strongSelf.installTextNode.frame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - installLayout.size.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - installLayout.size.height) / 2.0) + 1.0), size: installLayout.size)
|
strongSelf.installTextNode.frame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - installLayout.size.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - installLayout.size.height) / 2.0) + 1.0), size: installLayout.size)
|
||||||
strongSelf.installButtonNode.frame = buttonFrame
|
strongSelf.installButtonNode.frame = buttonFrame
|
||||||
|
|
||||||
strongSelf.installButtonNode.isHidden = false
|
let uninstallWidth: CGFloat = uninstallLayout.size.width + 32.0
|
||||||
strongSelf.installBackgroundNode.isHidden = false
|
let uninstallButtonFrame = CGRect(origin: CGPoint(x: params.width - params.rightInset - rightInset - uninstallWidth, y: 4.0 + topOffset), size: CGSize(width: uninstallWidth, height: 28.0))
|
||||||
strongSelf.installTextNode.isHidden = false
|
strongSelf.uninstallBackgroundNode.frame = uninstallButtonFrame
|
||||||
|
strongSelf.uninstallTextNode.frame = CGRect(origin: CGPoint(x: uninstallButtonFrame.minX + floor((uninstallButtonFrame.width - uninstallLayout.size.width) / 2.0), y: uninstallButtonFrame.minY + floor((uninstallButtonFrame.height - uninstallLayout.size.height) / 2.0) + 1.0), size: uninstallLayout.size)
|
||||||
|
strongSelf.uninstallButtonNode.frame = uninstallButtonFrame
|
||||||
|
|
||||||
|
strongSelf.installButtonNode.isHidden = item.installed
|
||||||
|
strongSelf.installBackgroundNode.isHidden = item.installed
|
||||||
|
strongSelf.installTextNode.isHidden = item.installed
|
||||||
|
|
||||||
|
strongSelf.uninstallButtonNode.isHidden = !item.installed
|
||||||
|
strongSelf.uninstallBackgroundNode.isHidden = !item.installed
|
||||||
|
strongSelf.uninstallTextNode.isHidden = !item.installed
|
||||||
|
|
||||||
let titleFrame = CGRect(origin: CGPoint(x: params.leftInset + leftInset, y: 2.0 + topOffset), size: titleLayout.size)
|
let titleFrame = CGRect(origin: CGPoint(x: params.leftInset + leftInset, y: 2.0 + topOffset), size: titleLayout.size)
|
||||||
strongSelf.titleNode.frame = titleFrame
|
strongSelf.titleNode.frame = titleFrame
|
||||||
|
@ -25,7 +25,7 @@ public enum TooltipActiveTextAction {
|
|||||||
|
|
||||||
private final class TooltipScreenNode: ViewControllerTracingNode {
|
private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||||
private let icon: TooltipScreen.Icon?
|
private let icon: TooltipScreen.Icon?
|
||||||
private let location: CGRect
|
private let location: TooltipScreen.Location
|
||||||
private let shouldDismissOnTouch: (CGPoint) -> TooltipScreen.DismissOnTouch
|
private let shouldDismissOnTouch: (CGPoint) -> TooltipScreen.DismissOnTouch
|
||||||
private let requestDismiss: () -> Void
|
private let requestDismiss: () -> Void
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
init(text: String, textEntities: [MessageTextEntity], icon: TooltipScreen.Icon?, location: CGRect, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: @escaping (TooltipActiveTextItem, TooltipActiveTextAction) -> Void) {
|
init(text: String, textEntities: [MessageTextEntity], icon: TooltipScreen.Icon?, location: TooltipScreen.Location, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: @escaping (TooltipActiveTextItem, TooltipActiveTextAction) -> Void) {
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.location = location
|
self.location = location
|
||||||
self.shouldDismissOnTouch = shouldDismissOnTouch
|
self.shouldDismissOnTouch = shouldDismissOnTouch
|
||||||
@ -184,27 +184,35 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
let textSize = self.textNode.updateLayout(CGSize(width: containerWidth - contentInset * 2.0 - animationSize.width - animationSpacing, height: .greatestFiniteMagnitude))
|
let textSize = self.textNode.updateLayout(CGSize(width: containerWidth - contentInset * 2.0 - animationSize.width - animationSpacing, height: .greatestFiniteMagnitude))
|
||||||
|
|
||||||
let backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
var backgroundFrame: CGRect
|
||||||
|
|
||||||
let backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
let backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
||||||
var backgroundFrame = CGRect(origin: CGPoint(x: self.location.midX - backgroundWidth / 2.0, y: self.location.minY - bottomInset - backgroundHeight), size: CGSize(width: backgroundWidth, height: backgroundHeight))
|
|
||||||
|
var invertArrow = false
|
||||||
|
switch self.location {
|
||||||
|
case let .point(rect):
|
||||||
|
let backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
||||||
|
backgroundFrame = CGRect(origin: CGPoint(x: rect.midX - backgroundWidth / 2.0, y: rect.minY - bottomInset - backgroundHeight), size: CGSize(width: backgroundWidth, height: backgroundHeight))
|
||||||
if backgroundFrame.minX < sideInset {
|
if backgroundFrame.minX < sideInset {
|
||||||
backgroundFrame.origin.x = sideInset
|
backgroundFrame.origin.x = sideInset
|
||||||
}
|
}
|
||||||
if backgroundFrame.maxX > layout.size.width - sideInset {
|
if backgroundFrame.maxX > layout.size.width - sideInset {
|
||||||
backgroundFrame.origin.x = layout.size.width - sideInset - backgroundFrame.width
|
backgroundFrame.origin.x = layout.size.width - sideInset - backgroundFrame.width
|
||||||
}
|
}
|
||||||
var invertArrow = false
|
|
||||||
if backgroundFrame.minY < layout.insets(options: .statusBar).top {
|
if backgroundFrame.minY < layout.insets(options: .statusBar).top {
|
||||||
backgroundFrame.origin.y = self.location.maxY + bottomInset
|
backgroundFrame.origin.y = rect.maxY + bottomInset
|
||||||
invertArrow = true
|
invertArrow = true
|
||||||
}
|
}
|
||||||
self.isArrowInverted = invertArrow
|
self.isArrowInverted = invertArrow
|
||||||
|
case .top:
|
||||||
|
backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: layout.insets(options: [.statusBar]).top + 13.0), size: CGSize(width: layout.size.width - sideInset * 2.0, height: backgroundHeight))
|
||||||
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.containerNode, frame: backgroundFrame)
|
transition.updateFrame(node: self.containerNode, frame: backgroundFrame)
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||||
if let image = self.arrowNode.image {
|
if let image = self.arrowNode.image, case let .point(rect) = self.location {
|
||||||
let arrowSize = image.size
|
let arrowSize = image.size
|
||||||
let arrowCenterX = self.location.midX
|
let arrowCenterX = rect.midX
|
||||||
|
|
||||||
let arrowFrame: CGRect
|
let arrowFrame: CGRect
|
||||||
|
|
||||||
@ -219,11 +227,13 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
ContainedViewLayoutTransition.immediate.updateTransformScale(node: self.arrowContainer, scale: CGPoint(x: 1.0, y: invertArrow ? -1.0 : 1.0))
|
ContainedViewLayoutTransition.immediate.updateTransformScale(node: self.arrowContainer, scale: CGPoint(x: 1.0, y: invertArrow ? -1.0 : 1.0))
|
||||||
|
|
||||||
self.arrowNode.frame = CGRect(origin: CGPoint(), size: arrowFrame.size)
|
self.arrowNode.frame = CGRect(origin: CGPoint(), size: arrowFrame.size)
|
||||||
|
} else {
|
||||||
|
self.arrowNode.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize))
|
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize))
|
||||||
|
|
||||||
transition.updateFrame(node: self.animatedStickerNode, frame: CGRect(origin: CGPoint(x: contentInset - animationInset, y: floor((backgroundHeight - animationSize.height) / 2.0) - animationInset), size: CGSize(width: animationSize.width + animationInset * 2.0, height: animationSize.height + animationInset * 2.0)))
|
transition.updateFrame(node: self.animatedStickerNode, frame: CGRect(origin: CGPoint(x: contentInset - animationInset, y: contentVerticalInset - animationInset), size: CGSize(width: animationSize.width + animationInset * 2.0, height: animationSize.height + animationInset * 2.0)))
|
||||||
self.animatedStickerNode.updateLayout(size: CGSize(width: animationSize.width + animationInset * 2.0, height: animationSize.height + animationInset * 2.0))
|
self.animatedStickerNode.updateLayout(size: CGSize(width: animationSize.width + animationInset * 2.0, height: animationSize.height + animationInset * 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,10 +264,19 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateIn() {
|
func animateIn() {
|
||||||
|
switch self.location {
|
||||||
|
case .top:
|
||||||
|
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
self.containerNode.layer.animateScale(from: 0.96, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
|
if let _ = self.validLayout {
|
||||||
|
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -13.0 - self.backgroundNode.frame.height), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||||
|
}
|
||||||
|
case .point:
|
||||||
self.containerNode.layer.animateSpring(from: NSNumber(value: Float(0.01)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.4, damping: 105.0)
|
self.containerNode.layer.animateSpring(from: NSNumber(value: Float(0.01)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.4, damping: 105.0)
|
||||||
let arrowY: CGFloat = self.isArrowInverted ? self.arrowContainer.frame.minY : self.arrowContainer.frame.maxY
|
let arrowY: CGFloat = self.isArrowInverted ? self.arrowContainer.frame.minY : self.arrowContainer.frame.maxY
|
||||||
self.containerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: self.arrowContainer.frame.midX - self.containerNode.bounds.width / 2.0, y: arrowY - self.containerNode.bounds.height / 2.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.4, damping: 105.0, additive: true)
|
self.containerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: self.arrowContainer.frame.midX - self.containerNode.bounds.width / 2.0, y: arrowY - self.containerNode.bounds.height / 2.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.4, damping: 105.0, additive: true)
|
||||||
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
let animationDelay: Double
|
let animationDelay: Double
|
||||||
switch self.icon {
|
switch self.icon {
|
||||||
@ -275,6 +294,16 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func animateOut(completion: @escaping () -> Void) {
|
func animateOut(completion: @escaping () -> Void) {
|
||||||
|
switch self.location {
|
||||||
|
case .top:
|
||||||
|
self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||||
|
completion()
|
||||||
|
})
|
||||||
|
self.containerNode.layer.animateScale(from: 1.0, to: 0.96, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||||
|
if let _ = self.validLayout {
|
||||||
|
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -13.0 - self.backgroundNode.frame.height), duration: 0.3, removeOnCompletion: false, additive: true)
|
||||||
|
}
|
||||||
|
case .point:
|
||||||
self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
|
||||||
completion()
|
completion()
|
||||||
})
|
})
|
||||||
@ -283,6 +312,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
let arrowY: CGFloat = self.isArrowInverted ? self.arrowContainer.frame.minY : self.arrowContainer.frame.maxY
|
let arrowY: CGFloat = self.isArrowInverted ? self.arrowContainer.frame.minY : self.arrowContainer.frame.maxY
|
||||||
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: self.arrowContainer.frame.midX - self.containerNode.bounds.width / 2.0, y: arrowY - self.containerNode.bounds.height / 2.0), duration: 0.2, removeOnCompletion: false, additive: true)
|
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: self.arrowContainer.frame.midX - self.containerNode.bounds.width / 2.0, y: arrowY - self.containerNode.bounds.height / 2.0), duration: 0.2, removeOnCompletion: false, additive: true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func addRelativeScrollingOffset(_ value: CGFloat, transition: ContainedViewLayoutTransition) {
|
func addRelativeScrollingOffset(_ value: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
self.scrollingContainer.bounds = self.scrollingContainer.bounds.offsetBy(dx: 0.0, dy: value)
|
self.scrollingContainer.bounds = self.scrollingContainer.bounds.offsetBy(dx: 0.0, dy: value)
|
||||||
@ -308,10 +338,15 @@ public final class TooltipScreen: ViewController {
|
|||||||
case dismiss(consume: Bool)
|
case dismiss(consume: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let text: String
|
public enum Location {
|
||||||
private let textEntities: [MessageTextEntity]
|
case point(CGRect)
|
||||||
|
case top
|
||||||
|
}
|
||||||
|
|
||||||
|
public let text: String
|
||||||
|
public let textEntities: [MessageTextEntity]
|
||||||
private let icon: TooltipScreen.Icon?
|
private let icon: TooltipScreen.Icon?
|
||||||
private let location: CGRect
|
private let location: TooltipScreen.Location
|
||||||
private let shouldDismissOnTouch: (CGPoint) -> TooltipScreen.DismissOnTouch
|
private let shouldDismissOnTouch: (CGPoint) -> TooltipScreen.DismissOnTouch
|
||||||
private let openActiveTextItem: (TooltipActiveTextItem, TooltipActiveTextAction) -> Void
|
private let openActiveTextItem: (TooltipActiveTextItem, TooltipActiveTextAction) -> Void
|
||||||
|
|
||||||
@ -324,7 +359,7 @@ public final class TooltipScreen: ViewController {
|
|||||||
|
|
||||||
public var becameDismissed: ((TooltipScreen) -> Void)?
|
public var becameDismissed: ((TooltipScreen) -> Void)?
|
||||||
|
|
||||||
public init(text: String, textEntities: [MessageTextEntity] = [], icon: TooltipScreen.Icon?, location: CGRect, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: @escaping (TooltipActiveTextItem, TooltipActiveTextAction) -> Void = { _, _ in }) {
|
public init(text: String, textEntities: [MessageTextEntity] = [], icon: TooltipScreen.Icon?, location: TooltipScreen.Location, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: @escaping (TooltipActiveTextItem, TooltipActiveTextAction) -> Void = { _, _ in }) {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.textEntities = textEntities
|
self.textEntities = textEntities
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
@ -346,7 +381,7 @@ public final class TooltipScreen: ViewController {
|
|||||||
|
|
||||||
self.controllerNode.animateIn()
|
self.controllerNode.animateIn()
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 20.0, execute: { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 15.0, execute: { [weak self] in
|
||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user