mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-04 10:30:42 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
5034080e93
@ -591,7 +591,7 @@ public protocol SharedAccountContext: class {
|
|||||||
func makeComposeController(context: AccountContext) -> ViewController
|
func makeComposeController(context: AccountContext) -> ViewController
|
||||||
func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
|
func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
|
||||||
func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController
|
func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController
|
||||||
func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?) -> ListViewItem
|
func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?, backgroundNode: ASDisplayNode?) -> ListViewItem
|
||||||
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
|
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
|
||||||
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
|
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
|
||||||
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController
|
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController
|
||||||
|
@ -12,6 +12,7 @@ swift_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||||
"//submodules/Display:Display",
|
"//submodules/Display:Display",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
private func shiftArray(array: [CGPoint], offset: Int) -> [CGPoint] {
|
private func shiftArray(array: [CGPoint], offset: Int) -> [CGPoint] {
|
||||||
var newArray = array
|
var newArray = array
|
||||||
@ -117,6 +118,26 @@ private func generateGradient(size: CGSize, colors: [UIColor], positions: [CGPoi
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class GradientBackgroundNode: ASDisplayNode {
|
public final class GradientBackgroundNode: ASDisplayNode {
|
||||||
|
public final class CloneNode: ASImageNode {
|
||||||
|
private weak var parentNode: GradientBackgroundNode?
|
||||||
|
private var index: SparseBag<Weak<CloneNode>>.Index?
|
||||||
|
|
||||||
|
public init(parentNode: GradientBackgroundNode) {
|
||||||
|
self.parentNode = parentNode
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.index = parentNode.cloneNodes.add(Weak<CloneNode>(self))
|
||||||
|
self.image = parentNode.contentView.image
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
if let parentNode = self.parentNode, let index = self.index {
|
||||||
|
parentNode.cloneNodes.remove(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static let basePositions: [CGPoint] = [
|
private static let basePositions: [CGPoint] = [
|
||||||
CGPoint(x: 0.80, y: 0.10),
|
CGPoint(x: 0.80, y: 0.10),
|
||||||
CGPoint(x: 0.60, y: 0.20),
|
CGPoint(x: 0.60, y: 0.20),
|
||||||
@ -156,7 +177,8 @@ public final class GradientBackgroundNode: ASDisplayNode {
|
|||||||
var numberOfFrames: Int
|
var numberOfFrames: Int
|
||||||
var curve: ContainedViewLayoutTransitionCurve
|
var curve: ContainedViewLayoutTransitionCurve
|
||||||
}
|
}
|
||||||
private var cachedPhaseTransition: [PhaseTransitionKey: [UIImage]] = [:]
|
|
||||||
|
private let cloneNodes = SparseBag<Weak<CloneNode>>()
|
||||||
|
|
||||||
override public init() {
|
override public init() {
|
||||||
self.contentView = UIImageView()
|
self.contentView = UIImageView()
|
||||||
@ -208,12 +230,32 @@ public final class GradientBackgroundNode: ASDisplayNode {
|
|||||||
animation.isRemovedOnCompletion = true
|
animation.isRemovedOnCompletion = true
|
||||||
self.contentView.layer.removeAnimation(forKey: "contents")
|
self.contentView.layer.removeAnimation(forKey: "contents")
|
||||||
self.contentView.layer.add(animation, forKey: "contents")
|
self.contentView.layer.add(animation, forKey: "contents")
|
||||||
|
|
||||||
|
for cloneNode in self.cloneNodes {
|
||||||
|
if let value = cloneNode.value {
|
||||||
|
value.image = images.last
|
||||||
|
value.layer.removeAnimation(forKey: "contents")
|
||||||
|
value.layer.add(animation.copy() as! CAAnimation, forKey: "contents")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.contentView.image = generateGradient(size: imageSize, colors: colors, positions: positions)
|
let image = generateGradient(size: imageSize, colors: colors, positions: positions)
|
||||||
|
self.contentView.image = image
|
||||||
|
|
||||||
|
for cloneNode in self.cloneNodes {
|
||||||
|
cloneNode.value?.image = image
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if sizeUpdated {
|
} else if sizeUpdated {
|
||||||
self.contentView.image = generateGradient(size: imageSize, colors: colors, positions: positions)
|
let image = generateGradient(size: imageSize, colors: colors, positions: positions)
|
||||||
|
self.contentView.image = image
|
||||||
|
|
||||||
|
for cloneNode in self.cloneNodes {
|
||||||
|
cloneNode.value?.image = image
|
||||||
|
}
|
||||||
|
|
||||||
self.validPhase = self.phase
|
self.validPhase = self.phase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
public final class Weak<T: AnyObject> {
|
||||||
|
private weak var _value: T?
|
||||||
|
|
||||||
|
public var value: T? {
|
||||||
|
return self._value
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ value: T) {
|
||||||
|
self._value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class Bag<T> {
|
public final class Bag<T> {
|
||||||
public typealias Index = Int
|
public typealias Index = Int
|
||||||
private var nextIndex: Index = 0
|
private var nextIndex: Index = 0
|
||||||
@ -73,6 +85,46 @@ public final class Bag<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class SparseBag<T>: Sequence {
|
||||||
|
public typealias Index = Int
|
||||||
|
private var nextIndex: Index = 0
|
||||||
|
private var items: [Index: T] = [:]
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public func add(_ item: T) -> Index {
|
||||||
|
let key = self.nextIndex
|
||||||
|
self.nextIndex += 1
|
||||||
|
self.items[key] = item
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
public func get(_ index: Index) -> T? {
|
||||||
|
return self.items[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
public func remove(_ index: Index) {
|
||||||
|
self.items.removeValue(forKey: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func removeAll() {
|
||||||
|
self.items.removeAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
public var isEmpty: Bool {
|
||||||
|
return self.items.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeIterator() -> AnyIterator<T> {
|
||||||
|
var iterator = self.items.makeIterator()
|
||||||
|
return AnyIterator { () -> T? in
|
||||||
|
return iterator.next()?.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class CounterBag {
|
public final class CounterBag {
|
||||||
private var nextIndex: Int = 1
|
private var nextIndex: Int = 1
|
||||||
private var items = Set<Int>()
|
private var items = Set<Int>()
|
||||||
|
@ -71,6 +71,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
|
|||||||
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
||||||
|
|
||||||
self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
|
self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
|
||||||
|
self.chatBackgroundNode.updateBubbleTheme(bubbleTheme: self.presentationData.theme, bubbleCorners: self.presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
self.toolbarNode = BubbleSettingsToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)
|
self.toolbarNode = BubbleSettingsToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)
|
||||||
|
|
||||||
@ -170,20 +171,20 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
|
|||||||
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||||
|
|
||||||
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
||||||
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
|
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
|
||||||
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
|
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
|
||||||
|
|
||||||
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -159,7 +159,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil, flags: [])
|
let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil, flags: [])
|
||||||
|
|
||||||
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)
|
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: nil)
|
||||||
|
|
||||||
var node: ListViewItemNode?
|
var node: ListViewItemNode?
|
||||||
if let current = currentNode {
|
if let current = currentNode {
|
||||||
|
@ -83,6 +83,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
||||||
|
|
||||||
self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
|
self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
|
||||||
|
self.chatBackgroundNode.updateBubbleTheme(bubbleTheme: self.presentationData.theme, bubbleCorners: self.presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
self.toolbarNode = TextSelectionToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)
|
self.toolbarNode = TextSelectionToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)
|
||||||
|
|
||||||
@ -316,20 +317,20 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||||
|
|
||||||
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
||||||
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
|
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
|
||||||
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
|
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
|
||||||
|
|
||||||
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -102,10 +102,12 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if colors.count >= 2 {
|
if colors.count >= 2 {
|
||||||
|
self.imageNode.layer.compositingFilter = "softLightBlendMode"
|
||||||
self.backgroundNode.image = generateGradientImage(size: CGSize(width: 80.0, height: 80.0), colors: colors.map(UIColor.init(rgb:)), locations: [0.0, 1.0], direction: .vertical)
|
self.backgroundNode.image = generateGradientImage(size: CGSize(width: 80.0, height: 80.0), colors: colors.map(UIColor.init(rgb:)), locations: [0.0, 1.0], direction: .vertical)
|
||||||
self.backgroundNode.backgroundColor = nil
|
self.backgroundNode.backgroundColor = nil
|
||||||
} else if colors.count >= 1 {
|
} else if colors.count >= 1 {
|
||||||
self.backgroundNode.image = nil
|
self.backgroundNode.image = nil
|
||||||
|
self.imageNode.layer.compositingFilter = "softLightBlendMode"
|
||||||
self.backgroundNode.backgroundColor = UIColor(rgb: colors[0])
|
self.backgroundNode.backgroundColor = UIColor(rgb: colors[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
updatedTheme = theme
|
updatedTheme = theme
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: updatedTheme!, wallpaper: wallpaper, bubbleCorners: bubbleCorners)
|
let _ = PresentationResourcesChat.principalGraphics(theme: updatedTheme!, wallpaper: wallpaper, bubbleCorners: bubbleCorners)
|
||||||
} else {
|
} else {
|
||||||
updatedTheme = nil
|
updatedTheme = nil
|
||||||
}
|
}
|
||||||
@ -486,12 +486,15 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
strongSelf.toolbarNode.updateThemeAndStrings(theme: theme, strings: strongSelf.presentationData.strings)
|
strongSelf.toolbarNode.updateThemeAndStrings(theme: theme, strings: strongSelf.presentationData.strings)
|
||||||
strongSelf.chatListBackgroundNode.backgroundColor = theme.chatList.backgroundColor
|
strongSelf.chatListBackgroundNode.backgroundColor = theme.chatList.backgroundColor
|
||||||
strongSelf.maskNode.image = generateMaskImage(color: theme.chatList.backgroundColor)
|
strongSelf.maskNode.image = generateMaskImage(color: theme.chatList.backgroundColor)
|
||||||
|
|
||||||
|
strongSelf.backgroundNode.updateBubbleTheme(bubbleTheme: theme, bubbleCorners: strongSelf.presentationData.chatBubbleCorners)
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.serviceBackgroundColor = serviceBackgroundColor
|
strongSelf.serviceBackgroundColor = serviceBackgroundColor
|
||||||
strongSelf.serviceBackgroundColorPromise.set(.single(serviceBackgroundColor))
|
strongSelf.serviceBackgroundColorPromise.set(.single(serviceBackgroundColor))
|
||||||
|
|
||||||
strongSelf.backgroundNode.update(wallpaper: wallpaper)
|
strongSelf.backgroundNode.update(wallpaper: wallpaper)
|
||||||
|
|
||||||
strongSelf.ready.set(.single(true))
|
strongSelf.ready.set(.single(true))
|
||||||
|
|
||||||
strongSelf.wallpaper = wallpaper
|
strongSelf.wallpaper = wallpaper
|
||||||
@ -840,7 +843,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
}, clickThroughMessage: { [weak self] in
|
}, clickThroughMessage: { [weak self] in
|
||||||
self?.updateSection(.background)
|
self?.updateSection(.background)
|
||||||
self?.requestSectionUpdate?(.background)
|
self?.requestSectionUpdate?(.background)
|
||||||
})
|
}, backgroundNode: self.backgroundNode)
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
self.ready.set(.single(true))
|
self.ready.set(.single(true))
|
||||||
self.instantChatBackgroundNode.update(wallpaper: wallpaper)
|
self.instantChatBackgroundNode.update(wallpaper: wallpaper)
|
||||||
|
|
||||||
self.instantChatBackgroundNode.view.contentMode = .scaleAspectFill
|
self.instantChatBackgroundNode.view.contentMode = .scaleAspectFill
|
||||||
|
|
||||||
self.remoteChatBackgroundNode = TransformImageNode()
|
self.remoteChatBackgroundNode = TransformImageNode()
|
||||||
@ -197,8 +198,10 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
if gradientColors.count >= 3 {
|
if gradientColors.count >= 3 {
|
||||||
self.chatContainerNode.insertSubnode(self.wallpaperNode, belowSubnode: self.messagesContainerNode)
|
self.chatContainerNode.insertSubnode(self.wallpaperNode, belowSubnode: self.messagesContainerNode)
|
||||||
self.wallpaperNode.update(wallpaper: self.wallpaper)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.wallpaperNode.update(wallpaper: self.wallpaper)
|
||||||
|
self.wallpaperNode.updateBubbleTheme(bubbleTheme: self.previewTheme, bubbleCorners: self.presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
self.remoteChatBackgroundNode.imageUpdated = { [weak self] image in
|
self.remoteChatBackgroundNode.imageUpdated = { [weak self] image in
|
||||||
if let strongSelf = self, strongSelf.blurredNode.supernode != nil {
|
if let strongSelf = self, strongSelf.blurredNode.supernode != nil {
|
||||||
@ -498,7 +501,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
sampleMessages.append(message8)
|
sampleMessages.append(message8)
|
||||||
|
|
||||||
items = sampleMessages.reversed().map { message in
|
items = sampleMessages.reversed().map { message in
|
||||||
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message], theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil)
|
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message], theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
|
@ -133,15 +133,16 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ThemeSettingsChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
func asyncLayout() -> (_ item: ThemeSettingsChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let currentItem = self.item
|
|
||||||
|
|
||||||
let currentNodes = self.messageNodes
|
let currentNodes = self.messageNodes
|
||||||
|
|
||||||
|
var currentBackgroundNode = self.backgroundNode
|
||||||
|
|
||||||
return { item, params, neighbors in
|
return { item, params, neighbors in
|
||||||
var updatedBackgroundSignal: Signal<(UIImage?, Bool)?, NoError>?
|
if currentBackgroundNode == nil {
|
||||||
if currentItem?.wallpaper != item.wallpaper {
|
currentBackgroundNode = WallpaperBackgroundNode(context: item.context)
|
||||||
updatedBackgroundSignal = chatControllerBackgroundImageSignal(wallpaper: item.wallpaper, mediaBox: item.context.sharedContext.accountManager.mediaBox, accountMediaBox: item.context.account.postbox.mediaBox)
|
|
||||||
}
|
}
|
||||||
|
currentBackgroundNode?.update(wallpaper: item.wallpaper)
|
||||||
|
currentBackgroundNode?.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
|
||||||
|
|
||||||
let insets: UIEdgeInsets
|
let insets: UIEdgeInsets
|
||||||
let separatorHeight = UIScreenPixel
|
let separatorHeight = UIScreenPixel
|
||||||
@ -160,7 +161,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode))
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodes: [ListViewItemNode] = []
|
var nodes: [ListViewItemNode] = []
|
||||||
@ -220,10 +221,9 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
|||||||
topOffset += node.frame.size.height
|
topOffset += node.frame.size.height
|
||||||
}
|
}
|
||||||
|
|
||||||
if strongSelf.backgroundNode == nil {
|
if let currentBackgroundNode = currentBackgroundNode, strongSelf.backgroundNode !== currentBackgroundNode {
|
||||||
let backgroundNode = WallpaperBackgroundNode(context: item.context)
|
strongSelf.backgroundNode = currentBackgroundNode
|
||||||
strongSelf.backgroundNode = backgroundNode
|
strongSelf.insertSubnode(currentBackgroundNode, at: 0)
|
||||||
strongSelf.insertSubnode(backgroundNode, at: 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if let updatedBackgroundSignal = updatedBackgroundSignal {
|
/*if let updatedBackgroundSignal = updatedBackgroundSignal {
|
||||||
@ -287,6 +287,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
|||||||
if let backgroundNode = strongSelf.backgroundNode {
|
if let backgroundNode = strongSelf.backgroundNode {
|
||||||
backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
|
backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
|
||||||
backgroundNode.update(wallpaper: item.wallpaper)
|
backgroundNode.update(wallpaper: item.wallpaper)
|
||||||
|
backgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
|
||||||
backgroundNode.updateLayout(size: backgroundNode.bounds.size, transition: .immediate)
|
backgroundNode.updateLayout(size: backgroundNode.bounds.size, transition: .immediate)
|
||||||
}
|
}
|
||||||
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
|
@ -280,6 +280,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
|
|
||||||
var isBlurrable = true
|
var isBlurrable = true
|
||||||
|
|
||||||
|
self.nativeNode.updateBubbleTheme(bubbleTheme: presentationData.theme, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
switch entry {
|
switch entry {
|
||||||
case let .wallpaper(wallpaper, _):
|
case let .wallpaper(wallpaper, _):
|
||||||
if case let .file(_, _, _, _, isPattern, _, _, _, settings) = wallpaper, isPattern {
|
if case let .file(_, _, _, _, isPattern, _, _, _, settings) = wallpaper, isPattern {
|
||||||
@ -1062,10 +1064,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
let theme = self.presentationData.theme.withUpdated(preview: true)
|
let theme = self.presentationData.theme.withUpdated(preview: true)
|
||||||
|
|
||||||
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode))
|
||||||
|
|
||||||
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
|
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode))
|
||||||
|
|
||||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||||
if let _ = self.messageNodes {
|
if let _ = self.messageNodes {
|
||||||
|
@ -1029,7 +1029,7 @@ final class MessageStoryRenderer {
|
|||||||
let theme = self.presentationData.theme.withUpdated(preview: true)
|
let theme = self.presentationData.theme.withUpdated(preview: true)
|
||||||
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.messages.first?.timestamp ?? 0, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.messages.first?.timestamp ?? 0, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
|
||||||
|
|
||||||
let items: [ListViewItem] = [self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: self.messages, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.theme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)]
|
let items: [ListViewItem] = [self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: self.messages, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.theme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: nil)]
|
||||||
|
|
||||||
let inset: CGFloat = 16.0
|
let inset: CGFloat = 16.0
|
||||||
let width = layout.size.width - inset * 2.0
|
let width = layout.size.width - inset * 2.0
|
||||||
|
@ -192,55 +192,48 @@ public final class PrincipalThemeEssentialGraphics {
|
|||||||
|
|
||||||
public let hasWallpaper: Bool
|
public let hasWallpaper: Bool
|
||||||
|
|
||||||
init(mediaBox: MediaBox, presentationTheme: PresentationTheme, wallpaper initialWallpaper: TelegramWallpaper, preview: Bool = false, knockoutMode: Bool, bubbleCorners: PresentationChatBubbleCorners) {
|
init(presentationTheme: PresentationTheme, wallpaper initialWallpaper: TelegramWallpaper, preview: Bool = false, bubbleCorners: PresentationChatBubbleCorners) {
|
||||||
let theme = presentationTheme.chat
|
let theme = presentationTheme.chat
|
||||||
var wallpaper = initialWallpaper
|
let wallpaper = initialWallpaper
|
||||||
self.hasWallpaper = !wallpaper.isEmpty
|
self.hasWallpaper = !wallpaper.isEmpty
|
||||||
|
|
||||||
let incoming: PresentationThemeBubbleColorComponents = wallpaper.isEmpty ? theme.message.incoming.bubble.withoutWallpaper : theme.message.incoming.bubble.withWallpaper
|
let incoming: PresentationThemeBubbleColorComponents = wallpaper.isEmpty ? theme.message.incoming.bubble.withoutWallpaper : theme.message.incoming.bubble.withWallpaper
|
||||||
let outgoing: PresentationThemeBubbleColorComponents = wallpaper.isEmpty ? theme.message.outgoing.bubble.withoutWallpaper : theme.message.outgoing.bubble.withWallpaper
|
let outgoing: PresentationThemeBubbleColorComponents = wallpaper.isEmpty ? theme.message.outgoing.bubble.withoutWallpaper : theme.message.outgoing.bubble.withWallpaper
|
||||||
|
|
||||||
if knockoutMode {
|
var incomingGradientColors: (UIColor, UIColor)?
|
||||||
let wallpaperImage = chatControllerBackgroundImage(theme: presentationTheme, wallpaper: wallpaper, mediaBox: mediaBox, knockoutMode: false)
|
if incoming.fill.rgb != incoming.gradientFill.rgb {
|
||||||
self.incomingBubbleGradientImage = wallpaperImage
|
incomingGradientColors = (incoming.fill, incoming.gradientFill)
|
||||||
self.outgoingBubbleGradientImage = wallpaperImage
|
}
|
||||||
wallpaper = presentationTheme.chat.defaultWallpaper
|
if let incomingGradientColors = incomingGradientColors {
|
||||||
|
self.incomingBubbleGradientImage = generateImage(CGSize(width: 1.0, height: 512.0), opaque: true, scale: 1.0, rotatedContext: { size, context in
|
||||||
|
var locations: [CGFloat] = [0.0, 1.0]
|
||||||
|
let colors = [incomingGradientColors.0.cgColor, incomingGradientColors.1.cgColor] as NSArray
|
||||||
|
|
||||||
|
let colorSpace = deviceColorSpace
|
||||||
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: &locations)!
|
||||||
|
|
||||||
|
context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
var incomingGradientColors: (UIColor, UIColor)?
|
self.incomingBubbleGradientImage = nil
|
||||||
if incoming.fill.rgb != incoming.gradientFill.rgb {
|
}
|
||||||
incomingGradientColors = (incoming.fill, incoming.gradientFill)
|
|
||||||
}
|
var outgoingGradientColors: (UIColor, UIColor)?
|
||||||
if let incomingGradientColors = incomingGradientColors {
|
if outgoing.fill.rgb != outgoing.gradientFill.rgb {
|
||||||
self.incomingBubbleGradientImage = generateImage(CGSize(width: 1.0, height: 512.0), opaque: true, scale: 1.0, rotatedContext: { size, context in
|
outgoingGradientColors = (outgoing.fill, outgoing.gradientFill)
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
}
|
||||||
let colors = [incomingGradientColors.0.cgColor, incomingGradientColors.1.cgColor] as NSArray
|
if let outgoingGradientColors = outgoingGradientColors {
|
||||||
|
self.outgoingBubbleGradientImage = generateImage(CGSize(width: 1.0, height: 512.0), opaque: true, scale: 1.0, rotatedContext: { size, context in
|
||||||
let colorSpace = deviceColorSpace
|
var locations: [CGFloat] = [0.0, 1.0]
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: &locations)!
|
let colors = [outgoingGradientColors.0.cgColor, outgoingGradientColors.1.cgColor] as NSArray
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
let colorSpace = deviceColorSpace
|
||||||
})
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: &locations)!
|
||||||
} else {
|
|
||||||
self.incomingBubbleGradientImage = nil
|
context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
||||||
}
|
})
|
||||||
|
} else {
|
||||||
var outgoingGradientColors: (UIColor, UIColor)?
|
self.outgoingBubbleGradientImage = nil
|
||||||
if outgoing.fill.rgb != outgoing.gradientFill.rgb {
|
|
||||||
outgoingGradientColors = (outgoing.fill, outgoing.gradientFill)
|
|
||||||
}
|
|
||||||
if let outgoingGradientColors = outgoingGradientColors {
|
|
||||||
self.outgoingBubbleGradientImage = generateImage(CGSize(width: 1.0, height: 512.0), opaque: true, scale: 1.0, rotatedContext: { size, context in
|
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
|
||||||
let colors = [outgoingGradientColors.0.cgColor, outgoingGradientColors.1.cgColor] as NSArray
|
|
||||||
|
|
||||||
let colorSpace = deviceColorSpace
|
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: &locations)!
|
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
self.outgoingBubbleGradientImage = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let incomingKnockout = self.incomingBubbleGradientImage != nil
|
let incomingKnockout = self.incomingBubbleGradientImage != nil
|
||||||
|
@ -86,10 +86,10 @@ public struct PresentationResourcesChat {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func principalGraphics(mediaBox: MediaBox, knockoutWallpaper: Bool, theme: PresentationTheme, wallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) -> PrincipalThemeEssentialGraphics {
|
public static func principalGraphics(theme: PresentationTheme, wallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners) -> PrincipalThemeEssentialGraphics {
|
||||||
let hasWallpaper = !wallpaper.isEmpty
|
let hasWallpaper = !wallpaper.isEmpty
|
||||||
return theme.object(PresentationResourceParameterKey.chatPrincipalThemeEssentialGraphics(hasWallpaper: hasWallpaper, bubbleCorners: bubbleCorners), { theme in
|
return theme.object(PresentationResourceParameterKey.chatPrincipalThemeEssentialGraphics(hasWallpaper: hasWallpaper, bubbleCorners: bubbleCorners), { theme in
|
||||||
return PrincipalThemeEssentialGraphics(mediaBox: mediaBox, presentationTheme: theme, wallpaper: wallpaper, preview: theme.preview, knockoutMode: knockoutWallpaper, bubbleCorners: bubbleCorners)
|
return PrincipalThemeEssentialGraphics(presentationTheme: theme, wallpaper: wallpaper, preview: theme.preview, bubbleCorners: bubbleCorners)
|
||||||
}) as! PrincipalThemeEssentialGraphics
|
}) as! PrincipalThemeEssentialGraphics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ import Markdown
|
|||||||
import TelegramPermissionsUI
|
import TelegramPermissionsUI
|
||||||
import Speak
|
import Speak
|
||||||
import UniversalMediaPlayer
|
import UniversalMediaPlayer
|
||||||
|
import WallpaperBackgroundNode
|
||||||
|
|
||||||
extension ChatLocation {
|
extension ChatLocation {
|
||||||
var peerId: PeerId {
|
var peerId: PeerId {
|
||||||
@ -215,7 +216,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
private let galleryHiddenMesageAndMediaDisposable = MetaDisposable()
|
private let galleryHiddenMesageAndMediaDisposable = MetaDisposable()
|
||||||
private let temporaryHiddenGalleryMediaDisposable = MetaDisposable()
|
private let temporaryHiddenGalleryMediaDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private let chatBackgroundNode: WallpaperBackgroundNode
|
||||||
private var controllerInteraction: ChatControllerInteraction?
|
private var controllerInteraction: ChatControllerInteraction?
|
||||||
private var interfaceInteraction: ChatPanelInterfaceInteraction?
|
private var interfaceInteraction: ChatPanelInterfaceInteraction?
|
||||||
|
|
||||||
@ -429,6 +431,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.botStart = botStart
|
self.botStart = botStart
|
||||||
self.peekData = peekData
|
self.peekData = peekData
|
||||||
|
|
||||||
|
self.chatBackgroundNode = WallpaperBackgroundNode(context: context)
|
||||||
|
|
||||||
var locationBroadcastPanelSource: LocationBroadcastPanelSource
|
var locationBroadcastPanelSource: LocationBroadcastPanelSource
|
||||||
var groupCallPanelSource: GroupCallPanelSource
|
var groupCallPanelSource: GroupCallPanelSource
|
||||||
@ -2690,7 +2694,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, cancelInteractiveKeyboardGestures: { [weak self] in
|
}, cancelInteractiveKeyboardGestures: { [weak self] in
|
||||||
(self?.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
|
(self?.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
|
||||||
self?.chatDisplayNode.cancelInteractiveKeyboardGestures()
|
self?.chatDisplayNode.cancelInteractiveKeyboardGestures()
|
||||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings)
|
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(backgroundNode: self.chatBackgroundNode))
|
||||||
|
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
|
|
||||||
@ -4083,7 +4087,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = ChatControllerNode(context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, subject: self.subject, controllerInteraction: self.controllerInteraction!, chatPresentationInterfaceState: self.presentationInterfaceState, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, navigationBar: self.navigationBar, controller: self)
|
self.displayNode = ChatControllerNode(context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, subject: self.subject, controllerInteraction: self.controllerInteraction!, chatPresentationInterfaceState: self.presentationInterfaceState, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, navigationBar: self.navigationBar, backgroundNode: self.chatBackgroundNode, controller: self)
|
||||||
|
|
||||||
self.chatDisplayNode.historyNode.didScrollWithOffset = { [weak self] offset, transition, itemNode in
|
self.chatDisplayNode.historyNode.didScrollWithOffset = { [weak self] offset, transition, itemNode in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
@ -138,6 +138,7 @@ public final class ChatControllerInteraction {
|
|||||||
var searchTextHighightState: (String, [MessageIndex])?
|
var searchTextHighightState: (String, [MessageIndex])?
|
||||||
var seenOneTimeAnimatedMedia = Set<MessageId>()
|
var seenOneTimeAnimatedMedia = Set<MessageId>()
|
||||||
var currentMessageWithLoadingReplyThread: MessageId?
|
var currentMessageWithLoadingReplyThread: MessageId?
|
||||||
|
let presentationContext: ChatPresentationContext
|
||||||
|
|
||||||
init(
|
init(
|
||||||
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,
|
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,
|
||||||
@ -216,7 +217,8 @@ public final class ChatControllerInteraction {
|
|||||||
cancelInteractiveKeyboardGestures: @escaping () -> Void,
|
cancelInteractiveKeyboardGestures: @escaping () -> Void,
|
||||||
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
|
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
|
||||||
pollActionState: ChatInterfacePollActionState,
|
pollActionState: ChatInterfacePollActionState,
|
||||||
stickerSettings: ChatInterfaceStickerSettings
|
stickerSettings: ChatInterfaceStickerSettings,
|
||||||
|
presentationContext: ChatPresentationContext
|
||||||
) {
|
) {
|
||||||
self.openMessage = openMessage
|
self.openMessage = openMessage
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
@ -297,6 +299,8 @@ public final class ChatControllerInteraction {
|
|||||||
|
|
||||||
self.pollActionState = pollActionState
|
self.pollActionState = pollActionState
|
||||||
self.stickerSettings = stickerSettings
|
self.stickerSettings = stickerSettings
|
||||||
|
|
||||||
|
self.presentationContext = presentationContext
|
||||||
}
|
}
|
||||||
|
|
||||||
static var `default`: ChatControllerInteraction {
|
static var `default`: ChatControllerInteraction {
|
||||||
@ -345,6 +349,9 @@ public final class ChatControllerInteraction {
|
|||||||
}, requestMessageUpdate: { _ in
|
}, requestMessageUpdate: { _ in
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
|
pollActionState: ChatInterfacePollActionState(),
|
||||||
|
stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false),
|
||||||
|
presentationContext: ChatPresentationContext(backgroundNode: nil)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
private var onLayoutCompletions: [(ContainedViewLayoutTransition) -> Void] = []
|
private var onLayoutCompletions: [(ContainedViewLayoutTransition) -> Void] = []
|
||||||
|
|
||||||
init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, chatPresentationInterfaceState: ChatPresentationInterfaceState, automaticMediaDownloadSettings: MediaAutoDownloadSettings, navigationBar: NavigationBar?, controller: ChatControllerImpl?) {
|
init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, chatPresentationInterfaceState: ChatPresentationInterfaceState, automaticMediaDownloadSettings: MediaAutoDownloadSettings, navigationBar: NavigationBar?, backgroundNode: WallpaperBackgroundNode, controller: ChatControllerImpl?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.chatLocation = chatLocation
|
self.chatLocation = chatLocation
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
@ -239,8 +239,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.navigationBar = navigationBar
|
self.navigationBar = navigationBar
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
|
||||||
self.backgroundNode = WallpaperBackgroundNode(context: context)
|
self.backgroundNode = backgroundNode
|
||||||
self.backgroundNode.displaysAsynchronously = false
|
|
||||||
|
|
||||||
self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer()
|
self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||||
self.titleAccessoryPanelContainer.clipsToBounds = true
|
self.titleAccessoryPanelContainer.clipsToBounds = true
|
||||||
@ -363,6 +362,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
})
|
})
|
||||||
|
|
||||||
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper)
|
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper)
|
||||||
|
self.backgroundNode.updateBubbleTheme(bubbleTheme: chatPresentationInterfaceState.theme, bubbleCorners: chatPresentationInterfaceState.bubbleCorners)
|
||||||
|
|
||||||
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
|
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
|
||||||
self.historyNode.enableExtractedBackgrounds = true
|
self.historyNode.enableExtractedBackgrounds = true
|
||||||
|
@ -28,7 +28,7 @@ final class ChatImportStatusPanel: ASDisplayNode {
|
|||||||
if self.theme !== presentationData.theme.theme {
|
if self.theme !== presentationData.theme.theme {
|
||||||
self.theme = presentationData.theme.theme
|
self.theme = presentationData.theme.theme
|
||||||
|
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
self.backgroundNode.image = graphics.dateFloatingBackground
|
self.backgroundNode.image = graphics.dateFloatingBackground
|
||||||
self.secondaryBackgroundNode.image = graphics.dateFloatingBackground
|
self.secondaryBackgroundNode.image = graphics.dateFloatingBackground
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import UIKit
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import WallpaperBackgroundNode
|
||||||
|
|
||||||
enum ChatMessageBackgroundMergeType: Equatable {
|
enum ChatMessageBackgroundMergeType: Equatable {
|
||||||
case None, Side, Top(side: Bool), Bottom, Both, Extracted
|
case None, Side, Top(side: Bool), Bottom, Both, Extracted
|
||||||
@ -65,6 +66,7 @@ class ChatMessageBackground: ASDisplayNode {
|
|||||||
private var maskMode: Bool?
|
private var maskMode: Bool?
|
||||||
private let imageNode: ASImageNode
|
private let imageNode: ASImageNode
|
||||||
private let outlineImageNode: ASImageNode
|
private let outlineImageNode: ASImageNode
|
||||||
|
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||||
|
|
||||||
var hasImage: Bool {
|
var hasImage: Bool {
|
||||||
self.imageNode.image != nil
|
self.imageNode.image != nil
|
||||||
@ -92,19 +94,20 @@ class ChatMessageBackground: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setMaskMode(_ maskMode: Bool) {
|
func setMaskMode(_ maskMode: Bool) {
|
||||||
if let type = self.type, let hasWallpaper = self.hasWallpaper, let highlighted = self.currentHighlighted, let graphics = self.graphics {
|
if let type = self.type, let hasWallpaper = self.hasWallpaper, let highlighted = self.currentHighlighted, let graphics = self.graphics, let backgroundNode = self.backgroundNode {
|
||||||
self.setType(type: type, highlighted: highlighted, graphics: graphics, maskMode: maskMode, hasWallpaper: hasWallpaper, transition: .immediate)
|
self.setType(type: type, highlighted: highlighted, graphics: graphics, maskMode: maskMode, hasWallpaper: hasWallpaper, transition: .immediate, backgroundNode: backgroundNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setType(type: ChatMessageBackgroundType, highlighted: Bool, graphics: PrincipalThemeEssentialGraphics, maskMode: Bool, hasWallpaper: Bool, transition: ContainedViewLayoutTransition) {
|
func setType(type: ChatMessageBackgroundType, highlighted: Bool, graphics: PrincipalThemeEssentialGraphics, maskMode: Bool, hasWallpaper: Bool, transition: ContainedViewLayoutTransition, backgroundNode: WallpaperBackgroundNode?) {
|
||||||
let previousType = self.type
|
let previousType = self.type
|
||||||
if let currentType = previousType, currentType == type, self.currentHighlighted == highlighted, self.graphics === graphics, self.maskMode == maskMode, self.hasWallpaper == hasWallpaper {
|
if let currentType = previousType, currentType == type, self.currentHighlighted == highlighted, self.graphics === graphics, backgroundNode === self.backgroundNode, self.maskMode == maskMode, self.hasWallpaper == hasWallpaper {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.type = type
|
self.type = type
|
||||||
self.currentHighlighted = highlighted
|
self.currentHighlighted = highlighted
|
||||||
self.graphics = graphics
|
self.graphics = graphics
|
||||||
|
self.backgroundNode = backgroundNode
|
||||||
self.hasWallpaper = hasWallpaper
|
self.hasWallpaper = hasWallpaper
|
||||||
|
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
@ -113,7 +116,7 @@ class ChatMessageBackground: ASDisplayNode {
|
|||||||
case .none:
|
case .none:
|
||||||
image = nil
|
image = nil
|
||||||
case let .incoming(mergeType):
|
case let .incoming(mergeType):
|
||||||
if maskMode && graphics.incomingBubbleGradientImage != nil {
|
if maskMode, let backgroundNode = backgroundNode, backgroundNode.hasBubbleBackground(for: .incoming) {
|
||||||
image = nil
|
image = nil
|
||||||
} else {
|
} else {
|
||||||
switch mergeType {
|
switch mergeType {
|
||||||
@ -136,7 +139,7 @@ class ChatMessageBackground: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .outgoing(mergeType):
|
case let .outgoing(mergeType):
|
||||||
if maskMode && graphics.outgoingBubbleGradientImage != nil {
|
if maskMode, let backgroundNode = backgroundNode, backgroundNode.hasBubbleBackground(for: .outgoing) {
|
||||||
image = nil
|
image = nil
|
||||||
} else {
|
} else {
|
||||||
switch mergeType {
|
switch mergeType {
|
||||||
|
@ -3,6 +3,7 @@ import AsyncDisplayKit
|
|||||||
import Display
|
import Display
|
||||||
import Postbox
|
import Postbox
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import WallpaperBackgroundNode
|
||||||
|
|
||||||
private let maskInset: CGFloat = 1.0
|
private let maskInset: CGFloat = 1.0
|
||||||
|
|
||||||
@ -54,19 +55,20 @@ func bubbleMaskForType(_ type: ChatMessageBackgroundType, graphics: PrincipalThe
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
||||||
private let backgroundContent: ASDisplayNode
|
private var backgroundContent: WallpaperBackgroundNode.BubbleBackgroundNode?
|
||||||
|
|
||||||
private var currentType: ChatMessageBackgroundType?
|
private var currentType: ChatMessageBackgroundType?
|
||||||
private var currentMaskMode: Bool?
|
private var currentMaskMode: Bool?
|
||||||
private var theme: ChatPresentationThemeData?
|
private var theme: ChatPresentationThemeData?
|
||||||
private var essentialGraphics: PrincipalThemeEssentialGraphics?
|
private var essentialGraphics: PrincipalThemeEssentialGraphics?
|
||||||
|
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||||
|
|
||||||
private var maskView: UIImageView?
|
private var maskView: UIImageView?
|
||||||
|
|
||||||
private var fixedMaskMode: Bool?
|
private var fixedMaskMode: Bool?
|
||||||
|
|
||||||
var hasImage: Bool {
|
var hasImage: Bool {
|
||||||
return self.backgroundContent.contents != nil
|
return self.backgroundContent != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
override var frame: CGRect {
|
override var frame: CGRect {
|
||||||
@ -77,32 +79,34 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
|||||||
maskView.frame = maskFrame
|
maskView.frame = maskFrame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let backgroundContent = self.backgroundContent {
|
||||||
|
backgroundContent.frame = self.bounds
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
self.backgroundContent = ASDisplayNode()
|
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.clipsToBounds = true
|
self.clipsToBounds = true
|
||||||
|
|
||||||
self.addSubnode(self.backgroundContent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMaskMode(_ maskMode: Bool, mediaBox: MediaBox) {
|
func setMaskMode(_ maskMode: Bool, mediaBox: MediaBox) {
|
||||||
if let currentType = self.currentType, let theme = self.theme, let essentialGraphics = self.essentialGraphics {
|
if let currentType = self.currentType, let theme = self.theme, let essentialGraphics = self.essentialGraphics, let backgroundNode = self.backgroundNode {
|
||||||
self.setType(type: currentType, theme: theme, mediaBox: mediaBox, essentialGraphics: essentialGraphics, maskMode: maskMode)
|
self.setType(type: currentType, theme: theme, essentialGraphics: essentialGraphics, maskMode: maskMode, backgroundNode: backgroundNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setType(type: ChatMessageBackgroundType, theme: ChatPresentationThemeData, mediaBox: MediaBox, essentialGraphics: PrincipalThemeEssentialGraphics, maskMode inputMaskMode: Bool) {
|
func setType(type: ChatMessageBackgroundType, theme: ChatPresentationThemeData, essentialGraphics: PrincipalThemeEssentialGraphics, maskMode inputMaskMode: Bool, backgroundNode: WallpaperBackgroundNode?) {
|
||||||
let maskMode = self.fixedMaskMode ?? inputMaskMode
|
let maskMode = self.fixedMaskMode ?? inputMaskMode
|
||||||
|
|
||||||
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.essentialGraphics !== essentialGraphics {
|
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.essentialGraphics !== essentialGraphics || self.backgroundNode !== backgroundNode {
|
||||||
|
let typeUpdated = self.currentType != type
|
||||||
|
|
||||||
self.currentType = type
|
self.currentType = type
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.essentialGraphics = essentialGraphics
|
self.essentialGraphics = essentialGraphics
|
||||||
|
self.backgroundNode = backgroundNode
|
||||||
|
|
||||||
if maskMode != self.currentMaskMode {
|
if maskMode != self.currentMaskMode {
|
||||||
self.currentMaskMode = maskMode
|
self.currentMaskMode = maskMode
|
||||||
@ -124,14 +128,33 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch type {
|
if let backgroundContent = self.backgroundContent {
|
||||||
case .none:
|
backgroundContent.frame = self.bounds
|
||||||
self.backgroundContent.contents = nil
|
}
|
||||||
case .incoming:
|
|
||||||
self.backgroundContent.contents = essentialGraphics.incomingBubbleGradientImage?.cgImage
|
if typeUpdated {
|
||||||
case .outgoing:
|
if let backgroundContent = self.backgroundContent {
|
||||||
self.backgroundContent.contents = essentialGraphics.outgoingBubbleGradientImage?.cgImage
|
self.backgroundContent = nil
|
||||||
|
backgroundContent.removeFromSupernode()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .none:
|
||||||
|
break
|
||||||
|
case .incoming:
|
||||||
|
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .incoming) {
|
||||||
|
backgroundContent.frame = self.bounds
|
||||||
|
self.backgroundContent = backgroundContent
|
||||||
|
self.insertSubnode(backgroundContent, at: 0)
|
||||||
|
}
|
||||||
|
case .outgoing:
|
||||||
|
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .outgoing) {
|
||||||
|
backgroundContent.frame = self.bounds
|
||||||
|
self.backgroundContent = backgroundContent
|
||||||
|
self.insertSubnode(backgroundContent, at: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let maskView = self.maskView {
|
if let maskView = self.maskView {
|
||||||
@ -141,22 +164,28 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func update(rect: CGRect, within containerSize: CGSize) {
|
func update(rect: CGRect, within containerSize: CGSize) {
|
||||||
self.backgroundContent.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
//self.backgroundContent.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
||||||
|
self.backgroundContent?.update(rect: rect, within: containerSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
||||||
let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: animationCurve)
|
//let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: animationCurve)
|
||||||
transition.animatePositionAdditive(node: self.backgroundContent, offset: CGPoint(x: -value.x, y: -value.y))
|
//transition.animatePositionAdditive(node: self.backgroundContent, offset: CGPoint(x: -value.x, y: -value.y))
|
||||||
|
self.backgroundContent?.offset(value: value, animationCurve: animationCurve, duration: duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
||||||
self.backgroundContent.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: value)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: duration, initialVelocity: 0.0, damping: damping, additive: true)
|
//self.backgroundContent.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: value)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: duration, initialVelocity: 0.0, damping: damping, additive: true)
|
||||||
|
self.backgroundContent?.offsetSpring(value: value, duration: duration, damping: damping)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateFrame(_ value: CGRect, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) {
|
func updateFrame(_ value: CGRect, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) {
|
||||||
if let maskView = self.maskView {
|
if let maskView = self.maskView {
|
||||||
transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
||||||
}
|
}
|
||||||
|
if let backgroundContent = self.backgroundContent {
|
||||||
|
transition.updateFrame(node: backgroundContent, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)))
|
||||||
|
}
|
||||||
transition.updateFrame(node: self, frame: value, completion: { _ in
|
transition.updateFrame(node: self, frame: value, completion: { _ in
|
||||||
completion()
|
completion()
|
||||||
})
|
})
|
||||||
@ -166,6 +195,9 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
|||||||
if let maskView = self.maskView {
|
if let maskView = self.maskView {
|
||||||
transition.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
transition.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
||||||
}
|
}
|
||||||
|
if let backgroundContent = self.backgroundContent {
|
||||||
|
transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)))
|
||||||
|
}
|
||||||
transition.updateFrame(layer: self.layer, frame: value, completion: { _ in
|
transition.updateFrame(layer: self.layer, frame: value, completion: { _ in
|
||||||
completion()
|
completion()
|
||||||
})
|
})
|
||||||
|
@ -22,6 +22,8 @@ import PersistentStringHash
|
|||||||
import GridMessageSelectionNode
|
import GridMessageSelectionNode
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import Markdown
|
import Markdown
|
||||||
|
import WallpaperBackgroundNode
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
enum InternalBubbleTapAction {
|
enum InternalBubbleTapAction {
|
||||||
case action(() -> Void)
|
case action(() -> Void)
|
||||||
@ -228,6 +230,14 @@ private enum ContentNodeOperation {
|
|||||||
case insert(index: Int, node: ChatMessageBubbleContentNode)
|
case insert(index: Int, node: ChatMessageBubbleContentNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ChatPresentationContext {
|
||||||
|
weak var backgroundNode: WallpaperBackgroundNode?
|
||||||
|
|
||||||
|
init(backgroundNode: WallpaperBackgroundNode?) {
|
||||||
|
self.backgroundNode = backgroundNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode {
|
class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode {
|
||||||
class ContentContainer {
|
class ContentContainer {
|
||||||
let contentMessageStableId: UInt32
|
let contentMessageStableId: UInt32
|
||||||
@ -237,7 +247,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
var backgroundNode: ChatMessageBackground?
|
var backgroundNode: ChatMessageBackground?
|
||||||
var selectionBackgroundNode: ASDisplayNode?
|
var selectionBackgroundNode: ASDisplayNode?
|
||||||
|
|
||||||
private var currentParams: (size: CGSize, contentOrigin: CGPoint, presentationData: ChatPresentationData, graphics: PrincipalThemeEssentialGraphics, backgroundType: ChatMessageBackgroundType, mediaBox: MediaBox, messageSelection: Bool?, selectionInsets: UIEdgeInsets)?
|
private var currentParams: (size: CGSize, contentOrigin: CGPoint, presentationData: ChatPresentationData, graphics: PrincipalThemeEssentialGraphics, backgroundType: ChatMessageBackgroundType, presentationContext: ChatPresentationContext, mediaBox: MediaBox, messageSelection: Bool?, selectionInsets: UIEdgeInsets)?
|
||||||
|
|
||||||
init(contentMessageStableId: UInt32) {
|
init(contentMessageStableId: UInt32) {
|
||||||
self.contentMessageStableId = contentMessageStableId
|
self.contentMessageStableId = contentMessageStableId
|
||||||
@ -301,8 +311,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
transition.updateAlpha(node: backgroundNode, alpha: 1.0)
|
transition.updateAlpha(node: backgroundNode, alpha: 1.0)
|
||||||
transition.updateAlpha(node: backgroundWallpaperNode, alpha: 1.0)
|
transition.updateAlpha(node: backgroundWallpaperNode, alpha: 1.0)
|
||||||
|
|
||||||
backgroundNode.setType(type: type, highlighted: false, graphics: currentParams.graphics, maskMode: true, hasWallpaper: currentParams.presentationData.theme.wallpaper.hasWallpaper, transition: .immediate)
|
backgroundNode.setType(type: type, highlighted: false, graphics: currentParams.graphics, maskMode: true, hasWallpaper: currentParams.presentationData.theme.wallpaper.hasWallpaper, transition: .immediate, backgroundNode: currentParams.presentationContext.backgroundNode)
|
||||||
backgroundWallpaperNode.setType(type: type, theme: currentParams.presentationData.theme, mediaBox: currentParams.mediaBox, essentialGraphics: currentParams.graphics, maskMode: true)
|
backgroundWallpaperNode.setType(type: type, theme: currentParams.presentationData.theme, essentialGraphics: currentParams.graphics, maskMode: true, backgroundNode: currentParams.presentationContext.backgroundNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let currentParams = self.currentParams {
|
if let currentParams = self.currentParams {
|
||||||
@ -335,8 +345,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
fileprivate func isExtractedToContextPreviewUpdated(_ isExtractedToContextPreview: Bool) {
|
fileprivate func isExtractedToContextPreviewUpdated(_ isExtractedToContextPreview: Bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func update(size: CGSize, contentOrigin: CGPoint, selectionInsets: UIEdgeInsets, index: Int, presentationData: ChatPresentationData, graphics: PrincipalThemeEssentialGraphics, backgroundType: ChatMessageBackgroundType, mediaBox: MediaBox, messageSelection: Bool?) {
|
fileprivate func update(size: CGSize, contentOrigin: CGPoint, selectionInsets: UIEdgeInsets, index: Int, presentationData: ChatPresentationData, graphics: PrincipalThemeEssentialGraphics, backgroundType: ChatMessageBackgroundType, presentationContext: ChatPresentationContext, mediaBox: MediaBox, messageSelection: Bool?) {
|
||||||
self.currentParams = (size, contentOrigin, presentationData, graphics, backgroundType, mediaBox, messageSelection, selectionInsets)
|
self.currentParams = (size, contentOrigin, presentationData, graphics, backgroundType, presentationContext, mediaBox, messageSelection, selectionInsets)
|
||||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
|
||||||
var incoming: Bool = false
|
var incoming: Bool = false
|
||||||
@ -2177,7 +2187,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
|
|
||||||
let layout = ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets)
|
let layout = ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets)
|
||||||
|
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: item.context.account.postbox.mediaBox, knockoutWallpaper: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.principalGraphics(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
var updatedMergedTop = mergedBottom
|
var updatedMergedTop = mergedBottom
|
||||||
var updatedMergedBottom = mergedTop
|
var updatedMergedBottom = mergedTop
|
||||||
@ -2207,6 +2217,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
hideBackground: hideBackground,
|
hideBackground: hideBackground,
|
||||||
incoming: incoming,
|
incoming: incoming,
|
||||||
graphics: graphics,
|
graphics: graphics,
|
||||||
|
presentationContext: item.controllerInteraction.presentationContext,
|
||||||
bubbleContentWidth: bubbleContentWidth,
|
bubbleContentWidth: bubbleContentWidth,
|
||||||
backgroundFrame: backgroundFrame,
|
backgroundFrame: backgroundFrame,
|
||||||
deliveryFailedInset: deliveryFailedInset,
|
deliveryFailedInset: deliveryFailedInset,
|
||||||
@ -2247,6 +2258,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
hideBackground: Bool,
|
hideBackground: Bool,
|
||||||
incoming: Bool,
|
incoming: Bool,
|
||||||
graphics: PrincipalThemeEssentialGraphics,
|
graphics: PrincipalThemeEssentialGraphics,
|
||||||
|
presentationContext: ChatPresentationContext,
|
||||||
bubbleContentWidth: CGFloat,
|
bubbleContentWidth: CGFloat,
|
||||||
backgroundFrame: CGRect,
|
backgroundFrame: CGRect,
|
||||||
deliveryFailedInset: CGFloat,
|
deliveryFailedInset: CGFloat,
|
||||||
@ -2305,8 +2317,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
backgroundType = .incoming(mergeType)
|
backgroundType = .incoming(mergeType)
|
||||||
}
|
}
|
||||||
let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper
|
let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper
|
||||||
strongSelf.backgroundNode.setType(type: backgroundType, highlighted: strongSelf.highlightedState, graphics: graphics, maskMode: strongSelf.backgroundMaskMode, hasWallpaper: hasWallpaper, transition: transition)
|
strongSelf.backgroundNode.setType(type: backgroundType, highlighted: strongSelf.highlightedState, graphics: graphics, maskMode: strongSelf.backgroundMaskMode, hasWallpaper: hasWallpaper, transition: transition, backgroundNode: presentationContext.backgroundNode)
|
||||||
strongSelf.backgroundWallpaperNode.setType(type: backgroundType, theme: item.presentationData.theme, mediaBox: item.context.account.postbox.mediaBox, essentialGraphics: graphics, maskMode: strongSelf.backgroundMaskMode)
|
strongSelf.backgroundWallpaperNode.setType(type: backgroundType, theme: item.presentationData.theme, essentialGraphics: graphics, maskMode: strongSelf.backgroundMaskMode, backgroundNode: presentationContext.backgroundNode)
|
||||||
strongSelf.shadowNode.setType(type: backgroundType, hasWallpaper: hasWallpaper, graphics: graphics)
|
strongSelf.shadowNode.setType(type: backgroundType, hasWallpaper: hasWallpaper, graphics: graphics)
|
||||||
if case .none = backgroundType {
|
if case .none = backgroundType {
|
||||||
strongSelf.clippingNode.clipsToBounds = false
|
strongSelf.clippingNode.clipsToBounds = false
|
||||||
@ -2587,7 +2599,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
selectionInsets.bottom = groupOverlap / 2.0
|
selectionInsets.bottom = groupOverlap / 2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
contentContainer?.update(size: relativeFrame.size, contentOrigin: contentOrigin, selectionInsets: selectionInsets, index: index, presentationData: item.presentationData, graphics: graphics, backgroundType: backgroundType, mediaBox: item.context.account.postbox.mediaBox, messageSelection: itemSelection)
|
contentContainer?.update(size: relativeFrame.size, contentOrigin: contentOrigin, selectionInsets: selectionInsets, index: index, presentationData: item.presentationData, graphics: graphics, backgroundType: backgroundType, presentationContext: item.controllerInteraction.presentationContext, mediaBox: item.context.account.postbox.mediaBox, messageSelection: itemSelection)
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
@ -3630,10 +3642,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
if self.highlightedState != highlighted {
|
if self.highlightedState != highlighted {
|
||||||
self.highlightedState = highlighted
|
self.highlightedState = highlighted
|
||||||
if let backgroundType = self.backgroundType {
|
if let backgroundType = self.backgroundType {
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: item.context.account.postbox.mediaBox, knockoutWallpaper: item.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.principalGraphics(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper
|
let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper
|
||||||
self.backgroundNode.setType(type: backgroundType, highlighted: highlighted, graphics: graphics, maskMode: self.mainContextSourceNode.isExtractedToContextPreview, hasWallpaper: hasWallpaper, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
|
self.backgroundNode.setType(type: backgroundType, highlighted: highlighted, graphics: graphics, maskMode: self.mainContextSourceNode.isExtractedToContextPreview, hasWallpaper: hasWallpaper, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate, backgroundNode: item.controllerInteraction.presentationContext.backgroundNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
|
|
||||||
let themeUpdated = presentationData.theme != currentTheme || type != currentType
|
let themeUpdated = presentationData.theme != currentTheme || type != currentType
|
||||||
|
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
let isDefaultWallpaper = serviceMessageColorHasDefaultWallpaper(presentationData.theme.wallpaper)
|
let isDefaultWallpaper = serviceMessageColorHasDefaultWallpaper(presentationData.theme.wallpaper)
|
||||||
let offset: CGFloat = -UIScreenPixel
|
let offset: CGFloat = -UIScreenPixel
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||||||
|
|
||||||
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
self.backgroundNode.image = graphics.dateStaticBackground
|
self.backgroundNode.image = graphics.dateStaticBackground
|
||||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||||
@ -198,7 +198,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||||||
let previousPresentationData = self.presentationData
|
let previousPresentationData = self.presentationData
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
self.backgroundNode.image = graphics.dateStaticBackground
|
self.backgroundNode.image = graphics.dateStaticBackground
|
||||||
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
self.stickBackgroundNode.image = graphics.dateFloatingBackground
|
||||||
|
@ -470,7 +470,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
if hasThumbnail {
|
if hasThumbnail {
|
||||||
fileIconImage = nil
|
fileIconImage = nil
|
||||||
} else {
|
} else {
|
||||||
let principalGraphics = PresentationResourcesChat.principalGraphics(mediaBox: context.account.postbox.mediaBox, knockoutWallpaper: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper, theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
let principalGraphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
|
|
||||||
fileIconImage = incoming ? principalGraphics.radialIndicatorFileIconIncoming : principalGraphics.radialIndicatorFileIconOutgoing
|
fileIconImage = incoming ? principalGraphics.radialIndicatorFileIconIncoming : principalGraphics.radialIndicatorFileIconOutgoing
|
||||||
}
|
}
|
||||||
|
@ -538,7 +538,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}, requestMessageUpdate: { _ in
|
}, requestMessageUpdate: { _ in
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
||||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
|
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: self.backgroundNode))
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
|
|
||||||
self.listNode.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
self.listNode.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
||||||
|
@ -155,7 +155,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
|||||||
}, requestMessageUpdate: { _ in
|
}, requestMessageUpdate: { _ in
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: true))
|
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: true), presentationContext: ChatPresentationContext(backgroundNode: nil))
|
||||||
|
|
||||||
self.blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
self.blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
|||||||
}, displayUndo: { _ in
|
}, displayUndo: { _ in
|
||||||
}, requestMessageUpdate: { _ in
|
}, requestMessageUpdate: { _ in
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
|
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: nil))
|
||||||
|
|
||||||
self.dimNode = ASDisplayNode()
|
self.dimNode = ASDisplayNode()
|
||||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
||||||
|
@ -2162,7 +2162,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
}, requestMessageUpdate: { _ in
|
}, requestMessageUpdate: { _ in
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
|
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: nil))
|
||||||
self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in
|
self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
@ -24,6 +24,7 @@ import AlertUI
|
|||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import LocationUI
|
import LocationUI
|
||||||
import AppLock
|
import AppLock
|
||||||
|
import WallpaperBackgroundNode
|
||||||
|
|
||||||
private final class AccountUserInterfaceInUseContext {
|
private final class AccountUserInterfaceInUseContext {
|
||||||
let subscribers = Bag<(Bool) -> Void>()
|
let subscribers = Bag<(Bool) -> Void>()
|
||||||
@ -1218,66 +1219,63 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return PeerSelectionControllerImpl(params)
|
return PeerSelectionControllerImpl(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)? = nil, clickThroughMessage: (() -> Void)? = nil) -> ListViewItem {
|
public func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)? = nil, clickThroughMessage: (() -> Void)? = nil, backgroundNode: ASDisplayNode?) -> ListViewItem {
|
||||||
let controllerInteraction: ChatControllerInteraction
|
let controllerInteraction: ChatControllerInteraction
|
||||||
if tapMessage != nil || clickThroughMessage != nil {
|
|
||||||
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, activateMessagePinch: { _ in
|
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, activateMessagePinch: { _ in
|
||||||
}, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
|
}, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
|
||||||
}, tapMessage: { message in
|
}, tapMessage: { message in
|
||||||
tapMessage?(message)
|
tapMessage?(message)
|
||||||
}, clickThroughMessage: {
|
}, clickThroughMessage: {
|
||||||
clickThroughMessage?()
|
clickThroughMessage?()
|
||||||
}, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in
|
}, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _ in return false }, sendGif: { _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _ in
|
||||||
return false
|
return false
|
||||||
}, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
}, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||||
}, presentController: { _, _ in }, navigationController: {
|
}, presentController: { _, _ in }, navigationController: {
|
||||||
return nil
|
return nil
|
||||||
}, chatControllerNode: {
|
}, chatControllerNode: {
|
||||||
return nil
|
return nil
|
||||||
}, reactionContainerNode: {
|
}, reactionContainerNode: {
|
||||||
return nil
|
return nil
|
||||||
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
|
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
|
||||||
}, canSetupReply: { _ in
|
}, canSetupReply: { _ in
|
||||||
return .none
|
return .none
|
||||||
}, navigateToFirstDateMessage: { _ in
|
}, navigateToFirstDateMessage: { _ in
|
||||||
}, requestRedeliveryOfFailedMessages: { _ in
|
}, requestRedeliveryOfFailedMessages: { _ in
|
||||||
}, addContact: { _ in
|
}, addContact: { _ in
|
||||||
}, rateCall: { _, _, _ in
|
}, rateCall: { _, _, _ in
|
||||||
}, requestSelectMessagePollOptions: { _, _ in
|
}, requestSelectMessagePollOptions: { _, _ in
|
||||||
}, requestOpenMessagePollResults: { _, _ in
|
}, requestOpenMessagePollResults: { _, _ in
|
||||||
}, openAppStorePage: {
|
}, openAppStorePage: {
|
||||||
}, displayMessageTooltip: { _, _, _, _ in
|
}, displayMessageTooltip: { _, _, _, _ in
|
||||||
}, seekToTimecode: { _, _, _ in
|
}, seekToTimecode: { _, _, _ in
|
||||||
}, scheduleCurrentMessage: {
|
}, scheduleCurrentMessage: {
|
||||||
}, sendScheduledMessagesNow: { _ in
|
}, sendScheduledMessagesNow: { _ in
|
||||||
}, editScheduledMessagesTime: { _ in
|
}, editScheduledMessagesTime: { _ in
|
||||||
}, performTextSelectionAction: { _, _, _ in
|
}, performTextSelectionAction: { _, _, _ in
|
||||||
}, updateMessageLike: { _, _ in
|
}, updateMessageLike: { _, _ in
|
||||||
}, openMessageReactions: { _ in
|
}, openMessageReactions: { _ in
|
||||||
}, displayImportedMessageTooltip: { _ in
|
}, displayImportedMessageTooltip: { _ in
|
||||||
}, displaySwipeToReplyHint: {
|
}, displaySwipeToReplyHint: {
|
||||||
}, dismissReplyMarkupMessage: { _ in
|
}, dismissReplyMarkupMessage: { _ in
|
||||||
}, openMessagePollResults: { _, _ in
|
}, openMessagePollResults: { _, _ in
|
||||||
}, openPollCreation: { _ in
|
}, openPollCreation: { _ in
|
||||||
}, displayPollSolution: { _, _ in
|
}, displayPollSolution: { _, _ in
|
||||||
}, displayPsa: { _, _ in
|
}, displayPsa: { _, _ in
|
||||||
}, displayDiceTooltip: { _ in
|
}, displayDiceTooltip: { _ in
|
||||||
}, animateDiceSuccess: { _ in
|
}, animateDiceSuccess: { _ in
|
||||||
}, openPeerContextMenu: { _, _, _, _, _ in
|
}, openPeerContextMenu: { _, _, _, _, _ in
|
||||||
}, openMessageReplies: { _, _, _ in
|
}, openMessageReplies: { _, _, _ in
|
||||||
}, openReplyThreadOriginalMessage: { _ in
|
}, openReplyThreadOriginalMessage: { _ in
|
||||||
}, openMessageStats: { _ in
|
}, openMessageStats: { _ in
|
||||||
}, editMessageMedia: { _, _ in
|
}, editMessageMedia: { _, _ in
|
||||||
}, copyText: { _ in
|
}, copyText: { _ in
|
||||||
}, displayUndo: { _ in
|
}, displayUndo: { _ in
|
||||||
}, requestMessageUpdate: { _ in
|
}, requestMessageUpdate: { _ in
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))
|
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: backgroundNode as? WallpaperBackgroundNode))
|
||||||
} else {
|
|
||||||
controllerInteraction = defaultChatControllerInteraction
|
|
||||||
}
|
|
||||||
|
|
||||||
let content: ChatMessageItemContent
|
let content: ChatMessageItemContent
|
||||||
let chatLocation: ChatLocation
|
let chatLocation: ChatLocation
|
||||||
|
@ -1,12 +1,2 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class Weak<T: AnyObject> {
|
|
||||||
private weak var _value: T?
|
|
||||||
var value: T? {
|
|
||||||
return self._value
|
|
||||||
}
|
|
||||||
|
|
||||||
init(_ value: T) {
|
|
||||||
self._value = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -504,8 +504,9 @@ public final class OngoingGroupCallContext {
|
|||||||
mainView?.updateIsEnabled(value)
|
mainView?.updateIsEnabled(value)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let cloneVideoView = cloneView.flatMap { cloneView in
|
var cloneVideoView: OngoingCallContextPresentationCallVideoView?
|
||||||
return OngoingCallContextPresentationCallVideoView(
|
if let cloneView = cloneView {
|
||||||
|
cloneVideoView = OngoingCallContextPresentationCallVideoView(
|
||||||
view: cloneView,
|
view: cloneView,
|
||||||
setOnFirstFrameReceived: { [weak cloneView] f in
|
setOnFirstFrameReceived: { [weak cloneView] f in
|
||||||
cloneView?.setOnFirstFrameReceived(f)
|
cloneView?.setOnFirstFrameReceived(f)
|
||||||
|
@ -220,6 +220,16 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if component.contains("~") {
|
||||||
|
let components = component.components(separatedBy: "~")
|
||||||
|
if components.count >= 1 && components.count <= 4 {
|
||||||
|
let colors = components.compactMap { component in
|
||||||
|
return UIColor(hexString: component)?.rgb
|
||||||
|
}
|
||||||
|
parameter = .gradient(colors, nil)
|
||||||
|
} else {
|
||||||
|
parameter = .color(UIColor(rgb: 0xffffff))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var options: WallpaperPresentationOptions = []
|
var options: WallpaperPresentationOptions = []
|
||||||
var intensity: Int32?
|
var intensity: Int32?
|
||||||
|
@ -14,6 +14,159 @@ import Postbox
|
|||||||
private let motionAmount: CGFloat = 32.0
|
private let motionAmount: CGFloat = 32.0
|
||||||
|
|
||||||
public final class WallpaperBackgroundNode: ASDisplayNode {
|
public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||||
|
public final class BubbleBackgroundNode: ASDisplayNode {
|
||||||
|
public enum BubbleType {
|
||||||
|
case incoming
|
||||||
|
case outgoing
|
||||||
|
}
|
||||||
|
|
||||||
|
private let bubbleType: BubbleType
|
||||||
|
private let contentNode: ASImageNode
|
||||||
|
|
||||||
|
private var cleanWallpaperNode: ASDisplayNode?
|
||||||
|
private var gradientWallpaperNode: GradientBackgroundNode.CloneNode?
|
||||||
|
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||||
|
private var index: SparseBag<BubbleBackgroundNode>.Index?
|
||||||
|
|
||||||
|
init(backgroundNode: WallpaperBackgroundNode, bubbleType: BubbleType) {
|
||||||
|
self.backgroundNode = backgroundNode
|
||||||
|
self.bubbleType = bubbleType
|
||||||
|
|
||||||
|
self.contentNode = ASImageNode()
|
||||||
|
self.contentNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.contentNode)
|
||||||
|
|
||||||
|
self.index = backgroundNode.bubbleBackgroundNodeReferences.add(BubbleBackgroundNodeReference(node: self))
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
if let index = self.index, let backgroundNode = self.backgroundNode {
|
||||||
|
backgroundNode.bubbleBackgroundNodeReferences.remove(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateContents() {
|
||||||
|
guard let backgroundNode = self.backgroundNode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let bubbleTheme = backgroundNode.bubbleTheme, let wallpaper = backgroundNode.wallpaper, let bubbleCorners = backgroundNode.bubbleCorners {
|
||||||
|
let graphics = PresentationResourcesChat.principalGraphics(theme: bubbleTheme, wallpaper: wallpaper, bubbleCorners: bubbleCorners)
|
||||||
|
var needsCleanBackground = false
|
||||||
|
self.contentNode.backgroundColor = backgroundNode.contentNode.backgroundColor
|
||||||
|
switch self.bubbleType {
|
||||||
|
case .incoming:
|
||||||
|
self.contentNode.image = graphics.incomingBubbleGradientImage
|
||||||
|
needsCleanBackground = bubbleTheme.chat.message.incoming.bubble.withWallpaper.fill.alpha <= 0.99 || bubbleTheme.chat.message.incoming.bubble.withWallpaper.gradientFill.alpha <= 0.99
|
||||||
|
case .outgoing:
|
||||||
|
self.contentNode.image = graphics.outgoingBubbleGradientImage
|
||||||
|
needsCleanBackground = bubbleTheme.chat.message.outgoing.bubble.withWallpaper.fill.alpha <= 0.99 || bubbleTheme.chat.message.outgoing.bubble.withWallpaper.gradientFill.alpha <= 0.99
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasComplexGradient = false
|
||||||
|
switch wallpaper {
|
||||||
|
case let .file(_, _, _, _, isPattern, _, _, _, settings):
|
||||||
|
hasComplexGradient = settings.colors.count >= 3
|
||||||
|
if !isPattern {
|
||||||
|
needsCleanBackground = false
|
||||||
|
}
|
||||||
|
case let .gradient(colors, _):
|
||||||
|
hasComplexGradient = colors.count >= 3
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var needsGradientBackground = false
|
||||||
|
var needsWallpaperBackground = false
|
||||||
|
|
||||||
|
if needsCleanBackground {
|
||||||
|
if hasComplexGradient {
|
||||||
|
needsGradientBackground = backgroundNode.gradientBackgroundNode != nil
|
||||||
|
} else {
|
||||||
|
needsWallpaperBackground = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if needsWallpaperBackground {
|
||||||
|
if self.cleanWallpaperNode == nil {
|
||||||
|
let cleanWallpaperNode = ASImageNode()
|
||||||
|
self.cleanWallpaperNode = cleanWallpaperNode
|
||||||
|
cleanWallpaperNode.frame = self.contentNode.frame
|
||||||
|
self.insertSubnode(cleanWallpaperNode, at: 0)
|
||||||
|
}
|
||||||
|
self.cleanWallpaperNode?.contents = backgroundNode.contentNode.contents
|
||||||
|
} else {
|
||||||
|
if let cleanWallpaperNode = self.cleanWallpaperNode {
|
||||||
|
self.cleanWallpaperNode = nil
|
||||||
|
cleanWallpaperNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if needsGradientBackground, let gradientBackgroundNode = backgroundNode.gradientBackgroundNode {
|
||||||
|
if self.gradientWallpaperNode == nil {
|
||||||
|
let gradientWallpaperNode = GradientBackgroundNode.CloneNode(parentNode: gradientBackgroundNode)
|
||||||
|
gradientWallpaperNode.frame = self.contentNode.frame
|
||||||
|
self.gradientWallpaperNode = gradientWallpaperNode
|
||||||
|
self.insertSubnode(gradientWallpaperNode, at: 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let gradientWallpaperNode = self.gradientWallpaperNode {
|
||||||
|
self.gradientWallpaperNode = nil
|
||||||
|
gradientWallpaperNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.contentNode.image = nil
|
||||||
|
if let cleanWallpaperNode = self.cleanWallpaperNode {
|
||||||
|
self.cleanWallpaperNode = nil
|
||||||
|
cleanWallpaperNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update(rect: CGRect, within containerSize: CGSize) {
|
||||||
|
self.contentNode.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
||||||
|
if let cleanWallpaperNode = self.cleanWallpaperNode {
|
||||||
|
cleanWallpaperNode.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
||||||
|
}
|
||||||
|
if let gradientWallpaperNode = self.gradientWallpaperNode {
|
||||||
|
gradientWallpaperNode.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
||||||
|
let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: animationCurve)
|
||||||
|
transition.animatePositionAdditive(node: self.contentNode, offset: CGPoint(x: -value.x, y: -value.y))
|
||||||
|
if let cleanWallpaperNode = self.cleanWallpaperNode {
|
||||||
|
transition.animatePositionAdditive(node: cleanWallpaperNode, offset: CGPoint(x: -value.x, y: -value.y))
|
||||||
|
}
|
||||||
|
if let gradientWallpaperNode = self.gradientWallpaperNode {
|
||||||
|
transition.animatePositionAdditive(node: gradientWallpaperNode, offset: CGPoint(x: -value.x, y: -value.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
||||||
|
self.contentNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: value)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: duration, initialVelocity: 0.0, damping: damping, additive: true)
|
||||||
|
if let cleanWallpaperNode = self.cleanWallpaperNode {
|
||||||
|
cleanWallpaperNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: value)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: duration, initialVelocity: 0.0, damping: damping, additive: true)
|
||||||
|
}
|
||||||
|
if let gradientWallpaperNode = self.gradientWallpaperNode {
|
||||||
|
gradientWallpaperNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: 0.0, y: value)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: duration, initialVelocity: 0.0, damping: damping, additive: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class BubbleBackgroundNodeReference {
|
||||||
|
weak var node: BubbleBackgroundNode?
|
||||||
|
|
||||||
|
init(node: BubbleBackgroundNode) {
|
||||||
|
self.node = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
|
|
||||||
private let contentNode: ASDisplayNode
|
private let contentNode: ASDisplayNode
|
||||||
@ -24,6 +177,10 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
private var wallpaper: TelegramWallpaper?
|
private var wallpaper: TelegramWallpaper?
|
||||||
|
|
||||||
private let patternImageDisposable = MetaDisposable()
|
private let patternImageDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private var bubbleTheme: PresentationTheme?
|
||||||
|
private var bubbleCorners: PresentationChatBubbleCorners?
|
||||||
|
private var bubbleBackgroundNodeReferences = SparseBag<BubbleBackgroundNodeReference>()
|
||||||
|
|
||||||
private var motionEnabled: Bool = false {
|
private var motionEnabled: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
@ -206,6 +363,8 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
self.patternImageNode.isHidden = true
|
self.patternImageNode.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.updateBubbles()
|
||||||
|
|
||||||
if let size = self.validLayout {
|
if let size = self.validLayout {
|
||||||
self.updateLayout(size: size, transition: .immediate)
|
self.updateLayout(size: size, transition: .immediate)
|
||||||
}
|
}
|
||||||
@ -236,4 +395,51 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
public func animateEvent(transition: ContainedViewLayoutTransition) {
|
public func animateEvent(transition: ContainedViewLayoutTransition) {
|
||||||
self.gradientBackgroundNode?.animateEvent(transition: transition)
|
self.gradientBackgroundNode?.animateEvent(transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func updateBubbleTheme(bubbleTheme: PresentationTheme, bubbleCorners: PresentationChatBubbleCorners) {
|
||||||
|
if self.bubbleTheme !== bubbleTheme || self.bubbleCorners != bubbleCorners {
|
||||||
|
self.bubbleTheme = bubbleTheme
|
||||||
|
self.bubbleCorners = bubbleCorners
|
||||||
|
|
||||||
|
self.updateBubbles()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateBubbles() {
|
||||||
|
for reference in self.bubbleBackgroundNodeReferences {
|
||||||
|
reference.node?.updateContents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hasBubbleBackground(for type: WallpaperBackgroundNode.BubbleBackgroundNode.BubbleType) -> Bool {
|
||||||
|
guard let bubbleTheme = self.bubbleTheme, let wallpaper = self.wallpaper, let bubbleCorners = self.bubbleCorners else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let graphics = PresentationResourcesChat.principalGraphics(theme: bubbleTheme, wallpaper: wallpaper, bubbleCorners: bubbleCorners)
|
||||||
|
switch type {
|
||||||
|
case .incoming:
|
||||||
|
if graphics.incomingBubbleGradientImage != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if bubbleTheme.chat.message.incoming.bubble.withWallpaper.fill.alpha <= 0.99 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case .outgoing:
|
||||||
|
if graphics.outgoingBubbleGradientImage != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if bubbleTheme.chat.message.incoming.bubble.withWallpaper.fill.alpha <= 0.99 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeBubbleBackground(for type: WallpaperBackgroundNode.BubbleBackgroundNode.BubbleType) -> WallpaperBackgroundNode.BubbleBackgroundNode? {
|
||||||
|
let node = WallpaperBackgroundNode.BubbleBackgroundNode(backgroundNode: self, bubbleType: type)
|
||||||
|
node.updateContents()
|
||||||
|
return node
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,25 +584,38 @@ public func gradientImage(_ colors: [UIColor], rotation: Int32? = nil) -> Signal
|
|||||||
}
|
}
|
||||||
return .single({ arguments in
|
return .single({ arguments in
|
||||||
let context = DrawingContext(size: arguments.drawingSize, clear: !arguments.corners.isEmpty)
|
let context = DrawingContext(size: arguments.drawingSize, clear: !arguments.corners.isEmpty)
|
||||||
|
|
||||||
|
let drawingRect = arguments.drawingRect
|
||||||
|
|
||||||
context.withContext { c in
|
context.withContext { c in
|
||||||
let gradientColors = colors.map { $0.withAlphaComponent(1.0).cgColor } as CFArray
|
if colors.count >= 3 {
|
||||||
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
let image = GradientBackgroundNode.generatePreview(size: CGSize(width: 60.0, height: 60.0), colors: colors)
|
||||||
|
c.translateBy(x: drawingRect.midX, y: drawingRect.midY)
|
||||||
var locations: [CGFloat] = []
|
c.scaleBy(x: 1.0, y: -1.0)
|
||||||
for i in 0 ..< colors.count {
|
c.translateBy(x: -drawingRect.midX, y: -drawingRect.midY)
|
||||||
locations.append(delta * CGFloat(i))
|
c.draw(image.cgImage!, in: drawingRect)
|
||||||
}
|
c.translateBy(x: drawingRect.midX, y: drawingRect.midY)
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
c.scaleBy(x: 1.0, y: -1.0)
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
c.translateBy(x: -drawingRect.midX, y: -drawingRect.midY)
|
||||||
|
} else {
|
||||||
|
let gradientColors = colors.map { $0.withAlphaComponent(1.0).cgColor } as CFArray
|
||||||
|
let delta: CGFloat = 1.0 / (CGFloat(colors.count) - 1.0)
|
||||||
|
|
||||||
if let rotation = rotation {
|
var locations: [CGFloat] = []
|
||||||
c.translateBy(x: arguments.drawingSize.width / 2.0, y: arguments.drawingSize.height / 2.0)
|
for i in 0 ..< colors.count {
|
||||||
c.rotate(by: CGFloat(rotation) * CGFloat.pi / 180.0)
|
locations.append(delta * CGFloat(i))
|
||||||
c.translateBy(x: -arguments.drawingSize.width / 2.0, y: -arguments.drawingSize.height / 2.0)
|
}
|
||||||
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
|
||||||
|
|
||||||
|
if let rotation = rotation {
|
||||||
|
c.translateBy(x: arguments.drawingSize.width / 2.0, y: arguments.drawingSize.height / 2.0)
|
||||||
|
c.rotate(by: CGFloat(rotation) * CGFloat.pi / 180.0)
|
||||||
|
c.translateBy(x: -arguments.drawingSize.width / 2.0, y: -arguments.drawingSize.height / 2.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: arguments.drawingSize.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
||||||
}
|
}
|
||||||
|
|
||||||
c.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: arguments.drawingSize.height), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addCorners(context, arguments: arguments)
|
addCorners(context, arguments: arguments)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user