Merge commit '9cf17045e2edf58cb5b99e06640bce81125f42a5'

This commit is contained in:
Ali 2021-08-30 17:44:21 +04:00
commit ed0d8a8409
26 changed files with 369 additions and 178 deletions

View File

@ -6768,3 +6768,21 @@ Sorry for the inconvenience.";
"Chat.NavigationNoChannels" = "You have no unread channels";
"Message.SponsoredLabel" = "sponsored";
"Stickers.Favorites" = "Favorites";
"Stickers.Recent" = "Recent";
"Stickers.Stickers" = "Stickers";
"Stickers.Gifs" = "GIFs";
"Stickers.Trending" = "Trending";
"Stickers.Settings" = "Settings";
"Gif.Emotion.Angry" = "Angry";
"Gif.Emotion.Surprised" = "Surprised";
"Gif.Emotion.Joy" = "Joy";
"Gif.Emotion.Kiss" = "Kiss";
"Gif.Emotion.Hearts" = "Hearts";
"Gif.Emotion.ThumbsUp" = "Thumbs Up";
"Gif.Emotion.ThumbsDown" = "Thumbs Down";
"Gif.Emotion.RollEyes" = "Roll-Eyes";
"Gif.Emotion.Cool" = "Cool";
"Gif.Emotion.Party" = "Party";

View File

@ -328,6 +328,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
private var reorderInProgress: Bool = false
private var reorderingItemsCompleted: (() -> Void)?
private var reorderScrollStartTimestamp: Double?
private var reorderScrollUpdateTimestamp: Double?
private var reorderLastTimestamp: Double?
public var reorderedItemHasShadow = true
@ -570,7 +571,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
for i in 0 ..< self.itemNodes.count {
if let itemNodeIndex = self.itemNodes[i].index, itemNodeIndex != reorderItemIndex {
let itemFrame = self.itemNodes[i].apparentContentFrame
// let itemOffset = itemFrame.midY
let offsetToMin = itemFrame.minY - verticalOffset
let offsetToMax = itemFrame.maxY - verticalOffset
let deltaOffset: CGFloat
@ -579,7 +580,6 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} else {
deltaOffset = offsetToMin
}
// let deltaOffset = min(itemFrame.minY - verticalOffset, itemFrame.maxY - verticalOffset)
if let (_, closestOffset) = closestIndex {
if abs(deltaOffset) < abs(closestOffset) {
closestIndex = (itemNodeIndex, deltaOffset)
@ -590,7 +590,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
}
if let (closestIndexValue, offset) = closestIndex {
//print("closest \(closestIndexValue) offset \(offset)")
// print("closest \(closestIndexValue) offset \(offset)")
var toIndex: Int
if offset > 0 {
toIndex = closestIndexValue
@ -604,7 +604,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
}
if toIndex != reorderItemNode.index {
if let reorderLastTimestamp = self.reorderLastTimestamp, timestamp < reorderLastTimestamp + 0.1 {
if let reorderLastTimestamp = self.reorderLastTimestamp, timestamp < reorderLastTimestamp + 0.2 {
return
}
if reorderNode.currentState?.0 != reorderItemIndex || reorderNode.currentState?.1 != toIndex {
@ -3996,7 +3996,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
var offset: CGFloat = 6.0
if let reorderScrollStartTimestamp = self.reorderScrollStartTimestamp, reorderScrollStartTimestamp + 2.0 < timestamp {
offset *= 2.0
offset *= 1.5
}
if reorderOffset < effectiveInsets.top + 10.0 {
if self.itemNodes[0].apparentFrame.minY < effectiveInsets.top {
@ -4101,7 +4101,13 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
self.enqueueUpdateVisibleItems(synchronous: false)
}
self.checkItemReordering()
if scrollingForReorder {
if let reorderScrollUpdateTimestamp = self.reorderScrollUpdateTimestamp, timestamp < reorderScrollUpdateTimestamp + 0.05 {
return
}
self.reorderScrollUpdateTimestamp = timestamp
self.checkItemReordering(force: true)
}
}
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

View File

@ -47,7 +47,7 @@ public final class ListViewReorderingGestureRecognizer: UIGestureRecognizer {
private func startLongPressTimer() {
self.longPressTimer?.invalidate()
let longPressTimer = SwiftSignalKit.Timer(timeout: 0.8, repeat: false, completion: { [weak self] in
let longPressTimer = SwiftSignalKit.Timer(timeout: 0.6, repeat: false, completion: { [weak self] in
self?.longPressTimerFired()
}, queue: Queue.mainQueue())
self.longPressTimer = longPressTimer

View File

@ -858,6 +858,8 @@ public final class VoiceChatController: ViewController {
private var currentLoadToken: String?
private var scrollAtTop = true
private var effectiveMuteState: GroupCallParticipantsContext.Participant.MuteState? {
if self.pushingToTalk {
return nil
@ -2175,6 +2177,22 @@ public final class VoiceChatController: ViewController {
}
}
self.listNode.visibleContentOffsetChanged = { [weak self] offset in
guard let strongSelf = self else {
return
}
var scrollAtTop = false
if case let .known(value) = offset, value < 180.0 {
scrollAtTop = true
} else {
scrollAtTop = false
}
if scrollAtTop != strongSelf.scrollAtTop {
strongSelf.scrollAtTop = scrollAtTop
strongSelf.updateTitle(transition: .immediate)
}
}
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
guard let strongSelf = self else {
return
@ -2613,8 +2631,14 @@ public final class VoiceChatController: ViewController {
self?.controller?.present(alertController, in: .window(.root))
}), false))
} else {
let text: String
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
text = strongSelf.presentationData.strings.LiveStream_StartRecording
} else {
text = strongSelf.presentationData.strings.VoiceChat_StartRecording
}
if strongSelf.callState?.scheduleTimestamp == nil {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_StartRecording, icon: { theme -> UIImage? in
items.append(.action(ContextMenuActionItem(text: text, icon: { theme -> UIImage? in
return generateStartRecordingIcon(color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
f(.dismissWithoutContent)
@ -2623,9 +2647,28 @@ public final class VoiceChatController: ViewController {
return
}
let controller = VoiceChatRecordingSetupController(context: strongSelf.context, completion: { [weak self] videoOrientation in
if let strongSelf = self {
strongSelf.call.setShouldBeRecording(true, title: "", videoOrientation: videoOrientation)
// let controller = VoiceChatRecordingSetupController(context: strongSelf.context, completion: { [weak self] videoOrientation in
// if let strongSelf = self {
// strongSelf.call.setShouldBeRecording(true, title: "", videoOrientation: videoOrientation)
//
// strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: text), action: { _ in return false })
// strongSelf.call.playTone(.recordingStarted)
// }
// })
let title: String
let text: String
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
title = strongSelf.presentationData.strings.LiveStream_StartRecordingTitle
text = strongSelf.presentationData.strings.LiveStream_StartRecordingText
} else {
title = strongSelf.presentationData.strings.VoiceChat_StartRecordingTitle
text = strongSelf.presentationData.strings.VoiceChat_StartRecordingText
}
let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: title, text: text, placeholder: strongSelf.presentationData.strings.VoiceChat_RecordingTitlePlaceholder, value: nil, maxLength: 40, apply: { title in
if let strongSelf = self, let title = title {
strongSelf.call.setShouldBeRecording(true, title: title, videoOrientation: nil)
let text: String
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
@ -2638,21 +2681,6 @@ public final class VoiceChatController: ViewController {
strongSelf.call.playTone(.recordingStarted)
}
})
// let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: presentationData.strings.VoiceChat_StartRecordingTitle, text: presentationData.strings.VoiceChat_StartRecordingText, placeholder: presentationData.strings.VoiceChat_RecordingTitlePlaceholder, value: nil, maxLength: 40, apply: { title in
// if let strongSelf = self, let title = title {
// strongSelf.call.setShouldBeRecording(true, title: title)
// let text: String
// if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
// text = strongSelf.presentationData.strings.LiveStream_RecordingStarted
// } else {
// text = strongSelf.presentationData.strings.VoiceChat_RecordingStarted
// }
//
// strongSelf.presentUndoOverlay(content: .voiceChatRecording(text: text), action: { _ in return false })
// strongSelf.call.playTone(.recordingStarted)
// }
// })
self?.controller?.present(controller, in: .window(.root))
})))
}
@ -4046,8 +4074,15 @@ public final class VoiceChatController: ViewController {
}
}
var subtitle = self.currentSpeakingSubtitle ?? self.currentSubtitle
var speaking = self.currentSpeakingSubtitle != nil
var subtitle = ""
var speaking = false
if self.scrollAtTop {
subtitle = self.currentSubtitle
speaking = false
} else {
subtitle = self.currentSpeakingSubtitle ?? self.currentSubtitle
speaking = self.currentSpeakingSubtitle != nil
}
if self.isScheduling {
subtitle = ""
speaking = false

View File

@ -565,23 +565,35 @@ private class PreviewIconNode: ASDisplayNode {
override init() {
self.avatar1Node = ASImageNode()
self.avatar1Node.cornerRadius = 4.0
self.avatar1Node.clipsToBounds = true
self.avatar1Node.displaysAsynchronously = false
self.avatar1Node.backgroundColor = UIColor(rgb: 0x834fff)
self.avatar1Node.image = UIImage(bundleImageName: "Call/Avatar1")
self.avatar1Node.contentMode = .bottom
self.avatar2Node = ASImageNode()
self.avatar2Node.cornerRadius = 4.0
self.avatar2Node.clipsToBounds = true
self.avatar2Node.displaysAsynchronously = false
self.avatar2Node.backgroundColor = UIColor(rgb: 0x63d5c9)
self.avatar2Node.image = UIImage(bundleImageName: "Call/Avatar2")
self.avatar2Node.contentMode = .scaleAspectFit
self.avatar3Node = ASImageNode()
self.avatar3Node.cornerRadius = 4.0
self.avatar3Node.clipsToBounds = true
self.avatar3Node.displaysAsynchronously = false
self.avatar3Node.backgroundColor = UIColor(rgb: 0xccff60)
self.avatar3Node.image = UIImage(bundleImageName: "Call/Avatar3")
self.avatar3Node.contentMode = .scaleAspectFit
self.avatar4Node = ASImageNode()
self.avatar4Node.cornerRadius = 4.0
self.avatar4Node.clipsToBounds = true
self.avatar4Node.displaysAsynchronously = false
self.avatar4Node.backgroundColor = UIColor(rgb: 0xf5512a)
self.avatar4Node.image = UIImage(bundleImageName: "Call/Avatar4")
self.avatar4Node.contentMode = .scaleAspectFit
super.init()

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar1.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar3.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Avatar4.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1058,7 +1058,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
accessoryPanelSize = accessoryPanelNode.measure(CGSize(width: layout.size.width, height: layout.size.height))
accessoryPanelNode.updateState(size: layout.size, inset: layout.safeInsets.left, interfaceState: self.chatPresentationInterfaceState)
accessoryPanelNode.animateIn()
if accessoryPanelNode !== self.accessoryPanelNode {
dismissedAccessoryPanelNode = self.accessoryPanelNode
@ -1069,6 +1068,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} else {
self.insertSubnode(accessoryPanelNode, aboveSubnode: self.inputPanelBackgroundNode)
}
accessoryPanelNode.animateIn()
accessoryPanelNode.dismiss = { [weak self, weak accessoryPanelNode] in
if let strongSelf = self, let accessoryPanelNode = accessoryPanelNode, strongSelf.accessoryPanelNode === accessoryPanelNode {

View File

@ -23,6 +23,7 @@ final class ChatMediaInputMetaSectionItem: ListViewItem {
let inputNodeInteraction: ChatMediaInputNodeInteraction
let type: ChatMediaInputMetaSectionItemType
let theme: PresentationTheme
let strings: PresentationStrings
let expanded: Bool
let selectedItem: () -> Void
@ -30,12 +31,13 @@ final class ChatMediaInputMetaSectionItem: ListViewItem {
return true
}
init(account: Account, inputNodeInteraction: ChatMediaInputNodeInteraction, type: ChatMediaInputMetaSectionItemType, theme: PresentationTheme, expanded: Bool, selected: @escaping () -> Void) {
init(account: Account, inputNodeInteraction: ChatMediaInputNodeInteraction, type: ChatMediaInputMetaSectionItemType, theme: PresentationTheme, strings: PresentationStrings, expanded: Bool, selected: @escaping () -> Void) {
self.account = account
self.inputNodeInteraction = inputNodeInteraction
self.type = type
self.selectedItem = selected
self.theme = theme
self.strings = strings
self.expanded = expanded
}
@ -45,7 +47,7 @@ final class ChatMediaInputMetaSectionItem: ListViewItem {
Queue.mainQueue().async {
node.inputNodeInteraction = self.inputNodeInteraction
node.setItem(item: self)
node.updateTheme(account: self.account, theme: self.theme, expanded: self.expanded)
node.updateTheme(account: self.account, theme: self.theme, strings: self.strings, expanded: self.expanded)
node.updateIsHighlighted()
node.updateAppearanceTransition(transition: .immediate)
@ -65,7 +67,7 @@ final class ChatMediaInputMetaSectionItem: ListViewItem {
Queue.mainQueue().async {
completion(ListViewItemNodeLayout(contentSize: self.expanded ? expandedBoundingSize : boundingSize, insets: node().insets), { _ in
(node() as? ChatMediaInputMetaSectionItemNode)?.setItem(item: self)
(node() as? ChatMediaInputMetaSectionItemNode)?.updateTheme(account: self.account, theme: self.theme, expanded: self.expanded)
(node() as? ChatMediaInputMetaSectionItemNode)?.updateTheme(account: self.account, theme: self.theme, strings: self.strings, expanded: self.expanded)
})
}
}
@ -174,7 +176,7 @@ final class ChatMediaInputMetaSectionItemNode: ListViewItemNode {
}
}
func updateTheme(account: Account, theme: PresentationTheme, expanded: Bool) {
func updateTheme(account: Account, theme: PresentationTheme, strings: PresentationStrings, expanded: Bool) {
let imageSize = CGSize(width: 26.0 * 1.6, height: 26.0 * 1.6)
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((expandedBoundingSize.width - imageSize.width) / 2.0), y: floor((expandedBoundingSize.height - imageSize.height) / 2.0) + UIScreenPixel), size: imageSize)
@ -189,49 +191,47 @@ final class ChatMediaInputMetaSectionItemNode: ListViewItemNode {
switch item.type {
case .savedStickers:
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelSavedStickersIcon(theme)
title = "Favorites"
title = strings.Stickers_Favorites
case .recentStickers:
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelRecentStickersIcon(theme)
title = "Recent"
title = strings.Stickers_Recent
case .stickersMode:
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelStickersModeIcon(theme)
title = "Stickers"
title = strings.Stickers_Stickers
case .savedGifs:
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelRecentStickersIcon(theme)
title = "GIFs"
title = strings.Stickers_Gifs
case .trendingGifs:
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelTrendingGifsIcon(theme)
title = "Trending"
title = strings.Stickers_Trending
case let .gifEmoji(emoji, file):
var emoji = emoji
switch emoji {
case "😡":
title = "Angry"
title = strings.Gif_Emotion_Angry
case "😮":
title = "Surprised"
title = strings.Gif_Emotion_Surprised
case "😂":
title = "Joy"
title = strings.Gif_Emotion_Joy
case "😘":
title = "Kiss"
title = strings.Gif_Emotion_Kiss
case "😍":
title = "Hearts"
title = strings.Gif_Emotion_Hearts
case "👍":
title = "Thumbs Up"
title = strings.Gif_Emotion_ThumbsUp
case "👎":
title = "Thumbs Down"
title = strings.Gif_Emotion_ThumbsDown
case "🙄":
title = "Roll-eyes"
title = strings.Gif_Emotion_RollEyes
case "😎":
title = "Cool"
title = strings.Gif_Emotion_Cool
case "🥳":
title = "Party"
title = strings.Gif_Emotion_Party
default:
break
}
self.imageNode.image = nil
if let file = file {
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
let animatedStickerNode: AnimatedStickerNode
if let current = self.animatedStickerNode {
@ -268,7 +268,7 @@ final class ChatMediaInputMetaSectionItemNode: ListViewItemNode {
expandTransition.updateTransformScale(node: self.scalingNode, scale: expandScale)
expandTransition.updatePosition(node: self.scalingNode, position: CGPoint(x: boundsSize.width / 2.0, y: boundsSize.height / 2.0 + (expanded ? -53.0 : -7.0)))
let titleSize = self.titleNode.updateLayout(CGSize(width: expandedBoundingSize.width, height: expandedBoundingSize.height))
let titleSize = self.titleNode.updateLayout(CGSize(width: expandedBoundingSize.width + 10.0, height: expandedBoundingSize.height))
let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((expandedBoundingSize.width - titleSize.width) / 2.0), y: expandedBoundingSize.height - titleSize.height + 6.0), size: titleSize)
let displayTitleFrame = expanded ? titleFrame : CGRect(origin: CGPoint(x: titleFrame.minX, y: self.imageNode.position.y - titleFrame.size.height), size: titleFrame.size)

View File

@ -162,16 +162,16 @@ func preparedChatMediaInputGridEntryTransition(account: Account, view: ItemColle
return ChatMediaInputGridTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: firstIndexInSectionOffset, stationaryItems: stationaryItems, scrollToItem: scrollToItem, updateOpaqueState: opaqueState, animated: animated)
}
func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, temporaryPackOrder: [ItemCollectionId]? = nil, trendingIsDismissed: Bool = false, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, theme: PresentationTheme, hasGifs: Bool = true, hasSettings: Bool = true, expanded: Bool = false) -> [ChatMediaInputPanelEntry] {
func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, temporaryPackOrder: [ItemCollectionId]? = nil, trendingIsDismissed: Bool = false, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, theme: PresentationTheme, strings: PresentationStrings, hasGifs: Bool = true, hasSettings: Bool = true, expanded: Bool = false) -> [ChatMediaInputPanelEntry] {
var entries: [ChatMediaInputPanelEntry] = []
if hasGifs {
entries.append(.recentGifs(theme, expanded))
entries.append(.recentGifs(theme, strings, expanded))
}
if trendingIsDismissed {
entries.append(.trending(true, theme, expanded))
entries.append(.trending(true, theme, strings, expanded))
}
if let savedStickers = savedStickers, !savedStickers.items.isEmpty {
entries.append(.savedStickers(theme, expanded))
entries.append(.savedStickers(theme, strings, expanded))
}
var savedStickerIds = Set<Int64>()
if let savedStickers = savedStickers, !savedStickers.items.isEmpty {
@ -192,7 +192,7 @@ func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: Ordere
}
}
if found {
entries.append(.recentPacks(theme, expanded))
entries.append(.recentPacks(theme, strings, expanded))
}
}
if let peerSpecificPack = peerSpecificPack {
@ -236,25 +236,25 @@ func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: Ordere
}
if hasSettings {
entries.append(.settings(theme, expanded))
entries.append(.settings(theme, strings, expanded))
}
return entries
}
func chatMediaInputPanelGifModeEntries(theme: PresentationTheme, reactions: [String], animatedEmojiStickers: [String: [StickerPackItem]], expanded: Bool) -> [ChatMediaInputPanelEntry] {
func chatMediaInputPanelGifModeEntries(theme: PresentationTheme, strings: PresentationStrings, reactions: [String], animatedEmojiStickers: [String: [StickerPackItem]], expanded: Bool) -> [ChatMediaInputPanelEntry] {
var entries: [ChatMediaInputPanelEntry] = []
entries.append(.stickersMode(theme, expanded))
entries.append(.savedGifs(theme, expanded))
entries.append(.trendingGifs(theme, expanded))
entries.append(.stickersMode(theme, strings, expanded))
entries.append(.savedGifs(theme, strings, expanded))
entries.append(.trendingGifs(theme, strings, expanded))
for reaction in reactions {
entries.append(.gifEmotion(entries.count, theme, reaction, animatedEmojiStickers[reaction]?.first?.file, expanded))
entries.append(.gifEmotion(entries.count, theme, strings, reaction, animatedEmojiStickers[reaction]?.first?.file, expanded))
}
return entries
}
func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, trendingPacks: [FeaturedStickerPackItem], trendingIsDismissed: Bool = false, hasSearch: Bool = true, hasAccessories: Bool = true, strings: PresentationStrings, theme: PresentationTheme) -> [ChatMediaInputGridEntry] {
func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, trendingPacks: [FeaturedStickerPackItem], installedPacks: Set<ItemCollectionId>, trendingIsDismissed: Bool = false, hasSearch: Bool = true, hasAccessories: Bool = true, strings: PresentationStrings, theme: PresentationTheme) -> [ChatMediaInputGridEntry] {
var entries: [ChatMediaInputGridEntry] = []
if hasSearch && view.lower == nil {
@ -282,8 +282,9 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered
}
}
if !trendingIsDismissed {
entries.append(.trendingList(theme: theme, strings: strings, packs: trendingPacks))
let filteredTrending = trendingPacks.filter { !installedPacks.contains($0.info.id) }
if !trendingIsDismissed && !filteredTrending.isEmpty {
entries.append(.trendingList(theme: theme, strings: strings, packs: filteredTrending))
}
if let recentStickers = recentStickers, !recentStickers.items.isEmpty {
@ -621,7 +622,7 @@ final class ChatMediaInputNode: ChatInputNode {
return .single(false)
}
self?.lastReorderItemIndex = toIndex
let fromEntry = entries[fromIndex]
guard case let .stickerPack(_, fromPackInfo, _, _, _) = fromEntry else {
return .single(false)
@ -743,7 +744,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
}
self?.startCollapseTimer(timeout: 1.0)
self?.startCollapseTimer(timeout: 2.0)
})
}
@ -1133,9 +1134,9 @@ final class ChatMediaInputNode: ChatInputNode {
trendingIsDismissed = true
}
let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, temporaryPackOrder: temporaryPackOrder, trendingIsDismissed: trendingIsDismissed, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, theme: theme, expanded: panelExpanded)
let gifPaneEntries = chatMediaInputPanelGifModeEntries(theme: theme, reactions: reactions, animatedEmojiStickers: animatedEmojiStickers, expanded: panelExpanded)
var gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, trendingPacks: trendingPacks, trendingIsDismissed: trendingIsDismissed, strings: strings, theme: theme)
let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, temporaryPackOrder: temporaryPackOrder, trendingIsDismissed: trendingIsDismissed, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, theme: theme, strings: strings, expanded: panelExpanded)
let gifPaneEntries = chatMediaInputPanelGifModeEntries(theme: theme, strings: strings, reactions: reactions, animatedEmojiStickers: animatedEmojiStickers, expanded: panelExpanded)
var gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: peerSpecificPack.0, canInstallPeerSpecificPack: peerSpecificPack.1, trendingPacks: trendingPacks, installedPacks: installedPacks, trendingIsDismissed: trendingIsDismissed, strings: strings, theme: theme)
if view.higher == nil {
var hasTopSeparator = true
@ -1274,7 +1275,7 @@ final class ChatMediaInputNode: ChatInputNode {
strongSelf.panelFocusScrollToIndex = nil
strongSelf.panelFocusInitialPosition = nil
}
strongSelf.startCollapseTimer(timeout: decelerated ? 0.5 : 2.0)
strongSelf.startCollapseTimer(timeout: decelerated ? 0.5 : 2.5)
strongSelf.scrollingStickerPacksListPromise.set(false)
}
@ -1291,6 +1292,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
if let index = index {
strongSelf.panelFocusScrollToIndex = index
strongSelf.panelFocusInitialPosition = position
}
strongSelf.interfaceInteraction?.updateTextInputStateAndMode { inputTextState, inputMode in
if case let .media(mode, expanded, _) = inputMode {
@ -1314,7 +1316,7 @@ final class ChatMediaInputNode: ChatInputNode {
strongSelf.panelFocusScrollToIndex = nil
strongSelf.panelFocusInitialPosition = nil
}
strongSelf.startCollapseTimer(timeout: decelerated ? 0.5 : 2.0)
strongSelf.startCollapseTimer(timeout: decelerated ? 0.5 : 2.5)
}
}
}
@ -2256,24 +2258,26 @@ final class ChatMediaInputNode: ChatInputNode {
}
var scrollToItem: ListViewScrollToItem?
if let targetIndex = self.panelFocusScrollToIndex, !self.listView.isReordering {
var position: ListViewScrollPosition
if self.panelIsFocused {
if let initialPosition = self.panelFocusInitialPosition {
position = .top(96.0 + (initialPosition.y - self.listView.frame.height / 2.0) * 0.5)
if self.paneArrangement.currentIndex == 1 {
if let targetIndex = self.panelFocusScrollToIndex, !self.listView.isReordering {
var position: ListViewScrollPosition
if self.panelIsFocused {
if let initialPosition = self.panelFocusInitialPosition {
position = .top(96.0 + (initialPosition.y - self.listView.frame.height / 2.0) * 0.5)
} else {
position = .top(96.0)
}
} else {
position = .top(96.0)
if let initialPosition = self.panelFocusInitialPosition {
position = .top(self.listView.frame.height / 2.0 + 96.0 + (initialPosition.y - self.listView.frame.height / 2.0))
} else {
position = .top(self.listView.frame.height / 2.0 + 96.0)
}
self.panelFocusScrollToIndex = nil
self.panelFocusInitialPosition = nil
}
} else {
if let initialPosition = self.panelFocusInitialPosition {
position = .top(self.listView.frame.height / 2.0 + 96.0 + (initialPosition.y - self.listView.frame.height / 2.0))
} else {
position = .top(self.listView.frame.height / 2.0 + 96.0)
}
self.panelFocusScrollToIndex = nil
self.panelFocusInitialPosition = nil
scrollToItem = ListViewScrollToItem(index: targetIndex, position: position, animated: true, curve: .Spring(duration: 0.4), directionHint: .Down, displayLink: true)
}
scrollToItem = ListViewScrollToItem(index: targetIndex, position: position, animated: true, curve: .Spring(duration: 0.4), directionHint: .Down, displayLink: true)
}
self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: scrollToItem, updateOpaqueState: transition.updateOpaqueState, completion: { [weak self] _ in
@ -2289,9 +2293,37 @@ final class ChatMediaInputNode: ChatInputNode {
private func enqueueGifPanelTransition(_ transition: ChatMediaInputPanelTransition, firstTime: Bool) {
var options = ListViewDeleteAndInsertOptions()
options.insert(.Synchronous)
options.insert(.LowLatency)
self.gifListView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateOpaqueState: nil, completion: { _ in
if firstTime {
options.insert(.Synchronous)
options.insert(.LowLatency)
} else {
options.insert(.AnimateInsertion)
}
var scrollToItem: ListViewScrollToItem?
if self.paneArrangement.currentIndex == 0 {
if let targetIndex = self.panelFocusScrollToIndex {
var position: ListViewScrollPosition
if self.panelIsFocused {
if let initialPosition = self.panelFocusInitialPosition {
position = .top(96.0 + (initialPosition.y - self.gifListView.frame.height / 2.0) * 0.5)
} else {
position = .top(96.0)
}
} else {
if let initialPosition = self.panelFocusInitialPosition {
position = .top(self.gifListView.frame.height / 2.0 + 96.0 + (initialPosition.y - self.gifListView.frame.height / 2.0))
} else {
position = .top(self.gifListView.frame.height / 2.0 + 96.0)
}
self.panelFocusScrollToIndex = nil
self.panelFocusInitialPosition = nil
}
scrollToItem = ListViewScrollToItem(index: targetIndex, position: position, animated: true, curve: .Spring(duration: 0.4), directionHint: .Down, displayLink: true)
}
}
self.gifListView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: scrollToItem, updateOpaqueState: nil, completion: { _ in
})
}

View File

@ -31,18 +31,18 @@ enum ChatMediaInputPanelEntryStableId: Hashable {
}
enum ChatMediaInputPanelEntry: Comparable, Identifiable {
case recentGifs(PresentationTheme, Bool)
case savedStickers(PresentationTheme, Bool)
case recentPacks(PresentationTheme, Bool)
case trending(Bool, PresentationTheme, Bool)
case settings(PresentationTheme, Bool)
case recentGifs(PresentationTheme, PresentationStrings, Bool)
case savedStickers(PresentationTheme, PresentationStrings, Bool)
case recentPacks(PresentationTheme, PresentationStrings, Bool)
case trending(Bool, PresentationTheme, PresentationStrings, Bool)
case settings(PresentationTheme, PresentationStrings, Bool)
case peerSpecific(theme: PresentationTheme, peer: Peer, expanded: Bool)
case stickerPack(index: Int, info: StickerPackCollectionInfo, topItem: StickerPackItem?, theme: PresentationTheme, expanded: Bool)
case stickersMode(PresentationTheme, Bool)
case savedGifs(PresentationTheme, Bool)
case trendingGifs(PresentationTheme, Bool)
case gifEmotion(Int, PresentationTheme, String, TelegramMediaFile?, Bool)
case stickersMode(PresentationTheme, PresentationStrings, Bool)
case savedGifs(PresentationTheme, PresentationStrings, Bool)
case trendingGifs(PresentationTheme, PresentationStrings, Bool)
case gifEmotion(Int, PresentationTheme, PresentationStrings, String, TelegramMediaFile?, Bool)
var stableId: ChatMediaInputPanelEntryStableId {
switch self {
@ -66,39 +66,39 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
return .savedGifs
case .trendingGifs:
return .trendingGifs
case let .gifEmotion(_, _, emoji, _, _):
case let .gifEmotion(_, _, _, emoji, _, _):
return .gifEmotion(emoji)
}
}
static func ==(lhs: ChatMediaInputPanelEntry, rhs: ChatMediaInputPanelEntry) -> Bool {
switch lhs {
case let .recentGifs(lhsTheme, lhsExpanded):
if case let .recentGifs(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .recentGifs(lhsTheme, lhsStrings, lhsExpanded):
if case let .recentGifs(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .savedStickers(lhsTheme, lhsExpanded):
if case let .savedStickers(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .savedStickers(lhsTheme, lhsStrings, lhsExpanded):
if case let .savedStickers(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .recentPacks(lhsTheme, lhsExpanded):
if case let .recentPacks(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .recentPacks(lhsTheme, lhsStrings, lhsExpanded):
if case let .recentPacks(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .trending(lhsElevated, lhsTheme, lhsExpanded):
if case let .trending(rhsElevated, rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsElevated == rhsElevated, lhsExpanded == rhsExpanded {
case let .trending(lhsElevated, lhsTheme, lhsStrings, lhsExpanded):
if case let .trending(rhsElevated, rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsElevated == rhsElevated, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .settings(lhsTheme, lhsExpanded):
if case let .settings(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .settings(lhsTheme, lhsStrings, lhsExpanded):
if case let .settings(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
@ -115,26 +115,26 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
} else {
return false
}
case let .stickersMode(lhsTheme, lhsExpanded):
if case let .stickersMode(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .stickersMode(lhsTheme, lhsStrings, lhsExpanded):
if case let .stickersMode(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .savedGifs(lhsTheme, lhsExpanded):
if case let .savedGifs(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .savedGifs(lhsTheme, lhsStrings, lhsExpanded):
if case let .savedGifs(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .trendingGifs(lhsTheme, lhsExpanded):
if case let .trendingGifs(rhsTheme, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsExpanded == rhsExpanded {
case let .trendingGifs(lhsTheme, lhsStrings, lhsExpanded):
if case let .trendingGifs(rhsTheme, rhsStrings, rhsExpanded) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsExpanded == rhsExpanded {
return true
} else {
return false
}
case let .gifEmotion(lhsIndex, lhsTheme, lhsEmoji, lhsFile, lhsExpanded):
if case let .gifEmotion(rhsIndex, rhsTheme, rhsEmoji, rhsFile, rhsExpanded) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsEmoji == rhsEmoji, lhsExpanded == rhsExpanded {
case let .gifEmotion(lhsIndex, lhsTheme, lhsStrings, lhsEmoji, lhsFile, lhsExpanded):
if case let .gifEmotion(rhsIndex, rhsTheme, rhsStrings, rhsEmoji, rhsFile, rhsExpanded) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsEmoji == rhsEmoji, lhsExpanded == rhsExpanded {
if let lhsFile = lhsFile, let rhsFile = rhsFile {
if !lhsFile.isEqual(to: rhsFile) {
return false
@ -162,7 +162,7 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
switch rhs {
case .recentGifs, savedStickers:
return false
case let .trending(elevated, _, _) where elevated:
case let .trending(elevated, _, _, _) where elevated:
return false
default:
return true
@ -171,7 +171,7 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
switch rhs {
case .recentGifs, .savedStickers, recentPacks:
return false
case let .trending(elevated, _, _) where elevated:
case let .trending(elevated, _, _, _) where elevated:
return false
default:
return true
@ -180,7 +180,7 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
switch rhs {
case .recentGifs, .savedStickers, recentPacks, .peerSpecific:
return false
case let .trending(elevated, _, _) where elevated:
case let .trending(elevated, _, _, _) where elevated:
return false
default:
return true
@ -189,7 +189,7 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
switch rhs {
case .recentGifs, .savedStickers, .recentPacks, .peerSpecific:
return false
case let .trending(elevated, _, _):
case let .trending(elevated, _, _, _):
if elevated {
return false
} else {
@ -206,7 +206,7 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
default:
return true
}
case let .trending(elevated, _, _):
case let .trending(elevated, _, _, _):
if elevated {
switch rhs {
case .recentGifs, .trending:
@ -237,11 +237,11 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
default:
return true
}
case let .gifEmotion(lhsIndex, _, _, _, _):
case let .gifEmotion(lhsIndex, _, _, _, _, _):
switch rhs {
case .stickersMode, .savedGifs, .trendingGifs:
return false
case let .gifEmotion(rhsIndex, _, _, _, _):
case let .gifEmotion(rhsIndex, _, _, _, _, _):
return lhsIndex < rhsIndex
default:
return true
@ -257,28 +257,28 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
func item(context: AccountContext, inputNodeInteraction: ChatMediaInputNodeInteraction) -> ListViewItem {
switch self {
case let .recentGifs(theme, expanded):
return ChatMediaInputRecentGifsItem(inputNodeInteraction: inputNodeInteraction, theme: theme, expanded: expanded, selected: {
case let .recentGifs(theme, strings, expanded):
return ChatMediaInputRecentGifsItem(inputNodeInteraction: inputNodeInteraction, theme: theme, strings: strings, expanded: expanded, selected: {
let collectionId = ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.recentGifs.rawValue, id: 0)
inputNodeInteraction.navigateToCollectionId(collectionId)
})
case let .savedStickers(theme, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .savedStickers, theme: theme, expanded: expanded, selected: {
case let .savedStickers(theme, strings, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .savedStickers, theme: theme, strings: strings, expanded: expanded, selected: {
let collectionId = ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.savedStickers.rawValue, id: 0)
inputNodeInteraction.navigateToCollectionId(collectionId)
})
case let .recentPacks(theme, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .recentStickers, theme: theme, expanded: expanded, selected: {
case let .recentPacks(theme, strings, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .recentStickers, theme: theme, strings: strings, expanded: expanded, selected: {
let collectionId = ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.recentStickers.rawValue, id: 0)
inputNodeInteraction.navigateToCollectionId(collectionId)
})
case let .trending(elevated, theme, expanded):
return ChatMediaInputTrendingItem(inputNodeInteraction: inputNodeInteraction, elevated: elevated, theme: theme, expanded: expanded, selected: {
case let .trending(elevated, theme, strings, expanded):
return ChatMediaInputTrendingItem(inputNodeInteraction: inputNodeInteraction, elevated: elevated, theme: theme, strings: strings, expanded: expanded, selected: {
let collectionId = ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0)
inputNodeInteraction.navigateToCollectionId(collectionId)
})
case let .settings(theme, expanded):
return ChatMediaInputSettingsItem(inputNodeInteraction: inputNodeInteraction, theme: theme, expanded: expanded, selected: {
case let .settings(theme, strings, expanded):
return ChatMediaInputSettingsItem(inputNodeInteraction: inputNodeInteraction, theme: theme, strings: strings, expanded: expanded, selected: {
inputNodeInteraction.openSettings()
})
case let .peerSpecific(theme, peer, expanded):
@ -290,20 +290,20 @@ enum ChatMediaInputPanelEntry: Comparable, Identifiable {
return ChatMediaInputStickerPackItem(account: context.account, inputNodeInteraction: inputNodeInteraction, collectionId: info.id, collectionInfo: info, stickerPackItem: topItem, index: index, theme: theme, expanded: expanded, selected: {
inputNodeInteraction.navigateToCollectionId(info.id)
})
case let .stickersMode(theme, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .stickersMode, theme: theme, expanded: expanded, selected: {
case let .stickersMode(theme, strings, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .stickersMode, theme: theme, strings: strings, expanded: expanded, selected: {
inputNodeInteraction.navigateBackToStickers()
})
case let .savedGifs(theme, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .savedGifs, theme: theme, expanded: expanded, selected: {
case let .savedGifs(theme, strings, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .savedGifs, theme: theme, strings: strings, expanded: expanded, selected: {
inputNodeInteraction.setGifMode(.recent)
})
case let .trendingGifs(theme, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .trendingGifs, theme: theme, expanded: expanded, selected: {
case let .trendingGifs(theme, strings, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .trendingGifs, theme: theme, strings: strings, expanded: expanded, selected: {
inputNodeInteraction.setGifMode(.trending)
})
case let .gifEmotion(_, theme, emoji, file, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .gifEmoji(emoji, file), theme: theme, expanded: expanded, selected: {
case let .gifEmotion(_, theme, strings, emoji, file, expanded):
return ChatMediaInputMetaSectionItem(account: context.account, inputNodeInteraction: inputNodeInteraction, type: .gifEmoji(emoji, file), theme: theme, strings: strings, expanded: expanded, selected: {
inputNodeInteraction.setGifMode(.emojiSearch(emoji))
})
}

View File

@ -12,15 +12,17 @@ final class ChatMediaInputRecentGifsItem: ListViewItem {
let selectedItem: () -> Void
let expanded: Bool
let theme: PresentationTheme
let strings: PresentationStrings
var selectable: Bool {
return true
}
init(inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, expanded: Bool, selected: @escaping () -> Void) {
init(inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, strings: PresentationStrings, expanded: Bool, selected: @escaping () -> Void) {
self.inputNodeInteraction = inputNodeInteraction
self.selectedItem = selected
self.theme = theme
self.strings = strings
self.expanded = expanded
}
@ -33,7 +35,7 @@ final class ChatMediaInputRecentGifsItem: ListViewItem {
node.updateIsHighlighted()
node.updateAppearanceTransition(transition: .immediate)
Queue.mainQueue().async {
node.updateTheme(theme: self.theme, expanded: self.expanded)
node.updateTheme(theme: self.theme, strings: self.strings, expanded: self.expanded)
completion(node, {
return (nil, { _ in })
})
@ -44,7 +46,7 @@ final class ChatMediaInputRecentGifsItem: ListViewItem {
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
Queue.mainQueue().async {
completion(ListViewItemNodeLayout(contentSize: self.expanded ? expandedBoundingSize : boundingSize, insets: ChatMediaInputNode.setupPanelIconInsets(item: self, previousItem: previousItem, nextItem: nextItem)), { _ in
(node() as? ChatMediaInputRecentGifsItemNode)?.updateTheme(theme: self.theme, expanded: self.expanded)
(node() as? ChatMediaInputRecentGifsItemNode)?.updateTheme(theme: self.theme, strings: self.strings, expanded: self.expanded)
})
}
}
@ -105,14 +107,14 @@ final class ChatMediaInputRecentGifsItemNode: ListViewItemNode {
deinit {
}
func updateTheme(theme: PresentationTheme, expanded: Bool) {
func updateTheme(theme: PresentationTheme, strings: PresentationStrings, expanded: Bool) {
if self.theme !== theme {
self.theme = theme
self.highlightNode.image = PresentationResourcesChat.chatMediaInputPanelHighlightedIconImage(theme)
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelRecentGifsIconImage(theme)
self.titleNode.attributedText = NSAttributedString(string: "GIFs", font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: strings.Stickers_Gifs, font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor)
}
let imageSize = CGSize(width: 26.0 * 1.6, height: 26.0 * 1.6)

View File

@ -12,15 +12,17 @@ final class ChatMediaInputSettingsItem: ListViewItem {
let selectedItem: () -> Void
let expanded: Bool
let theme: PresentationTheme
let strings: PresentationStrings
var selectable: Bool {
return true
}
init(inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, expanded: Bool, selected: @escaping () -> Void) {
init(inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, strings: PresentationStrings, expanded: Bool, selected: @escaping () -> Void) {
self.inputNodeInteraction = inputNodeInteraction
self.selectedItem = selected
self.theme = theme
self.strings = strings
self.expanded = expanded
}
@ -32,7 +34,7 @@ final class ChatMediaInputSettingsItem: ListViewItem {
node.inputNodeInteraction = self.inputNodeInteraction
node.updateAppearanceTransition(transition: .immediate)
Queue.mainQueue().async {
node.updateTheme(theme: self.theme, expanded: self.expanded)
node.updateTheme(theme: self.theme, strings: self.strings, expanded: self.expanded)
completion(node, {
return (nil, { _ in })
})
@ -43,7 +45,7 @@ final class ChatMediaInputSettingsItem: ListViewItem {
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
Queue.mainQueue().async {
completion(ListViewItemNodeLayout(contentSize: self.expanded ? expandedBoundingSize : boundingSize, insets: ChatMediaInputNode.setupPanelIconInsets(item: self, previousItem: previousItem, nextItem: nextItem)), { _ in
(node() as? ChatMediaInputSettingsItemNode)?.updateTheme(theme: self.theme, expanded: self.expanded)
(node() as? ChatMediaInputSettingsItemNode)?.updateTheme(theme: self.theme, strings: self.strings, expanded: self.expanded)
})
}
}
@ -96,7 +98,7 @@ final class ChatMediaInputSettingsItemNode: ListViewItemNode {
self.scalingNode.addSubnode(self.imageNode)
}
func updateTheme(theme: PresentationTheme, expanded: Bool) {
func updateTheme(theme: PresentationTheme, strings: PresentationStrings, expanded: Bool) {
let imageSize = CGSize(width: 26.0 * 1.6, height: 26.0 * 1.6)
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((expandedBoundingSize.width - imageSize.width) / 2.0), y: floor((expandedBoundingSize.height - imageSize.height) / 2.0) + UIScreenPixel), size: imageSize)
@ -105,7 +107,7 @@ final class ChatMediaInputSettingsItemNode: ListViewItemNode {
self.imageNode.image = PresentationResourcesChat.chatInputMediaPanelSettingsIconImage(theme)
self.titleNode.attributedText = NSAttributedString(string: "Settings", font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: strings.Stickers_Settings, font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor)
}
self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize)

View File

@ -349,7 +349,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
snapshotImageNode = imageNode
case let .animated(resource, _):
let animatedStickerNode = AnimatedStickerNode()
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .direct(cachePathPrefix: nil))
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
scalingNode.addSubnode(animatedStickerNode)

View File

@ -119,6 +119,8 @@ final class ChatMediaInputStickerPane: ChatMediaInputPane {
}
if let itemNode = itemNode as? ChatMediaInputStickerGridItemNode {
itemNode.updateIsPanelVisible(strongSelf.isPaneVisible)
} else if let itemNode = itemNode as? StickerPaneTrendingListGridItemNode {
itemNode.updateIsPanelVisible(strongSelf.isPaneVisible)
}
}
self.gridNode.scrollView.alwaysBounceVertical = true
@ -182,6 +184,8 @@ final class ChatMediaInputStickerPane: ChatMediaInputPane {
itemNode.updateIsPanelVisible(isVisible)
} else if let itemNode = itemNode as? StickerPaneSearchGlobalItemNode {
itemNode.updateCanPlayMedia()
} else if let itemNode = itemNode as? StickerPaneTrendingListGridItemNode {
itemNode.updateIsPanelVisible(isVisible)
}
}
}

View File

@ -13,17 +13,19 @@ final class ChatMediaInputTrendingItem: ListViewItem {
let elevated: Bool
let expanded: Bool
let theme: PresentationTheme
let strings: PresentationStrings
var selectable: Bool {
return true
}
init(inputNodeInteraction: ChatMediaInputNodeInteraction, elevated: Bool, theme: PresentationTheme, expanded: Bool, selected: @escaping () -> Void) {
init(inputNodeInteraction: ChatMediaInputNodeInteraction, elevated: Bool, theme: PresentationTheme, strings: PresentationStrings, expanded: Bool, selected: @escaping () -> Void) {
self.inputNodeInteraction = inputNodeInteraction
self.elevated = elevated
self.selectedItem = selected
self.expanded = expanded
self.theme = theme
self.strings = strings
}
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -35,7 +37,7 @@ final class ChatMediaInputTrendingItem: ListViewItem {
node.updateIsHighlighted()
node.updateAppearanceTransition(transition: .immediate)
Queue.mainQueue().async {
node.updateTheme(elevated: self.elevated, theme: self.theme, expanded: self.expanded)
node.updateTheme(elevated: self.elevated, theme: self.theme, strings: self.strings, expanded: self.expanded)
completion(node, {
return (nil, { _ in })
})
@ -46,7 +48,7 @@ final class ChatMediaInputTrendingItem: ListViewItem {
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
Queue.mainQueue().async {
completion(ListViewItemNodeLayout(contentSize: self.expanded ? expandedBoundingSize : boundingSize, insets: ChatMediaInputNode.setupPanelIconInsets(item: self, previousItem: previousItem, nextItem: nextItem)), { _ in
(node() as? ChatMediaInputTrendingItemNode)?.updateTheme(elevated: self.elevated, theme: self.theme, expanded: self.expanded)
(node() as? ChatMediaInputTrendingItemNode)?.updateTheme(elevated: self.elevated, theme: self.theme, strings: self.strings, expanded: self.expanded)
})
}
}
@ -113,7 +115,7 @@ final class ChatMediaInputTrendingItemNode: ListViewItemNode {
self.currentCollectionId = ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0)
}
func updateTheme(elevated: Bool, theme: PresentationTheme, expanded: Bool) {
func updateTheme(elevated: Bool, theme: PresentationTheme, strings: PresentationStrings, expanded: Bool) {
let imageSize = CGSize(width: 26.0 * 1.85, height: 26.0 * 1.85)
let imageFrame = CGRect(origin: CGPoint(x: floor((expandedBoundingSize.width - imageSize.width) / 2.0), y: floor((expandedBoundingSize.height - imageSize.height) / 2.0) + UIScreenPixel), size: imageSize)
self.imageNode.frame = imageFrame
@ -129,7 +131,7 @@ final class ChatMediaInputTrendingItemNode: ListViewItemNode {
self.badgeBackground.frame = CGRect(origin: CGPoint(x: floor(imageFrame.maxX - image.size.width - 7.0), y: 18.0), size: image.size)
}
self.titleNode.attributedText = NSAttributedString(string: "Trending", font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: strings.Stickers_Trending, font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor)
}
if self.elevated != elevated {

View File

@ -3560,7 +3560,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
if let selectionState = item.controllerInteraction.selectionState, canHaveSelection {
var selected = false
var incoming = true
let incoming = item.content.effectivelyIncoming(item.context.account.peerId, associatedData: item.associatedData)
switch item.content {
case let .message(message, _, _, _):
@ -3576,8 +3576,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
selected = allSelected
}
incoming = item.message.effectivelyIncoming(item.context.account.peerId)
let offset: CGFloat = incoming ? 42.0 : 0.0
if let selectionNode = self.selectionNode {

View File

@ -589,8 +589,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
installedPacks.insert(info.0)
}
let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, theme: theme, hasGifs: false, hasSettings: false)
let gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, trendingPacks: trendingPacks, hasSearch: false, hasAccessories: false, strings: strings, theme: theme)
let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, theme: theme, strings: strings, hasGifs: false, hasSettings: false)
let gridEntries = chatMediaInputGridEntries(view: view, savedStickers: savedStickers, recentStickers: recentStickers, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, trendingPacks: trendingPacks, installedPacks: installedPacks, hasSearch: false, hasAccessories: false, strings: strings, theme: theme)
let (previousPanelEntries, previousGridEntries) = previousStickerEntries.swap((panelEntries, gridEntries))
return (view, preparedChatMediaInputPanelEntryTransition(context: context, from: previousPanelEntries, to: panelEntries, inputNodeInteraction: stickersInputNodeInteraction, scrollToItem: nil), previousPanelEntries.isEmpty, preparedChatMediaInputGridEntryTransition(account: context.account, view: view, from: previousGridEntries, to: gridEntries, update: update, interfaceInteraction: controllerInteraction, inputNodeInteraction: stickersInputNodeInteraction, trendingInteraction: trendingInteraction), previousGridEntries.isEmpty)
@ -624,8 +624,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
installedPacks.insert(info.0)
}
let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: nil, recentStickers: nil, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, theme: theme, hasGifs: false, hasSettings: false)
let gridEntries = chatMediaInputGridEntries(view: view, savedStickers: nil, recentStickers: nil, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, trendingPacks: [], hasSearch: false, hasAccessories: false, strings: strings, theme: theme)
let panelEntries = chatMediaInputPanelEntries(view: view, savedStickers: nil, recentStickers: nil, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, theme: theme, strings: strings, hasGifs: false, hasSettings: false)
let gridEntries = chatMediaInputGridEntries(view: view, savedStickers: nil, recentStickers: nil, peerSpecificPack: nil, canInstallPeerSpecificPack: .none, trendingPacks: [], installedPacks: installedPacks, hasSearch: false, hasAccessories: false, strings: strings, theme: theme)
let (previousPanelEntries, previousGridEntries) = previousMaskEntries.swap((panelEntries, gridEntries))
return (view, preparedChatMediaInputPanelEntryTransition(context: context, from: previousPanelEntries, to: panelEntries, inputNodeInteraction: masksInputNodeInteraction, scrollToItem: nil), previousPanelEntries.isEmpty, preparedChatMediaInputGridEntryTransition(account: context.account, view: view, from: previousGridEntries, to: gridEntries, update: update, interfaceInteraction: controllerInteraction, inputNodeInteraction: masksInputNodeInteraction, trendingInteraction: trendingInteraction), previousGridEntries.isEmpty)

View File

@ -3495,7 +3495,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
canChangeColors = false
}
if canChangeColors {
if false, canChangeColors {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_ChangeColors, icon: { theme in
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in

View File

@ -61,22 +61,22 @@ private enum Entry: Comparable, Identifiable {
}
}
func item(account: Account, inputNodeInteraction: ChatMediaInputNodeInteraction) -> ListViewItem {
func item(account: Account, inputNodeInteraction: ChatMediaInputNodeInteraction, isVisible: @escaping () -> Bool) -> ListViewItem {
switch self {
case let .stickerPack(index, info, topItem, unread, theme):
return FeaturedPackItem(account: account, inputNodeInteraction: inputNodeInteraction, collectionId: info.id, collectionInfo: info, stickerPackItem: topItem, unread: unread, index: index, theme: theme, selected: {
inputNodeInteraction.openTrending(info.id)
})
}, isVisible: isVisible)
}
}
}
private func preparedEntryTransition(account: Account, from fromEntries: [Entry], to toEntries: [Entry], inputNodeInteraction: ChatMediaInputNodeInteraction) -> Transition {
private func preparedEntryTransition(account: Account, from fromEntries: [Entry], to toEntries: [Entry], inputNodeInteraction: ChatMediaInputNodeInteraction, isVisible: @escaping () -> Bool) -> Transition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, inputNodeInteraction: inputNodeInteraction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, inputNodeInteraction: inputNodeInteraction), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, inputNodeInteraction: inputNodeInteraction, isVisible: isVisible), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, inputNodeInteraction: inputNodeInteraction, isVisible: isVisible), directionHint: nil) }
return Transition(deletions: deletions, insertions: insertions, updates: updates)
}
@ -101,12 +101,13 @@ private final class FeaturedPackItem: ListViewItem {
let selectedItem: () -> Void
let index: Int
let theme: PresentationTheme
let isVisible: () -> Bool
var selectable: Bool {
return true
}
init(account: Account, inputNodeInteraction: ChatMediaInputNodeInteraction, collectionId: ItemCollectionId, collectionInfo: StickerPackCollectionInfo, stickerPackItem: StickerPackItem?, unread: Bool, index: Int, theme: PresentationTheme, selected: @escaping () -> Void) {
init(account: Account, inputNodeInteraction: ChatMediaInputNodeInteraction, collectionId: ItemCollectionId, collectionInfo: StickerPackCollectionInfo, stickerPackItem: StickerPackItem?, unread: Bool, index: Int, theme: PresentationTheme, selected: @escaping () -> Void, isVisible: @escaping () -> Bool) {
self.account = account
self.inputNodeInteraction = inputNodeInteraction
self.collectionId = collectionId
@ -116,6 +117,7 @@ private final class FeaturedPackItem: ListViewItem {
self.index = index
self.theme = theme
self.selectedItem = selected
self.isVisible = isVisible
}
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -124,6 +126,7 @@ private final class FeaturedPackItem: ListViewItem {
node.contentSize = boundingSize
node.insets = ChatMediaInputNode.setupPanelIconInsets(item: self, previousItem: previousItem, nextItem: nextItem)
node.inputNodeInteraction = self.inputNodeInteraction
node.panelIsVisible = self.isVisible
Queue.mainQueue().async {
completion(node, {
return (nil, { _ in
@ -161,6 +164,10 @@ private final class FeaturedPackItemNode: ListViewItemNode {
private let stickerFetchedDisposable = MetaDisposable()
var panelIsVisible: () -> Bool = {
return true
}
override var visibility: ListViewItemNodeVisibility {
didSet {
self.visibilityStatus = self.visibility != .none
@ -170,12 +177,17 @@ private final class FeaturedPackItemNode: ListViewItemNode {
var visibilityStatus: Bool = false {
didSet {
if self.visibilityStatus != oldValue {
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
self.animatedStickerNode?.visibility = self.visibilityStatus && loopAnimatedStickers
self.updateVisibility()
}
}
}
func updateVisibility() {
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
let panelVisible = self.panelIsVisible()
self.animatedStickerNode?.visibility = self.visibilityStatus && loopAnimatedStickers && panelVisible
}
init() {
self.containerNode = ASDisplayNode()
self.containerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
@ -278,13 +290,15 @@ private final class FeaturedPackItemNode: ListViewItemNode {
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: resource, animated: true, nilIfEmpty: true))
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
self.imageNode.isHidden = loopAnimatedStickers
let animatedStickerNode: AnimatedStickerNode
if let current = self.animatedStickerNode {
animatedStickerNode = current
} else {
animatedStickerNode = AnimatedStickerNode()
animatedStickerNode.started = { [weak self] in
self?.imageNode.isHidden = true
}
self.animatedStickerNode = animatedStickerNode
if let placeholderNode = self.placeholderNode {
self.containerNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
@ -396,6 +410,7 @@ class StickerPaneTrendingListGridItemNode: GridItemNode {
private var item: StickerPaneTrendingListGridItem?
private var appliedItem: StickerPaneTrendingListGridItem?
private var isPanelVisible = false
override var isVisibleInGrid: Bool {
didSet {
self.updateVisibility()
@ -446,15 +461,32 @@ class StickerPaneTrendingListGridItemNode: GridItemNode {
self.item = item
let entries = panelEntries(featuredPacks: item.trendingPacks, theme: item.theme)
let transition = preparedEntryTransition(account: item.account, from: self.currentEntries, to: entries, inputNodeInteraction: item.inputNodeInteraction)
let transition = preparedEntryTransition(account: item.account, from: self.currentEntries, to: entries, inputNodeInteraction: item.inputNodeInteraction, isVisible: { [weak self] in
if let strongSelf = self {
return strongSelf.isPanelVisible && strongSelf.isVisibleInGrid
} else {
return false
}
})
self.enqueuePanelTransition(transition, firstTime: self.currentEntries.isEmpty)
self.currentEntries = entries
self.setNeedsLayout()
}
func updateIsPanelVisible(_ isPanelVisible: Bool) {
if self.isPanelVisible != isPanelVisible {
self.isPanelVisible = isPanelVisible
self.updateVisibility()
}
}
func updateVisibility() {
self.listView.forEachItemNode { itemNode in
if let itemNode = itemNode as? FeaturedPackItemNode {
itemNode.updateVisibility()
}
}
}
override func layout() {